- Agent list items: replace dot with colored smart_toy icon, bold name
- Agent description: use MarkdownRenderer for rich text support
- Remove max-width constraints on Agent/Skill containers for responsive layout
- Dynamically switch grid columns based on visible group count (single group fills full width)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Improve the desktop Skills browser so SKILL.md metadata renders cleanly and the settings view uses space like a real document browser. Add coverage for the new detail, markdown, and i18n behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Server: GET /api/skills (list) and GET /api/skills/detail (tree + files)
- Desktop: Skills tab with grouped list, file tree navigation, Markdown/code preview
- i18n: EN/ZH support
- Types, API client, Zustand store
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add API client, Zustand store, and i18n for agents list
- Display installed agents from ~/.claude/agents/ with detail view
- Render agent system prompt as Markdown via MarkdownRenderer
- Include error state with retry and empty state guidance
- Add 11 component tests covering all UI states and navigation
- SkillList: grouped display by source with icons and token estimates
- SkillDetail: two-panel layout with file tree navigation + Markdown/code preview
- Settings: integrated Skills tab with auto_awesome icon
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Server: GET /api/skills (list) and GET /api/skills/detail (tree + files)
- Desktop: type definitions, API client, Zustand store
- i18n: EN/ZH translation keys for Skills tab
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Tab drag-and-drop reordering with visual drop indicator
- Add moveTab action to tabStore with localStorage persistence
- Context menu: add "Close Left" and "Close All" options
- Add i18n translations for new menu items (en/zh)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- TabBar: darker background (surface-container), active tab uses top brand
accent + lighter bg, consistent bottom border, draggable empty area
- Settings sidebar width matches TAB_WIDTH (180px) for vertical alignment
- Remove rounded corners and side borders from tabs for cleaner look
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The 38px absolute drag overlay was blocking tab clicks, requiring
padding that created a visible gap. Sidebar already handles its own
drag region, and TabBar uses data-tauri-drag-region directly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move Tauri title bar padding into TabBar instead of main container,
eliminating the double spacing (38px gap + 36px tab bar)
- Remove StatusBar entirely (project/model info already in ChatInput)
- TabBar renders a drag region spacer even when no tabs are open
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Settings and Scheduled Tasks now open as special tabs in the TabBar,
matching IDE conventions (closeable, icon-prefixed, persistent)
- New Session directly creates a session with the current workDir
- ChatInput shows DirectoryPicker before first message, locks after
- Remove connection status from StatusBar (unnecessary noise)
- ContentRouter routes by tab type instead of activeView
- Settings page no longer has a back-button header
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove .claude/ and docs/superpowers/ from git tracking as they are
local-only config and planning files. Also remove stale screenshots
and update docs/channel content.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Support multiple concurrent sessions in the desktop webapp with VS Code-style tabs.
Each tab maintains its own independent WebSocket connection and message state.
Key changes:
- WebSocket manager: singleton → multi-connection Map
- chatStore: flat state → per-session isolated state
- New tabStore with localStorage persistence
- TabBar component with scroll overflow and context menu
- Sidebar/EmptySession integrated with tab system
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update all components, hooks, and tests to use the new per-session
chatStore API where state is keyed by sessionId under `sessions` and
all action methods require sessionId as the first parameter.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both components now look up state via activeTabId from useTabStore,
reading from sessions[activeTabId] in chatStore. Action calls
(sendMessage, stopGeneration) pass the sessionId as first argument.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add useTabStore.openTab call after session creation so new sessions are
registered as tabs, and update sendMessage to pass sessionId as first arg.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add TabBar, useTabStore, useChatStore imports to AppShell
- Restore tabs from localStorage during bootstrap and connect active session
- Render <TabBar /> before <ContentRouter /> in the main content area
- Replace useSessionStore/activeSessionId with useTabStore/activeTabId in ContentRouter
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The desktop chat view flattened Agent tool activity, which made sub-agent work
hard to follow and separated key evidence from the main conversation. This
change threads parent tool linkage through the server bridge and desktop store,
renders dispatched sub-agents as grouped cards with nested tool activity, and
moves long final outputs into a markdown preview dialog so the main transcript
stays readable on narrow layouts.
Constraint: Existing sessions and live websocket events both needed to preserve parent-child relationships
Rejected: Add brand-new subagent websocket event types | unnecessary protocol expansion when parent linkage already existed upstream
Rejected: Inline full sub-agent markdown in the card body | too cramped for narrow desktop chat layouts
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: Keep Agent card summaries compact; route long-form sub-agent output through the preview dialog unless the main chat layout is widened substantially
Tested: cd desktop && bun run test -- MessageList.test.tsx chatStore.test.ts
Tested: cd desktop && bun run lint
Tested: bun test src/server/__tests__/sessions.test.ts -t should\ reconstruct\ parent\ agent\ tool\ linkage\ from\ parentUuid\ chains
Not-tested: Full end-to-end visual verification against live CLI sessions with sub-agent text/thinking nested inline
Cron task metadata writes can overlap closely enough that a timestamp-only
$temp filename is not stable. Harden the atomic write path by using a
collision-resistant temp name and retrying once when rename reports ENOENT.
Constraint: Scheduled task persistence must keep atomic replace semantics in ~/.claude/scheduled_tasks.json
Rejected: Add explicit file locking around every scheduled task write | more coordination overhead than the observed transient rename race warrants
Confidence: high
Scope-risk: narrow
Directive: Keep scheduled task writes collision-resistant and retriable; do not revert to timestamp-only temp file names without reproducing concurrent writes
Tested: bun test src/server/__tests__/scheduled-tasks.test.ts
Not-tested: bun test src/server/__tests__/cron-scheduler.test.ts (existing timeouts and unrelated assertion failures in this checkout)
The session view exposed copy affordances in a way that implied the
whole conversation would be copied, while user prompts had no copy
path at all. This changes copy to a per-message footer action so the
scope is explicit for both prompts and assistant replies, and reuses
the shared clipboard helper instead of maintaining a second copy path.
Constraint: The worktree contains unrelated in-progress changes that must stay uncommitted
Rejected: Keep a floating action above each message | it interrupted reading order and still looked session-scoped
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep copy affordances attached to individual message blocks so the copied scope stays obvious
Tested: bun run test src/components/chat/MessageList.test.tsx; bun run lint
Not-tested: Manual desktop visual QA across dense multi-message sessions
Previously, creating a new session without selecting a project directory
defaulted to process.cwd(), which in the desktop app resolves to the app
installation path. Now it defaults to os.homedir().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add core🪟allow-start-dragging permission and acceptFirstMouse
config to fix window dragging on macOS with overlay title bar. Also add
JS-based startDragging() fallback in AppShell and Sidebar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rate limit: max 5 failed pairing attempts per user per 5 minutes
- Default closed: reject all users when no allowedUsers/pairedUsers configured
- Extract isAllowedUser() to common/pairing.ts to eliminate duplication
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use rejection sampling to ensure uniform distribution across the
safe alphabet. Values >= 232 are rejected and resampled.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After the first assistant response, derive a quick placeholder title from
the user message, then asynchronously call the provider's Haiku model to
generate a polished 3-7 word title. Titles update again at message 3 with
fuller conversation context. Updates push to frontend in real-time via
WebSocket `session_title_updated` event.
- extractTitle now reads `ai-title` JSONL entries (priority: custom > ai > first message)
- New titleService with deriveTitle + generateTitle using active provider config
- Handler tracks per-session message count and triggers generation on result
- Frontend sessionStore receives live title updates for sidebar + header
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
executeTask() lacked a runningTasks guard, so manual "Run Now" or
server restarts could spawn a second subprocess while one was already
running. Now checks runningTasks at entry and skips if already in flight.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>