Skip to content

feat(agent-panel): mid-session worktree switch confirmation - #198

Open
liyakhar wants to merge 16 commits into
flazouh:mainfrom
liyakhar:feat/mid-session-worktree-switch
Open

liyakhar wants to merge 16 commits into
flazouh:mainfrom
liyakhar:feat/mid-session-worktree-switch

Conversation

@liyakhar

@liyakhar liyakhar commented May 19, 2026

Copy link
Copy Markdown
Contributor

What

When the user enables the worktree toggle after a session is already active, Acepe now treats Continue as a real backend-owned runtime switch instead of a frontend metadata flip.

The dialog remains the product surface, but the Continue path now asks Rust to move the active session runtime to a new worktree so future prompts/tool calls run from that cwd.

Why

The first version of this PR created the worktree and updated UI/session metadata, but existing-session sends still called sendPrompt(sessionId, ...) on the already-registered provider client. That could make the UI say “worktree” while the live agent still operated in the original checkout.

How

  • Added acp_switch_session_to_worktree Tauri command.
  • Added a backend per-session switch gate so sends/model/mode/config/autonomous/cancel paths reject while a switch is in progress.
  • Added managed worktree creation without prepared-launch reservation tokens, preventing new-session launch-token leaks.
  • Runs worktree setup before provider rebind.
  • Creates a replacement provider client rooted at the new worktree, reconnects the existing session ID, restores current model/mode where needed, persists worktreePath, then swaps the runtime in SessionRegistry.
  • Frontend service now calls the backend switch command and no longer uses prepareWorktreeSessionLaunch, PreparedWorktreeLaunch, or pendingWorktreeEnabled for mid-session Continue.
  • Added reviewed architecture plan: docs/plans/2026-05-20-mid-session-worktree-runtime-rebind-plan.md.

Also included from the original PR

  • Worktree pill stays visible mid-session and after attach.
  • Browser webview bounds stay synced during horizontal scroll.
  • Terminal opens as a right-side trailing pane.
  • Sidebar project cards no longer duplicate terminal/browser icons.

Validation

  • cd packages/desktop && bun run check
  • cd packages/desktop/src-tauri && cargo check --quiet
  • cd packages/desktop/src-tauri && cargo clippy --quiet (passes with existing warnings)
  • cd packages/desktop && bun test src/lib/acp/components/agent-panel/logic/__tests__/pre-session-worktree-card-visibility.test.ts

Deferred

Move session changes remains disabled. It should build on the same backend switch command after adding ownership-proof and transfer preflight.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

@cubic-dev-ai cubic-dev-ai 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.

2 issues found across 42 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/desktop/src-tauri/tauri.conf.json">

<violation number="1" location="packages/desktop/src-tauri/tauri.conf.json:25">
P1: Production hardening regression: enabling Tauri devtools unconditionally in `tauri.conf.json` exposes webview developer tools in packaged builds, allowing arbitrary JS execution. Change `devtools` back to `false` or guard it behind a debug-only config.</violation>
</file>

<file name="packages/ui/src/components/app-layout/project-tab-bar.svelte">

<violation number="1" location="packages/ui/src/components/app-layout/project-tab-bar.svelte:66">
P2: Hidden absolute `+` button remains interactive because it is hidden only via `opacity-0`, enabling accidental clicks and invisible keyboard focus.</violation>
</file>

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

"titleBarStyle": "Overlay",
"dragDropEnabled": true,
"devtools": false
"devtools": true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Production hardening regression: enabling Tauri devtools unconditionally in tauri.conf.json exposes webview developer tools in packaged builds, allowing arbitrary JS execution. Change devtools back to false or guard it behind a debug-only config.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/desktop/src-tauri/tauri.conf.json, line 25:

<comment>Production hardening regression: enabling Tauri devtools unconditionally in `tauri.conf.json` exposes webview developer tools in packaged builds, allowing arbitrary JS execution. Change `devtools` back to `false` or guard it behind a debug-only config.</comment>

<file context>
@@ -22,7 +22,7 @@
 				"titleBarStyle": "Overlay",
 				"dragDropEnabled": true,
-				"devtools": false
+				"devtools": true
 			}
 		],
</file context>
Suggested change
"devtools": true
"devtools": false

