Skip to content

feat: v3.0.4 β€” VNC UTF-8 clipboard + ClawKeep pair UX + bug fixes - #139

Merged
KrasimirKralev merged 8 commits into
ID-Robots:betafrom
KrasimirKralev:feat/refresh-catalog-on-configure
May 19, 2026
Merged

feat: v3.0.4 β€” VNC UTF-8 clipboard + ClawKeep pair UX + bug fixes#139
KrasimirKralev merged 8 commits into
ID-Robots:betafrom
KrasimirKralev:feat/refresh-catalog-on-configure

Conversation

@KrasimirKralev

@KrasimirKralev KrasimirKralev commented May 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • fix(remote-control): Cloudflare Quick Tunnel panel keeps polling instead of exiting the loop once the service is 'active' but the URL hasn't been printed yet β€” no more manual Refresh to see the tunnel link (RemoteControlPanel.tsx).
  • feat(picker): model picker merges live OpenClaw catalog with the static PROVIDER_CATALOGS and filters retired Claude IDs (claude-sonnet-4-20250514, claude-opus-4-20250514) via a DEPRECATED_MODEL_IDS denylist. Dropdown also surfaces when allowCustom is set, so users can type their own model ID against Anthropic OAuth (ai-models/catalog/route.ts, ChatPopup.tsx).
  • feat(clawkeep): pair card redesigned to match the ClawAI subscription panel β€” explicit 'Open authorization page' button so the device code is readable before focus shifts, a 'Get a new code' affordance for expired codes, and reuse of the existing ai.openAuthPage translation key. Removes four orphaned clawkeep.pair.* keys across all 10 locales (ClawKeepApp.tsx, clawkeep-translations.ts).
  • feat(vnc): bidirectional UTF-8 clipboard via a new /setup-api/vnc/clipboard route that shells out to xclip on the guest X CLIPBOARD. Replaces the basic RFB ClientCutText path that mangled Cyrillic / CJK / emoji as Latin-1 mojibake. Paste modal posts text through the route then sends Ctrl+V via RFB; copy uses noVNC's clipboard event as a change signal and reads the real UTF-8 via the same endpoint. Manual-copy toast for HTTP origins uses the shared copyToClipboard helper. Requires xclip installed on the device.
  • fix(clawai-tier): preserve last-known tier on transient /setup-api/ai-models/status failures so the 'You are on the free plan' modal stops popping every time the gateway WebSocket blips. The server already caches portal lookups with proper TTLs, so a 2xx response is the only authoritative signal; anything else is 'unknown', not 'downgraded'. Hook returns the same state ref when no logical change so React bails out and consumers don't re-render every 30s on flaky networks (use-clawbox-login.ts).
  • feat(catalog): trigger a background catalog refresh when a provider is configured, so the picker reflects the new entitlement without waiting for the next periodic refresh (ai-models/configure/route.ts β€” already in this branch).
  • chore(release): bump version to 3.0.4.

Test plan

  • Open the Remote Desktop panel β†’ click Start. Tunnel link should appear automatically within ~2s of cloudflared printing it, no manual Refresh needed.
  • Open the ClawKeep app β†’ click Pair. Modal shows orange 'Open authorization page' button; clicking it opens the portal in a new tab; code is visible/copyable beforehand.
  • On the device, run apt install -y xclip (or wait for the next install.sh update). Open the Remote Desktop, click the 'Paste to VNC' button, paste Bulgarian/Chinese/emoji into the textarea, hit Send. Text should appear correctly inside Chromium with no mojibake.
  • Inside Chromium in the Remote Desktop, copy Cyrillic text. Toast appears top-right with the original characters (not оих). Click Copy β†’ paste somewhere on your host machine and verify the round-trip.
  • In the Chat app, open the model picker. Confirm only currently-supported Claude IDs appear; the deprecated claude-sonnet-4-20250514 and claude-opus-4-20250514 should not be selectable.
  • Drop the gateway connection briefly (kill network for ~5s). The 'free plan' downgrade modal should NOT appear. Reconnect β†’ tier stays on Paid throughout.
  • Pair a Free-tier token, then unpair it. The downgrade modal should fire exactly once (on the confirmed transition), and dismissing it should persist across page reloads.
  • Verify package.json shows 3.0.4.

