- Add isValidToolType() type guard to replace unsafe `as ToolType` casts
- Make `raw` field optional in ParsedEvent interface since never read
- Fix MockParser in tests to implement missing error detection methods
- Add @internal JSDoc to test-only exports (hasOutputParser, getAllOutputParsers, clearParserRegistry)
- Update AGENT_SUPPORT.md to reference canonical ParsedEvent source instead of duplicating type definition
- Add tests for new isValidToolType function
- Add GlobalAgentStats and ProviderStats interfaces to src/shared/types.ts
- Update agentSessions.ts to import and re-export from shared types
- Update AboutModal.tsx to import GlobalAgentStats from shared types
- Update test file to use shared GlobalAgentStats type instead of duplicate
Eliminates 3 duplicate definitions of GlobalAgentStats across the codebase.
All 47 AboutModal tests pass. TypeScript type checking passes.
- Created src/main/utils/pricing.ts with calculateCost() and calculateClaudeCost()
- Added TOKENS_PER_MILLION constant to constants.ts
- Removed dead code: STATS_BATCH_SIZE, ClaudeSessionParseLimits, ClaudePricing type exports
- Updated agentSessions.ts, claude.ts, claude-session-storage.ts to use new utility
- Added 8 unit tests for pricing module
Eliminates ~60 lines of duplicated cost calculation code across 3 files.
- Added per-session SSH remote binding, overriding agent-level SSH settings 🎯
- New instance creation now passes SSH remote config per session 🧩
- Process handler resolves SSH config by session > agent > global defaults 🧭
- SSH now forces no-TTY mode to avoid sourcing shell rc files 🧯
- Remote commands now run via `$SHELL -lc` for full user PATH 🛤️
- Introduced safe double-quote shell escaping for layered SSH execution 🧷
- Added detailed SSH command build logging for easier remote debugging 🔍
- Settings UI revamped: context warnings toggle separated from threshold sliders 🧰
- Threshold sliders now visually disable/ghost when warnings are off 🫥
- Session and process types updated to include session-level SSH configuration 🧾
"message": "Invalid 'input[0].content': string too long. Expected a string with maximum length 10485760, but got a string with length 11952519 instead.",
"type": "invalid_request_error",
"param": "input[0].content",
"code": "string_above_max_length"
}
Removes 4 duplicate implementations of tilde expansion (~/) and
consolidates them into a single shared function in pathUtils.ts.
Changes:
- Add optional homeDir param to expandTilde for dependency injection
- Refactor agent-detector.ts to use shared expandTilde
- Refactor ssh-command-builder.ts to use shared expandTilde
- Refactor ssh-config-parser.ts to use shared expandTilde
- Refactor ssh-remote-manager.ts to use shared expandTilde
- Update ssh-command-builder tests to mock os.homedir()
Net reduction: 38 lines of code.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace duplicated version comparison logic with shared utility:
- process-manager.ts: use compareVersions for Node version sorting
- update-checker.ts: remove local parseVersion/compareVersions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Extract common utilities to src/shared/pathUtils.ts:
- expandTilde: tilde expansion for paths
- parseVersion: parse semver strings to arrays
- compareVersions: compare version strings (1/-1/0)
These consolidate duplicated logic found across multiple files.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Extract duplicated sortNodeVersionsDescending() helper function
- Add comprehensive unit tests for version sorting logic
- Reduces code duplication from 4 inline sorts to 1 reusable function
Wire up SSH context to git:status, git:diff, git:isRepo, git:numstat,
git:branch, git:branches, git:tags, git:remote, and git:info handlers.
These operations now support executing on remote hosts via SSH when
an sshRemoteId parameter is provided.
Changes:
- Add sshRemoteId parameter to git handlers in git.ts
- Import execGitRemote from remote-git.ts for SSH execution
- Update preload.ts with new function signatures
- Update global.d.ts with TypeScript types
- Update gitService in renderer with SSH support
- Wire SSH context to useGitStatusPolling hook
- Wire SSH context to useWorktreeValidation hook
- Update tests to expect new parameter signatures
Test fixes for SSH context propagation:
- AutoRun.test.tsx: Add undefined sshRemoteId to writeDoc assertions
- AutoRunBlurSaveTiming.test.tsx: Add undefined sshRemoteId to writeDoc assertions
- AutoRunContentSync.test.tsx: Add undefined sshRemoteId to writeDoc assertions
- AutoRunSessionIsolation.test.tsx: Add undefined sshRemoteId to writeDoc assertions
- useBatchProcessor.test.ts: Add undefined sshRemoteId to worktreeSetup/worktreeCheckout assertions
All tests now correctly expect the optional sshRemoteId parameter that was added
for SSH remote session support. For local sessions, this parameter is undefined.
- Added sshRemoteId parameter to useWorktreeValidation deps interface
- Updated worktreeInfo() and getRepoRoot() calls to pass SSH context
- Added sshRemoteId to WorktreeConfig interface in useWorktreeManager
- Updated worktreeSetup() and worktreeCheckout() to use sshRemoteId
- Modified useBatchProcessor to inject session.sshRemoteId into worktree config
This ensures batch processing worktree operations work correctly on
remote SSH sessions, completing the SSH remote support implementation.
All 12 existing worktree validation tests pass.
Document Graph requires local filesystem access to scan markdown files
and cannot work with remote hosts via SSH. Added remote session detection
to show a styled unavailable message when sshRemoteId is present.
- Added sshRemoteId prop to DocumentGraphViewProps interface
- Added remote session unavailable UI with themed styling
- Pass sshRemoteId from activeSession to DocumentGraphView in App.tsx
Updates the AutoRun component to pass SSH context for remote session support:
- Add sshRemoteId prop to AutoRunProps interface
- Update AttachmentImage component to use SSH context for loading remote images
- Pass sshRemoteId to all window.maestro.fs.readFile() calls (3 locations)
- Pass sshRemoteId to window.maestro.autorun.writeDoc() in handleSave and handleResetTasks
- Update both baseMarkdownComponents and searchHighlightedComponents useMemo hooks
- Update RightPanel.tsx to pass session.sshRemoteId through autoRunSharedProps
- Update AutoRunExpandedModal.tsx interface for TypeScript correctness
This completes Task 5.2 of SSH Remote Full Support - Auto Run can now read/write
documents and load images on remote sessions via SSH.
Add SSH support to core Auto Run document operations for remote file
access when sessions are running on SSH remote hosts.
Changes:
- autorun.ts: Added imports for Store, SshRemoteConfig, remote-fs utils
- autorun.ts: Added AutorunHandlerDependencies interface with settingsStore
- autorun.ts: Created getSshRemoteById helper and scanDirectoryRemote function
- autorun.ts: Updated listDocs handler to scan remote directories via SSH
- autorun.ts: Updated readDoc handler to read files via readFileRemote()
- autorun.ts: Updated writeDoc handler to write files via writeFileRemote()
- autorun.ts: Updated watchFolder to return isRemote: true for remote sessions
(chokidar cannot watch remote directories, UI should poll instead)
- index.ts: Pass settingsStore to registerAutorunHandlers()
- preload.ts: Added sshRemoteId parameter to listDocs, readDoc, writeDoc, watchFolder
- global.d.ts: Updated type signatures with sshRemoteId parameter
This enables Phase 5 tasks 5.1 and 5.3 of SSH remote support. Task 5.2
(updating AutoRun.tsx component) remains to wire up the SSH context.
Phase 4 implementation for SSH remote sessions:
- Create remote-git.ts module with SSH-enabled git operations:
- worktreeInfoRemote(), worktreeSetupRemote(), worktreeCheckoutRemote()
- listWorktreesRemote(), getRepoRootRemote()
- Uses shell escaping and executes git commands via SSH
- Update git IPC handlers to accept optional sshRemoteId:
- git:worktreeInfo, git:worktreeSetup, git:worktreeCheckout
- git:listWorktrees, git:getRepoRoot
- Dispatches to remote or local execution based on presence of sshRemoteId
- Handle remote file watching gracefully:
- git:watchWorktreeDirectory returns isRemote: true for SSH sessions
- UI can detect this and fall back to polling via listWorktrees
- Add GitHandlerDependencies interface for settingsStore access
- Update preload.ts and global.d.ts with new method signatures
Pass sshRemoteId to fs.readDir and fs.directorySize calls in:
- loadFileTree() for remote directory listing
- useFileTreeManagement hook for all file tree operations
This completes Phase 3 of SSH remote support, enabling the
File Explorer to work with remote sessions over SSH.
Added unit tests for SSH context propagation.
Update fs:readDir, fs:readFile, fs:stat, and fs:directorySize IPC handlers
to accept optional sshRemoteId parameter. When provided, operations dispatch
to remote-fs utilities that execute commands via SSH on the remote host.
This completes Task 2.2 of the SSH Remote Full Support feature:
- Created getSshRemoteById helper to look up SSH config by ID
- fs:readDir dispatches to readDirRemote when sshRemoteId provided
- fs:readFile dispatches to readFileRemote with image handling
- fs:stat dispatches to statRemote with mtime fallback for createdAt
- fs:directorySize dispatches to directorySizeRemote (size only)
- Updated preload.ts and global.d.ts type signatures
Creates src/main/utils/remote-fs.ts with SSH wrappers for:
- readDirRemote: ls -1AF command parsing
- readFileRemote: cat command for file contents
- statRemote: stat command with GNU/BSD format support
- directorySizeRemote: du command for directory sizes
- writeFileRemote: base64-encoded file writing
- existsRemote: test -e path existence check
- mkdirRemote: directory creation
All functions use shell escaping for security and return
RemoteFsResult<T> with success/failure status and error messages.
Includes 43 unit tests covering output parsing, error handling,
and SSH context integration.
Phase 1, Task 1.3: Updated hooks and components to access session.sshRemoteId
and session.remoteCwd for future remote file operations support.
Changes:
- Added SshContext interface to fileExplorer.ts
- Updated loadFileTree() to accept optional SSH context parameter
- Added getSshContext() helper in useFileTreeManagement hook
- Updated refreshFileTree, refreshGitFileState, and initial load effect
to pass SSH context when session has sshRemoteId
- Added test for SSH context propagation
This prepares the codebase for Phase 2 (Remote File System Utilities)
where actual SSH-aware file operations will be implemented.
- Extended SSH remote event payload to include remoteWorkingDir field
- Updated onSshRemote handler in App.tsx to populate session-wide SSH context
- sshRemoteId and remoteCwd are now set when a process spawns on an SSH remote
- These fields enable future features: remote file explorer, git, auto run
Phase 1, Task 1.1 of SSH Remote Full Support:
- Added sshRemoteId?: string for flat access to SSH remote config ID
- Added remoteCwd?: string for remote working directory tracking
- These complement existing sshRemote object for easier component tree access
- Added cloud sync IPC to restore leaderboard stats on new installs 🚀
- Exposed `maestro.leaderboard.sync` in preload with typed results for safety 🧩
- Leaderboard modal now supports “Sync from Cloud” to pull down stats ☁️
- Auto-run stats can be updated from synced server values, including badges 🏅
- Added clear sync status messaging plus robust token/email error handling 🛡️
- Document graph double-click now focuses nodes and expands neighbor ego-network 🕸️
- ForceGraph gained real double-click detection instead of ignoring the handler 🖱️
- Reworked graph link rendering for sharper widths/colors and null-safe endpoints 🎨
- Usage dashboard added Cmd+Shift+[ / ] shortcuts to cycle tabs quickly ⌨️
- Usage dashboard UI refined: cleaner dropdown styling and removed refresh button 🧼
- Settings checkboxes upgraded into sleek right-aligned toggle switches 🎛️
- Full-row setting cards now toggle on click for faster changes 🖱️
- Keyboard accessibility added: Enter/Space toggles settings cleanly ⌨️
- Toggle buttons now prevent event bubbling for reliable interactions 🛑
- Context Window Warnings setting redesigned with the new toggle UI ⚠️
- Toggle styling now reflects theme colors for clearer on/off states 🎨
- Batch progress totals now track net task changes, not just additions 📈
- Document processor computes `totalTasksChange` for accurate task accounting 🧮
- Overall batch state updates now correctly handle added and completed tasks 🔄
- Run git commands remotely via SSH with optional `sshRemoteId` support 🚀
- New `execGit` dispatcher seamlessly chooses local vs remote execution 🧭
- Git IPC handlers now accept remote working directory overrides for flexibility 🛰️
- Git handler registration injects settings store for SSH remote lookups 🧩
- SSH execution hardened: disable forwarding and TTY to avoid flaky runs 🛡️
- Document Graph fully rewritten to `react-force-graph-2d` for smoother visuals 🎛️
- Added focus mode with neighbor-depth slider for ego-network exploration 🔍
- Node size now reflects connection counts for instant relationship insight 📈
- Graph data builder decoupled from React Flow; positions handled by D3 physics 🧠
- Persistence now avoids saving empty sessions before initial load completes 🔒
Removes 4 duplicate implementations of tilde expansion (~/) and
consolidates them into a single shared function in pathUtils.ts.
Changes:
- Add optional homeDir param to expandTilde for dependency injection
- Refactor agent-detector.ts to use shared expandTilde
- Refactor ssh-command-builder.ts to use shared expandTilde
- Refactor ssh-config-parser.ts to use shared expandTilde
- Refactor ssh-remote-manager.ts to use shared expandTilde
- Update ssh-command-builder tests to mock os.homedir()
Net reduction: 38 lines of code.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace duplicated version comparison logic with shared utility:
- process-manager.ts: use compareVersions for Node version sorting
- update-checker.ts: remove local parseVersion/compareVersions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Extract common utilities to src/shared/pathUtils.ts:
- expandTilde: tilde expansion for paths
- parseVersion: parse semver strings to arrays
- compareVersions: compare version strings (1/-1/0)
These consolidate duplicated logic found across multiple files.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
GUI applications (like Electron) don't inherit shell PATH configuration,
causing 'env: node: No such file or directory' errors for users who install
Node via version managers (nvm, fnm, volta, mise, asdf, n).
This adds automatic detection of common Node version manager installations
and includes their bin paths when spawning AI agent and terminal processes.
Supported version managers:
- nvm (reads default version from ~/.nvm)
- fnm (Fast Node Manager)
- volta
- mise (formerly rtx)
- asdf
- n
The detection runs at process spawn time and only adds paths that exist
on the system. This ensures node/npm are available without requiring
users to set up wrapper scripts or launchctl environment variables.
Fixes the "Agent exited with code 127" error for nvm users.
## CHANGES - Import SSH remotes straight from `~/.ssh/config` via new dropdown picker 🚀 - Run remotes using SSH Host patterns, not raw IPs anymore 🧭 - Username and private key become optional when SSH config is enabled 🔑 - SSH commands now omit `-i` unless you explicitly override keys 🎛️ - Default port 22 no longer forced; only send `-p` when overriding 🔌 - New SSH config parser supports HostName, User, Port, IdentityFile, ProxyJump 🧩 - Wildcard-only hosts (`Host *`, `dev-*`) are ignored for cleaner imports 🧹 - UI shows “Using SSH Config” indicator with one-click clear toggle 🏷️ - Added IPC + preload API to fetch SSH config hosts safely 🛡️ - Expanded test coverage for SSH-config mode command-building and parsing ✅
- Import SSH remotes straight from `~/.ssh/config` via new dropdown picker 🚀
- Run remotes using SSH Host patterns, not raw IPs anymore 🧭
- Username and private key become optional when SSH config is enabled 🔑
- SSH commands now omit `-i` unless you explicitly override keys 🎛️
- Default port 22 no longer forced; only send `-p` when overriding 🔌
- New SSH config parser supports HostName, User, Port, IdentityFile, ProxyJump 🧩
- Wildcard-only hosts (`Host *`, `dev-*`) are ignored for cleaner imports 🧹
- UI shows “Using SSH Config” indicator with one-click clear toggle 🏷️
- Added IPC + preload API to fetch SSH config hosts safely 🛡️
- Expanded test coverage for SSH-config mode command-building and parsing ✅
- Bumped Maestro to v0.14.0 with a fresh release cutover 🚀
- Added self-serve “Resend Confirmation” for leaderboard token recovery 📧
- Wired new `leaderboard:resendConfirmation` IPC handler end-to-end 🧩
- Upgraded registration modal with resend-first flow, manual token fallback 🛟
- Added Quick Actions entry to open the Document Graph instantly ⚡
- Document Graph now persists external-links toggle back into settings 💾
- Document Graph modal now preserves state across closes for continuity 🔒
- React Flow controls are fully theme-styled with dynamic injected CSS 🎨
- Improved graph layouts to reduce external-node overlap in both modes 🧭
- Wizard now detects provider errors and shows recovery hints + “Go Back” 🧠
- Bumped Maestro version to 0.13.1 for the latest improvements 🚀
- Added Document Graph IPC handlers to enable live file watching 📈
- Introduced SSH Remote IPC handlers for managing saved SSH configurations 🛰️
- Added a dedicated SSH tab in Settings for cleaner navigation 🗂️
- Updated Settings keyboard tab-cycling to include the new SSH section ⌨️
- Refined Settings UI with a new Server icon for SSH tab branding 🖥️
- Moved SSH Remote hosts configuration into its own SSH Settings panel 🔐
Add comprehensive documentation for the SSH remote execution feature:
- New ssh-remote-execution.md with full guide
- Update configuration.md with SSH Remotes section reference
- Update features.md with feature highlight
- Add to docs.json navigation
Implements SSH-specific error handling in the process manager output parsing:
- Added SSH_ERROR_PATTERNS to error-patterns.ts covering:
- permission_denied: SSH authentication failures, host key verification, passphrase prompts
- network_error: Connection refused, timeouts, hostname resolution, network unreachable
- agent_crashed: Command not found, agent binary missing, broken pipe, connection drops
- Integrated SSH error detection in process-manager.ts:
- Checks stdout lines for SSH errors after agent-specific error detection
- Checks stderr data for SSH errors (SSH errors typically appear on stderr)
- Checks at process exit for any SSH errors that may have been missed
- Added helper functions:
- matchSshErrorPattern(): Match a line against SSH-specific patterns
- getSshErrorPatterns(): Get the SSH error patterns object
- Added 36 new tests for SSH error pattern detection covering all error categories
All 12,265 tests pass.
Added visual indicator in session header showing when an agent is running on a
remote SSH host. Implementation includes:
- Session type: Added sshRemote field to track active SSH remote (id, name, host)
- IPC event: Added process:ssh-remote event emitted after process spawn
- Event handler: Added onSshRemote listener in App.tsx to update session state
- UI indicator: Added purple-themed pill badge in MainPanel header with Server
icon, remote name (truncated to 100px), and tooltip showing full details
- Test fixes: Added getMainWindow mock to process handler tests
The indicator only appears when a session is actively using SSH remote execution,
providing clear visibility into where agent commands are being run.
All Phase 6 tasks were already implemented as part of Phase 3 work:
- T033: ssh-remote:test handler in src/main/ipc/handlers/ssh-remote.ts
- T034: test IPC exposed in src/main/preload.ts
- T035: testConnection function in useSshRemotes hook
- T036: Test Connection button and result display in SshRemoteModal
- T037: Test button per remote in SshRemotesSection list
75 SSH-related tests pass confirming complete functionality.
- Add SSH remote selection UI to AgentConfigPanel.tsx with dropdown options:
- "Use Global Default" (follows global SSH remote setting)
- "Force Local Execution" (override to run locally even if global default is set)
- Individual SSH remotes by name
- Add status indicator showing effective remote (local vs. SSH with remote name)
- Update NewInstanceModal.tsx to:
- Load SSH remote configurations when modal opens
- Pass SSH remote props to AgentConfigPanel
- Save SSH remote config to agent config store on create
- Update EditAgentModal to:
- Load and display current SSH remote config
- Save SSH remote config changes on save
- Add sshRemote mock to test setup for window.maestro API
- T032 was already implemented in Phase 4 (getSshRemoteConfig already checks agent override first)
Add SSH remote detection and command wrapping to the process:spawn IPC handler.
When an SSH remote is configured (global default or agent-specific override),
agent commands are wrapped with SSH for remote execution.
Changes:
- Import SSH utilities (getSshRemoteConfig, createSshRemoteStoreAdapter, buildSshCommand)
- Update MaestroSettings interface with sshRemotes and defaultSshRemoteId fields
- Add SSH remote resolution after agent args are built
- Wrap command with buildSshCommand when SSH remote is configured
- Disable PTY when using SSH (SSH handles terminal emulation)
- Pass custom env vars via remote command string, not locally
- Terminal sessions always run locally (need PTY for shell interaction)
Tests:
- 8 new unit tests for SSH remote execution scenarios
- All existing tests pass (12,232 tests)