• v1.9: settings pane + per-project defaults + bulk archive + themes lift

    indifferentketchup released this 2026-05-17 17:37:29 +00:00 | 168 commits to main since this release

    Adds a singleton, ephemeral 'settings' pane kind to the workspace.
    Opened via a new bottom-pinned button in ProjectSidebar (emits an
    open_settings_pane event when a session is mounted; navigates to
    /settings otherwise). Pane has three sections — Session, Project,
    Theme — and a maximize toggle that hides sibling pane columns via
    display:none on desktop only. Settings panes don't count toward
    MAX_PANES and are filtered out of the localStorage persistence layer
    so reload always restores a clean workspace.

    Schema (additive):

    • projects.default_system_prompt TEXT NOT NULL DEFAULT ''
    • projects.default_web_search_enabled BOOLEAN NOT NULL DEFAULT false
    • sessions.web_search_enabled BOOLEAN (nullable; null = inherit)

    Inference resolves user_prompt = session.system_prompt.trim() ||
    project.default_system_prompt.trim() — empty/whitespace at either
    layer means "no override". Keeps the columns NOT NULL and matches
    the existing inherit semantics.

    Server routes:

    • GET /api/projects/:id (new; settings pane refetches on
      project_updated)
    • PATCH /api/projects/:id accepts default_system_prompt,
      default_web_search_enabled
    • PATCH /api/sessions/:id accepts web_search_enabled (tri-state)
    • POST /api/projects/:id/sessions/archive-all + GET
      /api/projects/:id/sessions/open-count
    • POST /api/sessions/:id/chats/archive-all + GET
      /api/sessions/:id/chats/open-count
    • PATCH /api/sessions/:id now broadcasts session_updated on every
      successful PATCH (was rename-only). Lets SettingsPane open in
      another tab pick up edits without a refetch.

    Bulk-archive publishes one session_archived / chat_archived frame
    per affected id so useSidebar's existing reducer cases handle them
    incrementally — no new frame type, no payload widening.

    ModelPicker refactored: shared ModelList inside a responsive shell.
    Desktop = labeled trigger + DropdownMenu, mobile = icon-only Cpu
    button + BottomSheet. Header in Session.tsx drops the pill wrap on
    mobile since the new trigger is the visual.

    ChatInput gains an icon-only '+' DropdownMenu next to AgentPicker
    when sessionId + webSearchEnabled props are provided. One item for
    now — Web search — with a checkmark reflecting the stored value
    (true), not the effective one. Click PATCHes the override; to
    restore inherit-from-project the user opens SettingsPane.

    ThemePicker lifted out of pages/Settings.tsx into a reusable
    component. The standalone /settings route is now a thin wrapper
    that mounts with a Back button on top
    (navigate(-1) with fallback to '/'); the SettingsPane Theme tab
    renders the same picker bare.

    Project section delete-flow removed (button + confirm dialog +
    handler). Replaced with "Archive all sessions" using the same
    two-step count → confirm → fire pattern as "Archive all chats" in
    the Session section. api.projects.remove() stays in the client
    because useProjects.ts still uses it.

    Hand-rolled Switch primitive in SettingsPane (no shadcn switch in
    the project; spec said no new deps). Section nav is plain buttons
    (no shadcn Tabs).

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

    Downloads