Commit Graph

108 Commits

Author SHA1 Message Date
morgmart 84df964b05 simplify focus-visible behavior and remove keyboard nav detection (#127)
* refactor: simplify focus-visible behavior and remove keyboard nav detection

Remove the useKeyboardNavDetection hook that gated focus rings behind a
data-keyboard-nav attribute. Focus-visible rings are now always available
via the browser's native :focus-visible heuristic, which already
distinguishes keyboard from pointer interaction.

- Delete useKeyboardNavDetection hook and its App.tsx usage
- Make global focus-visible ring unconditional in globals.css
- Switch Dialog/Sheet close buttons from focus: to focus-visible:
- Opt Input/Textarea out of global ring (rely on border change)
- Remove input-group focus ring state (handled by global rule)

* style: enhance focus-visible styles for input components

- Added focus-visible border styles to InputGroup, Input, and Textarea components to improve accessibility and visual feedback.
- Updated class names to ensure consistent focus behavior across all input-related components.
2026-04-08 10:03:54 -07:00
Matt Toohey bbdce16649 fix: preserve tool call expand/collapse state across re-renders (#119)
* fix: preserve tool call expand/collapse state across re-renders

When viewing a session, expanded tool calls would collapse whenever a new
message arrived or the streaming message updated. This happened because the
Radix Collapsible was uncontrolled — its open/closed state lived in React
internal state and reset on every re-render.

Changes:
- Lift expand/collapse state into ToolChainCards via a tracked Set<string>
- Pass controlled open/onOpenChange props through ToolCallAdapter to Collapsible
- Wrap MessageBubble in React.memo so non-streaming messages skip re-renders
- Extract ToolChainCards into its own file to stay under file size limit

* chore: remove justfile changes from tool-call fix

* fix: stabilize callback props so MessageBubble memo works

Pass onRetryMessage/onEditMessage as stable references instead of
creating fresh inline closures per render. This ensures React.memo
on MessageBubble actually prevents re-renders for non-streaming
messages when the parent updates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Bradley Axen <baxen@squareup.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:29:08 +10:00
Matt Toohey a28d5a4b9f fix: sidebar highlight pill follows active session after list re-sort (#121)
* fix: sidebar highlight pill follows active session after list re-sort

When the session list re-sorts (e.g. because updateSession bumps
updatedAt), the active SidebarChatRow moves to a new DOM position but
the highlight pill stays at its old pixel offset. This happens because
the SidebarChatRow effect that re-measures position depends on
[activeRef, isActive] — neither of which changes on a re-sort.

Fix: compute a listOrderKey (joined session IDs) that changes whenever
the list order changes, and include it in the activeSessionRefCallback
and activeProjectRefCallback dependency arrays. This makes the callback
a new reference on re-sort, which triggers SidebarChatRow's existing
effect to re-fire and re-measure the highlight position.

* fix: use MutationObserver for layout-driven highlight remeasurement

Replace the listOrderKey workaround with a MutationObserver in
useSidebarHighlight that watches for any DOM subtree changes in the
nav container. This handles all cases where the active row's pixel
position changes: list re-sorts, project expand/collapse, filtering,
and show-more toggles.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: debounce MutationObserver callback with requestAnimationFrame

Wrap the MutationObserver callback in rAF to measure after the browser
has completed layout, avoiding stale geometry from pre-layout reads.
The trailing rAF also coalesces rapid-fire mutations into a single
measurement, preventing redundant intermediate renders.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:25:35 +10:00
Matt Toohey 29dfc25b51 fix: move tool elapsed time to stable badge before chevron (#124)
Extract the elapsed time from the tool title string into a separate
`tabular-nums` badge rendered before the chevron. This prevents the
title text and subsequent elements from shifting each second as the
number width changes.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:21:20 +10:00
Matt Toohey 1fb4429b42 fix: use real start time for tool call elapsed timer (#123)
Record the epoch timestamp when a tool call begins executing and pass it
through to the elapsed-time hook, so the timer reflects actual wall-clock
duration instead of resetting when the component re-mounts.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 17:01:00 +10:00
Matt Toohey 6474330faa chore: bump acp-client to 6cb674a (raw_input support) (#122)
Bump the acp-client crate from block/builderbot to pick up the
raw_input forwarding change (builderbot#495). This updates the
MessageWriter trait to accept optional raw_input parameters on
record_tool_call and update_tool_call_title.

Changes:
- src-tauri/Cargo.toml: update acp-client rev to 6cb674a7
- src-tauri/Cargo.lock: updated lockfile
- writer.rs: adapt TauriMessageWriter to new trait signatures
  (raw_input ignored for now — no frontend consumer yet)
- dispatcher.rs: forward raw_input from ACP notifications to the
  writer, and guard update_tool_call_title on title OR raw_input
  being present
2026-04-08 15:51:29 +10:00
Matt Toohey 3fd6c9b01c fix: preserve newlines in user message display (#120)
User messages were rendered through Streamdown (markdown), which collapses
single newlines per markdown rules. Now user text content renders as plain
text with whitespace-pre-wrap so newlines are preserved as typed.
2026-04-08 15:28:40 +10:00
Matt Toohey 08106b67ef fix: treat Option+Return as newline in multiline text inputs (#118)
* fix: treat Option+Return as newline in multiline text inputs

Currently only Shift+Return inserts a newline in multiline text areas
(like the chat input). Option+Return (Alt+Return) was treated the same
as plain Return, triggering the send action.

Add altKey checks alongside the existing shiftKey checks in both:
- ChatInput: skip send when altKey is held
- PromptInputTextarea: early-return (allow newline) when altKey is held

* test: add alt-enter multiline regression coverage
2026-04-08 15:06:39 +10:00
Matt Toohey 5b8aebdde2 fix: don't bump session updatedAt on metadata-only updates (#117)
Opening a session triggers acpLoadSession which replays events like
acp:session_info and acp:model_state. Each of these called updateSession
which unconditionally stamped a fresh updatedAt, causing the session to
jump to the top of the sidebar recents list (sorted by updatedAt desc).

Change updateSession to preserve the existing updatedAt unless the caller
explicitly provides one in the patch. Callers that intentionally want to
bump the timestamp (e.g. sendMessage in useChat) already pass updatedAt
explicitly, so their behavior is unchanged.

Update the test to verify both behaviors: updatedAt is preserved when not
in the patch, and updated when explicitly provided.
2026-04-08 14:26:55 +10:00
Matt Toohey 7ff4d2a6a4 fix: highlight project row in sidebar for new conversations, clear for standalone drafts (#116)
* fix: highlight project row in sidebar when starting new chat in a project

When starting a new conversation with a project selected, the sidebar
now highlights the project row instead of leaving the previous session
highlighted (or showing no highlight at all).

The root cause: draft sessions are excluded from the sidebar's session
list, so the activeSessionRefCallback never fires for them. The
highlight useEffect would early-return when activeSessionId was set,
leaving a stale highlight.

The fix computes an activeProjectId when the active session is a draft
belonging to a project, and uses an activeProjectRefCallback to position
the sliding highlight on the parent project row.

* Clear sidebar highlight for standalone draft sessions

When starting a new conversation without a project, the sidebar now
shows no highlight instead of keeping the previous selection.

The highlight logic now distinguishes three draft cases:
- Draft in project → highlight the project row (previous commit)
- Standalone draft → clear the highlight entirely (this commit)
- Non-draft session → ref callback positions the highlight as before
2026-04-08 14:26:21 +10:00
Bradley Axen 2a8fa0d3bc Wire up ACP session lifecycle: create, load, list, and stream (#115)
Replace the old chat/sessions commands and frontend stores with direct
ACP integration. Sessions are created lazily, loaded via list_sessions
and load_session, and messages stream through the existing ACP event
pipeline.

- Add acp::create_session, list_sessions, load_session Tauri commands
- Simplify chatSessionStore to drive state from ACP responses
- Add ChatLoadingSkeleton for session loading transitions
- Add shared/api/acp.ts frontend bindings
- Remove legacy chat.rs, sessions.rs, catchup.rs, and store.rs
- Support GOOSE_LOCAL_BINARY env var for local dev
- Add tests for session loading and draft persistence

Co-authored-by: morgmart <98432065+morgmart@users.noreply.github.com>
2026-04-07 19:06:53 -07:00
Taylor Ho 354ac358cc feat: add single-message queue during agent streaming (#112)
* feat: add single-message queue during agent streaming

Enable typing while the agent is responding. When the user sends a
message during streaming, it is held in a one-slot queue and auto-sent
once the current response completes. The send button contextually
replaces the stop button when text is entered; stop only appears on a
truly empty input.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: persist queued messages across tab switches

Move message queue state from React local state into the Zustand store
keyed by session ID so queued follow-ups survive navigation between
sessions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: persist draft input text across tab switches

Store the ChatInput text field value in the Zustand store keyed by
session so typed-but-unsent text survives navigating between sessions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: persist draft input text to localStorage

Drafts now survive app restarts. Uses the same load-on-init /
persist-on-write pattern as session and project caches. Empty drafts
are pruned from storage automatically.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add useMessageQueue and draft localStorage tests

- useMessageQueue: auto-send on idle, enqueue/dismiss, session scoping,
  image forwarding
- chatStore drafts: localStorage persist/clear/cleanup, cross-session
  isolation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: lazy session creation with empty draft cleanup

Sessions start as local-only drafts and are promoted to backend
sessions on first message send. Empty drafts (no typed text, no
messages) are cleaned up when navigating away. Drafts with typed text
persist across tab switches and app restarts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address PR review comments

- Pass personaId through when auto-sending queued messages so the
  original persona is preserved instead of using the current one
- Persist draft sessions with typed text to localStorage so drafts
  survive app restart (previously filtered out, orphaning draft text)
- Skip empty draft cleanup when reusing the active session to avoid
  deleting the session we're about to activate

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:18:23 -10:00
tulsi baf56fb661 drag and drop chats between projects in sidebar (#114)
* feat: drag and drop chats between projects

Chat rows are draggable. Drop on a project header to move a chat into
that project, or drop on the Recents header to unassign from a project.
Visual feedback (highlight + ring) on valid drop targets.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: expand drop zones to full section containers and fix grab cursor

Drop targets now cover the entire project section (header + chat list)
and entire recents section, not just the headers. Grab cursor now
appears on the button element directly to override default pointer.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: replace drop zone indicators with ghost fill on dragged element

Remove ring/highlight from drop targets. Instead, the dragged chat row
gets opacity-40 with a subtle accent fill to indicate it's being moved.
Cleaned up unused dragOver state variables.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add black line drop indicator below project and recents headers

A thin horizontal line appears below the section header when dragging
a chat over a project or recents section, indicating where it will land.
Uses proper dragLeave with contains() check to prevent flicker.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: prevent layout shift from drop indicator and fix grab cursor

Drop indicator line is now absolutely positioned within the section
header so it doesn't push content down. Grab cursor only appears
during active drag (active:cursor-grabbing), not on hover.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: remove leftover rounded-md from drop target wrapper divs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: always render Recents drop target even when empty

The Recents section header and drop zone now render regardless of
whether standalone chats exist, so users can always drag a project
chat to Recents to unassign it. The chat list inside still only
renders when there are standalone sessions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 14:35:18 -07:00
tulsi 00b167be07 add session history, search, and smart naming (#113)
* docs: add session management design spec

Covers three features: Session History view, search-as-you-type,
and smart session naming. Defers import/export, fork, and
multi-window.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add session management implementation plan

12-task plan covering smart naming, session history view,
and sidebar search. TDD approach with exact file paths and code.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add userSetName field to session model

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add useSessionAutoTitle hook for AI session naming

Watches for the streaming → idle transition when messageCount === 2 to
auto-generate a session title via the backend LLM. Falls back to the
first 50 characters of the user's message on API failure. Skips sessions
where the user has manually set a title (userSetName).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: wire auto-title hook into ChatView

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add groupSessionsByDate utility

Groups chat sessions into date-labeled buckets (Today, Yesterday, or
formatted date) sorted newest-first within each group. Uses UTC-based
day boundaries for consistent behavior across timezones.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add filterSessions utility for search-as-you-type

Case-insensitive text filter that matches against session title,
resolved persona name, resolved project name, and formatted date.
Accepts resolver functions to decouple from store dependencies.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add SessionCard component

Presentational card component for displaying session metadata (title,
relative date, message count, persona, project with color dot, working
directory, and archived state). Includes 5 passing tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add SessionHistoryView page component

Full-page session history view with date-grouped cards, search
filtering, archived session loading, and empty states. Composes
SessionCard, SearchBar, groupSessionsByDate, and filterSessions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add Session History route and sidebar nav item

Add "session-history" to AppView type, render SessionHistoryView in
AppShell, and add Session History nav item with History icon to
the sidebar navigation. Bump AppShell file-size limit to 575.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add search-as-you-type to sidebar

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: prevent infinite re-render in SessionHistoryView

Zustand selector returning .filter() created a new array reference
on every render, causing React useSyncExternalStore to loop.
Memoize the filtered result instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add card actions and separate archived sessions view

- SessionCard now has dropdown menu with Rename/Archive (or Restore
  for archived sessions), inline title editing on rename
- Archived sessions moved behind an "Archived" toggle button instead
  of being mixed in with active sessions
- SessionHistoryView wired to AppShell's rename and archive handlers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use consistent ghost variant for archived toggle button

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use normal font weight on archived toggle button

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add ghost-light button variant with normal font weight

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add right padding to session card title to clear menu button

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: remove spec and plan docs from PR

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 11:47:51 -07:00
tulsi 027aa3f7f2 feat: sidebar polish — resize, ordering, button visibility (#111)
* feat: resizable sidebar with snap-to-collapse

Add drag handle between sidebar and main content for free resizing.
Sidebar snaps to collapsed below 100px threshold, min width 180px,
max 380px. Double-click handle resets to default 240px.

Also: bump session title limit from 40 to 100 chars so titles aren't
pre-truncated in storage, position chat row menu button absolutely
to reclaim horizontal space for titles, and hide the sliding highlight
when sidebar is collapsed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: only bump chat updatedAt when messages are sent

Remove unconditional updatedAt bump from updateSession so metadata
changes (provider, persona, model) don't reorder the sidebar list.
Explicitly pass updatedAt in the message-sending paths instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: swap visibility of section header vs project row action buttons

Make New Project and New Chat section header buttons always visible
(muted) so users discover them without hover. Make per-project "+"
buttons hover-only to reduce visual noise.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use opacity instead of visibility for project + button

Replace invisible/visible with opacity-0/opacity-100 so E2E tests
can still interact with the button via getByTitle while keeping the
hover-only visual behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address code review — timestamp divergence and resize cleanup

Backend: only bump updated_at when title changes, not on metadata-only
patches (provider, persona, model), preventing local/server timestamp
divergence that caused sidebar reordering after app restart.

Frontend: add window blur listener as fallback cleanup for sidebar
resize, preventing stuck cursor/userSelect if mouseup fires outside
the window.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update sidebar button visibility per feedback

Per morganm's feedback: keep per-project + buttons always visible
since new-chat-in-project is the most common CTA. Switch Recents
new chat icon to IconPlus for consistency. Revert New Project button
to hover-only to reduce confusion with new chat actions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 16:44:26 -07:00
tulsi db6edb0d83 feat: add rounded-overlay token and apply to all floating surfaces (#110)
Add --radius-overlay (20px) as a semantic token for floating UI
surfaces. Migrate dropdown-menu, context-menu, popover, hover-card,
select, and menubar from rounded-dropdown (10px) to rounded-overlay
for softer, more consistent rounding across all overlay components.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 13:40:52 -07:00
tulsi 0a8f17dc5f fix: sidebar dropdown padding and border-radius tokens (#109)
* fix: use rounded-card + pill tokens for sidebar dropdown menus

Sidebar context menus (chat row and project row) were using rounded-sm
with inline borderRadius: 0 overrides, bypassing the design system.
Updated to use rounded-card container with p-1 padding and rounded-pill
items to match other dropdown menus in the app.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: use shared DropdownMenu component for sidebar menus

Replace hand-rolled menu implementations with Radix DropdownMenu
component so future design system updates apply automatically.
Add icons to project menu (Edit/Archive) to match chat row menu.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 13:21:06 -07:00
morgmart 55f153dc33 lazy session creation with draft persistence (#108)
* feat: lazy session creation and draft content persistence

Prevent blank "New Chat" entries from accumulating in the sidebar by
deferring backend session creation until the first message is sent.
Unsent input text is now preserved across navigation for all chats
(new, existing, and home screen) via a debounced draft system backed
by localStorage.

* fix: skip backend call when setting title on a just-promoted draft

The title update fired before ensure_session created the backend
record, causing a swallowed console error. Pass localOnly to
updateSession so the title is only persisted locally until the
backend session exists.

* test: add E2E tests for draft persistence and session lifecycle

Covers home-screen draft survival across navigation, project-scoped
draft reuse, empty-draft cleanup, and sidebar filtering. Extends
the Tauri mock with session and project handlers so draft flows can
run without the real backend.

* fix: shorten ChatView constants to stay under 500-line limit

* fix: sync draft metadata to backend and flush draft on unmount

After ensure_session creates the backend record, push the draft's
local metadata (title, projectId, providerId, personaId) so it
survives a loadSessions refresh.

On ChatInput unmount, flush the pending debounced draft value
instead of dropping it, preventing draft loss on fast navigation.
2026-04-06 12:15:57 -07:00
morgmart db3b31a91a feat: auto-hide scrollbars globally, show on scroll (#107)
Scrollbar thumbs are now hidden by default and appear when the user
scrolls, fading out after 1.2s of inactivity. Uses a global scroll/wheel
event listener (useScrollFade hook) that swaps injected stylesheet
content to work around WebKit's limitation of not re-painting scrollbar
pseudo-elements on class changes. Removes hardcoded scrollbar colors in
favor of the muted-foreground semantic token. Adds 4px right padding to
the chat column so the scrollbar doesn't sit flush against the window
edge.
2026-04-06 11:10:05 -07:00
tulsi da703c6f22 fix: sidebar UI polish — menus, rename, hover, new chat button (#106)
* feat: sidebar UI tweaks

- Fix context menu hover: remove pill rounding on menu items, use
  rounded-sm container with overflow-hidden for edge-to-edge hover
- Fix inline rename offset: match Input height to Button (32px),
  remove unnecessary wrapper div
- Fix hover lag: set sliding highlight transition to 0ms so it syncs
  with the ... button appearance
- Add New Chat button next to Recents header with IconMessagePlus,
  wired to createNewTab()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add aria-label and keyboard focusability to new chat button

- Add aria-label="New chat" for screen reader accessibility
- Replace invisible/visible with opacity-only hiding so the button
  stays in tab order and is keyboard reachable (focus-visible:opacity-100)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 10:55:24 -07:00
Taylor Ho 9f78bbaaf3 feat: add native zoom support (Cmd+/- and Cmd+0) (#97)
* feat: add native zoom support (Cmd+/- and Cmd+0)

Adds keyboard-driven zoom using Tauri's webview setZoom API.
Zoom level persists across restarts via localStorage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add max boundary clamp test for useZoom

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 07:55:33 -10:00
Bradley Axen c294b0ad4c fix: improve ensure-local-goose error handling and resilience (#103)
- In check mode, exit code 2 signals 'not ready' so just dev/dev-debug
  can block with a clear message instead of silently continuing without
  a goose binary.
- Replace pull --ff-only with reset --hard in the managed build checkout
  so force-pushed (rebased/amended) remote branches don't break setup.
2026-04-04 16:57:10 -07:00
Bradley Axen 4eb5e7f495 Remove header and footer border separators (#102)
Remove border-b from TopBar and border-t from StatusBar for a cleaner,
borderless look between the header, content, and footer areas.
2026-04-04 16:55:36 -07:00
Wes 446e06fdc6 fix: display all project directories in sidebar and toolbar (#96)
The ProjectOption type used a singular workingDir that only captured the
first directory. Switch to workingDirs array so every directory added in
the project dialog is shown in the context panel, toolbar tooltip, and
project selector dropdown.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 10:59:51 -07:00
Bradley Axen bc3f2f5f5d refactor(acp): route goose2 through goose serve (#101) 2026-04-04 10:37:51 -07:00
tulsi 3b156b619e feat: wire output files into Context Panel files tab (#100)
* feat: add getAllSessionArtifacts to ArtifactPolicyContext

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style: use template literal in shortenPath

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add resolvedDirectoryPath and share artifacts index

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add FilesList component with file icons and search filter

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: wire FilesList into context panel files tab

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add FilesList tests and update ContextPanel tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use biome-ignore for directory path click handler inside button

* fix: add overflow-hidden to file rows to prevent text overflow

* fix: recognize edit/update/modify tools as write-oriented for artifact extraction

* fix: filter out non-existent files from context panel files list

* fix: add width constraints to prevent file list overflow

* fix: add min-w-0 to button element to allow text truncation

Button elements have an intrinsic min-width of min-content in browsers,
preventing flex children from shrinking below content width. Adding
min-w-0 overrides this default and allows truncate to work properly.

* refactor: match skills card styling, remove version badges, use SearchBar component

* feat: add file type icons for spreadsheets, images, and more code extensions

* fix: memoize artifacts to prevent render loop, restore .hermit/ gitignore

* fix: add pathExists to ContextPanel test mock

* revert: reduce lucide icon imports to original 5 to lower memory pressure

* fix: increase Node heap limit for unit tests to prevent OOM in CI

* feat: restore expanded file type icons (spreadsheet, image, 40+ extensions)

* fix: prevent infinite rerender loop in FilesList empty-state effect

setExistingPaths(new Set()) created a new object each render,
triggering state update → rerender → effect → state update loop.
Use functional update to check if already empty before setting.

* revert: remove NODE_OPTIONS heap increase, root cause was rerender loop

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 15:08:14 -07:00
morgmart d12acb05ff polish chat input and sidebar interactions (#99)
* Polish chat input and sidebar interactions.

Standardize keyboard focus behavior and tighten sidebar and composer controls so the compact UI feels more consistent while preserving drag-and-drop image workflows.

* Fix lint follow-ups for UI polish.

Extract the chat image drop-target logic and tighten the shared focus selector so CI passes without changing the polished behavior.

* Fix keyboard focus detection for non-Tab navigation.

Preserve hidden pointer focus rings while restoring visible focus for keyboard shortcuts and other keyboard-driven flows that move focus without Tab.
2026-04-03 14:27:38 -07:00
morgmart 481af65328 context panel: default closed, widget UI, and worktree list (#98)
- Default context panel to closed; persist open/close state per session
  in chatSessionStore (in-memory, not localStorage)
- Redesign panel sections as widget cards with bordered containers and
  filled headers, replacing the accordion pattern
- Show worktree list directly in workspace widget instead of count text
- Migrate icons from lucide-react to @tabler/icons-react
- Clean up placeholder section copy
2026-04-03 14:07:58 -07:00
Wes 97b5ba393a fix: refresh sidebar when project is edited (#95)
* fix: refresh sidebar when project is edited from Projects page

Route loadProjects() through the Zustand projectStore instead of
calling listProjects() directly so mutations update the sidebar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: prevent project edit dialog from resetting form fields mid-typing

The useEffect that populated form fields ran on every editingProject prop
change. Since AppShell recreated this object on every render, any parent
re-render would reset all form fields, losing user input.

- Track dialog open transition with prevOpenRef to only populate on open
- Track editingProject.id with prevEditingIdRef for project identity changes
- Memoize editingProject prop in AppShell to stabilize object reference
- Add 12 tests covering form state preservation behavior

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use stable Zustand selector to prevent fetch loop in ProjectsView

Address PR review feedback: useProjectStore() subscribed to the full
store, causing loadProjects to be recreated on every state change and
triggering repeated IPC calls. Select fetchProjects directly for a
stable reference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 12:03:52 -07:00
morgmart 7f6db5bcc1 polish chat toolbar and sidebar with provider icons and cleaner labels (#93)
* UI polish: provider icons, dynamic placeholder, sidebar refinements

- Add provider icons (Goose, Claude Code, Codex) to the provider
  selector dropdown and trigger button
- Make chat input placeholder dynamic based on selected provider
  ("Message Claude Code, @ to mention personas")
- Lighten placeholder text color and font weight
- Update toolbar button variant to use text-foreground
- Fix dropdown icon alignment for single-line vs multi-line items
- Hide sidebar scrollbar while preserving scroll functionality
- Shrink sidebar collapse toggle button from 32px to 24px
- Add right padding to chat row for ellipsis menu breathing room
- Extract formatProviderLabel as shared utility

* fix code review issues: lint, dead code, theme token, tests

- Remove unused Plus import and onNewChat prop from Sidebar
- Fix Biome formatting in ChatInputToolbar, ProviderIcons, HomeScreen
- Fix invalid text-foreground-muted token to text-muted-foreground
- Remove dead onCreateProjectFromFolder prop chain across all components
- Fix CodexIcon hardcoded white fill to transparent
- Update tests for renamed labels (provider, project, placeholder)
- Remove extra blank line in Sidebar

* fix e2e smoke test for updated placeholder text

Update Playwright regex to match new placeholder format
"Message {name}, @ to mention personas".

* fix keyboard accessibility for show-on-hover sidebar buttons

Add group-focus-within:visible and group-focus-within:opacity-100
so the "New project" and item menu buttons are reachable via tab
navigation, not just mouse hover.
2026-04-03 10:53:53 -07:00
Nahiyan Khan 970d99b982 fix: sidebar hover text and project item styling (#89)
* fix: sidebar project/recent items hover text and styling

- Style project items to match recent chat row appearance (padding, gap, font-light)
- Fix hover text color on project and recent items by adding relative z-10
  to the projects section so it renders above the sliding highlight overlay
- Use group-hover for consistent text color change across the full row
- Switch sidebar settings to top bar, remove overflow-hidden on main

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: resolve biome lint errors

Replace `any` with `unknown` in debounce, remove unused biome-ignore
comments, fix exhaustive-deps warning, and suppress static element
interaction lint for hover wrapper div.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: extract useSidebarHighlight hook to stay under file size limit

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 22:59:11 -04:00
morgmart a0bbe236ca add context panel with git workspace details to chat view (#92)
* feat(chat): add context panel toggle to ChatView

- Introduced a context panel in ChatView that can be opened or closed via a button, enhancing the user interface by allowing users to manage context visibility.
- Updated the layout to accommodate the context panel, ensuring a responsive design that maintains usability.
- Added imports for new components and adjusted state management to handle the context panel's open/close state.

This change improves the overall chat experience by providing users with more control over the interface elements they wish to view.

* feat(chat): integrate @tabler/icons-react for context panel toggle

- Added @tabler/icons-react to the project dependencies to enhance icon usage.
- Replaced existing icon imports in ChatView with Tabler icons for better visual consistency.
- Updated the context panel toggle button to utilize the new icons, improving the user interface.
- Refactored the ContextPanel component to implement tabs for better organization of content.

This update enhances the chat interface by providing a more modern and visually appealing icon set, while also improving the overall user experience with better content organization.

* chore: transition from lucide-react to @tabler/icons-react for icon usage

- Updated AGENTS.md to reflect the migration from `lucide-react` to `@tabler/icons-react` for icon components.
- Adjusted ChatView to maintain existing `lucide-react` usage until full migration is complete.
- Enhanced documentation to guide future icon implementation.

This change ensures a consistent iconography across the project while preparing for a complete transition to the new icon library.

* refactor(git): streamline git state retrieval and improve code readability

- Consolidated the retrieval of the current repository root and branch into a more concise format.
- Enhanced the readability of the code by restructuring the way worktree paths and branches are processed.
- Improved the handling of dirty file counts by maintaining consistent function calls.

These changes optimize the git state retrieval process and enhance code clarity, making future maintenance easier.
2026-04-02 19:48:36 -07:00
Nahiyan Khan 9660b4af65 Remove unused use-text-animator hook (#90)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 19:21:25 -04:00
Wes d6e9359fca fix: update E2E tests for Radix dialog component changes (#87)
The Tailwind v4 upgrade (#85) replaced dialog components with Radix UI
primitives that use aria-labelledby instead of aria-label. Update E2E
tests to check DialogTitle h2 text instead of missing aria-label attrs,
and use getByRole("button", { name: "Close" }) for the X close button.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 15:13:19 -07:00
Wes ffed31739a Sort project chats newest-first and increase show-more limit to 5 (#84)
- Add descending updatedAt sort for project chat lists in sidebar so new chats appear at the top instead of the bottom
- Increase MAX_VISIBLE_CHATS from 3 to 5 so more chats are visible before the 'Show more' button
2026-04-02 14:57:02 -07:00
morgmart a22980320a resize large images before sending and preserve images across home-to-chat transition (#86)
* feat(chat): enhance image handling in chat input and views

- Added image resizing functionality to optimize pasted images before sending.
- Updated ChatInput to utilize the new resizing feature when adding images.
- Modified ChatView and AppShell to support initial image state and handle images in message sending.
- Adjusted HomeScreen to pass images along with messages during chat initiation.

This improves the user experience by ensuring images are properly processed and displayed in the chat interface.

* refactor(chat): centralize PastedImage type definition

- Moved the PastedImage type definition from ChatInput to a shared types file for better code organization and reusability.
- Updated imports in ChatInput, ChatView, HomeScreen, and AppShell to reference the new location of PastedImage.

This change enhances maintainability by ensuring a single source of truth for the PastedImage type across the application.

* refactor(chat): extract resizeImage to lib and fix formatting

* fix(chat): enhance initial message handling in ChatView

- Updated the condition for sending the initial message to include checks for both initialMessage and initialImages, ensuring that images are also sent when available.
- This change improves the functionality of the chat interface by allowing for a more comprehensive initial message setup.

* fix(chat): fix formatting and type error in initial message handler
2026-04-02 14:54:26 -07:00
Taylor Ho 99a4d62b07 feat: import boss-ui components + Tailwind v4 upgrade (#85)
* feat: import boss-ui components + upgrade to Tailwind v4

- Upgrade Tailwind CSS v3 → v4 with @tailwindcss/postcss, tw-animate-css
- Replace tailwind.config.js with CSS @theme blocks in globals.css
- Import boss-ui token system (semantic backgrounds, borders, text, shadows,
  shapes, typography scale, animations, layout tokens)
- Import 49 shared UI components from squareup/boss-ui
- Import 48 AI element components from squareup/boss-ui
- Import 4 hooks from squareup/boss-ui
- Install all required dependencies (Radix UI primitives, UI libs, content
  libs, form/utility libs)
- Migrate all 35+ feature files from custom tokens to standard shadcn/boss-ui
  tokens (bg-background, text-foreground, bg-accent, text-muted-foreground,
  border-border, etc.)
- Align to boss-ui visual language: flat border-driven design, no elevation
  on sidebars/inputs, shadow-popover for menus, shadow-card for dialogs
- Fix low-contrast text by removing opacity modifiers on text-muted-foreground
- Update biome.json, tsconfig.json, check-file-sizes.mjs for imported code
- Re-add custom Button variants (toolbar, xs, icon-sm, icon-lg)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: swap vanilla HTML to boss-ui components

- Replace hand-rolled dialogs with Dialog/DialogContent in
  CreateSkillDialog, CreateProjectDialog, PersonaEditor
- Replace delete confirmations with AlertDialog in AgentsView,
  ProjectsView, SkillsView, SettingsModal, DoctorCheckRow
- Replace raw <input> with Input component (6 instances)
- Replace raw <textarea> with Textarea component (3 instances)
- Replace raw <select> with Select/SelectTrigger/SelectContent/
  SelectItem (5 instances)
- Replace raw <label> with Label component throughout
- Replace <input type="checkbox"> with Checkbox component
- Replace div border-t dividers with Separator in settings
- Fix Radix SelectItem empty-string value crash by using sentinel
- Set sidebar to bg-background

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use default Button variant for send and remove focus ring on textarea

Use the boss-ui Button default variant (bg-primary) for the send button
instead of custom bg-foreground overrides. Suppress the global
focus-visible ring on the chat textarea to prevent the black outline.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add Cash Sans Wide display font to headlines

- Download Cash Sans Wide font files (5 weights) from boss-ui
- Add @font-face declarations in globals.css
- Switch page titles, settings headings, home clock/greeting, and
  chat empty state to font-display (Cash Sans Wide) with tracking-tight
- Use Badge component with secondary variant for PersonaCard pills
- Remove redundant "Personas" section subtitle
- Upgrade "Active Agents" heading to display font

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: swap remaining vanilla HTML to boss-ui components

Replace ~56 raw <button> elements across 20 files with the Button
component, hand-rolled toggle groups with ToggleGroup, img/div avatar
patterns with Avatar, animate-pulse skeletons with Skeleton, and a
raw <input> with Input.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: move ai-elements into shared/ui directory

Relocate src/components/ai-elements/ to src/shared/ui/ai-elements/
to colocate with the rest of the boss-ui component library. No import
updates needed as these components are not yet consumed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style: remove mono font from skill names

Use default sans-serif for skill names in the list and create dialog
to match persona card styling. Keep mono only for instructions textarea.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: swap chat sub-components to boss-ui ai-elements

Replace hand-rolled ToolCallCard, ThinkingBlock, and MarkdownContent
with the ai-elements Tool, Reasoning, and MessageResponse compounds.
Action buttons now use MessageAction with built-in tooltip support.
Add @source for streamdown so Tailwind generates its utility classes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: prevent whole chat pane from scrolling

Add overflow-hidden to main content area so the flex layout chain
properly constrains scrolling to the MessageTimeline, keeping the
chat input and status bar pinned at the bottom.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: prevent document-level scrolling in chat view

Two issues caused the entire page to scroll when viewing chat:

1. scrollIntoView() in MessageTimeline scrolls all ancestors including
   the document. Replaced with container.scrollTo() which only scrolls
   within the message timeline container.

2. Tailwind v4 preflight doesn't set height/overflow on html/body like
   v3 did. Added height: 100% + overflow: hidden on html, body, #root
   outside @layer base so the cascade can't override them.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: prevent tool call results from overflowing chat viewport

Add min-w-0 and w-full to message content containers so flex items
respect the max-w-[85%] boundary. Wrap tool output pre blocks with
whitespace-pre-wrap so result text flows within the code block.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use accent color for text selection highlight

The previous selection background (#1a1a1a) was nearly invisible against
the dark input background. Now uses the user's accent color at 60% opacity.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: minimize tool call UI — remove icon, borders, and completed badge

Strip visual noise from collapsed tool calls: remove wrench icon
(via optional showIcon prop), remove border/rounded container, replace
status pill with plain text, hide "Completed" status entirely, and
use inline chevron caret next to the tool name.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: center sidebar icons in collapsed state

Add gap-0 to collapsed button styles to prevent hidden text spans
(w-0 opacity-0) from creating flex gaps that shift icons off-center.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: align button, input-group, and toggle to pill shape

Restore rounded-full on button base and remove redundant rounded-md
from size variants. Update input-group container to rounded-full and
toggle to rounded-full to match the pill design language.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: override browser text-align:center default on buttons

Browsers default <button> to text-align:center. This causes short text
inside flex-1 spans to appear centered even when justify-start is set,
since justify-start controls flex child positioning but text-align
controls text within those children.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: replace main's color tokens with our theme tokens

The merge from main brought in color tokens (foreground-tertiary,
foreground-secondary, background-primary, background-tertiary, etc.)
that don't exist in our theme. Map them to our equivalents:

- foreground-tertiary/secondary → muted-foreground
- foreground-danger → destructive
- background-primary → background
- background-tertiary → accent
- background-danger → destructive
- border-border-secondary → border-border

Fixes invisible send button arrow (text-background-primary → text-background).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add compat color scales and register brand/danger in theme

The Tailwind v4 theme resets all colors with --color-*: initial then
only declares a minimal palette. This silently broke ~120 class usages
across ai-elements that rely on standard Tailwind scales (red-400,
green-600, zinc-800, etc.).

Add compat color stops for the specific scales actually used:
- red-{50,400,500,600,700,900}
- green-{400,500,600,700,900}
- blue-{400,500,600,700,900}
- yellow-{400,500,600,700,900}
- orange-{100,400,600,700,900}
- zinc-{100,400,800,950}
- amber-500

Also register brand and danger in @theme inline so Tailwind can
generate text-brand, bg-brand, text-danger, etc. utilities.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address PR review — SidebarRail type + artifact link policy

1. Add type="button" to SidebarRail button to prevent accidental form
   submissions per AGENTS.md requirement.

2. Restore artifact policy enforcement for markdown links in chat.
   The switch to MessageResponse/Streamdown lost the link interception
   that enforced allowed roots. Extract useArtifactLinkHandler hook
   that intercepts local link clicks via event delegation and routes
   them through useArtifactPolicyContext.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: restore artifact open-file actions in tool call cards

The switch from ToolCallCard to ToolCallAdapter dropped the artifact
policy integration that showed "Open file" buttons on tool results.
Add ArtifactActions component that uses resolveToolCardDisplay from
ArtifactPolicyContext to render primary and secondary open actions
with path safety enforcement.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: add confidence labels, blocked reasons, and artifact policy tests

ArtifactActions was missing "detected" labels for low-confidence
candidates and per-candidate blockedReason text. This made the
feature appear broken even though the plumbing was correct. Also
adds test coverage for ToolCallAdapter artifact integration and
useArtifactLinkHandler to prevent future regressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 13:59:46 -07:00
tulsi e6e7c8b7cd Allow opening explicit outputs outside artifact roots (#82)
* Allow opening explicit outputs outside artifact roots

* fix: tighten artifact path opening rules
2026-04-02 10:45:30 -07:00
morgmart 7b09bdcc18 add project colors and icon support to chat input toolbar (#83)
* feat(chat): enhance chat input components with project color and icon support

- Added optional `color` property to `ProjectOption` interface for project color representation.
- Updated `ChatInputSelectorItem` to include an optional `icon` property for enhanced item display.
- Introduced `ProjectDot` component in `ChatInputToolbar` to visually represent project colors.
- Modified `ChatView` and `HomeScreen` to utilize the new `color` property for projects.
- Improved button components to support left and right icons for better UI flexibility.

* fix: apply biome formatting and guard asChild against icon props
2026-04-02 10:45:08 -07:00
Wes 15f512eae3 fix: restore sidebar goose icon (#81) 2026-04-02 09:25:58 -07:00
Wes 9d268e6463 document setup flow and clean node_modules (#80) 2026-04-02 08:38:25 -07:00
Matt Toohey 4b1d9e70c5 fix: add new project includes to the bottom instead of the top (#77)
* fix: add new project includes to the bottom instead of the top

Previously, `buildEditorText` placed `include:` lines at the top of
the editor text, above the prompt. This meant clicking "Add directory"
would insert the new include above any text the user had already typed.

Now includes are placed at the bottom of the editor as a trailing block,
and `parseEditorText` collects them from the bottom instead of the top.
This feels more natural — the user's prompt text stays at the top and
directory includes accumulate below it.

No migration needed: workingDirs and prompt are stored separately in
project.json, and `buildEditorText` reconstructs the editor text in
the new layout when the dialog opens.

* fix: parse project includes anywhere in prompt editor
2026-04-02 21:12:47 +11:00
Matt Toohey 1915aa4e3d fix: persist ACP streaming messages incrementally (#76)
* feat(chat): persist ACP assistant messages while streaming

* perf(chat): batch ACP persistence at content boundaries

* fix(chat): resolve ACP streaming stop races

* fix(chat): resolve ACP terminal-state races
2026-04-02 17:06:58 +11:00
Matt Toohey 8036e814b5 fix: set binary name to 'Goose' for macOS Dock and App Switcher (#75)
Without an explicit [[bin]] section, Cargo uses the package name 'goose2'
as the binary name. macOS uses the process/binary name for the Dock and
App Switcher labels in dev mode, so the app appeared as 'goose2' instead
of 'Goose'.
2026-04-02 17:04:19 +11:00
Matt Toohey 096baecd06 fix: resolve ACP working directories to absolute paths (#72)
* fix(acp): validate and absolutize session working dir

* fix(chat): show ACP session errors in history

* fix(chat): surface tauri invoke error messages

* fix(acp): expand tilde working directories

* fix(acp): recreate missing working directories

* refactor(chat): simplify ACP error handling

* style: format rust changes
2026-04-02 16:04:08 +11:00
Matt Toohey d15244758a fix: prevent file drags from replacing the app view (#71)
* fix: prevent dropped files from replacing the app view

* test: use drag events in app navigation test
2026-04-02 13:42:32 +11:00
Matt Toohey 25710dc534 refactor: remove top-level chat tabs (#70)
* refactor: remove top-level tabs

Replace tab-based navigation with a single active session flow in the app shell and sidebar. Remove the persisted ui_state save/load path from the frontend and Tauri backend, keeping only the unrelated home-directory command in a dedicated system command module. Update affected tests and fixtures to match the new session-only model.

* feat: restore top bar home button
2026-04-02 12:00:21 +11:00
morgmart 905c85775f feat: add image paste support to chat input (#68)
* feat: add image paste support to chat input

Users can now paste screenshots and images directly into the chat input with Cmd+V. Pasted images show as thumbnails with a click-to-expand lightbox and a hover-reveal remove button. Images are forwarded to the ACP agent as base64 content blocks alongside the text prompt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: update ChatInput tests for new images argument

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: scope object URL cleanup to unmount only

Revoke only runs on component unmount (via a ref to latest images),
not on every add/remove. Previously the effect's cleanup re-ran on
every images state change, revoking URLs that were still in use.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: render image content blocks in message timeline

Add 'image' case to renderContentBlock in MessageBubble so pasted
images appear in the chat history after sending. Base64 sources are
rendered as data: URLs; URL sources rendered directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: handle image-only sends and clean up debug logs

- Pass a single space as prompt when images are present but text is empty,
  preventing goose from rejecting empty-text ACP content blocks
- Make images in the message timeline clickable via lightbox (ClickableImage)
- Suppress Radix Dialog aria-describedby warning in ImageLightbox
- Remove temporary debug console.logs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add drag-and-drop image support to chat input

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: extract ClickableImage to fix file-size lint limit

MessageBubble.tsx was 516 lines (limit 500). Moves ClickableImage
into its own file to bring it under the limit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 17:10:09 -07:00
Wes 8d8a2fd3bd Prevent tab name text from being selectable (#67)
Add select-none to the tab container className, consistent with
how other interactive elements like dropdown menus are styled.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-01 15:24:44 -07:00
Wes d3408296a6 fix: update chat title immediately on send (#66)
When a user sends a message from a "New Chat" tab, the session title
now updates instantly from the message text instead of waiting for the
full AI response to complete (acp:done) or the backend title generation
(acp:session_info). This gives immediate feedback in the sidebar and
tab bar.

The backend-generated title from acp:session_info will still overwrite
this initial title if it arrives later, providing the best of both
worlds: instant feedback + quality titles.
2026-04-01 14:40:15 -07:00