Skip to content

fix(browser/vnc): make end-to-end browser integration work on Jetson - #66

Merged
KrasimirKralev merged 4 commits into
ID-Robots:betafrom
KrasimirKralev:fix/browser-integration-config-timeout
Apr 18, 2026
Merged

KrasimirKralev merged 4 commits into
ID-Robots:betafrom
KrasimirKralev:fix/browser-integration-config-timeout

Conversation

@KrasimirKralev

@KrasimirKralev KrasimirKralev commented Apr 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Three coordinated fixes so Steps 1–3 of the browser integration page all succeed on a fresh Jetson Orin install, plus bidirectional VNC clipboard so the user can actually type into the remote browser.

Commits

  1. fix(browser): bump openclaw config set timeout from 10s β†’ 30s (CLI startup is ~10.5s on Jetson, so 10s times out every time), and surface config-set errors as HTTP 500 instead of swallowing and continuing. Fixes Step 2 stuck forever on "Enabling…".
  2. fix(vnc): add CLAWBOX_VNC_MODE=virtual env override and wire it into clawbox-vnc.service. On Jetson, :0 is GDM's greeter β€” apps launched into it are covered and invisible to VNC. Forcing the Xvfb :99 path gives a clean surface the browser service and VNC viewer share.
  3. feat(vnc): bidirectional clipboard β€” noVNC clipboard event β†’ host clipboard write (guest β†’ host works out of the box). Host β†’ guest needs secure context for navigator.clipboard.readText, which fails on LAN HTTP β€” added a "πŸ“‹ Paste to VNC" toolbar button that opens a textarea modal where paste works natively; clicking Send calls rfb.clipboardPasteFrom. Server-side adds autocutsel to keep X CLIPBOARD / PRIMARY alive across windows.

Test plan

  • Jetson: Step 2 "Activate" completes and UI shows "enabled" (was stuck on "Enabling…")
  • Jetson: VNC viewer shows the dark virtual desktop + Chromium window (was NVIDIA wallpaper only)
  • Jetson: paste-modal round-trip β€” PC text β†’ modal β†’ guest Chromium address bar
  • Jetson: guest select+copy β†’ host clipboard β†’ paste into other app on PC
  • Fresh install on a Jetson without VNC pre-installed β€” install.sh picks up autocutsel

Summary by CodeRabbit

  • New Features

    • Added text pasting functionality for remote VNC sessions with modal interface and Ctrl/Cmd+V shortcut support.
    • Implemented bidirectional clipboard integration between remote and host environments.
    • Enhanced virtual desktop mode with improved clipboard persistence.
  • Improvements

    • Increased command execution timeouts for browser operations.
    • Enhanced error handling with detailed HTTP responses.
    • Simplified service startup dependencies.
  • Documentation

    • Added multi-language translations for paste feature across 8+ languages.

… to UI

On Jetson Orin, the openclaw CLI takes ~10.5s just to start up
(measured via 'time openclaw config get'). The browser/manage route
used a 10-second timeout on both 'config set' calls, so the first
set routinely timed out, the second never ran, persistBrowserEnabled(true)
never wrote the flag, and the UI stuck forever at 'Enabling...' because
subsequent status polls kept returning enabled: false.

Changes:
- All 'openclaw config set' calls in enable/disable use a 30s timeout
  (3x headroom over observed CLI startup).
- When config set throws, return 500 with the error instead of swallowing
  it and continuing to restart the gateway. The UI now shows a real error
  instead of infinite spinner.
On a Jetson, :0 is owned by GDM. Even when GDM's Xauthority is shared
with the clawbox user, windows drawn on :0 by apps launched through
the clawbox-browser.service are hidden by the GDM greeter β€” the user
sees only the NVIDIA wallpaper and no Chromium. start-vnc.sh took the
mirror-:0 path whenever :0 was reachable, which on Jetson is always.

