# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
Add a HotkeyRecorder UI component that lets users click to enter
recording mode, press a modifier+key combination, and immediately
save it as the new Quick Prompt global shortcut.
- New HotkeyRecorder component in ui/ with live modifier preview,
animated recording indicator, click-outside/Escape to cancel,
platform-aware key symbol display, and disabled state support
- Integrate into QuickPromptSettingsSection with separate enable
toggle and recorder rows
- Recorder is disabled when the global hotkey toggle is off
- Existing GlobalHotkeyService.update() re-registers automatically
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove shadow-2xl shadow-black/50 from the ModelSelector dropdown. On
transparent Electron windows (Windows), box-shadows paint onto the
transparent canvas and create a visible rectangle behind the UI — the
panel itself already avoided this with a comment explaining why.
Add full arrow-key navigation to the model picker listbox: ArrowUp/Down
cycle through options, Enter/Space selects, Home/End jump to extremes,
Escape closes. The container auto-focuses on mount so keyboard input
works immediately after opening via Tab+Enter. Mouse hover also syncs
the focused index for consistent visual feedback.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add the ability to select from saved workspace agents when configuring
agent nodes in the workflow editor. Previously, adding an agent node
always created a new inline agent with empty fields.
Changes:
- Thread workspaceAgents prop through SettingsPanel → WorkflowEditor →
WorkflowGraphInspector → AgentNodeInspector
- Add Inline/Saved Agent source toggle in the agent node inspector
- Add workspace agent picker dropdown with stale-agent detection
- Add override-aware fields that show inherited values from the saved
agent with per-field reset buttons and visual indicators
- Support clean bidirectional switching between inline and linked modes
- Show saved workspace agents as directly-addable items in the node
palette with link icon, separated from the generic New Agent button
- Add handleAddWorkspaceAgentNode to create pre-linked agent nodes
The underlying data model (AgentNodeConfig.workspaceAgentId, overrides)
and resolution logic (resolveWorkflowAgentNode) already existed but were
never exposed in the UI.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add animation-fill-mode 'both' to .qp-panel-enter so the from-keyframe
(opacity: 0) applies immediately on mount, preventing the single-frame
flash of the opaque surface background before the entrance animation
begins.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Document StreamingTranscriptBuffer as the single owner of text assembly
- Note provider adapter layer (IProviderEventAdapter.TryAdapt) for event
normalization and how to add new providers
- Add capability metadata to protocol boundary description
- Update assistant-intent events as provider-neutral (not Copilot-specific)
- Add provider event normalization to sidecar runtime boundary
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>
- Main process now always emits resolved content in message-delta events,
making it the single authoritative text assembly point
- Renderer no longer imports or runs mergeStreamingText; uses main-process
resolved content directly with simple append as defensive fallback
- Forward assistant-intent events through the session event pipeline; track
currentIntent on SessionRecord, cleared on turn completion/cancellation
- Forward reasoning-delta events through the session event pipeline so
renderers can consume incremental reasoning text
- Add SessionEventKind entries: assistant-intent, reasoning-delta
- Add SessionEventRecord fields: intent, reasoningId, reasoningDelta
- Remove dead applyTurnDelta, applyMessageReclassified, applyAgentActivity
methods from AryxAppService (superseded by SessionTurnExecutor)
- Remove stale mergeStreamingText and appendRunActivityEvent imports from
AryxAppService
- Add 5 regression tests: resolved content path, simple append fallback,
intent set/clear lifecycle, duplicate suppression, intent preservation
during status transitions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add turn-stream capability metadata and richer normalized provider events for reasoning blocks, tool lifecycle, and turn boundaries. Track those signals in turn execution state and cover the new Copilot adapter/state behavior with tests.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The sidecar's fire-and-forget event handler pattern
(invokeRunTurnHandler) causes events to arrive out of order:
message-complete and status:idle can arrive before all
message-delta events have been emitted. Additionally, deltas
from multiple messages (thinking, response, sub-agent) were
naively concatenated into a single string, producing garbled
output.
Replace the single-string accumulation with a proper message
tracking model (Map<messageId, TrackedMessage>) that mirrors the
main app's SessionRecord.messages approach:
- Track each message independently by messageId
- Use message-complete event's content field as the authoritative
final text, replacing any garbled intermediate streaming state
- Mark messages as finalized on message-complete to skip late
arriving deltas that would corrupt the final content
- Derive display from the last non-thinking message's content
- Only transition to 'complete' when all tracked messages are
not-pending AND at least one non-thinking message has content,
preventing premature completion from setup/init events
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The session emits completion signals (agent-activity:completed,
message-complete, status:idle) during initialization before any
response content arrives. These early events were incorrectly
transitioning the popup to 'complete' phase, causing the
Nothing → In Progress → Nothing cycling pattern.
Track whether response content has been received via a ref and
only transition to 'complete' when hasContentRef is true. This
ensures setup/init completion events are ignored and the popup
stays in streaming until actual content has arrived and a
terminal event follows.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The popup stayed in 'streaming' phase because it only transitioned
to 'complete' on message-complete or status:idle when prev was
exactly 'streaming'. If other events (agent-activity, run-updated)
arrived between the last delta and idle, the phase guard could miss.
Broaden completion detection:
- status:idle now completes from any non-idle/non-complete phase
- agent-activity:completed also triggers completion
- Covers all paths the sidecar uses to signal turn end
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The popup window has its own document and never received the
data-theme attribute. Pass the current theme setting from the main
process via the show event, resolve 'system' to effective dark/light,
and apply to document.documentElement.dataset.theme so all CSS
variables match the main app's appearance.
- Add getCurrentTheme() to AryxAppService
- Pass theme in toggleQuickPromptWindow / showQuickPromptWindow
- Update onShow listener signature to receive theme string
- Apply theme to documentElement on each popup activation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When no explicit default model is configured in settings, fall back
to the first available model so the input bar always displays a
selected model name instead of 'Select model'. Also always reset
model/reasoning to defaults on each new prompt activation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Rewrite ModelSelector to group models by AI provider (OpenAI,
Anthropic, Google) using providerMeta and ProviderIcon instead of
grouping by tier; show tier as compact badge per model row
- Remove all box-shadow from qp-panel and border state variants;
on Windows transparent BrowserWindows, shadows paint on the
transparent canvas creating a visible dark rectangle behind the
rounded panel
- Add transparent background to html element in quickprompt.html
and CSS override via :has(body[data-quickprompt]) to ensure no
ancestor paints a visible background
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace translucent glass background with solid surface-1 color;
backdrop-filter does not work with transparent BrowserWindows on
Windows, leaving the panel nearly invisible
- Add data-quickprompt body attribute to quickprompt.html and CSS
overrides to ensure body/root are truly transparent, eliminating
the visible rectangle behind the rounded panel
- Remove overflow-hidden from qp-panel so model selector dropdown
is no longer clipped; the dropdown was positioned absolute and
rendered entirely outside the panel bounds
- Change ModelSelector to open downward (top-full) instead of upward
(bottom-full) for natural command-bar flow
- Update dropdown animation direction to match downward opening
- Increase blur handler delay to 200ms for safer dropdown interactions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix window lifecycle: await renderer load before showing, debounce
blur handler to prevent dropdown-induced dismiss
- Increase window height from 72px to 520px for response display
- Rewrite ModelSelector with tier-grouped upward-opening dropdown,
reasoning effort controls, and Brain icon for reasoning models
- Rewrite QuickPromptInput with visible model trigger, animated
chevron, auto-resize textarea, and proper stop button
- Improve QuickPromptResponse with compact thinking block, markdown
code/pre/link styling, and refined spacing
- Polish QuickPromptActions with consistent sizing and hover states
- Redesign settings QuickPromptSettingsSection: replace flat radio
list with compact grouped dropdown selector, only show reasoning
effort when selected model supports it, combine hotkey toggle
into single row
- Add markdown code block, inline code, and link CSS styles
- Fix dropdown animation direction for upward-opening selector
- Handle message-complete event in QuickPromptApp
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Change default hotkey from Super+Shift+A to Alt+Shift+A — Win key
combinations are frequently reserved by the OS and fail to register
- Make quick prompt window creation lazy (first hotkey press) so it
cannot interfere with main window startup
- Track failed accelerators to prevent error log spam from repeated
workspace-updated events
- Fix process.platform crash in renderer SettingsPanel — use isMac
from @renderer/lib/platform instead (renderer has no node globals)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix accelerator: convert 'Super' to 'Meta' in toElectronAccelerator()
since Electron uses 'Meta' for the Win/Cmd key, not 'Super'
- Defer quick prompt window creation until after workspace loads so a
failure cannot block the main window from rendering
- Extract registerQuickPromptIpcHandlers into a separate function called
after the quick prompt window is created
- Wrap quick prompt window creation in try/catch for resilience
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a system-wide global hotkey (Win+Shift+A / Cmd+Shift+A) that summons
a floating, frameless popup window for quick AI interactions from any app.
Main process:
- GlobalHotkeyService for registering/unregistering system-wide shortcuts
- Frameless, transparent, always-on-top BrowserWindow factory
- IPC handlers for send, discard, close, continue-in-aryx, cancel
- Session event routing from sidecar to quick prompt window
- Settings persistence for default model, hotkey, and reasoning effort
Renderer (separate lightweight entry):
- QuickPromptApp with session state, streaming, keyboard shortcuts
- QuickPromptInput with model selector trigger and cancel support
- QuickPromptResponse with streamed markdown and thinking blocks
- QuickPromptActions (Discard / Close / Continue in Aryx)
- ModelSelector dropdown with tier badges and reasoning effort
- Glass Command Bar aesthetic with animated gradient border
Settings:
- Quick Prompt section in SettingsPanel with enable toggle, hotkey
display, default model selector, and reasoning effort picker
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
On Linux, fs.watch() on a non-existent directory emits an asynchronous
'error' event instead of throwing synchronously. Without an error handler,
this crashes the process. Tests that create AryxAppService with fake
project paths (e.g. C:\workspace\project-one) trigger this on Linux CI
because those paths don't exist.
Attach an 'error' event handler to the FSWatcher that logs a warning and
closes the watcher gracefully. This fixes the Linux CI 'bun test' failure
and also prevents production crashes if a watched directory is deleted
at runtime.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Renderer code splitting:
- Lazy-load 15 components with React.lazy() and Suspense (ChatPane,
ActivityPanel, SettingsPanel, TerminalPanel, WelcomePane, BottomPanel,
GitPanel, CommandPalette, CommitComposer, WorkflowPicker, BookmarksPanel,
SessionSearchPanel, KeyboardShortcutsPanel, DiscoveredToolingModal,
ProjectSettingsPanel)
- This moves ~1.2 MB of optional dependencies (Lexical, @xyflow/react,
@xterm/xterm, highlight.js, motion) out of the critical bundle
- Critical bundle reduced from ~1.5 MB to ~759 KB
- Defer JetBrains Mono font load to TerminalPanel (saves ~80 KB at startup)
Main process optimizations:
- Use show: false + ready-to-show on BrowserWindow to eliminate blank flash
- Decouple workspace loading from bootstrap — no longer blocks window, tray,
and auto-update setup
- Defer sidecar-dependent approval tool pruning to run in background after
workspace is returned to renderer (removes sidecar spawn from critical path)
- Parallelize independent workspace sync operations (user tooling, project
tooling, project customization) with Promise.all()
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extract TryResolveSubWorkflowDefinition that returns null instead of
throwing when a referenced workflow is missing from the library.
Use the tolerant variant in all graph-walking helpers that build
agent indexes, collect agent nodes, and find sub-workflow nodes.
These operations are used for activity UI enrichment and agent
identity resolution — they should degrade gracefully rather than
crash the turn.
The throwing ResolveSubWorkflowDefinition is now only used by
WorkflowRunner.CreateNodeRoute, which is the actual execution
path and correctly fails with a clear error if a reference is
truly missing.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Deep agent resolution in the sidecar now walks sub-workflow nodes so
nested agents carry subworkflowNodeId and subworkflowName on activity
events. New subworkflow-started / subworkflow-completed activity types
let the frontend track sub-workflow lifecycle.
The Activity panel groups nested agents under collapsible sub-workflow
cards with status badges, accent-colored left borders, and smooth
expand/collapse transitions. Cards auto-expand when a sub-workflow
starts running. Workflows without sub-workflow nodes render identically
to before.
Extracted AgentRow, SubWorkflowGroup, and shared accent constants to
a new components/activity/ feature directory. Added
resolveWorkflowAgentHierarchy and buildGroupedActivityRows for
hierarchical activity grouping with dynamic fallback for unresolved
sub-workflow agents.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add toolArguments to normalizeRunTimelineEvent output so persisted
sessions retain tool argument data across app restarts
- Add toolArguments field to AgentActivityState and propagate it in
applySessionEventActivity for real-time activity labels
- Add tests for normalization round-trip with and without toolArguments
- Add test for activity state including toolArguments
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The CopilotTurnExecutionState was ignoring ToolExecutionStartData.Arguments
when creating tool-calling activity events, despite the Copilot SDK providing
them. This caused the activity panel to show 'Viewed a file' / 'Used rg'
with no contextual details (file paths, search patterns, etc.).
The fix adds NormalizeRawToolArguments to WorkflowRequestInfoInterpreter for
converting the raw object? payload (typically JsonElement) into the normalized
dictionary, then passes ToolExecutionStartData.Arguments through
CreateToolCallingActivity.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When toolArguments doesn't contain the expected key (e.g. 'path' for
view), fall back to the first usable string value from any argument
key instead of showing misleading placeholders like 'Viewed a file'.
When no arguments exist at all, show just the tool name.
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>
Extract seven responsibility clusters from the 3,466-line AryxAppService
monolith into focused service classes under src/main/services/:
- WorkflowManager: workflow CRUD, templates, validation, resolution
- McpProbeManager: MCP server probing, OAuth pre-auth, probe queuing
- DiscoveredToolingSyncService: tooling/customization scanning, watchers
- GitContextManager: git refresh orchestration, context updates, mutations
- CheckpointRecoveryManager: checkpoint retry/recovery state handling
- ApprovalCoordinator: approval/user-input/plan-review/OAuth state machine
- SessionTurnExecutor: turn execution, streaming deltas, finalization
AryxAppService remains the public facade consumed by IPC handlers but now
delegates internally via constructor-injected service instances. A new
AppServiceDeps type provides a clean dependency injection seam for testing.
The facade is reduced from 3,466 to 2,572 lines. All existing tests pass
with two test files migrated to constructor DI (appServiceGitRefresh,
appServiceMcpProbing). New focused tests added for WorkflowManager and
the DI seam itself.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CopilotAgentBundle.CreateAsync unconditionally resolved the Copilot CLI
path and started a CopilotClient, even for workflows with no agent
nodes (e.g. request-port-only workflows). This caused a hard failure
in CI where the copilot binary is not on PATH.
Move CLI path resolution, client creation, and agent setup inside a
guard that checks whether the workflow actually contains agent nodes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The sidecar projects were updated to target net10.0 but the CI
workflow still installed dotnet-version 9.0.x, causing all validate
jobs to fail at the sidecar test step.
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>