Summary by CodeRabbit

  • New Features

    • Added VNC clipboard support for copying and pasting between host and guest systems.
    • Redesigned pairing flow UI with explicit authorization link and improved code display.
    • Enhanced AI model catalog with better filtering and availability.
  • Bug Fixes

    • Improved login state preservation during transient network issues.
    • Optimized remote control polling cadence for faster tunnel negotiation.
    • Fixed chat model picker visibility when custom model IDs are enabled.
  • Localization

    • Added VNC clipboard toast message translations across all supported languages.

Review Change Stack

Symptom: a device's AI picker shows only 1 (or 0) models for a
provider the user just configured. Example from a live device that
added Anthropic credentials after first boot:

  models.providers.anthropic = {}
  catalog cache: 1 anthropic model (a default placeholder)
  picker: only the placeholder selectable
  chat: silently falls back to ClawBox AI / deepseek

Root cause: the catalog refresh job only runs at clawbox-setup boot
warmup. When the user adds an API key after boot (the normal path β€”
the wizard prompts for credentials hours/days after the device
first comes online), no refresh fires for that provider. The
catalog stays on whatever the pre-auth snapshot found, which for
Anthropic is the single fallback model. ClawBox AI gets configured
as the fallback at the same time and silently absorbs every
Claude-selected chat request.

Fix: trigger a single-provider catalog refresh at the end of
configure/route.ts, right before the gateway restart. The refresh
runs out-of-band (single-flight guarded, no await), so the
configure response doesn't slow down. Once the refresh completes
(seconds to a couple minutes on Jetson) the live model list is
written to the disk cache and the picker sees it on next open.

Implementation:
- Export `refreshInBackground` from `catalog/route.ts` (was already
  designed for fire-and-forget use; just needed the export).
- Import it from `configure/route.ts` and call after the existing
  step 8b (anthropic-plugin gating) and before step 9 (gateway
  restart). Map `ocProvider === "deepseek"` β†’ `clawai` because the
  catalog uses the user-facing label, not the openclaw provider id.
  Gate on `isCatalogProvider()` so local-only providers (llamacpp)
  don't trip the refresh.

This means the `models.providers.<p>` block in openclaw.json (and
the picker UI that reads from it) reflects whatever the upstream
provider actually exposes β€” no hard-coded model lists ever, not
even temporarily.

Verified on a live device: re-saving Anthropic now triggers a
`[catalog] refreshed anthropic: <N> models` log line within seconds
of the configure call returning, and the picker subsequently shows
all available Claude variants instead of the single boot-time
placeholder.
@KrasimirKralev
KrasimirKralev requested a review from a team as a code owner May 19, 2026 09:42
@coderabbitai

coderabbitai Bot commented May 19, 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 43 minutes and 19 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

βŒ› 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: 7784815c-e6c6-4b8d-bc22-1a9cd3f082fd

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 05d0fbf and d2a05b3.

πŸ“’ Files selected for processing (3)
  • src/app/setup-api/vnc/clipboard/route.ts
  • src/components/ClawKeepApp.tsx
  • src/components/VNCApp.tsx
πŸ“ Walkthrough

Walkthrough

This PR enhances clipboard bridging between host and guest VNC sessions via a new xclip API, refactors the VNCApp paste/copy flows to use it with toast notifications, improves AI models catalog filtering and provider refresh wiring, redesigns the ClawKeep pairing challenge UI with explicit authorization, updates pairing translations across 10 locales, and improves login state resilience.

Changes

VNC Clipboard Bridge and Paste/Copy Refactoring