{/if}
</button>
</button>
{#if project.sessionCount != null && onCreateSession}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Hidden absolute + button remains interactive because it is hidden only via opacity-0, enabling accidental clicks and invisible keyboard focus.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/ui/src/components/app-layout/project-tab-bar.svelte, line 66:

<comment>Hidden absolute `+` button remains interactive because it is hidden only via `opacity-0`, enabling accidental clicks and invisible keyboard focus.</comment>

<file context>
@@ -30,52 +30,53 @@
 						{/if}
-				</button>
+					</button>
+					{#if project.sessionCount != null && onCreateSession}
+						<button
+							type="button"
</file context>

@liyakhar
liyakhar force-pushed the feat/mid-session-worktree-switch branch from 15c7207 to 9aae19d Compare May 20, 2026 13:22
liyakhar and others added 4 commits May 20, 2026 16:33
…zouh#199)

## Problem

When starting a new session, the model selector shows a pre-filled model
(e.g. GPT 5.4) based on saved preferences. However, if the user sends a
message without explicitly re-clicking the selector, the backend ignores
the displayed model and uses its own default (e.g. Claude Sonnet).

## Root Cause

`getProvisionalModelId()` returned `null` when the user never interacted
with the selector — even though `preferredDefaultModelId` was being used
for display via `resolveToolbarModelId`. The session creation path then
sent no `initialModelId`, letting the backend pick freely.

## Fix

Fall back to `preferredDefaultModelId` when `provisionalModelId` is
null:

```ts
// Before
getProvisionalModelId: () => provisionalModelId,

// After
getProvisionalModelId: () => provisionalModelId ?? preferredDefaultModelId,
```

This ensures the `initialModelId` sent during session creation matches
what the user sees in the selector. The fallback is validated downstream
(`session-connection-manager` checks against available models) and only
applies to new sessions (`props.sessionId ? null :
host.getProvisionalModelId()`).

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes the “pre-filled” model being ignored when starting a new session
and adds a mid-session Worktree switch confirmation so future turns can
continue in a new worktree without silently moving existing changes.

- New Features
- Mid-session Worktree switch dialog in the agent panel (Continue-only
path): existing changes stay in the source checkout; future turns run in
the new worktree. Backed by a new `prepareMidSessionWorktreeSwitch`
service.
- Worktree toggle pill is now visible mid-session and after attach;
terminal can render as a right-side trailing pane for better space use.

- Bug Fixes
- Model selector: when `provisionalModelId` is null, fall back to
`preferredDefaultModelId` so `initialModelId` matches what the UI shows
on new session creation.
- Browser panel scroll-sync now subscribes to overflow ancestors before
they become scrollable, fixing webview bleed during horizontal
scrolling.

<sup>Written for commit c240b4c.
Summary will update on new commits. <a
href="https://cubic.dev/pr/flazouh/acepe/pull/199?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
## Why

Acepe's marketing site had solid SEO bones (sitemap, robots.txt,
per-page titles, baseline JSON-LD), but several signals were leaking
value:

- `app.html` declared a homepage title/description/OG/Twitter that
appeared **on every route alongside** the per-page versions — duplicate
meta confuses crawlers and previews.
- JSON-LD claimed `aggregateRating: 5/1` with a single fake review
(Google can flag this as spam).
- Private surfaces (`/pitch`, `/dev/*`, `/login`) were both indexable
and inconsistently blocked.
- Several routes were missing OG/Twitter cards, canonical URLs, or
structured data.
- Sitemap referenced a nonexistent `/roadmap` and omitted `/privacy`,
`/terms`, `/zeus`.

This PR makes every route's SEO complete, consistent, and
crawler-friendly.

## What

### Central `<Seo>` component
Single source of truth in
`packages/website/src/lib/components/seo/seo.svelte`:
- Title with auto-suffix
- Description, canonical (absolute, derived from `canonicalizePathname`)
- Full Open Graph (`og:type`, `og:site_name`, `og:url`, `og:title`,
`og:description`, `og:image`, `og:image:alt`, `og:locale`, optional
dimensions, `article:published_time`/`modified_time`)
- Full Twitter card (`summary_large_image` + title/desc/image/alt)
- Configurable `robots` + `googlebot` (defaults include
`max-image-preview:large`, `max-snippet:-1`, `max-video-preview:-1`)
- `noindex` flag
- Optional `keywords`, `author`, `imageWidth`/`imageHeight`, multiple
JSON-LD blocks

### Stripped `app.html`
Removed duplicated dynamic meta. Kept favicon, manifest, viewport,
fonts, theme, and added `application-name`, `apple-mobile-web-app-*`,
`format-detection`, `color-scheme`.

### Strengthened site-wide JSON-LD (`json-ld.svelte`)
- Removed the fake `aggregateRating`
- Added a separate `WebSite` schema (with publisher + language)
- Structured `ImageObject` logo with dimensions
- `sameAs` linking to the GitHub repo
- `downloadUrl`, real `applicationSubCategory`, richer `featureList`

### Per-route structured data
| Route | Schema |
|-------|--------|
| `/` | keywords + canonical |
| `/pricing` | **FAQPage** from real FAQ items |
| `/download` | `SoftwareApplication` offer with `availability: InStock`
|
| `/compare` | **ItemList** of all comparisons |
| `/compare/[slug]` | **FAQPage + BreadcrumbList** (Home → Compare →
tool) |
| `/blog` | **Blog** schema listing all posts |
| `/blog/*` (via `BlogPostLayout`) | **BlogPosting + BreadcrumbList**
with publisher logo, `timeRequired`, `mainEntityOfPage`,
`articleSection` |
| `/changelog`, `/privacy`, `/terms`, `/zeus` | full meta + canonical |

### Indexing posture
- `noindex` via `<Seo>` on `/pitch`, `/login`, and dev-only routes.
- Removed `Disallow` for any route that relies on `noindex` meta (Google
must fetch the page to see it; `Disallow` makes `noindex` invisible to
the crawler).
- `Disallow` reserved for surfaces we never want crawled: `/admin`,
`/auth`, `/api`, legacy locale paths.
- Full-block scraper user agents: `GPTBot`, `ClaudeBot`, `anthropic-ai`,
`CCBot`, `Google-Extended`.

### Sitemap
- Added `/privacy`, `/terms`, `/zeus`
- Removed nonexistent `/roadmap`
- Bumped `/download` priority
- Test updated (23 expectations passing)

## Tests
- `bun test src/routes/sitemap.xml/` — passes (23 expect calls)
- `bun run check` — same pre-existing errors as baseline on `main`; no
new errors in SEO files
- Reviewed via `/review` skill; all four findings (GPTBot/ClaudeBot
grouping semantics, `/zeus` indexing inconsistency, robots+noindex
contradiction, hardcoded OG dimensions) addressed before merge

## Verifying manually
After deploy, validate at:
- https://search.google.com/test/rich-results — paste
`https://acepe.dev/`, `/blog`, `/pricing`, `/compare/cursor`,
`/blog/attention-queue`
- https://www.opengraph.xyz/ — paste any route to inspect OG/Twitter
rendering
- View source of any page to confirm exactly one set of meta tags

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Unifies SEO with a single `<Seo>` component and adds complete,
route-level structured data. Fixes duplicate meta, tightens indexing,
corrects the sitemap, normalizes OG image URLs, and hardens SSR for
reliable previews and tests.

- New Features
- Central `packages/website/src/lib/components/seo/seo.svelte` for
title, description, canonical, OG/Twitter, `robots`/`googlebot`,
`noindex`, keywords/author, optional image dims, article times, and
JSON-LD.
- Stronger site-wide JSON-LD: `Organization`, `WebSite`, and
`SoftwareApplication` with structured logo, `sameAs`, `downloadUrl`, and
a richer `featureList`.
- Per-route SEO: homepage keywords; pricing `FAQPage`; download
`SoftwareApplication` offer (`InStock`); compare `ItemList` + per-slug
`FAQPage` and `BreadcrumbList`; blog index `Blog` + posts `BlogPosting`;
full meta on changelog/privacy/terms/zeus.
- `app.html` now only static head tags (favicon, manifest, fonts, theme,
mobile web app).

- Bug Fixes
  - Removed duplicate title/description/OG/Twitter across routes.
- Normalized relative OG image paths to absolute URLs in meta and
JSON-LD.
  - Dropped fake `aggregateRating` JSON-LD.
- Corrected indexing posture: `noindex` on `/pitch` and `/login`; keep
`robots.txt` Disallow for `/admin`, `/auth`, `/api`, `/es/`, `/en/`;
block `GPTBot`, `ClaudeBot`, `anthropic-ai`, `CCBot`, `Google-Extended`.
- Fixed sitemap: added `/privacy`, `/terms`, `/zeus`; removed
`/roadmap`; increased `/download` priority; tests updated and passing.
- Guarded `page.url` access in `<Seo>` for SSR/test contexts to prevent
crashes.

<sup>Written for commit 45a6b84.
Summary will update on new commits. <a
href="https://cubic.dev/pr/flazouh/acepe/pull/197?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When the user enables the worktree toggle after a session is already
active, surface a confirmation dialog instead of silently flipping
pending state. Ships the Continue-in-new-worktree path; future agent
turns run in the new worktree while existing changes remain in the
source checkout.

- New AgentPanelWorktreeSwitchDialog presentational component (@acepe/ui)
- New prepareMidSessionWorktreeSwitch service wrapping the Tauri
  prepareWorktreeSessionLaunch call + background setup orchestration
- Wire the dialog into agent-panel.svelte; the Move-session-changes
  branch is rendered disabled until the backend ownership-proof flow
  ships

Also includes session UI polish picked up while implementing this:
- Worktree pill stays visible mid-session and after attach
- Browser pane subscribes scroll sync to overflow containers before
  they become scrollable, fixing webview bleed during horizontal scroll
- Terminal opens as a right-side trailing pane instead of a bottom
  drawer; sidebar project card no longer duplicates terminal/browser
  icons

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@liyakhar
liyakhar force-pushed the feat/mid-session-worktree-switch branch from 9aae19d to 5bdf133 Compare May 20, 2026 14:50
liyakhar and others added 5 commits May 20, 2026 18:20
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep the pre-session worktree card wired without adding a packages/ui diff, so the worktree PR does not trigger unrelated website SEO tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Apply the repository formatter/import ordering for the desktop package so the PR passes the frontend CI gate without adding website or SEO changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
## Summary

Fixes a critical bug where hundreds of ghost agent panels accumulate on
every app reload, plus three UI polish issues.

## Changes

### 🐛 Fix: Ghost panel flood on reload
**Problem:** Every time the app reloads, `syncLiveSessionPanels`
re-materializes panels for ALL live sessions because the suppression map
(in-memory only) is lost on reload. This caused 200+ ghost tabs to
reappear.

**Fix:** Added an `initialSyncComplete` guard in
`live-session-panel-sync.ts`. The first sync pass now seeds the
suppression map with existing live sessions without materializing
panels. Subsequent reactive updates materialize normally for genuinely
new activity only.

### 🎨 Fix: Worktree toggle pill styling
- Changed text from `text-[0.6875rem]` to `text-xs font-mono lowercase`
to match branch name styling
- Fixed toggle knob alignment: symmetric 2px padding instead of
asymmetric 1px

### 🎨 Fix: Session list search bar sizing  
- Reduced height from `h-7` to `h-6`
- Shrunk text to 11px
- Added `pt-1` padding above the search container

## Testing
- All 12 tests in `live-session-panel-sync.test.ts` pass (including new
test for initial seed behavior)
- TypeScript check passes
- Manually verified: 0 panels after reload (was 207)

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Prevents ghost agent panels from reappearing on reload by seeding
suppression on the first sync pass. Also tweaks the worktree toggle pill
and session list search bar for better alignment and sizing.

- **Bug Fixes**
- First sync seeds suppression for existing live sessions without
materializing panels; only new activity opens panels.
- Added `resetLiveSessionPanelSync()` and tests for the initial seed
behavior.

- **UI Polish**
- Worktree toggle pill: `text-xs` `font-mono` lowercase label; fixed
knob translation for symmetric padding.
  - Session list search: height `h-6`, 11px text, added `pt-1`.

<sup>Written for commit 3d6175d.
Summary will update on new commits. <a
href="https://cubic.dev/pr/flazouh/acepe/pull/200?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@liyakhar

Copy link
Copy Markdown
Contributor Author

P1: enabling Tauri devtools unconditionally in tauri.conf.json exposes webview developer tools in packaged builds

Fixed: set devtools back to false in tauri.conf.json.

P2: Hidden absolute + button remains interactive because it is hidden only via opacity-0

Fixed: added pointer-events-none to the hidden state and group-hover/session-badge:pointer-events-auto to restore interactivity on hover, preventing accidental clicks and invisible keyboard focus when the button is not visible.

liyakhar and others added 2 commits May 20, 2026 22:24
## Problem

As identified by cubic in flazouh#200, `initialSyncComplete` was set
unconditionally after every `syncLiveSessionPanels` call — including
when `inputs` is empty.

If the first reactive `$effect` run in `app-queue-row.svelte` fires
before sessions have loaded (`liveSessionSyncInputs` is empty), the
guard is consumed immediately. The next non-empty call then treats all
live sessions as genuinely new and materializes their panels —
recreating the ghost-panel flood the guard was meant to prevent.

## Fix

Gate the `initialSyncComplete = true` flip behind `inputs.length > 0`.
An empty-inputs call is a no-op that must not advance the first-run
state machine.

```diff
-\tinitialSyncComplete = true;
+\tif (inputs.length > 0) {
+\t\tinitialSyncComplete = true;
+\t}
```

Fixes the cubic finding from flazouh#200.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Prevent ghost panels by guarding the initial sync against an empty first
call. `initialSyncComplete` now flips only when `syncLiveSessionPanels`
receives non-empty inputs.

- **Bug Fixes**
- Gate `initialSyncComplete = true` behind `inputs.length > 0` so empty
calls don’t advance the first-run guard.

<sup>Written for commit f68c500.
Summary will update on new commits. <a
href="https://cubic.dev/pr/flazouh/acepe/pull/201?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

@cubic-dev-ai cubic-dev-ai 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.

2 issues found across 35 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/desktop/src-tauri/src/acp/commands/session_commands.rs">

<violation number="1" location="packages/desktop/src-tauri/src/acp/commands/session_commands.rs:1248">
P1: Post-reconnect error paths in acp_switch_session_to_worktree leak replacement_client and worktree on failure</violation>
</file>

<file name="packages/desktop/src-tauri/src/acp/commands/interaction_commands.rs">

<violation number="1" location="packages/desktop/src-tauri/src/acp/commands/interaction_commands.rs:250">
P2: Blocking `acp_cancel` during session switch violates established design principle that cancellation must remain gated on connection status, not send readiness or temporary operation locks</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

}
};

