- Fix useElapsedTimer to use completedAt instead of Date.now() for
finished runs, preventing wildly inaccurate durations (e.g. 9802m)
when reopening old sessions
- Extract formatElapsedMs as a shared pure formatter; reuse in
SubagentActivityCard
- Standardize icon column alignment across all activity row types
using consistent w-4 + h-[18px] icon containers
- Redesign collapsed header: status dot with pulse animation, bolder
status label, tabular-nums on elapsed time, cleaner hierarchy
- Polish expanded stream: timeline spine connecting activity items,
more prominent intent dividers with pill-style background,
tightened vertical rhythm
- Add unit tests for formatElapsedMs
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- ChatPane header now prefers session.currentIntent over the activity-
derived label from summarizeSessionActivity for the busy status display
- TurnActivityPanel receives currentIntent via props and prefers it over
extractLatestIntent (report_intent tool-call scanning) when the panel
is active; falls back to tool-call scan for completed/inactive runs
- This replaces the report_intent-as-status inference pattern with the
normalized assistant-intent event data from the backend
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the flat, repetitive 'Agent used X' activity list with a
structured narrative timeline:
- Group consecutive same-tool calls into collapsible rows with context
(e.g. 'Viewed 4 files' with file names listed below)
- Use verb-based labels with arguments: 'Viewed ChatPane.tsx:148-250',
'Searched for tool-call', 'Edited runTimeline.ts'
- Promote report_intent events to phase dividers that segment the
timeline into labeled stages of work
- Show latest intent text in the collapsed header summary
- Use category-specific icons (Eye, Search, Pencil, Terminal, etc.)
instead of the universal wrench
- Render thinking steps as quoted blocks with 'N more' toggle for
consecutive groups
All data was already available in RunTimelineEventRecord.toolArguments;
this change surfaces it prominently instead of hiding it behind
expandable detail panels.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Thread toolArguments from the sidecar through shared contracts, main-process pipeline, and into the renderer. Add ToolCallDetailPanel with inline summaries (command, path, pattern, etc.) and expandable argument details for every tool-call event in the activity timeline.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
In sequential workflows, multiple collapsible turn-activity panels shared
the same SessionRunRecord and displayed identical aggregate metrics (tool
calls, approvals, etc.) instead of per-agent counts.
Root cause: ChatPane grouped thinking messages correctly per agent, but
passed the full unfiltered run object to every TurnActivityPanel, so
summarizeActivity() counted all events from the entire run for each panel.
Changes:
- Extract filterEventsByAgent() and summarizeActivity() to
runTimelineFormatting.ts as pure, testable helpers
- Add agentNames (derived from thinking message authors) and isLastRunPanel
to the DisplayItem turn-activity variant in ChatPane
- TurnActivityPanel now filters run.events through filterEventsByAgent()
so each panel only counts events belonging to its agents
- Git summary / discard actions only render on the last panel of a run
- Per-agent timing derived from scoped events instead of run-level start
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The panel was only emitted as a DisplayItem when classified thinking
messages existed. During most of the turn, thinking messages haven't
been reclassified yet, so the panel appeared late with all activities
already populated.
Two fixes:
- After the message loop, inject a turn-activity item for any active
run that wasn't already attached to a thinking group. This makes the
panel appear as soon as the run record exists.
- Remove the guard that required run events to exist before rendering.
The panel now shows in its 'Working' state immediately when the run
starts, and populates progressively as events arrive.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the separate RunTimeline in the ActivityPanel with a generalized
TurnActivityPanel that renders inline in the chat pane between user
messages and assistant responses.
The new component:
- Shows all turn activities (thinking steps, tool calls, approvals,
handoffs, run status) in a single collapsible panel
- Merges chat thinking messages with run timeline events into a
chronological activity stream
- Auto-expands when a turn starts, auto-collapses on completion
- Displays a compact summary header (elapsed time, tool call count,
handoff count, etc.) when collapsed
- Includes post-run git change summary with discard/commit actions
- Uses subtle entrance animations for rows
Removed components:
- ThinkingProcess.tsx (subsumed by TurnActivityPanel)
- RunTimeline.tsx (no longer needed as a standalone component)
The ActivityPanel retains its agents, session usage, and turn events
(diagnostics/hooks) sections.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Show agent activity label in chat header (Thinking…, Using bash…, etc.)
instead of an anonymous pulsing dot
- Fix ThinkingProcess elapsed timer to tick live every second using
useElapsedTimer hook instead of stale useMemo computation
- Show completed/failed subagents for 3s grace period with fade-out
transition instead of instantly hiding them
- Transition activity labels to Completed state for 1.5s grace period
on session idle instead of abrupt removal
- Eliminate message flash during thinking reclassification by folding
trailing pending assistant messages into the thinking group
optimistically when they follow existing thinking messages
- Stabilize ThinkingProcess isActive flag by checking for pending
messages in the group rather than relying solely on array position
- Skip rendering empty pending messages inside ThinkingProcess steps
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Delete src/shared/domain/pattern.ts and all pattern-specific renderer
components (PatternEditor, NewSessionModal, pattern-graph directory,
patternGraph lib) and their tests
- Migrate all renderer imports from @shared/domain/pattern to
@shared/domain/workflow (ReasoningEffort, reasoningEffortOptions,
WorkflowOrchestrationMode, AgentNodeConfig, WorkflowDefinition)
- Update App.tsx: remove workflowToPattern bridge, createDraftPattern,
NewSessionModal; sessions now created directly with default workflow
- Update ChatPane, ActivityPanel, Sidebar to accept WorkflowDefinition
instead of PatternDefinition and derive agents/mode from workflow
- Update SettingsPanel: remove PatternsSection nav item, pattern editing
state, and pattern-related props; update text references
- Update RunTimeline and modeAccent/modeVisuals records to use
WorkflowOrchestrationMode (drop magentic mode entry)
- Update sessionActivity.ts to use generic agent interface
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Surface prompt model and argumentHint metadata across the UI:
- InlinePromptPill: send model in promptInvocation, show model badge
in dropdown, show argumentHint preview, support armed-prompt state
for prompts with argumentHint (prompt stays pinned, hint becomes
composer placeholder, user types additional context before sending)
- ChatPane: armed-prompt state management, argumentHint-driven
placeholder, send button enabled when prompt is armed, clear armed
state on session change
- PromptInvocationChrome: model badge in transcript, parent-repo badge
and shortened source path display for ancestor-relative paths
- ProjectSettingsPanel: model and argumentHint on prompt cards,
parent-repo badge on instructions and prompts with ancestor paths,
.claude/rules mentioned in instructions description and empty state
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Update InlinePromptPill to build ProjectPromptInvocation from
selected prompt file and send it via onSubmit instead of pasting
raw resolved text as chat content
- Thread promptInvocation through ChatPane.onSend and App.tsx to
the sendSessionMessage IPC call
- Add PromptInvocationChrome component for user messages that were
triggered by a prompt file, showing prompt name, agent badge,
tool count, source path, and expandable resolved body
- Surface prompt agent and tools metadata in InlinePromptPill
dropdown list items and ProjectSettingsPanel PromptCard
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the narrow 256px sidebar git section with a shared tabbed
bottom panel that hosts both Terminal and Git as peer tabs. This gives
git operations full horizontal width for file paths, diff previews,
branch lists, and commit history.
- Create BottomPanel with shared resize handle, tab bar, and content
switching (terminal stays mounted via CSS visibility when inactive)
- Simplify TerminalPanel by extracting resize/close to BottomPanel
- Add InlineGitPill toggle in composer footer next to Terminal pill
- Wire tab switching: clicking active tab closes panel, clicking
inactive tab switches to it
- Remove GitPanel from ActivityPanel sidebar
- Update ARCHITECTURE.md to describe tabbed bottom panel layout
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- RunChangeSummaryCard: post-run change review card with expandable
file diffs, origin badges, selective discard with confirmation,
and commit composer launch button
- CommitComposer: slide-over panel for staging files, editing AI-
suggested commit messages, conventional commit type selection,
and commit with optional push
- GitPanel: embedded activity panel section with branch management,
push/pull/fetch operations, working tree inspection with inline
diffs, and recent commit history
- Wire RunChangeSummaryCard into RunTimeline after completed runs
- Wire CommitComposer as overlay in App.tsx with state management
- Wire GitPanel into ActivityPanel for non-scratchpad sessions
- Update ARCHITECTURE.md with frontend git integration description
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Wire message-reclassified sidecar events through the main process to
the renderer, where reclassified messages are filtered out of the main
transcript and collected into a collapsible ThinkingProcess component.
Main process changes:
- Route message-reclassified via dedicated onMessageReclassified callback
- Add applyMessageReclassified handler that sets messageKind and emits
the session event for the renderer
- Forward assistant-intent and reasoning-delta as turn-scoped events
Renderer changes:
- Split session.messages into visibleMessages and thinkingMessages
- Render ThinkingProcess above the last assistant message
- ThinkingProcess auto-expands during active turns, collapses on finish
- Update messagePhase to skip thinking-kind messages for final detection
Tests:
- 3 new sessionWorkspace tests for reclassification apply/dedup/ignore
- 2 new messagePhase tests for thinking-kind handling
- Updated runTurnPending test fixtures for new callback
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two fixes in the auto-approval pill:
1. GroupToggle now uses brand-gradient-bg with glow shadow and matches
ToggleSwitch sm dimensions, making MCP group toggles visually
consistent with individual tool toggles.
2. Individual tool toggles now reflect server-level approval state.
When a server key is approved, all tool rows show as enabled.
Toggling a single tool OFF in a server-approved group expands the
server key to individual tool IDs minus the excluded tool, enabling
the 'approve all → disable one specific tool' workflow.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add bulk action buttons to the Tools and Auto-approval pill popovers:
- Tools pill: sticky header with Enable all / Disable all toggle button
that enables or disables every MCP server and LSP profile at once
- Approval pill: Approve all / Unapprove all button in the existing
sticky header next to the Reset button, approving or clearing all
tool and server approval keys
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Show expandable file change previews on tool-call timeline events
when file changes are present. Each tool-call row gains a compact
summary (file count, +/- stats, GitHub-style stats bar) that
expands to per-file entries with collapsible unified diffs.
- FileChangePreview component in chat/ feature directory
- DiffLine with background highlighting for additions/deletions
- DiffStatsBar mini visualization (5-block addition/deletion ratio)
- New file detection with FilePlus2 icon and 'new' badge
- TimelineEventRow restructured to wrapper div for proper nesting
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Complete visual overhaul of the Aryx application with the Luminous Depth
design language — blue-tinted dark surfaces, brand gradient accents,
glass-morphism effects, and refined typography.
Design Foundation:
- New color system with CSS custom properties for all surfaces, borders,
text, accents, and status colors
- Typography: Outfit (display), DM Sans (body), JetBrains Mono (code)
- Animations: accent-flow, thinking-wave, ambient-glow
- Utility classes: glass-surface, glow-border, brand-gradient-bg/text
- Light theme with cool-tinted whites and blue-tinted shadows
Components Updated:
- UI primitives (TextInput, SelectInput, ToggleSwitch, FormField, etc.)
- AppShell with ambient glow background
- Sidebar with brand gradient selection and accent-flow running bars
- ChatPane with semantic phase tinting and gradient user avatars
- WelcomePane with nebula background and motion entrance animations
- All chat banners (Approval, UserInput, PlanReview, MCP Auth, etc.)
- ActivityPanel and RunTimeline with glass-surface cards
- Settings panels, modals, and editor shells
- TerminalPanel with harmonized ANSI palette
- PatternGraph nodes with glass-surface styling
- MarkdownComposer toolbar
Zero hardcoded zinc/indigo color classes remain in renderer components.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Display compact status cards in the chat transcript showing each
sub-agent's name, current activity (Thinking, Using grep, etc.),
and elapsed time. Cards appear while sub-agents are running and
clear when the session goes idle.
- Extend SessionEventRecord with description, error, toolCallId,
and model fields for subagent events
- Forward additional subagent fields in handleTurnScopedEvent
- Add subagentTracker reducer to derive active subagent state from
session events, including agent-activity correlation
- Create SubagentActivityCard component with spinner, status icon,
agent name, activity label, and live elapsed timer
- Wire activeSubagents state in App.tsx and pass to ChatPane
- Add 16 unit tests for the subagent tracker
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Declutter the pill row above the chat composer by relocating Terminal
and Prompts pills from the session-config rows into the composer's
bottom action bar (left side). The session-config row now only shows
session-scoped controls: Tools, Approval, Model, and Thinking.
The relocated pills use a lighter, borderless style matching the
inner-composer aesthetic alongside the existing Attach, Plan mode,
and Send buttons.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Thread mcpProbingServerIds from workspace state through App → ChatPane → InlineApprovalPill
- Show animated spinner and 'probing…' label on pill button while any MCP server is being probed
- Show per-server probing indicator in popover: spinning icon, 'probing…' badge, hidden toggle
- Render approval pill during probing even when no MCP tools are known yet
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Change the approval group header from <button> to a <div> with
role='button' and keyboard handling to avoid nesting the GroupToggle
<button> inside another <button>, which is invalid HTML.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
MCP servers configured with empty tools arrays (wildcard) now appear in the
auto-approval pill with a server-level toggle. When toggled, a server-level
approval key (mcp_server:<name>) is added to autoApprovedToolNames. The
sidecar matches this key against PermissionRequestMcp.ServerName to auto-
approve all tools from that server without needing individual tool names.
- Add buildMcpServerApprovalKey/isMcpServerApprovalKey helpers
- Create approval groups for all MCP servers including empty-tools ones
- Add serverApprovalKey to ApprovalToolGroup for server-level toggles
- Update sidecar RequiresToolCallApproval to check server-level keys
- Include server-level keys in listApprovalToolNames for pruning safety
- Add tests for both shared domain and sidecar approval matching
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Group MCP tools by server and LSP tools by profile in the approval popover
instead of showing a flat list. Each server/profile group gets a collapsible
header with a batch toggle to approve/unapprove all tools at once. Add a
search filter (visible when >10 tools) and partial-state indicators for
groups with mixed approval. Add groupApprovalToolsByProvider shared helper
with tests.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add Copilot Customization section to ProjectSettingsPanel with instruction file
previews, agent profile enable/disable toggles, and prompt file listing. Add
InlinePromptPill to chat input for selecting and sending prompt files with
variable substitution. Wire rescan and agent profile IPC in App.tsx. Update
website with Copilot Customization feature card.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The auto-approval pill displayed effectiveAutoApproved.size as the
numerator, which could include tool names not present in the approval
tool list (e.g. names added via 'Always approve' for tools that aren't
in runtimeTools yet). This caused impossible counts like '17/14'.
Compute the count by intersecting effectiveAutoApproved with the actual
approvalTools list, so the numerator never exceeds the denominator.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When a tool-call approval banner appears, users can now click 'Always
approve' to both approve the current call AND add the tool to the
session's autoApprovedToolNames. Future calls to that tool are then
auto-approved without showing the banner.
- Add alwaysApprove?: boolean to ResolveSessionApprovalInput
- In resolveSessionApproval, atomically append tool to session
approvalSettings when alwaysApprove is true (avoids running guard)
- Add 'Always approve' button in ApprovalBanner (tool-call kind only)
- Wire through ChatPane and App.tsx with updated callback signatures
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Create mcpTokenStore: in-memory token storage keyed by normalized server URL
with automatic expiry checking
- Create mcpOAuthService: full OAuth 2.1 + PKCE flow implementation
- Protected Resource Metadata discovery (RFC 9728)
- Authorization Server Metadata fetch (RFC 8414)
- Dynamic Client Registration (RFC 7591) when no static client ID
- PKCE S256 code challenge generation
- Local HTTP callback server for auth code receipt
- Browser-based consent via Electron shell.openExternal
- Authorization code to token exchange
- Add startSessionMcpAuth IPC channel and handler to trigger OAuth flow
- Inject stored OAuth tokens as Authorization headers in buildRunTurnToolingConfig
- Update McpAuthBanner with 'Authenticate in browser' button and loading state
- Add tests for token store (7 tests) and token injection (3 tests)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add McpOauthRequiredEvent and McpOauthStaticClientConfigEvent to sidecar contracts
- Add PendingMcpAuthRecord domain type with status tracking (pending/authenticating/failed/done)
- Add pendingMcpAuth field to SessionRecord for session-level auth state
- Wire onMcpOAuthRequired callback through sidecarProcess, runTurnPending, and AryxAppService
- Handle mcp-oauth-required events: set session pendingMcpAuth, clear on turn finalize/cancel
- Add dismissSessionMcpAuth IPC channel with preload binding and handler registration
- Create McpAuthBanner component (amber-themed, shows server name/URL, dismiss button)
- Integrate McpAuthBanner into ChatPane with placeholder text and App.tsx callback
- Update test fixtures for new RunTurnPendingCommand.onMcpOAuthRequired field
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Move plan mode toggle from pills row to composer send button area
- Plan toggle sits next to the send button as a mode switch icon
- Send button turns emerald when plan mode is active
- Add mode indicator strip below composer when plan mode is on
- Replace 'Implement this plan' auto-send button with instructional
guidance text that tells the user to send a follow-up message
- Keep Dismiss button to clear the plan review banner
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add InteractionMode type and ExitPlanModeRequestedEvent to sidecar contracts
- Add PendingPlanReviewRecord domain type and interactionMode to SessionRecord
- Wire onExitPlanMode callback through SidecarClient and RunTurnPendingCommand
- Pass session interaction mode to RunTurnCommand for sidecar consumption
- Handle exit-plan-mode-requested events in AryxAppService
- Add setSessionInteractionMode and dismissSessionPlanReview IPC methods
- Create PlanReviewBanner component with summary, markdown content, and actions
- Add plan mode toggle pill in ChatPane composer area
- Wire implement action as follow-up message (graceful degradation)
- Clear pending plan review on new turn, turn completion, and cancellation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Wire the sidecar user-input-requested protocol event through the main
process, IPC layer, and renderer UI so agents can ask the user
interactive questions with choices and freeform input.
- Add UserInputRequestedEvent and ResolveUserInputCommand to sidecar
protocol types
- Add resolveUserInput method to SidecarClient and onUserInput callback
to runTurn
- Create PendingUserInputRecord domain type and add pendingUserInput to
SessionRecord
- Add handleUserInputRequested and resolveSessionUserInput to
AryxAppService with handle management
- Register sessions:resolve-user-input IPC channel with preload bridge
- Create UserInputBanner component with choice buttons and freeform
input
- Integrate UserInputBanner into ChatPane with header indicator
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove .pill-trigger CSS class and restore the idiomatic Tailwind v4
@theme approach: --text-pill in @theme generates the text-pill utility.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The @theme --text-pill token and text-[8px] arbitrary value both
failed to apply at dev time due to @tailwindcss/vite not generating
the utility rule during HMR. Use a plain .pill-trigger CSS class
in styles.css instead, which is always available regardless of
Tailwind's JIT scanner behavior.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The arbitrary text-[8px] class was not being generated by the
Tailwind v4 Vite plugin at dev time. Register --text-pill in
@theme so text-pill becomes a first-class utility that is always
generated. Uses 0.5rem (8px) with line-height 1.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add explicit leading-none alongside text-[8px] so both font-size
and line-height shrink, making the size reduction visually apparent.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reduce font to text-[8px], restore icons to size-2.5 for legibility,
and bump padding to px-1.5 py-0.5 so icons aren't flush with the
pill border.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Shrink padding (px-2 py-1 → px-1.5 py-0.5), font (12px → 11px),
gap (1.5 → 1), icon size (3 → 2.5), and model name max-width
(140px → 120px) on all four pill trigger buttons. Dropdown popovers
remain unchanged.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>