Layer / File(s) Summary
VNC clipboard bridge API route
src/app/setup-api/vnc/clipboard/route.ts
New Next.js route handler exposes GET/POST endpoints for clipboard read/write via xclip, with dynamic rendering, X display resolution, 5s timeout, and structured error handling.
VNCApp clipboard and paste flow refactoring
src/components/VNCApp.tsx
Routes clipboard text through /setup-api/vnc/clipboard API instead of direct noVNC/browser clipboard APIs, adds paste state tracking with error display, introduces late-bound refs to prevent closure stale-ness, and implements auto-dismissing remote-copy toast with "Copied from VNC" messaging.
RemoteControlPanel polling loop cadence
src/components/RemoteControlPanel.tsx
Refactors polling from state-conditional scheduling to a continuous loop that re-schedules on each iteration, using 2s cadence during tunnel negotiation and 15s otherwise.
VNC remote copy toast translations
src/lib/desktop-translations.ts, src/lib/desktop-translations-part{1,2,3}.ts
Adds vnc.copyToast.fromRemote translation key across English, Bulgarian, German, Spanish, French, Italian, Japanese, Dutch, Swedish, and Chinese locales.

AI Models Catalog Filtering, Augmentation, and Provider Configuration

Layer / File(s) Summary
Catalog model filtering and static augmentation
src/app/setup-api/ai-models/catalog/route.ts
Filters deprecated Anthropic snapshot IDs from live catalog, introduces static context-window fallback data, merges curated provider models with live catalog entries (live takes precedence), and updates payload construction to use the merged model list for defaultModelId and models.
Export and wire background catalog refresh
src/app/setup-api/ai-models/catalog/route.ts, src/app/setup-api/ai-models/configure/route.ts
Marks refreshInBackground(provider) as exported; wires refresh triggering in configure route after provider setup with OpenClaw-to-catalog provider mapping; refresh runs out-of-band without awaiting.
ChatPopup inline model picker visibility logic
src/components/ChatPopup.tsx
Updates picker visibility condition to show picker when catalog.allowCustom is true even if curated catalog has fewer than two models.

ClawKeep Pairing Challenge UI Redesign

Layer / File(s) Summary
ClawKeepApp pairing flow and props wiring
src/components/ClawKeepApp.tsx
Removes auto-opening of verification URL on pair start; adds onGetNewCode callback and busy prop to PairChallengeCard; stops direct tab-open behavior in favor of modal-driven authorization.
PairChallengeCard UI redesign
src/components/ClawKeepApp.tsx
Expands PairChallengeCard props to accept onGetNewCode and busy; redesigns UI with explicit authorization button, code display with copy action, expiry hint, configuring/waiting status indicator, and "get new code" button disabled when busy.
Pairing flow translations across all locales
src/lib/clawkeep-translations.ts
Replaces old pairing instruction keys (enter-code, type-code-on-portal, waiting-approval, reopen-portal) with new guidance keys (intro, then-enter-code, code-expires, waiting-authorization, get-new-code) across 10 locales.

Version Bump and Infrastructure Improvements

Layer / File(s) Summary
Package version update
package.json
Bumps version from 3.0.3 to 3.0.4.
useClawboxLogin transient failure resilience
src/lib/use-clawbox-login.ts
Adds preserveOnTransient helper to retain the last-known loggedIn/tier state when HTTP responses fail or network exceptions occur, instead of clearing to a "free" posture; polling loop continues as before.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • ID-Robots/clawbox#83: Main PR's src/app/setup-api/ai-models/configure/route.ts triggers a background catalog refresh after provider config, directly complementing PR #83's provider-switch session sweep and model picker state changes.
  • ID-Robots/clawbox#125: Both PRs modify src/app/setup-api/ai-models/catalog/route.ts model filtering, caching, and metadata handling.
  • ID-Robots/clawbox#66: Both PRs modify the VNC clipboard/paste flow in src/components/VNCApp.tsx, overlapping in clipboard handling and paste-modal refactoring.

Suggested labels

enhancement, bug

Suggested reviewers

  • yalexx
  • GeorgiK77

🐰 Hop through clipboards and pastries anew,
The VNC bridge now sees what's true,
A pairing card with buttons bright,
And catalogs filtered just right,
Version bumpedβ€”let's ship it through! πŸš€

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

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
βœ… Passed checks (4 passed)
Check name Status Explanation
Title check βœ… Passed The title clearly summarizes the main changes: v3.0.4 release with VNC UTF-8 clipboard, ClawKeep pair UX redesign, and bug fixes. It is concise and directly reflects the significant features in the changeset.
Description check βœ… Passed The PR description provides comprehensive detail on all major changes, includes specific file references, explains the motivation behind each change, and provides a detailed test plan covering all functionality areas.
Linked Issues check βœ… Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check βœ… Passed Check skipped because no linked issues were found for this pull request.

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

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

Warning

Review ran into problems

πŸ”₯ Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


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.

…de IDs + show dropdown for allowCustom providers

Three picker-experience fixes uncovered on a device whose Claude.ai
OAuth scope only enumerates `claude-sonnet-4-20250514` (a model
Anthropic has scheduled for retirement on 2026-06-15).

## 1. Merge static PROVIDER_CATALOGS into the live catalog response

When `openclaw models list --provider anthropic` returns just one
model β€” which is what Claude.ai consumer OAuth scopes do today β€”
the picker had nothing to offer. The curated list in
`src/lib/provider-models.ts` already tracks the current Anthropic
lineup (Opus 4.7, Sonnet 4.6, Haiku 4.5 per
https://platform.claude.com/docs/en/about-claude/models), so we
now union the live response with the static list. Live entries
take precedence (their `contextWindow`, `input`, and `label`
reflect what the gateway negotiated); ids in the static list but
not the live response get appended as fallback entries with
`contextWindow` from a small known-good lookup table.

Net effect: the picker always shows the curated current lineup,
plus anything extra the upstream actually exposes.

## 2. DEPRECATED_MODEL_IDS denylist

Anthropic's docs list `claude-sonnet-4-20250514` and
`claude-opus-4-20250514` as retiring on 2026-06-15. The openclaw
plugin does not tag them as deprecated (so the existing
`entry.tags?.includes("deprecated")` filter doesn't catch them),
which means a fresh device hitting Claude.ai OAuth gets these as
the *only* selectable Claude model β€” i.e. the picker silently
defaults users to a soon-to-be-dead model. Hardcode the two
known-retired ids in a denylist that filters them out at
catalog transform time.

When Anthropic publishes the next deprecation notice, add the
new ids to this set.

## 3. Show dropdown for `allowCustom: true` providers with only 1 model

`ChatPopup.tsx` previously hid the model dropdown when
`catalog.models.length < 2`. With Anthropic's single-model OAuth
catalog and `allowCustom: true`, the user had no UI affordance to
switch models at all β€” even though typing a custom id was the
documented escape hatch. Relax the gate: show the dropdown when
the catalog has multiple models OR allows custom ids.

## Verified on a live device

- `openclaw models list --provider anthropic --all --json` returns
  the single deprecated model.
- `/setup-api/ai-models/catalog?provider=anthropic` now returns
  the three curated current Claude models (Opus 4.7 / Sonnet 4.6 /
  Haiku 4.5) and the disk cache at
  `data/catalog-cache/anthropic.json` is consistent.
- The chat picker shows the dropdown with those three entries. The
  deprecated `claude-sonnet-4-20250514` is no longer reachable from
  the curated list (still typeable as a custom id if a user really
  needs it before the 2026-06-15 retirement, since
  `allowCustom: true` is preserved).
…thout a manual refresh

The Cloudflare Quick Tunnel panel exited its poll loop as soon as the
service entered the 'active' state without a URL yet β€” leaving the
'Negotiating tunnel with Cloudflare...' spinner up until the user
hit Refresh by hand. Restructure the loop to always reschedule with
an adaptive cadence (2s while negotiating, 15s when settled) so the
URL appears the moment cloudflared prints it.
…anel

- Replace the auto-window.open with an explicit 'Open authorization
  page' button so the device code is visible before focus shifts to
  the portal tab.
- Add a 'Get a new code' affordance for when the code expires or
  the user wants to retry against a different account.
- Reuse the existing 'ai.openAuthPage' translation key instead of a
  near-duplicate; remove four pair-flow keys (enterCode, reopenPortal,
  typeCodeOnPortal, waitingApproval) that the redesigned card no
  longer references, in all 10 locales.
Both copy directions used the basic RFB ClientCutText path, which is
Latin-1 only β€” Cyrillic / CJK / emoji round-tripped as mojibake. Route
both directions through xclip on the guest X CLIPBOARD instead, since
xclip handles UTF-8 natively.

- New /setup-api/vnc/clipboard route: GET reads the guest CLIPBOARD,
  POST writes it. xclip's write daemon-forks to keep the selection
  alive, so the write side uses 'ignore' stdio to avoid the parent
  hanging on inherited pipes.
- Paste modal posts text to the route, then sends Ctrl+V over RFB so
  the focused field inside Chromium pastes from the freshly-updated
  CLIPBOARD.
- Copy uses noVNC's 'clipboard' event as a change signal only β€” the
  Latin-1 payload is ignored; we GET the real UTF-8 text via xclip.
  An in-flight guard + pending flag collapses rapid copy stampedes.
- On insecure HTTP origins where navigator.clipboard is gated, a
  toast with a manual 'Copy' button uses the shared copyToClipboard
  helper (execCommand fallback inside a user gesture).
- One new translation key, 'vnc.copyToast.fromRemote', in 10 locales.

Note: requires 'xclip' installed on the device (apt install xclip).
The 'You are on the free plan' modal was popping up every time the
network blipped or the gateway WebSocket reconnected. Cause: the
useClawboxLogin poll cleared loggedIn + tier to null on any non-2xx
response or fetch throw, which TierUpgradeCelebration then detected
as a downgrade (currentRank=0 while seenRank>0).

The server-side /status route already has portal-failure resilience
(it caches the last-known tier with TTLs), so a 2xx response is the
authoritative signal β€” anything else is 'I don't know right now',
not 'you've been downgraded'.

- On transient failure: return the previous state ref so React bails
  out and downstream consumers don't re-render every 30s on a flaky
  network.
- On 2xx: keep trusting the server response as before. A confirmed
  Paid β†’ Free transition still fires the modal exactly once.
@KrasimirKralev KrasimirKralev changed the title feat: refresh model catalog when a provider gets configured feat: v3.0.4 β€” VNC UTF-8 clipboard + ClawKeep pair UX + bug fixes May 19, 2026

@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: 5

πŸ€– Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/setup-api/vnc/clipboard/route.ts`:
- Around line 47-65: runXclip is currently unboundedly concatenating
proc.stdout/proc.stderr into stdout/stderr which can spike memory; add a hard
cap (e.g. XCLIP_MAX_BYTES) and stop/ignore further data once reached, mark the
result as truncated and terminate the child (proc.kill) and settle the promise;
implement this by tracking bytesRead for stdout and stderr inside the existing
proc.stdout.on("data")/proc.stderr.on("data") handlers, only append up to the
remaining allowed bytes, set a truncated flag (or append a β€œ[xclip] truncated”
marker to stderr), clear the timer, kill the process if the cap is hit, and then
call settle(...) with code -1 to ensure the function (runXclip) returns a
bounded-size payload.
- Around line 110-123: Before calling request.json() in POST, read and validate
the Content-Length header: use request.headers.get('content-length'), parse it
to an integer, and if it exists and is greater than MAX_CLIPBOARD_BYTES return
NextResponse.json({ error: "text exceeds 1 MiB cap" }, { status: 413 })
immediately; if the header is present but not a valid positive integer return
400; only then call await request.json() and continue with the existing checks.
Reference: the POST function, request.json(), MAX_CLIPBOARD_BYTES, and
NextResponse.json.

In `@src/components/ClawKeepApp.tsx`:
- Around line 1007-1013: In ClawKeepApp update the JSX that renders the pairing
status so the changing text is announced to assistive tech: keep the existing
phase conditional but wrap the status string (the t(...) output) in an element
with aria-live="polite" (or role="status" and aria-live="polite") so screen
readers get updates, and mark the decorative spinner span (the inline-block w-3
h-3 ... animate-spin element) as aria-hidden="true" so it is ignored by
assistive tech; ensure you only expose the translated string (phase variable) in
the live region and do not interpolate untrusted content into that element to
avoid XSS.

In `@src/components/VNCApp.tsx`:
- Around line 736-780: Wrap the remote-copy toast container (the div that
renders when copyToast && status === "connected") with proper ARIA live-region
attributes so assistive tech announces changes: add aria-live="polite"
role="status" and aria-atomic="true" to that outer div, ensure the
human-readable message nodes (the p elements showing copied state and
copyToast.text) are within that region, and keep existing handlers
(copyToastTextToHost, dismissCopyToast) unchanged; this makes updates to
copyToast (including copied vs. not copied and the remote text) announced
without moving focus.
- Around line 522-534: The sendPaste callback can run concurrently on rapid
submits; add an immediate guard that returns if pasteBusy is true at the top of
sendPaste, and ensure setPasteBusy(false) is called in a finally block so the
busy flag is cleared even on errors. Specifically, in the sendPaste function
(which uses pasteText, setPasteBusy, setPasteError, writeAndPaste, pasteOpenRef,
setPasteOpen, setPasteText, focusVncSurface) check pasteBusy and bail early, set
pasteBusy true before awaiting writeAndPaste, and move the setPasteBusy(false)
into a finally so duplicate clipboard writes/Ctrl+V injections won't occur.
πŸͺ„ 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: 95102eee-ac71-4383-9b2d-73a53ac881cc

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 8c7e0e1 and 05d0fbf.

β›” Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
πŸ“’ Files selected for processing (14)
  • package.json
  • src/app/setup-api/ai-models/catalog/route.ts
  • src/app/setup-api/ai-models/configure/route.ts
  • src/app/setup-api/vnc/clipboard/route.ts
  • src/components/ChatPopup.tsx
  • src/components/ClawKeepApp.tsx
  • src/components/RemoteControlPanel.tsx
  • src/components/VNCApp.tsx
  • src/lib/clawkeep-translations.ts
  • src/lib/desktop-translations-part1.ts
  • src/lib/desktop-translations-part2.ts
  • src/lib/desktop-translations-part3.ts
  • src/lib/desktop-translations.ts
  • src/lib/use-clawbox-login.ts

Comment thread src/app/setup-api/vnc/clipboard/route.ts
Comment thread src/app/setup-api/vnc/clipboard/route.ts
Comment thread src/components/ClawKeepApp.tsx
Comment thread src/components/VNCApp.tsx Outdated
Comment thread src/components/VNCApp.tsx
- VNC clipboard route: cap xclip stdout buffering at MAX_CLIPBOARD_BYTES
  and SIGTERM the child when exceeded, returning HTTP 413 β€” prevents a
  giant guest selection from spiking Jetson RAM during the JSON hop.
- VNC clipboard route: reject oversized POST bodies via Content-Length
  pre-check, before request.json() buffers the whole payload.
- ClawKeep PairChallengeCard: mark the phase indicator with role=status
  + aria-live=polite, hide the decorative spinner with aria-hidden, so
  assistive tech announces waiting/configuring transitions.
- VNCApp sendPaste: add a pasteBusy early-return guard and move
  setPasteBusy(false) into a finally β€” kills the duplicate-paste race
  on rapid Ctrl+Enter / double-click.
- VNCApp copy toast: wrap the remote-clipboard toast in
  role=status + aria-live=polite + aria-atomic=true so screen readers
  announce that remote text is available without focus motion.
@KrasimirKralev
KrasimirKralev merged commit bbf235f into ID-Robots:beta May 19, 2026
7 checks passed
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