Move React DevTools profiling instructions from CLAUDE-PERFORMANCE.md
to CONTRIBUTING.md under the Profiling section:
- Full installation and launch commands
- Components and Profiler tab descriptions
- Step-by-step profiler workflow
- Chrome DevTools Performance tab guidance
CLAUDE-PERFORMANCE.md now references CONTRIBUTING.md for profiling
workflow (keeping it focused on code patterns for AI).
Claude ID: 286ae250-379b-4b74-a24e-b23e907dba0b
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
Document the standalone React DevTools app for render profiling:
- Installation and launch commands
- Auto-connection via script in src/renderer/index.html
- Components and Profiler tab descriptions
- Basic profiler workflow for identifying render issues
Claude ID: 286ae250-379b-4b74-a24e-b23e907dba0b
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
Document how to use the standalone React DevTools app for component
inspection and render profiling. The connection script already exists
in src/renderer/index.html but wasn't documented.
Claude ID: 286ae250-379b-4b74-a24e-b23e907dba0b
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
- Test button is inline within Ungrouped Agents header when ungrouped sessions exist
- Test button is standalone (full-width) when no ungrouped sessions exist
- Prevents regression of button placement behavior
## Windows Command Line Length Fix
Resolved 'Die Befehlszeile ist zu lang' (command line too long) error on Windows by:
- Modified inline document generation to use sendPromptViaStdin on Windows
- Passes prompt via stdin instead of as command line argument
- Bypasses Windows cmd.exe ~8KB command line length limit
- Matches approach already used for SSH remote execution
- Added --input-format stream-json when using stdin with stream-json compatible agents
- Added logging for prompt length and stdin usage for debugging
## OpenCode Agent Support
Extended inline wizard to support OpenCode agent alongside Claude Code and Codex:
- Added 'opencode' to supported wizard agents list in useInlineWizard hook
- OpenCode batch mode args handling already present in buildArgsForAgent functions
- Added SSH-aware availability checking in both conversation and document generation phases
## SSH Remote Configuration
Improved SSH remote session handling:
- Added sessionSshRemoteConfig to DocumentGenerationConfig interface
- Added sendPromptViaStdin and sendPromptViaStdinRaw to renderer ProcessConfig
- Pass sessionSshRemoteConfig through entire wizard lifecycle (conversation → document generation)
- Skip local agent availability checks when executing on remote hosts
- Use agent type as command fallback for remote-only agents
- Added logging to distinguish remote execution from local
## Remote Agent Availability Fix
Fixed critical bug preventing remote SSH agents from being used:
- Split agent availability checks to allow null agents for remote sessions
- For remote sessions: skip both null-check AND availability-check
- For local sessions: enforce both checks as before
- Allows remote-only agents (like SSH-configured OpenCode) to work for both conversation and document generation
## Test Updates
- Fixed useInlineWizard.test.ts by adding window.maestro.agents.get mock
- Mock returns agent info needed for availability checks
- Added comprehensive test coverage for remote agent scenarios
- Move Top and Bottom navigation buttons outside the scrollable section
- Add distinct background styling with accent color tint
- Add border separators for visual hierarchy (border-b for Top, border-t for Bottom)
- Reduce scrollable section height to account for fixed sash buttons
- Add data-testid attributes for testing
- Add test coverage for sash button visibility and functionality
- When ungrouped agents exist: inline button in header (like Group Chats)
- When no ungrouped agents: standalone full-width button (folder hidden)
- When no groups exist (flat list): standalone full-width button below sessions
- Added “View Git Log” action right inside GitStatusWidget tooltip 🧭
- Wired MainPanel to open Git Log directly from the widget 🪟
- Expanded GitStatusWidget API with optional `onViewLog` callback 🧩
- Improved test coverage for Git log tooltip interactions and rendering 🧪
- Cleaned repo by removing auto-generated CLAUDE.md memory context files 🧹
- Enhanced release notes frontmatter with a new newspaper icon 🗞️
- Preview panel now supports back/forward history with arrow-key navigation 🧭
- Added slick chevron buttons for preview back/forward with disabled states 🔙
- Wiki-link resolution now scans *all* markdown files, not just graphed ones 🗂️
- Graph data builder now pre-scans markdown paths for faster preview linking 🔎
- Stats dashboards gained a new “This Quarter” time range everywhere 📆
- Activity heatmap adds quarter support with richer 4-hour block granularity 🧱
- Brand-new Agent Efficiency chart compares average response time per agent ⏱️
- New Weekday vs Weekend comparison chart highlights productivity patterns 🗓️
- New “Tasks by Time of Day” chart surfaces Auto Run hourly hotspots 🌙
- Modal PR link is now keyboard-accessible and opens externally safely ♿
When sendPromptViaStdin or sendPromptViaStdinRaw is set, the prompt
will be sent via stdin as stream-json data. The ChildProcessSpawner
was incorrectly ALSO adding the prompt to the command line args,
causing shell escaping issues with zsh on remote hosts.
This fix skips adding the prompt to args when it will be sent via
stdin, preventing:
- "zsh:35: parse error near 'do'" from multi-line prompts
- "zsh:3: no matches found: **Summary:**" from glob-like patterns
The prompt still gets sent correctly via stdin in the isStreamJsonMode
block at line 389+.
When zsh/bash parse errors are detected, log the pattern source,
matched text, and line preview to help diagnose where the error
is coming from. Also log detailed stderr/stdout info before
SSH error pattern matching at process exit.
Embedding prompts in the SSH command line caused persistent failures
with "zsh:35: parse error" on remote hosts using zsh. The issue was
that prompts with newlines create multi-line bash -c arguments that
zsh parses incorrectly before bash can interpret them.
This fix removes the 4000-char threshold and always sends prompts via
stdin (using --input-format stream-json) for SSH remote execution.
This completely bypasses all shell escaping issues:
- No more quote escaping through multiple shell layers
- No more issues with embedded newlines in prompts
- No more problems with special characters like $, !, etc.
The root cause of the persistent "zsh:35: parse error" was that SSH passes
the command to the remote's login shell (zsh) which parses it before bash
runs. Double quotes allowed zsh to interpret $, `, \, etc. within the command.
Solution: Wrap the entire bash -c argument in single quotes. Single quotes
are parsed literally by zsh - it passes the content to bash unchanged.
Changes:
- Use shellEscape() to wrap the bash command in single quotes
- Remove shellEscapeForDoubleQuotes (no longer needed)
- Update pathSetup to use unescaped double quotes (they're inside single quotes)
- Update tests to expect new escaping format
This works because:
1. SSH sends: /bin/bash --norc --noprofile -c 'export PATH=... && cmd'
2. zsh sees single quotes, doesn't parse the content, executes /bin/bash
3. bash receives the literal content and executes it
The pathPrefix string contained unescaped double quotes which broke the
outer -c "..." wrapper when SSH passed the command to zsh on the remote.
The quotes are now escaped as \" so they survive the shell parsing layers.
Before: export PATH="$HOME/..." (breaks outer double-quote context)
After: export PATH=\"$HOME/...\" (properly nested)
Updated the prompt escaping test to match the actual output format when
prompts go through both shellEscape and shellEscapeForDoubleQuotes layers:
- $PATH becomes \$PATH (to prevent variable expansion)
- Single quotes become '\\'' (backslash escaping within double-quoted context)
SSH passes commands to the remote's login shell (zsh on this system)
which parses them. Using just 'bash' still causes zsh to source its
profile files while resolving the command path, triggering the
"zsh:35: parse error" from .zshrc.
Using /bin/bash directly bypasses this - zsh executes the absolute
path without sourcing any profile files first.
- Add error pattern for zsh/bash parse errors that occur when remote
profile files have incompatible syntax (e.g., "zsh:35: parse error")
- Improve SSH error detection to check BOTH stdout and stderr, since
shell errors often appear in stdout
- Log SSH failures at INFO/WARN level with stdout/stderr previews
for better debugging visibility
- Add fallback logging for SSH failures that don't match known patterns
Profile files (bash_profile, profile) often chain to zsh or contain
syntax incompatible with -c embedding, causing "zsh:35: parse error"
or command-not-found errors.
New approach uses `bash --norc --noprofile -c` with explicit PATH setup:
- ~/.local/bin (Claude Code, pip --user)
- ~/bin (user scripts)
- /usr/local/bin (Homebrew Intel, manual installs)
- /opt/homebrew/bin (Homebrew Apple Silicon)
- ~/.cargo/bin (Rust tools)
This completely avoids sourcing any profile files while ensuring
agent binaries are found in common installation locations.
The previous fix removed the shell wrapper entirely, which broke PATH
resolution for user-installed binaries like 'claude' in ~/.local/bin.
Exit code 127 (command not found) occurred because SSH's non-login
execution doesn't load profile files.
Now using "bash -lc" instead of "$SHELL -lc":
- bash is universally available on macOS/Linux
- bash -l sources /etc/profile, ~/.bash_profile, ~/.profile for PATH
- bash profile files rarely have syntax incompatible with -c embedding
- Avoids zsh profile issues (loops/conditionals that break -c embedding)
The double-quote escaping ensures $ variables in the inner command are
passed literally and evaluated by bash, not by SSH's outer shell.
Remove the $SHELL -ilc wrapper from SSH command building. This fixes
the "zsh:35: parse error near 'do'" error that occurred when user
profile files (.zshrc, .zprofile) contained syntax that couldn't be
embedded in a -c command string.
SSH executes commands through the remote's login shell by default,
which provides PATH from /etc/profile. The direct command approach
is simpler and more reliable across different shell configurations.
Also:
- Update tests to reflect that $ escaping is no longer needed (single
quotes already prevent variable expansion)
- Improve logging from debug to info level for visibility
- Added stats DB initialization result tracking with reset/corruption details 🧩
- Exposed new IPC endpoints to fetch and clear init results 🛰️
- Renderer now toasts a clear warning when stats DB gets reset ⚠️
- Stats DB init now returns structured success/reset/error metadata 📋
- Improved corruption recovery with “last-chance” reset and backup path 💾
- Added friendlier native SQLite module failure messages for users 🛠️
- IPC error logging now serializes Error objects for richer diagnostics 🔎
- SSH remote command wrapper now uses `$SHELL -ilc` (no manual sourcing) 🐚
- SSH manager now only passes `-i` when a private key is explicitly set 🔑
When username or privateKeyPath are empty, SSH command builders were
passing malformed arguments like `-i ""` or `@host`. Now these fields
are only added when non-empty, allowing SSH to use ~/.ssh/config,
ssh-agent, or system defaults.
Also removes remote path validation as a blocker for save in Edit/New
Agent modals - validation is now informational only.
SSH can resolve authentication through ~/.ssh/config, ssh-agent, or
system defaults. The validation was too strict, requiring these fields
when not explicitly importing from SSH config. Now the connection test
verifies if the configuration works rather than requiring all fields
upfront.
- Test New Group button visible when no groups exist (flat list mode)
- Test New Group button visible when groups exist with ungrouped sessions
- Test New Group button visible when all sessions are grouped
- Test Ungrouped Agents folder hidden when all sessions are in groups
- Space bar now recenters the graph on the focused document node
- Enter opens the in-graph preview (unchanged)
- Removed redundant P shortcut (Enter serves the same purpose)
- Updated help panel with Space shortcut
- Clarified `path.join` behavior; tightened autorun path-validation security expectations 🔐
- Added custom shell path, args, and env vars to Settings modal props 🐚
- Introduced “default show thinking” preference wiring for Settings UI 🧠
- Added startup update-check toggle plus beta updates support in Settings 🚀
- Enabled crash reporting preference plumbing through Settings props 🧯
- Mocked new sync-folder selection API for tests and setup coverage 📁
- Added stats API support for earliest timestamp lookup in test mocks ⏱️
- Refreshed History Detail modal header with top-right close button redesign 🎛️
When clicking a [[wikilink]] in the in-graph markdown preview,
the preview now navigates to that document instead of affecting
the graph. This allows seamless document exploration within
the preview panel.
Changes:
- Build file tree from graph nodes for wiki-link resolution
- Pass fileTree to MarkdownRenderer in preview panel
- onFileClick handler updates preview content without affecting graph
Add a scrollable markdown preview panel that opens within the graph view:
- Press P to preview the focused document in-graph
- Preview panel is focusable for keyboard scrolling (arrows, Page Up/Down)
- Escape closes the preview and returns focus to the graph
- Preview panel registers with layer stack for proper focus management
Keyboard shortcuts updated:
- Enter: Recenter on focused node
- P: Preview in-graph
- O: Open in main preview
- Esc: Close preview / modal
- Add unit tests for buildExpandedPath() covering Unix and Windows paths,
deduplication, custom paths, and empty PATH handling
- Add unit tests for buildExpandedEnv() covering tilde expansion,
custom env vars, and immutability guarantees
- Add CRLF line ending tests to cliDetection to verify Windows 'where'
command output parsing works correctly with \r\n line endings
Clarify in the system prompt that all checkbox tasks in auto-run docs
must be machine-executable by AI agents. Human-only tasks (manual
testing, visual verification) should use plain bullet points instead
of checkbox syntax.
Add a new preview panel that opens within the Document Graph view when
pressing Enter on a focused node. This allows exploring markdown files
without leaving the graph view.
Changes:
- Enter key now opens in-graph preview panel (double-click to recenter)
- Preview panel slides in from the right with full markdown rendering
- Escape closes the preview and returns focus to the graph for navigation
- Preview content is focusable for keyboard scrolling
- Updated Help panel to reflect new keyboard shortcuts
- Fix CLI storage path handling: use path.join instead of path.posix.join
for proper Windows path construction on local filesystem operations
- Fix streamJsonBuilder format: restore correct Claude Code stream-json
format with type: 'user' and nested message structure (was incorrectly
changed to type: 'user_message' which causes Claude CLI errors)
- Add shellEscape utility: create proper shell argument escaping module
with documentation and comprehensive tests for cmd.exe and PowerShell
- Refactor ChildProcessSpawner: use new shellEscape utility instead of
inline escaping logic for better maintainability
- Fix type errors: correct ToolType usage (remove invalid 'claude' value)
and add explicit Record<string, AgentSshRemoteConfig> typing
- Fix Windows agent execution by using buildExpandedEnv for proper PATH expansion
- Add PowerShell support for SSH commands to handle long command lines (32K+ chars)
- Implement here document support for large OpenCode prompts over SSH
- Add raw stdin prompt sending for agents without stream-json support
- Restrict inline wizard to Claude, Claude Code, and Codex (OpenCode incompatible)
- Improve argument escaping for both cmd.exe and PowerShell shells
- Update tsconfig.main.json to include shared files for proper compilation
- Enhance agent path resolution for packaged Electron applications
- Add read-only mode for OpenCode in wizard conversations
- Update tests and UI components for better SSH remote configuration
- Fix locale formatting issues in AgentSessionsModal and AgentPromptComposerModal tests
- Update path normalization in stats-db tests for Windows compatibility
- Correct mock signatures in AutoRun and agent-spawner tests
- Make agent detection tests platform-aware (powershell.exe vs bash)
- Fix PATH expansion test to handle platform-specific delimiters
- Ensure consistent 'en-US' locale usage across components and tests
All tests now pass on both Windows and Unix systems.
* refactor: consolidate PATH building logic into shared utilities
- Add buildExpandedPath() and buildExpandedEnv() to shared/pathUtils.ts
- Refactor 5 files to use shared PATH functions, eliminating ~170 lines of duplication
- Fix Windows .NET SDK PATH issue by including dotnet installation paths
- Ensure consistent cross-platform PATH handling across CLI agents, detectors, and process managers
Files changed:
- src/shared/pathUtils.ts (added 2 functions)
- src/cli/services/agent-spawner.ts (refactored 3 functions)
- src/main/utils/cliDetection.ts (refactored 1 function)
- src/main/agent-detector.ts (refactored 1 method)
- src/main/process-manager/utils/envBuilder.ts (refactored 1 function)
* refactor: consolidate PATH building logic into shared utilities
- Add buildExpandedPath() and buildExpandedEnv() to shared/pathUtils.ts
- Refactor 5 files to use shared PATH functions, eliminating ~170 lines of duplication
- Fix Windows .NET SDK PATH issue by including dotnet installation paths
- Ensure consistent cross-platform PATH handling across CLI agents, detectors, and process managers
Files changed:
- src/shared/pathUtils.ts (added 2 functions)
- src/cli/services/agent-spawner.ts (refactored 3 functions)
- src/main/utils/cliDetection.ts (refactored 1 function)
- src/main/agent-detector.ts (refactored 1 method)
- src/main/process-manager/utils/envBuilder.ts (refactored 1 function)
* fix(windows): enable PATH access for agent processes
Remove faulty basename rewriting that prevented shell execution from working properly on Windows. Full executable paths are now passed directly to cmd.exe, allowing agents to access PATH and run commands like node -v and dotnet -h.
- Modified process.ts to keep full paths when using shell execution
- Updated ChildProcessSpawner.ts to avoid basename rewriting
- Fixes ENOENT errors when agents spawn on Windows
Resolves issue where agents couldn't execute PATH-based commands.
fix: add missing lint-staged configuration
Add lint-staged configuration to package.json to run prettier and eslint on staged TypeScript files before commits.
* fix(windows): resolve SSH path detection with CRLF line endings
Fix SSH command spawning failure on Windows by properly handling CRLF line endings from the 'where' command. The issue was that result.stdout.trim().split('\n')[0] left trailing \r characters in detected paths, causing ENOENT errors when spawning SSH processes.
Updated detectSshPath() to use split(/\r?\n/) for cross-platform line ending handling
Applied same fix to detect cloudflared and gh paths for consistency
Ensures SSH binary paths are clean of trailing whitespace/carriage returns
Resolves "spawn C:\Windows\System32\OpenSSH\ssh.exe\r ENOENT" errors when using SSH remote agents on Windows.
* fix: resolve SSH remote execution issues with stream-json and slash commands
- Fix SSH remote execution failing with stream-json input by detecting
--input-format stream-json and sending prompts via stdin instead of
command line arguments, preventing shell interpretation of markdown
content (fixes GitHub issue #262)
- Add sendPromptViaStdin flag to ProcessConfig interface for explicit
stream-json mode detection
- Implement proper image support in buildStreamJsonMessage for Claude
Code stream-json format, parsing data URLs and including images as
base64 content in the message
- Add file existence check in discoverSlashCommands to prevent ENOENT
errors when agent paths are invalid
- Simplify ChildProcessSpawner stdin handling to ensure images are
always included in stream-json messages sent via stdin
- Update stream-json message format to use proper {"type": "user_message",
"content": [...]} structure with text and image content arrays
- Add useClickOutside hook to FilePreview for click-outside-to-dismiss
with same behavior as Escape key (handles unsaved changes, TOC overlay)
- Fix extractHeadings to track code fence boundaries and skip comments
inside ``` or ~~~ code blocks from appearing in table of contents
- Add test coverage for both features
- Add refresh/sync button to active contribution cards for manual status sync
- Add symphony:syncContribution IPC handler to recover from missed updates:
- Syncs PR info from metadata files when missing from state
- Detects merged/closed PRs and moves contributions to history
- Updates status when PR transitions from draft to ready
- Add periodic auto-sync (2 min) for active contributions
- Add comprehensive test coverage for sync functionality
This addresses issues where Symphony contributions get stuck in "Running"
status due to Claude Code connection errors or missed IPC events.
- Centralize all context calculations in shared/contextUsage.ts as single source of truth
- Add SYNC comments to all 11 locations that use context calculations
- Document provider-specific formulas (Claude-style vs OpenAI-style)
- Remove legacy 'claude' from ToolType - only 'claude-code' is a valid agent
- Update all references from 'claude' to 'claude-code' across codebase
- Use calculateContextTokens() consistently instead of inline calculations
- Add note about known issue: Claude Code reports per-turn values, not cumulative