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>
The Activity Panel already shows premium request counts in the
Session Usage section, so the ChatPane footer only needs the
context-window bar.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add three layers of usage visibility:
- ChatPane footer: premium request count, AIU consumed, and quota
remaining below the existing context-window bar
- Settings / CopilotStatusCard: on-demand account quota section with
progress bars, overage indicators, and reset dates fetched via
the new get-quota sidecar command
- Activity Panel: per-agent token/cost/duration totals on each agent
row and a Session Usage summary section between agents and timeline
Backend (sidecar):
- New get-quota command using SDK account.getQuota RPC
- New assistant-usage turn-scoped event from SDK assistant.usage
- QuotaSnapshotMapper for both typed and untyped SDK quota payloads
- DTOs: GetQuotaCommandDto, QuotaSnapshotDto, AccountQuotaResultEventDto,
AssistantUsageEventDto
Frontend:
- Shared types: AssistantUsageEvent, QuotaSnapshot, GetQuotaCommand
- IPC bridge: getQuota channel, assistant-usage event dispatch
- State: SessionRequestUsageMap accumulator with per-agent breakdown
- 8 new tests for accumulator logic and formatting helpers
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The CodeHighlightPlugin's selection restoration could create an invalid
Lexical selection targeting a LineBreakNode with type 'element'. Since
LineBreakNode is not an ElementNode, Lexical threw during reconciliation
and the LexicalErrorBoundary replaced the editor with an error state.
The fix ensures findPoint never targets a LineBreakNode directly.
Instead it falls back to an element-level selection on the parent
CodeNode using the child index, which is always a valid target.
Extracted the selection helpers (getCodeNodeAbsoluteOffset,
findCodeNodeSelectionPoint, restoreCodeNodeSelection) into
markdownEditor.ts for testability and added regression tests.
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>
Change the bottom action bar from absolute positioning to normal
document flow so it sits below the editable area instead of floating
on top. Reduce editable bottom padding since buttons no longer overlap.
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>
When multiple MCP servers expose the same tool names (e.g., several
kusto-mcp instances), each server's group now shows its tools instead
of only the first server getting the tools and others showing 0/0.
Deduplicate the effectiveAutoApprovedCount to avoid double-counting
shared tools in the pill header.
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>
When MCP server configs declare wildcard tools (empty tools array),
the Copilot SDK has no API to list individual tool names. Add direct
MCP protocol probing using @modelcontextprotocol/sdk to discover
available tools from each accepted server.
- Add McpToolProber service supporting stdio/SSE/HTTP transports
- Probe accepted MCP servers on project load, acceptance, and rescan
- Store probed tools on DiscoveredMcpServer and McpServerDefinition
- Use probed tools in listApprovalToolDefinitions when declared tools
are empty, so the approval pill shows individual tool toggles
- Remove unused isMcpServerApprovalKey helper
- Fix effectiveAutoApprovedCount Math.max workaround in ChatPane
- Add comprehensive tests for probed tool behavior
- Update ARCHITECTURE.md tooling integration section
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>
Move project-specific settings (discovered MCP servers) out of the
global Settings panel and into a dedicated ProjectSettingsPanel overlay.
Users can now access any project's settings via a gear icon on the
sidebar project header, or by clicking the pending-discovery badge.
- Add ProjectSettingsPanel component with project info, discovered MCP
server management (accept/dismiss/rescan), and project removal
- Add gear icon and clickable discovery badge to Sidebar ProjectGroup
- Remove project-specific discovery props from SettingsPanel (now
shows only user-level discovered servers)
- Wire ProjectSettingsPanel overlay in App.tsx with auto-close on
project removal
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the old disconnected-node addAgentNodeToGraph with the
mode-aware addAgentToGraph so new agents are automatically wired
into the graph topology. Replace the graph-nuking removeAgent
path with removeAgentFromGraph for surgical node removal. Split
emitChange into graph-preserving and mode-change paths so editing
agent properties no longer discards custom positions and edges.
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>
Generalize the scratchpad-only model/reasoning-effort selector to work
in any session whose pattern has exactly one agent. This enables model
switching above the chat input for project 1-on-1 chats, not just
scratchpads.
- Rename ScratchpadSessionConfig -> SessionModelConfig across domain,
contracts, IPC, preload, and renderer
- Replace isScratchpadProject guard with agents.length === 1 check in
EryxAppService.updateSessionModelConfig and ChatPane pills gate
- Apply session model config in buildEffectivePattern whenever present,
regardless of project type
- Seed sessionModelConfig on session creation for any single-agent
pattern
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds cancel-turn IPC channel, SidecarClient.cancelTurn(), TurnCancelledError,
EryxAppService.cancelSessionTurn(), finalizeCancelledTurn(), stop button in
ChatPane, and cancelled run status throughout the run timeline.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move the Tool Auto-Approval Defaults section into the tool-call
ApprovalCheckpointRow card so the tool list appears directly under
the toggle instead of in a disconnected section below. Extend
ApprovalCheckpointRow with an optional children prop rendered
inside the card when the checkpoint is enabled.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a Troubleshooting section under a Support nav group in Settings:
- Open App Data Folder: reveals the user-data directory in the OS file
explorer via shell.openPath.
- Reset Local Workspace: destructive action that deletes workspace.json
and scratchpad contents, clears the in-memory cache, and reseeds
defaults. Auth secrets are preserved. Requires two-step confirmation.
New IPC channels, ElectronApi methods, and preload bridge added for
openAppDataFolder and resetLocalWorkspace. Existing electron mock in
tests updated to include shell.
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>
PrismJS's CJS global state is fundamentally incompatible with Vite's ESM
dev mode, causing missing language support (~40% of dropdown languages)
and fragile loading hacks (optimizeDeps, global assignment).
Replace the entire Prism integration with highlight.js/lib/common which
is ESM-native, has no global state, and covers all 22 dropdown languages
out of the box (~37 common languages included).
Implementation:
- Custom CodeHighlightPlugin using hljs.highlight() for tokenization
- HTML parser extracts flat tokens from hljs output (handles nested spans)
- Token type mapping from hljs scopes to Lexical codeHighlight theme keys
- Selection preservation via absolute character offset save/restore
- Re-entrancy guard prevents infinite transform loops
- Removed @lexical/code-prism import and Vite optimizeDeps workaround
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The previous approach imported prismjs component files directly in
MarkdownComposer.tsx. In Vite dev mode, each component is served
as a separate ESM module whose IIFE references a bare 'Prism' global
that doesn't exist yet, crashing the app.
Fix: create a dedicated prismSetup module that imports prismjs and
assigns globalThis.Prism, then import it from the renderer entry
point (main.tsx) before any component that loads @lexical/code-prism.
ESM evaluation order guarantees the global is set before the
tokenizer captures its reference.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Register CodeHighlightNode in the editor node set
- Add CodeHighlightPlugin that calls registerCodeHighlighting
- Map 20+ Prism token types to mc-tok-* CSS classes with dark theme colors
- Explicitly import prismjs + language components and set globalThis.Prism
before @lexical/code-prism loads, fixing a Vite dev-mode race where
the CJS shim could initialize the tokenizer before the global was set
- Added @types/prismjs for type checking
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>