Changes:
- start-vnc.sh honors $CLAWBOX_VNC_MODE. When set to 'virtual', skips
  the :0 mirror attempt and goes straight to the Xvfb :99 path. The
  existing auto behavior is preserved when the env var is unset.
- clawbox-vnc.service now sets Environment=CLAWBOX_VNC_MODE=virtual.
  This matches where the browser service launches Chromium (DISPLAY=:99)
  so both the browser and the VNC viewer share one Xvfb surface.
Adds copy/paste between the host browser and the VNC guest.

Server-side (start-vnc.sh + install.sh):
- Install and run autocutsel on the VNC :99 display to keep X CLIPBOARD
  and PRIMARY selections alive between windows. Without it, selections
  vanish when the owning window loses focus, breaking paste across apps.

Client-side (VNCApp.tsx):
- Listen to noVNC's 'clipboard' event and mirror the remote's cut-text
  into the host browser's clipboard via navigator.clipboard.writeText
  (works on insecure origins). Guest β†’ host copy 'just works'.
- The 'paste' DOM event never fires on a canvas, so Ctrl+V inside the
  VNC surface wouldn't inject the host clipboard. Added a keydown
  handler for Ctrl/Cmd+V that calls navigator.clipboard.readText() and
  forwards via rfb.clipboardPasteFrom. Secure-context only (silently
  no-ops on plain HTTP LAN URLs like http://clawbox.local).
- For the HTTP-LAN case added a visible 'Paste to VNC' toolbar button
  (top-right of the surface). Opens a modal with a textarea β€” the user
  pastes into the textarea (Ctrl+V works natively in textareas), clicks
  Send, and the text lands in the guest X CLIPBOARD. Round-trip confirmed
  on the Jetson where Chrome blocks clipboard.readText over HTTP.
- Freeze the VNC-input focus/key handlers while the modal is open so
  the textarea keeps focus for the native paste.

Translations (en + bg + de + es + fr + it + ja + nl + sv + zh):
- vnc.pasteToRemote, vnc.pasteHelp, vnc.pastePlaceholder, vnc.sendPaste
@coderabbitai

coderabbitai Bot commented Apr 18, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@KrasimirKralev has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 44 minutes and 0 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 44 minutes and 0 seconds.

βŒ› How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
βš™οΈ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: cc1ac71d-b176-41da-8c5e-78842e1a8ba3

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 036c2ac and 71af7ef.

πŸ“’ Files selected for processing (2)
  • src/app/setup-api/browser/manage/route.ts
  • src/components/VNCApp.tsx
πŸ“ Walkthrough

Walkthrough

The changes introduce a VNC paste-to-remote feature with bidirectional clipboard support, refactor the VNC service to support virtual desktop mode with clipboard persistence via autocutsel, increase operation timeouts for browser service config updates to 30 seconds, and add comprehensive localization for the new paste UI across eight languages.

Changes

Cohort / File(s) Summary
VNC Service Configuration
install.sh, scripts/start-vnc.sh
Updated VNC service to use CLAWBOX_VNC_MODE=virtual, removed GDM display-manager dependency, and added autocutsel to persist clipboard/PRIMARY selection in virtual desktop mode. Service now conditionally mirrors display :0 only when not in virtual mode.
VNC Paste Feature UI
src/components/VNCApp.tsx
Added modal-driven paste interface with bidirectional clipboard sync: clipboard event listener copies guest clipboard to host; Ctrl+V interception reads host clipboard and forwards to remote via clipboardPasteFrom. Includes focus guards, paste modal state management, and textarea input with send/cancel actions.
VNC Paste Localization
src/lib/desktop-translations.ts, src/lib/desktop-translations-part1.ts, src/lib/desktop-translations-part2.ts, src/lib/desktop-translations-part3.ts
Added four new i18n keys (vnc.pasteToRemote, vnc.pasteHelp, vnc.pastePlaceholder, vnc.sendPaste) across English, Bulgarian, German, Spanish, French, Italian, Japanese, Dutch, Swedish, and Chinese translation maps.
Browser Service Operation Handling
src/app/setup-api/browser/manage/route.ts
Increased command execution timeouts from 10s to 30s for openclawBin config updates and service shutdown. Added explicit HTTP 500 JSON error responses (with error message) on execution failures instead of silent logging.

Sequence Diagram(s)

sequenceDiagram
    participant User as User (Host)
    participant VNC as VNC App
    participant ClipboardAPI as Browser Clipboard API
    participant Remote as Remote Session (VNC Server)
    
    User->>VNC: Click "Paste to Remote" button
    VNC->>VNC: Open paste modal
    User->>VNC: Paste clipboard into textarea (or Ctrl+V)
    VNC->>ClipboardAPI: navigator.clipboard.readText()
    ClipboardAPI-->>VNC: Return clipboard text
    VNC->>VNC: Display text in modal textarea
    User->>VNC: Click "Send" or Ctrl+Cmd+Enter
    VNC->>Remote: clipboardPasteFrom(text)
    Remote-->>VNC: Clipboard updated on remote
    
    Note over Remote: Remote application can paste (Ctrl+V) from clipboard
    
    Remote->>VNC: clipboard event (guest copied text)
    VNC->>ClipboardAPI: navigator.clipboard.writeText(guestText)
    ClipboardAPI-->>User: Host clipboard updated
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 A rabbit hops through clipboards bright,
Pasting text with modal might,
Ctrl+V whispers cross the wire,
Remote desktops now inspire! βœ¨πŸ“‹

πŸš₯ Pre-merge checks | βœ… 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
βœ… Passed checks (2 passed)
Check name Status Explanation
Title check βœ… Passed The title clearly and concisely summarizes the main objective: fixing browser integration on Jetson hardware by addressing VNC configuration issues.
Description check βœ… Passed The description provides a comprehensive summary of the changes, detailed commit descriptions, and a test plan, though testing checklist boxes are unchecked.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❀️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@KrasimirKralev
KrasimirKralev marked this pull request as ready for review April 18, 2026 14:21
@KrasimirKralev
KrasimirKralev requested a review from a team as a code owner April 18, 2026 14:21
@KrasimirKralev

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Apr 18, 2026

Copy link
Copy Markdown
βœ… Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@KrasimirKralev

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Apr 18, 2026

Copy link
Copy Markdown
βœ… Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

πŸ€– Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@install.sh`:
- Around line 970-992: The VNC systemd unit and related bits are only installed
by step_vnc_install, so existing installs won't get the updated
clawbox-vnc.service (with Environment=CLAWBOX_VNC_MODE=virtual) or the
autocutsel package; to fix, move the clawbox-vnc.service template out of
step_vnc_install into the shared config directory (e.g., config/) and add
deployment of that unit from step_systemd_services (or alternatively add an
idempotent refresh routine called during rebuild/update that reinstalls
autocutsel, updates start-vnc.sh/ensure-vnc-on-first-boot.sh ownership/perm, and
runs systemctl daemon-reload + systemctl restart/enable clawbox-vnc.service);
update references to start-vnc.sh, ensure-vnc-on-first-boot.sh, and the service
unit to ensure CLAWBOX_VNC_MODE=virtual is present and the unit is consistently
applied across installs.

In `@src/app/setup-api/browser/manage/route.ts`:
- Line 327: The handler that runs exec("/usr/bin/sudo", ["/usr/bin/systemctl",
"stop", "clawbox-browser.service"], { timeout: 30000 }) currently swallows
errors with an empty catch; update that catch in the close-browser route to at
least log the failure (e.g., console.warn or the module's logger like
processLogger.warn) including the error object and a short context message so
failures of systemctl stop are visible for debugging without changing the
fallback behavior (leave pkill + lock cleanup intact).

In `@src/components/VNCApp.tsx`:
- Around line 417-459: The modal markup for pasteOpen lacks dialog semantics and
the textarea lacks an accessible label; update the container to include
role="dialog" and aria-modal="true" and wire aria-labelledby to the modal title
(give the h3 a stable id like paste-dialog-title) and aria-describedby to the
help paragraph (give it an id like paste-dialog-desc), then add aria-labelledby
(or aria-label) on the textareaRef-controlled element (pasteTextareaRef)
pointing to that title/id so screen readers announce the dialog and textarea
properly; keep existing keyboard handlers (sendPaste, closePasteModal) and
ensure the title ids match the strings used in the JSX.
- Around line 217-235: The onKeyDown handler (used with pasteOpenRef,
vncFocusedRef and rfbRef.current.clipboardPasteFrom) must prevent the original
Ctrl/Cmd+V from propagating before starting the async
navigator.clipboard.readText: call event.preventDefault() and
event.stopPropagation() immediately once isPasteShortcut is detected, then
perform readText() and call rfbRef.current.clipboardPasteFrom(text) and only
after that (or on read error) call sendKey to emit the remote paste keystroke;
also ensure releaseRemoteModifiers is included in the useEffect dependency array
that registers onKeyDown so the closure sees it.
πŸͺ„ Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
βš™οΈ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a225002e-fa2b-43c9-acb8-5416c1f4a293

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 8676a95 and 036c2ac.

πŸ“’ Files selected for processing (8)
  • install.sh
  • scripts/start-vnc.sh
  • src/app/setup-api/browser/manage/route.ts
  • src/components/VNCApp.tsx
  • src/lib/desktop-translations-part1.ts
  • src/lib/desktop-translations-part2.ts
  • src/lib/desktop-translations-part3.ts
  • src/lib/desktop-translations.ts

Comment thread install.sh
Comment on lines 970 to 992
step_vnc_install() {
# Install x11vnc, Xvfb (virtual framebuffer fallback), websockify, and a lightweight WM
apt-get install -y x11vnc xvfb websockify dbus-x11 openbox xterm x11-xserver-utils
apt-get install -y x11vnc xvfb websockify dbus-x11 openbox xterm x11-xserver-utils autocutsel

chmod +x "$PROJECT_DIR/scripts/start-vnc.sh"
chown "$CLAWBOX_USER:$CLAWBOX_USER" "$PROJECT_DIR/scripts/start-vnc.sh"
chmod +x "$PROJECT_DIR/scripts/ensure-vnc-on-first-boot.sh"
chown root:root "$PROJECT_DIR/scripts/ensure-vnc-on-first-boot.sh"

# Systemd service for VNC
# Systemd service for VNC β€” force virtual display mode. On headless
# Jetsons, :0 is GDM's greeter; apps launched into it are covered by
# the greeter and invisible to VNC viewers. Xvfb :99 gives a clean
# dedicated surface that matches what the browser service targets.
cat > /etc/systemd/system/clawbox-vnc.service <<VNCSVC
[Unit]
Description=ClawBox VNC (mirrors display or virtual desktop)
After=display-manager.service network.target
Description=ClawBox VNC (virtual desktop)
After=network.target

[Service]
Type=simple
User=$CLAWBOX_USER
Environment=CLAWBOX_VNC_MODE=virtual
ExecStart=$PROJECT_DIR/scripts/start-vnc.sh

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Ensure the VNC fix is applied on existing installs.

Line 972 and Lines 983-992 only run from step_vnc_install; the update paths shown in this file don’t call that step, so already-installed devices can keep the old clawbox-vnc.service without CLAWBOX_VNC_MODE=virtual and without autocutsel. Move the service into config/ and deploy it from step_systemd_services, or invoke an idempotent VNC service/package refresh during rebuild/update.

πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@install.sh` around lines 970 - 992, The VNC systemd unit and related bits are
only installed by step_vnc_install, so existing installs won't get the updated
clawbox-vnc.service (with Environment=CLAWBOX_VNC_MODE=virtual) or the
autocutsel package; to fix, move the clawbox-vnc.service template out of
step_vnc_install into the shared config directory (e.g., config/) and add
deployment of that unit from step_systemd_services (or alternatively add an
idempotent refresh routine called during rebuild/update that reinstalls
autocutsel, updates start-vnc.sh/ensure-vnc-on-first-boot.sh ownership/perm, and
runs systemctl daemon-reload + systemctl restart/enable clawbox-vnc.service);
update references to start-vnc.sh, ensure-vnc-on-first-boot.sh, and the service
unit to ensure CLAWBOX_VNC_MODE=virtual is present and the unit is consistently
applied across installs.

Comment thread src/app/setup-api/browser/manage/route.ts
Comment thread src/components/VNCApp.tsx
Comment on lines +217 to +235
const onKeyDown = (event: KeyboardEvent) => {
if (pasteOpenRef.current) return;
if (!vncFocusedRef.current) return;
const isPasteShortcut =
(event.ctrlKey || event.metaKey) &&
!event.shiftKey &&
!event.altKey &&
event.key.toLowerCase() === "v";
if (!isPasteShortcut) return;
if (!navigator.clipboard?.readText) return;
navigator.clipboard
.readText()
.then((text) => {
if (text) rfbRef.current?.clipboardPasteFrom(text);
})
.catch(() => {
// Non-secure origin or clipboard permission denied β€” silently skip.
});
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, verify the file exists and check its size
wc -l src/components/VNCApp.tsx

Repository: ID-Robots/clawbox

Length of output: 90


🏁 Script executed:

# Read the VNCApp.tsx file with line numbers, focusing on the area around lines 217-235
cat -n src/components/VNCApp.tsx | sed -n '200,250p'

Repository: ID-Robots/clawbox

Length of output: 2871


🏁 Script executed:

# Find the useCallback definition that wraps this onKeyDown handler
cat -n src/components/VNCApp.tsx | sed -n '180,220p'

Repository: ID-Robots/clawbox

Length of output: 2221


🏁 Script executed:

# Look further up to find the useCallback or useEffect that contains these handlers
cat -n src/components/VNCApp.tsx | sed -n '140,185p'

Repository: ID-Robots/clawbox

Length of output: 1906


🏁 Script executed:

# Find the end of the useEffect (the dependency array)
cat -n src/components/VNCApp.tsx | sed -n '235,280p'

Repository: ID-Robots/clawbox

Length of output: 2715


🏁 Script executed:

# Search for releaseRemoteModifiers function
rg -n "releaseRemoteModifiers" src/components/VNCApp.tsx

Repository: ID-Robots/clawbox

Length of output: 293


🏁 Script executed:

# Read the releaseRemoteModifiers definition and surrounding context
cat -n src/components/VNCApp.tsx | sed -n '80,110p'

Repository: ID-Robots/clawbox

Length of output: 1236


🏁 Script executed:

# Check for sendKey calls and understand the API
rg -n "sendKey" src/components/VNCApp.tsx -A 1 -B 1

Repository: ID-Robots/clawbox

Length of output: 885


🏁 Script executed:

# Search for other keydown listeners or handlers that might process the event
rg -n "keydown|keypress|keyup" src/components/VNCApp.tsx -i

Repository: ID-Robots/clawbox

Length of output: 1259


🏁 Script executed:

# Let's examine the handleKeyDown function that processes keydown events
cat -n src/components/VNCApp.tsx | sed -n '276,310p'

Repository: ID-Robots/clawbox

Length of output: 1643


🏁 Script executed:

# Check the comment about noVNC forwarding keys and understand the event flow
cat -n src/components/VNCApp.tsx | sed -n '205,215p'

Repository: ID-Robots/clawbox

Length of output: 904


🏁 Script executed:

# Verify the sendKey method signature with keysym values like 0xffe3
rg -n "0xffe3|0x0076|ControlLeft|KeyV" src/components/

Repository: ID-Robots/clawbox

Length of output: 132


🏁 Script executed:

# Verify the KeyV keysym value
rg -n "KeyV|0x0076" src/components/

Repository: ID-Robots/clawbox

Length of output: 43


🏁 Script executed:

# Search for key mappings and getTrackedVncKey function
rg -n "getTrackedVncKey|keysym" src/components/VNCApp.tsx -A 2 -B 2 | head -50

Repository: ID-Robots/clawbox

Length of output: 1828


🏁 Script executed:

# Check the vnc-keys file to understand keysym values for V
find src -name "*vnc-keys*" -o -name "*keys*" | grep -v node_modules

Repository: ID-Robots/clawbox

Length of output: 80


🏁 Script executed:

# Read the vnc-keys file to understand key mappings
cat -n src/lib/vnc-keys.ts | head -80

Repository: ID-Robots/clawbox

Length of output: 2400


Prevent the original paste shortcut from propagating until the host clipboard is pushed to the remote.

The onKeyDown handler starts an async clipboard.readText() without preventing event propagation. Meanwhile, the document's handleKeyDown listener (lines 284–305) checks if (e.defaultPrevented) return and will forward the Ctrl/Cmd+V keystroke to the remote immediately, before clipboardPasteFrom() completes. This causes the remote to paste its stale clipboard contents on the first paste, not the freshly-synced host clipboard.

Call event.preventDefault() and event.stopPropagation() before the async read, then manually send the keystroke via sendKey() only after the clipboard update succeeds or fails. This serializes the clipboard sync before the remote paste shortcut fires.

Also add releaseRemoteModifiers to the dependency array at line 274 since the fix calls it.

πŸ› Proposed fix to serialize clipboard update before the remote paste shortcut
     const onKeyDown = (event: KeyboardEvent) => {
       if (pasteOpenRef.current) return;
       if (!vncFocusedRef.current) return;
       const isPasteShortcut =
         (event.ctrlKey || event.metaKey) &&
         !event.shiftKey &&
         !event.altKey &&
         event.key.toLowerCase() === "v";
       if (!isPasteShortcut) return;
       if (!navigator.clipboard?.readText) return;
+
+      const sendRemotePasteShortcut = () => {
+        releaseRemoteModifiers();
+        rfbRef.current?.sendKey(0xffe3, "ControlLeft", true);
+        rfbRef.current?.sendKey(0x0076, "KeyV");
+        rfbRef.current?.sendKey(0xffe3, "ControlLeft", false);
+      };
+
+      event.preventDefault();
+      event.stopPropagation();
       navigator.clipboard
         .readText()
         .then((text) => {
-          if (text) rfbRef.current?.clipboardPasteFrom(text);
+          if (!text) return;
+          rfbRef.current?.clipboardPasteFrom(text);
+          sendRemotePasteShortcut();
         })
         .catch(() => {
-          // Non-secure origin or clipboard permission denied β€” silently skip.
+          // Clipboard permission denied β€” preserve normal remote paste behavior.
+          sendRemotePasteShortcut();
         });
     };
-  }, [activateVncInput, deactivateVncInput, focusVncSurface, status]);
+  }, [activateVncInput, deactivateVncInput, focusVncSurface, releaseRemoteModifiers, status]);
πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/VNCApp.tsx` around lines 217 - 235, The onKeyDown handler
(used with pasteOpenRef, vncFocusedRef and rfbRef.current.clipboardPasteFrom)
must prevent the original Ctrl/Cmd+V from propagating before starting the async
navigator.clipboard.readText: call event.preventDefault() and
event.stopPropagation() immediately once isPasteShortcut is detected, then
perform readText() and call rfbRef.current.clipboardPasteFrom(text) and only
after that (or on read error) call sendKey to emit the remote paste keystroke;
also ensure releaseRemoteModifiers is included in the useEffect dependency array
that registers onKeyDown so the closure sees it.

Comment thread src/components/VNCApp.tsx
…s, add a11y to paste modal

CodeRabbit PR ID-Robots#66 findings that were accurate and worth acting on:

1. browser/manage/route.ts close-browser handler: previously swallowed
   both systemctl-stop and pkill errors with empty catches, so wedged
   systemctl or real pkill failures were invisible. Now logs
   systemctl-stop failures with console.warn, and logs pkill failures
   only when the error isn't the benign 'no process matched' exit code
   (which is the happy path once systemctl has already stopped the
   service). Fallback behavior β€” pkill + cleanBrowserLocks β€” is
   unchanged.

2. VNCApp paste modal accessibility: the dialog was missing ARIA
   semantics, so screen readers announced neither the dialog itself
   nor the textarea purpose. Added:
   - role="dialog", aria-modal="true" on the modal container.
   - aria-labelledby pointing at the new id="vnc-paste-dialog-title"
     on the h3, so the dialog name is the 'Paste to VNC' heading.
   - aria-describedby pointing at id="vnc-paste-dialog-desc" on the
     help paragraph, so the dialog description is the usage hint.
   - Matching aria-labelledby / aria-describedby on the textarea so it
     inherits the same label + description without a separate <label>.

CodeRabbit also suggested preventDefault+stopPropagation on the
Ctrl/Cmd+V keydown before the async clipboard read, but that would
block noVNC from forwarding the V keystroke to the guest β€” which is
the intended 'both events ship, X CLIPBOARD arrives first' design. The
suggestion to add releaseRemoteModifiers to the useEffect deps was
also a false positive: onKeyDown doesn't reference it, so adding it
would be a no-op dep. Skipped both.
@KrasimirKralev
KrasimirKralev merged commit 4b3f68b into ID-Robots:beta Apr 18, 2026
5 checks passed
KrasimirKralev added a commit to KrasimirKralev/clawbox that referenced this pull request Apr 18, 2026
…D-Robots#66 followup)

The clawbox-vnc.service unit template and autocutsel package only land
on a fresh install via step_vnc_install. Existing devices that update
through the in-app updater never re-run that step, so they stay on the
pre-PR ID-Robots#66 configuration:

  - clawbox-vnc.service unit without Environment=CLAWBOX_VNC_MODE=virtual,
    so start-vnc.sh takes the mirror-:0 path and VNC viewers see GDM's
    greeter instead of Chromium.
  - No autocutsel daemon, so copy/paste between the VNC client and the
    guest doesn't survive focus changes β€” the bidirectional clipboard
    wiring in PR ID-Robots#66 has nothing to keep the selection alive.

This was the outside-diff 'Major' finding on the CodeRabbit review of
PR ID-Robots#66 that we deliberately deferred at merge time.

Adds step_vnc_refresh β€” a narrow idempotent subset of step_vnc_install:
  - apt-get install -y -qq autocutsel (no-op when already installed)
  - rewrite /etc/systemd/system/clawbox-vnc.service with the current
    unit contents (including CLAWBOX_VNC_MODE=virtual)
  - systemctl daemon-reload + restart clawbox-vnc.service

Called from step_post_update, which runs after reboot on every in-app
update. By then git_pull has already placed the updated start-vnc.sh
on disk, so the restart picks up both the new env var and the script
that honors it.

Whitelisted in DISPATCH_STEPS so 'install.sh --step vnc_refresh' is
runnable on its own for hotfix scenarios.

Deliberately narrower than step_vnc_install β€” does not re-touch the
firstboot-pending flag (which would cause clawbox-firstboot-vnc to
re-run on every reboot), the websockify unit, or the clawbox-browser
service unit. Those are already on-disk from the original install and
aren't part of this specific pre-ID-Robots#66 regression.

Verified on Jetson via 'install.sh --step vnc_refresh' β€” syntax clean,
unit rewritten with the env var present, service restart completes.
@coderabbitai coderabbitai Bot mentioned this pull request May 2, 2026
14 tasks
@KrasimirKralev
KrasimirKralev deleted the fix/browser-integration-config-timeout branch July 4, 2026 17:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant