Skip to content

fix(jarvis-web): router-navigate docs button (#477) + gate Tab-to-cycle on empty composer (#478) - #488

Draft
TYRMars wants to merge 1 commit into
mainfrom
claude/vibrant-dijkstra-2b3c3i
Draft

fix(jarvis-web): router-navigate docs button (#477) + gate Tab-to-cycle on empty composer (#478)#488
TYRMars wants to merge 1 commit into
mainfrom
claude/vibrant-dijkstra-2b3c3i

Conversation

@TYRMars

@TYRMars TYRMars commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Auto-resolves two open jarvis-web bug reports. Both target real code in the current tree; each fix is minimal and follows patterns already established elsewhere in the SPA.

#477 — docs button does a hard document navigation

apps/jarvis-web/src/components/AppChatPane.tsx — the "open docs" composer button used window.location.href = "/docs", a full-document navigation inside a react-router SPA.

  • Browser mode: the assignment tore down the app — chat WebSocket, in-flight stream, composer value, and staged attachments all lost for what should be a client-side route change.
  • Desktop mode (HashRouter): routes live in the hash, so a hash-less /docs reload rendered / (the chat surface) instead of docs; before the sidecar was healthy the window was on file://, where /docs resolved to a dead file:///docs page.

Fix: call useNavigate()("/docs"), matching the rest of the app's navigation. There is already a /docs route in App.tsx, and useNavigate is used across the SPA (DocsPage, ProjectsPage, AppSidebar, …).

#478 — bare Tab cycles permission mode regardless of composer content

apps/jarvis-web/src/components/Composer/Composer.tsx — the onKeyDown Tab branch preventDefault()'d and called cyclePermissionMode() whenever the slash palette was closed and no modifier was held, never checking that the textarea was empty (which the handler's own comment claims it does).

  • Silent permission-mode changes mid-typing: a user pressing Tab after typing a prompt flipped the permission mode (and could pop the bypass window.confirm).
  • One-way focus trap: preventDefault() ran before cyclePermissionMode()'s if (!isOpen()) return early-out, so forward Tab never moved focus even when nothing else happened.

Fix: add the value.length === 0 guard to the Tab branch, matching the adjacent Backspace branch that already gates on empty content. Non-empty Tab now falls through to normal browser focus traversal / indent.

Notes

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ltebc8xx243roKDvh9Dy9X


Generated by Claude Code

…le on empty composer (#478)

#477 — AppChatPane docs button did a hard `window.location.href = "/docs"`
inside an SPA. In browser mode this tore down the chat WebSocket, in-flight
stream, composer value, and staged attachments for what should be a
client-side route change; in the desktop shell (HashRouter) a hash-less
`/docs` reload rendered `/` (chat) instead, or a dead `file:///docs` page
before the sidecar was healthy. Switch to `useNavigate()("/docs")`, matching
the rest of the app's navigation.

#478 — Composer's bare-Tab handler cycled the permission mode and
`preventDefault()`'d unconditionally, regardless of textarea content. That
silently flipped the permission mode (and could pop the bypass confirm) when
a user pressed Tab mid-typing, and trapped forward keyboard focus in the
composer even when nothing happened. Add the `value.length === 0` guard the
handler's own comment already describes, matching the adjacent Backspace
branch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ltebc8xx243roKDvh9Dy9X
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.

2 participants