if let Some(capabilities) = previous_capabilities {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Post-reconnect error paths in acp_switch_session_to_worktree leak replacement_client and worktree on failure

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/desktop/src-tauri/src/acp/commands/session_commands.rs, line 1248:

<comment>Post-reconnect error paths in acp_switch_session_to_worktree leak replacement_client and worktree on failure</comment>

<file context>
@@ -1145,6 +1146,164 @@ pub async fn acp_new_session(
+                }
+            };
+
+            if let Some(capabilities) = previous_capabilities {
+                if let Some(model_state) = capabilities.models {
+                    if let Some(model_id) = model_state.current_model_id {
</file context>

expected_acp_command_result(
"acp_set_model",
async {
super::session_switch_gate::reject_if_session_switching(&session_id)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Blocking acp_cancel during session switch violates established design principle that cancellation must remain gated on connection status, not send readiness or temporary operation locks

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/desktop/src-tauri/src/acp/commands/interaction_commands.rs, line 250:

<comment>Blocking `acp_cancel` during session switch violates established design principle that cancellation must remain gated on connection status, not send readiness or temporary operation locks</comment>

<file context>
@@ -247,6 +247,7 @@ pub(crate) async fn acp_set_model_for_handle<R: tauri::Runtime>(
     expected_acp_command_result(
         "acp_set_model",
         async {
+            super::session_switch_gate::reject_if_session_switching(&session_id)?;
             tracing::debug!(session_id = %session_id, model_id = %model_id, "acp_set_model called");
             let session_registry = app.state::<SessionRegistry>();
</file context>
Suggested change
super::session_switch_gate::reject_if_session_switching(&session_id)?;
// Do NOT gate cancel on session switch; cancellation must remain
// available based on connection status per design guidance.
// (Remove this line; keep the rest of the function unchanged.)

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 35 files

Re-trigger cubic

liyakhar and others added 5 commits May 20, 2026 22:34
- Apply Biome formatting/import ordering after merging main
- Remove autofocus from the worktree switch dialog action
- Add an aria-label to the worktree toggle button

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A small batch of composer/voice UX tweaks made interactively while
reviewing the app.

## Changes

### Composer prompt container
- Bump interior padding to \`px-3 py-2.5\` so text and the send button
no longer hug the borders.
- Toolbar row remains flush with the container edges so the circular
icon buttons can hit the bottom corners cleanly (the hover ring extends
into the corner instead of being trapped behind extra padding).

### \`InputContainer\` / \`AgentPanelComposer\` shared API
- Add an optional \`footerClass\` prop so hosts can opt into footer
padding without touching shared defaults. Existing call sites are
unaffected.

### Voice model menu
- Group models by tier (\`Tiny / Base / Small / Medium / Large\`) with a
one-line tradeoff description per tier (\`Fastest · least accurate\`,
\`Balanced · recommended\`, …) and a separator between groups.
- Rows now show only \`English\` / \`Multilingual\` since the tier is
the section header — less repetition, easier to scan.
- Align row heights for downloaded vs. not-downloaded models (\`min-h-7
+ py-1\`) so the vertical rhythm is consistent regardless of whether a
row shows a download button or just a size.
- Robust to future catalog entries: unknown tiers fall back to the raw
label with no description rather than disappearing.

### Mode pill (Plan / Build)
- Replace the native \`title\` attribute with a rich \`Tooltip\` (label
+ muted description) explaining when to use each mode.
- Descriptions are exposed as \`planDescription\` / \`buildDescription\`
props for host overrides.

### Empty state heading
- Reduce \"What do you want to build?\" font size by 4px (\`1.9rem\` →
\`1.65rem\`, \`text-4xl\` → \`text-[2rem]\`) for a slightly less heavy
welcome screen. Stays centered.

## Verification
- \`bun run check\` (TypeScript) passes in \`packages/desktop\`.
- Changes are presentational only; no store, transport, or canonical
state touched.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Polishes the composer layout and upgrades the voice model menu for
clearer choices and more consistent spacing. Adds a tooltip-based mode
switch and lightens the empty state heading.

- New Features
- Composer: increased interior padding to px-3 py-2.5 so text and the
send button don’t hug the edges; toolbar stays flush with the container.
- `InputContainer` / `AgentPanelComposer`: added optional `footerClass`
prop for opt‑in footer padding.
- Voice model menu: grouped by tier with short tradeoff notes, rows show
only “English” / “Multilingual,” consistent row heights, safe fallback
for unknown tiers, and a wider menu for readability.
- Mode pill (Plan / Build): replaced native title with a rich `Tooltip`;
descriptions are overridable via `planDescription` / `buildDescription`.
- Empty state: reduced “What do you want to build?” font size for a
calmer first view.

<sup>Written for commit cd5a60d.
Summary will update on new commits. <a
href="https://cubic.dev/pr/flazouh/acepe/pull/202?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This restores the autonomous toggle's active icon color to purple so the
prompt container button matches its intended violet state again. The
shared `@acepe/ui` toggle had drifted to `Colors.red`, which made an
enabled autonomous mode read like a destructive state.

---

[![Compound
Engineering](https://img.shields.io/badge/Built_with-Compound_Engineering-6366f1)](https://github.com/EveryInc/compound-engineering-plugin)
![GPT-5.4](https://img.shields.io/badge/GPT--5.4-000000)

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Restores the autonomous toggle’s active icon to purple. Also fixes live
session panel sync so an empty first call doesn’t flip the initial-sync
flag and create ghost panels.

- **Bug Fixes**
- UI (`@acepe/ui`): Autonomous toggle now uses `Colors.purple` for the
active icon and CSS variable.
- Desktop: Only set `initialSyncComplete = true` when `inputs.length >
0` to prevent ghost panel materialization.

<sup>Written for commit 340dd57.
Summary will update on new commits. <a
href="https://cubic.dev/pr/flazouh/acepe/pull/203?utm_source=github">Review
in cubic</a></sup>

<!-- End of auto-generated description by cubic. -->

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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