Skip to content

feat(settings): two-layer takeover shell, migrate pages (PR1 of #604)#951

Merged
Astro-Han merged 16 commits into
devfrom
claude/settings-rewrite
May 27, 2026
Merged

feat(settings): two-layer takeover shell, migrate pages (PR1 of #604)#951
Astro-Han merged 16 commits into
devfrom
claude/settings-rewrite

Conversation

@Astro-Han

@Astro-Han Astro-Han commented May 27, 2026

Copy link
Copy Markdown
Owner

What

PR1 of the #604 settings rewrite: replace the old tab-router settings page with the new two-layer takeover shell. Every existing page moves over by reuse — the surface is migration-first, with two deliberate settings removals called out below.

This is the "swap the foundation" PR — atomic by necessity. The moment layout mounts the new shell the old one is gone, so all six existing pages and their tests must move in the same change. Visual polish and new functionality land as follow-up additive PRs.

Intentional removals (not pure migration)

The migration preserves behaviour except for two settings we chose to drop here rather than carry over:

  • Auto-accept permissions toggle — it toggled auto-accept for the current session/directory but lived in global settings, so it sat inert whenever settings opened without an active session. The same control already exists in-session as the mod+shift+a command, so the redundant (and confusing) settings entry is removed.
  • "Default-expand shell / edit tool" toggles — tools now always fold by default and the user expands on demand. The persisted general.shellToolPartsExpanded / editToolPartsExpanded settings and their timeline plumbing (SessionTurn / AssistantParts) are removed.

Upgrade impact: a user who had turned on "default-expand" will see those tool parts fold by default after upgrade — the stale localStorage values are ignored rather than migrated. This is the intended new default, not a regression we plan to undo.

Done

  • New settings-shell.tsx: two-layer takeover, 240px left nav (Back-to-app + General / Shortcuts / Models / Worktrees / Memory + version foot).
  • Migrate 6 pages by reuse: general/shortcuts/worktrees/memory wrap the existing settings-* components; providers+models merge into a single Models page stacking SettingsProviders + SettingsModels.
  • Remote / Integrations omitted from the type and TAB_VALUES until their pages land (they had no content branch, so a programmatic open would have rendered an empty page); connection management stays in the right-panel Connections for now.
  • Remove the two settings described under "Intentional removals" above.
  • Delete old settings-page.tsx.
  • Bug fix: Escape now reliably closes settings. The old shell only closed via its Close button because a global keybind consumed Escape in the bubble phase; the new shell listens in the capture phase and defers to any open dialog.
  • Bug fix: pass the current directory into the settings content so SettingsMemory keeps its project scope.

Tests

  • Migrated the settings specs to the new shell (providers → Models tab, smoke → surface region, memory contract → settings-shell, new settings-shell spec/snap locking nav / switch / close).
  • Auto-accept E2E now drives the in-session mod+shift+a keybind instead of the removed settings toggle.
  • Retired the dead notification/sound tests left by Redesign notification sounds: two warm sounds + single three-state control #923 (those controls were collapsed into a single notify tri-state) and fixed the theme-migration assertion for the current cache-overwrite behavior.
  • CI green (typecheck / unit-app / unit-ui / e2e-artifacts / lint / frontend-architecture).

Not in this PR (follow-up additive PRs)

Refs #604.

Summary by CodeRabbit

  • New Features
    • Redesigned Settings UI with improved navigation tabs: General, Shortcuts, Models, Worktrees, and Memory.
    • Added "Back to app" button to quickly exit Settings.
    • Escape key now closes the Settings shell.
    • Models tab consolidates provider and model configuration in one place.
    • Planned upcoming tabs for Remote Access and Integrations.

Review Change Stack

Astro-Han added 2 commits May 27, 2026 19:04
Replace the old tab-router settings-page with a two-layer takeover shell
(240px left nav + content region). Migrate the six existing pages by reuse:
general/shortcuts/worktrees/memory wrap the existing settings-* components,
and providers+models merge into a single "Models" page that stacks the
existing SettingsProviders + SettingsModels. Remote and Integrations pages
are scaffolded but hidden from the nav until their real content lands; their
connection management stays available in the right-panel Connections for now.

Fix Escape not closing settings: the old shell only ever closed via its
Close button because a global keybind consumed Escape in the bubble phase.
The new shell listens in the capture phase and defers to any open dialog, so
Esc reliably closes the surface without dismissing a nested provider dialog.

Migrate the settings tests to the new shell: the providers spec targets the
Models tab, the smoke test asserts the surface region instead of a page h1,
the memory contract test reads settings-shell, and a new settings-shell
spec/snap locks nav items, page switching, and close behavior. Also retire
the dead notification/sound tests left by #923 (those controls were collapsed
into a single notify tri-state) and fix the theme-migration assertion for the
current cache-overwrite behavior.

Part of #604.
The notification and sound controls were collapsed into a single notify
tri-state in #923, so the settings-sounds snapshot has no target and the six
data-action selectors it relied on are unused. Remove both.

Part of #604.
@github-actions github-actions Bot added app Application behavior and product flows ui Design system and user interface labels May 27, 2026
@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@Astro-Han, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 27 minutes and 43 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, 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 include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c02f5a30-e3ef-467b-b230-eb787478b6fa

📥 Commits

Reviewing files that changed from the base of the PR and between ce13400 and f94fd96.

📒 Files selected for processing (32)
  • packages/app/e2e/actions.ts
  • packages/app/e2e/perf/perf-probe.spec.ts
  • packages/app/e2e/perf/profiles.ts
  • packages/app/e2e/perf/profiles.unit.ts
  • packages/app/e2e/prompt/prompt-shell.spec.ts
  • packages/app/e2e/session/session-composer-dock.spec.ts
  • packages/app/e2e/settings/settings-close-on-nav.spec.ts
  • packages/app/e2e/settings/settings-shell.spec.ts
  • packages/app/e2e/settings/settings.spec.ts
  • packages/app/e2e/snap/fixtures/trow-snap-fixture.tsx
  • packages/app/e2e/snap/session-trow.snap.ts
  • packages/app/e2e/snap/settings-shell.snap.ts
  • packages/app/src/components/session/session-new-view.tsx
  • packages/app/src/components/settings-general.tsx
  • packages/app/src/components/settings-keybinds.tsx
  • packages/app/src/components/settings-memory.test.ts
  • packages/app/src/components/settings-models.tsx
  • packages/app/src/components/settings-providers.tsx
  • packages/app/src/context/settings.tsx
  • packages/app/src/i18n/en.ts
  • packages/app/src/i18n/zh.ts
  • packages/app/src/pages/layout.tsx
  • packages/app/src/pages/layout/pawwork-sidebar.tsx
  • packages/app/src/pages/session/message-timeline.tsx
  • packages/app/src/pages/settings/integrations.tsx
  • packages/app/src/pages/settings/models.tsx
  • packages/app/src/pages/settings/remote.tsx
  • packages/app/src/pages/settings/settings-shell.tsx
  • packages/opencode/test/config/e2e-smoke-tagging.test.ts
  • packages/ui/src/components/message-part/assistant-parts.tsx
  • packages/ui/src/components/session-turn.tsx
  • packages/ui/src/components/timeline-playground.stories.tsx
📝 Walkthrough

Walkthrough

This PR migrates the legacy SettingsPage component to a new SettingsShell with reorganized tabs, adds new settings pages for Models/Remote/Integrations, updates all type references throughout the codebase, consolidates notification/sound controls into a single tri-state level, and validates the changes with comprehensive E2E test coverage.

Changes

Settings Shell Migration & Tab Reorganization

Layer / File(s) Summary
Settings Shell Core Component and Type System
packages/app/src/pages/settings/settings-shell.tsx
Introduces SettingsShell component and SettingsTab type defining tabs as "general" | "shortcuts" | "models" | "remote" | "integrations" | "worktrees" | "memory". Implements keyboard focus management: auto-focuses the first focusable element on mount, installs a capture-phase Escape listener that closes settings only when no dialog overlay is present, traps Tab navigation within the shell by cycling focus to first/last focusable elements, and restores prior focus on unmount.
Settings Tab Page Components
packages/app/src/pages/settings/models.tsx, packages/app/src/pages/settings/remote.tsx, packages/app/src/pages/settings/integrations.tsx
Adds ModelsPage composing SettingsProviders and SettingsModels, RemotePage with localized remote access placeholder, and IntegrationsPage with placeholder and developer notes for future MCP/LSP/remote-server integration.
Type System and Import Migration
packages/app/src/context/shell-surface.tsx, packages/app/src/pages/layout.tsx, packages/app/src/pages/layout/shell-navigation.ts
Updates ShellSurfaceContextValue.openSettings parameter type from SettingsPageTab to SettingsTab. Changes Layout component's settingsTab signal type and openSettingsSurface callback to use SettingsTab, swaps rendered overlay from SettingsPage to SettingsShell. Updates createShellNavigation to accept SettingsTab in its openSettingsSurface callback and internal openSettings function.
Localization, Selectors, and Navigation Updates
packages/app/src/i18n/en.ts, packages/app/src/i18n/zh.ts, packages/app/e2e/selectors.ts, packages/app/src/components/rate-limit-card-wiring.tsx
Adds i18n entries for settings.tab.models, settings.tab.remoteAccess, settings.tab.integrations, settings.backToApp, and placeholder strings in both English and Chinese. Removes obsolete settingsNotificationsAgentSelector, settingsNotificationsPermissionsSelector, settingsNotificationsErrorsSelector, settingsSoundsAgentSelector, settingsSoundsPermissionsSelector, settingsSoundsErrorsSelector. Updates rate-limit card wiring to open settings("models") instead of settings("providers").
E2E Test Coverage for Settings Shell
packages/app/e2e/settings/settings-shell.spec.ts, packages/app/e2e/settings/settings-providers.spec.ts, packages/app/e2e/settings/settings.spec.ts, packages/app/e2e/snap/settings-shell.snap.ts, packages/app/src/components/settings-memory.test.ts
Adds new settings-shell.spec.ts with tests validating tab visibility (General/Shortcuts/Models/Worktrees/Memory shown; Remote/Integrations hidden), Models-page content presence, page-content switching, and Escape/back-button dismissal. Updates five provider tests to select Models tab before interacting with custom provider forms. Updates settings.spec.ts to assert Settings page via ARIA region instead of H1, validates theme migration CSS caching behavior, and refactors notification persistence tests from separate agent/permissions/errors toggles to a single tri-state notification-level control expecting notify: "always". Adds snapshot test for settings-shell and general/Models/Memory views. Updates settings-memory.test.ts to validate memory tab in new shell source.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • #862: Decides whether right-panel Connections section (server/MCP/LSP health) stays in Status tab or moves to Settings; this PR's new Integrations tab and placeholder structure provides scaffolding for future integration-related features that may absorb Connections management.

Possibly related PRs

  • Astro-Han/pawwork#417: Updates shell-frame.spec.ts to use settingsUpdatesStartupSelector, which is directly affected by this PR's removal of obsolete notification/sound selectors from packages/app/e2e/selectors.ts.
  • Astro-Han/pawwork#938: Introduces the tri-state notification-level control and merged notify behavior that this PR's E2E tests validate and expect in localStorage as notify: "always".

Suggested labels

enhancement, P2, app, ui

Poem

🐰 A shell so new, with tabs arranged just right,
Keyboard focus dances, Escape and Tab in sight.
Models, remote, integrations join the fold,
Settings glow brighter as the story is told.
Thump thump!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The linked issue #862 requires a written decision on Connections position and alert-channel design for ambient health, not code implementation. This PR makes no changes to Connections; it only scaffolds Remote/Integrations pages for future use. The PR does not address the decision or design required by the issue. Either address issue #862's decision/design requirements in this PR, or clarify why this PR should not be blocked by that issue's requirements.
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: replacing the old settings page with a new two-layer shell and migrating all pages, which matches the core scope of this PR.
Out of Scope Changes check ✅ Passed All changes are scoped to the settings rewrite: shell implementation, page migrations, test updates, i18n, and related type/import updates. No unrelated refactors, dependency changes, or file removals outside the stated scope are present.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering the what, why, intentional removals, completed work, tests, and follow-ups.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/settings-rewrite

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.

@github-actions github-actions Bot added the P2 Medium priority label May 27, 2026

@github-actions github-actions 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.

Suggested priority: P2 (includes user-path files (packages/app/src/components/rate-limit-card-wiring.tsx, packages/app/src/components/settings-memory.test.ts, packages/app/src/components/settings-page.tsx, packages/app/src/context/shell-surface.tsx, packages/app/src/i18n/en.ts, packages/app/src/i18n/zh.ts, packages/app/src/pages/layout.tsx, packages/app/src/pages/layout/shell-navigation.ts, packages/app/src/pages/settings/integrations.tsx, packages/app/src/pages/settings/models.tsx, packages/app/src/pages/settings/remote.tsx, packages/app/src/pages/settings/settings-shell.tsx)).

P1/P0 are reserved for maintainer confirmation. Please relabel manually if this is a release blocker, security issue, data-loss risk, or updater/runtime failure.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request replaces the old settings page with a new SettingsShell component, introducing a two-column layout with a left navigation bar and a right content area. It merges the "Providers" and "Models" tabs into a single "Models" tab, simplifies notification and sound settings into a single tri-state selector, and adds placeholders for future "Remote access" and "Integrations" tabs. Feedback focuses on fixing a critical SolidJS memory leak in SettingsShell caused by registering onCleanup inside onMount, and replacing flaky page.waitForTimeout() calls in E2E snapshot tests with robust assertions on DOM visibility.

Comment thread packages/app/src/pages/settings/settings-shell.tsx Outdated
Comment thread packages/app/e2e/snap/settings-shell.snap.ts
@github-actions

github-actions Bot commented May 27, 2026

Copy link
Copy Markdown

Perf delta summary

Comparator: pass

Profile / Scenario interaction median interaction worst long task max tbt frame gap p95 frame gap max jank count cls status
default / homepage-cold 40 -> 24 (-16) 40 -> 40 (0) 80 -> 71 (-9) 30 -> 21 (-9) 49.9 -> 16.8 (-33.1) 166.7 -> 150 (-16.7) 4 -> 3 (-1) 0 -> 0 (0) pass
default / long-session-input-lag 48 -> 48 (0) 48 -> 48 (0) 0 -> 0 (0) 0 -> 0 (0) 16.7 -> 16.7 (0) 16.7 -> 16.8 (+0.1) 0 -> 0 (0) 0 -> 0 (0) pass
default / session-streaming-long 40 -> 40 (0) 64 -> 56 (-8) 0 -> 0 (0) 0 -> 0 (0) 16.7 -> 16.7 (0) 33.3 -> 16.7 (-16.6) 0 -> 0 (0) 0 -> 0 (0) pass
default / tool-call-expand 24 -> 24 (0) 24 -> 40 (+16) 0 -> 0 (0) 0 -> 0 (0) 16.8 -> 16.8 (0) 16.8 -> 16.8 (0) 0 -> 0 (0) 0 -> 0 (0) pass
default / terminal-side-panel-open 48 -> 48 (0) 48 -> 56 (+8) 0 -> 0 (0) 0 -> 0 (0) 33.4 -> 33.4 (0) 33.4 -> 33.4 (0) 0 -> 0 (0) 0 -> 0 (0) pass
default / session-scroll-reading 16 -> 16 (0) 16 -> 16 (0) 0 -> 0 (0) 0 -> 0 (0) 16.7 -> 33.3 (+16.6) 16.7 -> 33.3 (+16.6) 0 -> 0 (0) 0 -> 0 (0) pass
low-end / session-scroll-reading-long 0 -> 0 (0) 0 -> 0 (0) 50 -> 53 (+3) 0 -> 3 (+3) 33.3 -> 33.3 (0) 50 -> 50.1 (+0.1) 0 -> 1 (+1) 0 -> 0 (0) pass
low-end / session-timeline-recompute 32 -> 32 (0) 40 -> 40 (0) 0 -> 0 (0) 0 -> 0 (0) 33.3 -> 33.4 (+0.1) 33.4 -> 33.4 (0) 0 -> 0 (0) 1.075 -> 1.075 (0) pass
low-end / concurrent-shimmer-extreme 0 -> 0 (0) 0 -> 0 (0) 0 -> 0 (0) 0 -> 0 (0) 16.8 -> 16.7 (-0.1) 16.8 -> 16.8 (0) 0 -> 0 (0) 0 -> 0 (0) pass

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
packages/app/e2e/settings/settings.spec.ts (1)

450-457: ⚡ Quick win

Use a direct localStorage read here instead of expect.poll(...).

For this persisted-settings path, writes are synchronous after the interaction; polling can hide write regressions.

Suggested fix
-  await expect
-    .poll(async () => {
-      return await page.evaluate((key) => {
-        const raw = localStorage.getItem(key)
-        return raw ? JSON.parse(raw) : null
-      }, settingsKey)
-    })
-    .toMatchObject({ notify: "always" })
+  const stored = await page.evaluate((key) => {
+    const raw = localStorage.getItem(key)
+    return raw ? JSON.parse(raw) : null
+  }, settingsKey)
+  expect(stored).toMatchObject({ notify: "always" })
Based on learnings: “In this repo’s Playwright Chromium E2E tests… `localStorage` write happens synchronously on `setStore`… Don’t recommend wrapping these `localStorage` assertions with `expect.poll()` for this storage path.”
🤖 Prompt for 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.

In `@packages/app/e2e/settings/settings.spec.ts` around lines 450 - 457, Replace
the expect.poll usage with a direct synchronous read of localStorage after the
interaction: call page.evaluate passing settingsKey to read
localStorage.getItem(key), JSON.parse it (or return null) and then assert the
result matches { notify: "always" } (same shape as the current toMatchObject).
Update the block that currently uses expect.poll(...) in settings.spec.ts to
perform the immediate page.evaluate(localStorage read) and assert its return
value, referencing the existing settingsKey and the page.evaluate call used in
the diff.
🤖 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 `@packages/app/e2e/settings/settings-shell.spec.ts`:
- Around line 33-38: The test currently only checks for
'[data-component="settings-page"]' which can miss cases where openSettings
returned a dialog; update the assertions to verify the actual returned locator
`settings` closes after Escape/back, e.g. use Playwright expectations on the
`settings` locator such as expect(settings).toBeHidden() or
expect(settings).toBeDetached() (or both) instead of checking the generic
selector; apply the same change for the other case where `openSettings` is used
(the block around lines 43-48).

In `@packages/app/e2e/snap/settings-shell.snap.ts`:
- Around line 21-23: Replace the brittle sleep with a locator-based wait: after
calling settings.getByRole("tab", { name: tab }).click(), remove
page.waitForTimeout(300) and instead await a specific UI element that indicates
the tab finished rendering (e.g., the tabpanel or a unique content element)
using locator.waitFor() or Playwright expect(locator).toBeVisible(); then take
the screenshot (shots.push with settings.screenshot()). Update the code around
settings.getByRole("tab", { name: tab }).click(), settings.screenshot, and the
shots array to use that locator-based wait.

In `@packages/app/src/pages/layout.tsx`:
- Line 2458: SettingsShell is being mounted without the directory prop so
SettingsMemory receives undefined; update the SettingsShell invocation to pass
the current directory (e.g., directory={directory}) so SettingsMemory keeps
project-scoped behavior, ensuring the surrounding component uses the correct
variable (directory or currentDirectory) in scope and that the SettingsShell
prop signature accepts directory alongside active={settingsTab()}
onSelect={setSettingsTab} onClose={closeSettings}.

---

Nitpick comments:
In `@packages/app/e2e/settings/settings.spec.ts`:
- Around line 450-457: Replace the expect.poll usage with a direct synchronous
read of localStorage after the interaction: call page.evaluate passing
settingsKey to read localStorage.getItem(key), JSON.parse it (or return null)
and then assert the result matches { notify: "always" } (same shape as the
current toMatchObject). Update the block that currently uses expect.poll(...) in
settings.spec.ts to perform the immediate page.evaluate(localStorage read) and
assert its return value, referencing the existing settingsKey and the
page.evaluate call used in the diff.
🪄 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: CHILL

Plan: Pro Plus

Run ID: c3ee1828-6e3d-4ed8-b606-53f2be23071b

📥 Commits

Reviewing files that changed from the base of the PR and between c75256e and ce13400.

📒 Files selected for processing (18)
  • packages/app/e2e/selectors.ts
  • packages/app/e2e/settings/settings-providers.spec.ts
  • packages/app/e2e/settings/settings-shell.spec.ts
  • packages/app/e2e/settings/settings.spec.ts
  • packages/app/e2e/snap/settings-shell.snap.ts
  • packages/app/e2e/snap/settings-sounds.snap.ts
  • packages/app/src/components/rate-limit-card-wiring.tsx
  • packages/app/src/components/settings-memory.test.ts
  • packages/app/src/components/settings-page.tsx
  • packages/app/src/context/shell-surface.tsx
  • packages/app/src/i18n/en.ts
  • packages/app/src/i18n/zh.ts
  • packages/app/src/pages/layout.tsx
  • packages/app/src/pages/layout/shell-navigation.ts
  • packages/app/src/pages/settings/integrations.tsx
  • packages/app/src/pages/settings/models.tsx
  • packages/app/src/pages/settings/remote.tsx
  • packages/app/src/pages/settings/settings-shell.tsx
💤 Files with no reviewable changes (3)
  • packages/app/e2e/snap/settings-sounds.snap.ts
  • packages/app/e2e/selectors.ts
  • packages/app/src/components/settings-page.tsx

Comment thread packages/app/e2e/settings/settings-shell.spec.ts Outdated
Comment thread packages/app/e2e/snap/settings-shell.snap.ts
Comment thread packages/app/src/pages/layout.tsx Outdated
Astro-Han added 3 commits May 27, 2026 21:16
Settings now renders into the existing shell slots: the nav fills the
sidebar slot and the page fills the main slot, inheriting their
width/background/border so there is no alignment drift with the session
layout. The session sidebar and main subtree stay mounted but hidden
(inert + aria-hidden + invisible) to preserve terminal/scroll state.

- Drop Kobalte Tabs (cannot span two slots); hand-roll role=tablist with
  roving tabindex + arrow/home/end keys and a shared active signal.
- Fix settings opening blank: the sidebar button forwarded its click event
  as the tab arg; openSettingsSurface now validates the tab and the wiring
  drops the event.
- Settings content canvas is bg-base; update the 4 sticky-header gradients
  from surface-raised to bg-base to match.
- Align nav tabs to the session row visuals (px-2, gap-0.5 row gap,
  row-hover / row-active overlays).
- Update e2e helpers/specs and snapshot; remove the close-on-nav spec
  (path removed by the takeover; covered by the shell-navigation unit test).
@Astro-Han Astro-Han added the enhancement New feature or request label May 27, 2026
Astro-Han added 6 commits May 27, 2026 21:31
Tools always fold by default now; users expand them on demand. The two
opt-in settings only ever flipped that default, so drop them along with
their full plumbing:

- settings schema entries, defaults, and getter/setters
- the two settings-general rows and their i18n strings
- the shellToolDefaultOpen/editToolDefaultOpen props threaded through
  AssistantParts, session-turn, message-timeline, and the playground
- the snapshot fixture scenarios and perf-probe scenario that existed
  solely to exercise the removed setting

Part of the settings rewrite (#604).
The settings toggle controlled auto-accept for the current session/directory,
yet lived in global settings, so it sat inert whenever settings opened without
an active session. The same control already exists in-session as the
mod+shift+a command, making the settings row a confusing duplicate.

- remove the settings row and its permission/params/decode64 plumbing
- remove the orphaned permissions.autoApprove settings schema (no readers)
- migrate the two e2e tests that enabled auto-accept through the toggle to
  press the command keybind instead; drop the switch-only "toggle works
  before first submit" test, whose logic stays covered by the
  permission-auto-respond unit tests

Part of the settings rewrite (#604).
The settings takeover mounted SettingsContent without a directory, so
SettingsMemory received undefined and created its SDK client with no
project scope, losing project-scoped memory behaviour. Forward currentDir().

Addresses review feedback on #951.
- snap: wait for each tab's content to render instead of a fixed 300ms delay
- spec: assert the locator returned by openSettings actually closes, rather
  than a hard-coded settings-page selector that passes even on a dialog
  fallback

Addresses review feedback on #951.
Astro-Han added 4 commits May 27, 2026 23:25
remote and integrations were valid SettingsTab values and listed in
TAB_VALUES, yet SettingsContent has no content branch for them, so a
programmatic openSettings("remote") landed on an empty settings page.
They have no page yet, so remove them from both the type and TAB_VALUES
(isSettingsTab now rejects them and the open path falls back to general).
They return — type, TAB_VALUES, NAV_ITEMS and a content Match together —
when their pages land.

Addresses review feedback on #951.
…shell-content

openSettings returns the shell-content slot ancestor, which also hosts the
session view and never detaches, so expect(settings).toBeHidden() could never
hold. The close tests are not @smoke-tagged, so PR CI (smoke-only) never ran
them and the broken assertion went unnoticed. Key the close assertion on
settings-page (mounted only while settings is open) like closeSettingsPanel.
PR CI runs the smoke suite only (--grep @smoke). The PR1 foundation-lock spec
had no @smoke tag, so its nav-takeover / tab-switch / close tests never ran on
PRs and could not guard the shell. Tag all three so the lock is real; they are
local-only UI (no network), ~6s total, sharing the already-booted smoke worker.
The e2e smoke-tagging guard locks the exact @smoke inventory. Tagging the three
settings-shell tests (2cfcc0a) broke it; add them to expectedSmokeTests in
sorted order.
@github-actions github-actions Bot added the harness Model harness, prompts, tool descriptions, and session mechanics label May 27, 2026
…down is open

The Escape capture listener runs before Kobalte's bubble-phase dropdown
dismissal, so pressing Escape to close a Select (language / notify / theme)
tore down the whole settings shell. Bail while a select-content layer is open
(alongside dialog-overlay) so the popover consumes Escape first. Adds an e2e
guard and registers it in the smoke inventory.
@Astro-Han Astro-Han merged commit ae6b778 into dev May 27, 2026
27 checks passed
@Astro-Han Astro-Han deleted the claude/settings-rewrite branch May 27, 2026 16:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app Application behavior and product flows enhancement New feature or request harness Model harness, prompts, tool descriptions, and session mechanics P2 Medium priority ui Design system and user interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Task] Decide right-panel Connections section position (move to Settings or keep, alert channel needed)

1 participant