Commit Graph

2676 Commits

Author SHA1 Message Date
Raza Rauf
4fe009e30f Merge branch 'main' into code-refactor 2026-02-04 03:35:43 +05:00
Raza Rauf
d4d94471f0 resolved merge conflicts 2026-02-04 03:27:32 +05:00
Raza Rauf
234d13ac08 Merge branch 'code-refactor' of https://github.com/pedramamini/Maestro into code-refactor 2026-02-04 03:24:31 +05:00
Pedram Amini
44e11ecf16 Merge branch 'fix-opencode'
Merges OpenCode fixes and SSH stdin improvements:
- Use stdin passthrough for all SSH prompts (simplifies escaping)
- Add question:deny to OpenCode permission block for robust tool disabling
- Simplify stdin prompt delivery by appending after exec (no heredoc needed)
2026-02-03 15:21:21 -06:00
Pedram Amini
963531e4ff ## CHANGES
- Swapped moderator selection tiles for a clean agent dropdown picker 🔽
- Added expandable “Customize” panel directly inside both group chat modals ⚙️
- Lazily loads agent config/models only when customization panel expands 🚀
- Resets custom path/args/env overrides automatically when changing agents 🧹
- Displays clear “Detecting agents…” inline spinner during agent discovery 
- Labels Codex, OpenCode, and Factory Droid options as “(Beta)” 🧪
- Expands empty-state messaging to recommend installing Factory Droid too 🧩
- Simplified modal flow by removing separate config-view navigation entirely 🧭
- Improved accessibility with proper combobox/button roles in modal controls 
- Strengthened test coverage for dropdown options and moderator-change warning 🧯
2026-02-03 15:17:25 -06:00
Pedram Amini
63d15d1a16 fix(opencode): add question:deny to permission block for robust tool disabling
Per OpenCode GitHub issue workaround, add "question": "deny" to the
permission block in addition to the existing "tools":{"question":false}.

This ensures the question tool is disabled via both configuration methods,
preventing stdin hangs in batch mode.

Config now: {"permission":{"*":"allow","external_directory":"allow","question":"deny"},"tools":{"question":false}}
2026-02-03 15:17:01 -06:00
Pedram Amini
ccabe75248 refactor(ssh): simplify stdin prompt delivery with passthrough approach
Replace heredoc-based prompt delivery with simpler stdin passthrough.

How it works:
1. Bash script is sent via stdin to /bin/bash on the remote
2. Script sets up PATH, cd, env vars, then calls `exec <agent>`
3. The `exec` replaces bash with the agent process
4. The agent inherits stdin and reads the remaining content (the prompt)

Benefits:
- No heredoc syntax needed
- No delimiter collision detection
- No prompt escaping required - prompt is never parsed by any shell
- Works with any prompt content (quotes, newlines, $, backticks, etc.)
- Simpler, more maintainable code

Changes:
- Remove heredoc logic from buildSshCommandWithStdin()
- Update process.ts to use stdin passthrough for ALL agents over SSH
  (not just OpenCode - all agents benefit from this approach)
- Update tests to verify stdin passthrough behavior

Verified locally that both OpenCode and Claude Code read prompts from stdin.
2026-02-03 15:13:55 -06:00
Raza Rauf
e409123d9e feat: add conservative context growth estimation during multi-tool turns
When Claude Code performs multi-tool turns (many internal API calls),
accumulated token values cause estimateContextUsage to return null,
freezing the context gauge. This adds estimateAccumulatedGrowth which
provides conservative 1-3% per-turn growth estimates so the gauge
keeps moving during tool-heavy sessions.

Safety: App.tsx caps all estimates at yellowThreshold - 5, guaranteeing
that estimates can never trigger compact warnings — only real
measurements from non-accumulated turns can.
2026-02-04 01:43:00 +05:00
Pedram Amini
ed374bc69d fix(dashboard): use accurate agent count excluding terminal sessions
Update SummaryCards to accept sessions prop and filter out terminal-only
sessions when calculating agent count for consistent metrics display.
This ensures queries-per-session and total sessions accurately reflect
AI agent sessions rather than including terminal sessions.
2026-02-03 14:27:30 -06:00
Pedram Amini
4bdfa86b83 fix(wizard): use navigator.platform for Windows detection in renderer
Replace process.platform with navigator.platform for Windows detection
in the inline wizard conversation service, as process.platform is not
available in the browser/renderer context.
2026-02-03 14:27:24 -06:00
Pedram Amini
078a837ef4 feat(agents): add Factory Droid to Beta badge list
Adds 'factory-droid' agent to the Beta badge display in:
- NewInstanceModal agent selection
- AgentSelectionScreen wizard tiles
2026-02-03 14:27:19 -06:00
Pedram Amini
69b6299677 fix(windows): handle full paths in known exe command detection
Fixes an issue in PR #288's Windows shell fix where full paths like
'C:\Program Files\Git\bin\git' weren't recognized as known commands.

Changes:
- Extract command basename using regex for both Unix and Windows separators
- Change from array to Set for O(1) lookup performance
- Add additional common commands: npx, pnpm, pip, pip3
- Export needsWindowsShell for testability
- Add comprehensive test suite for needsWindowsShell function
2026-02-03 14:27:03 -06:00
Pedram Amini
fb64d4a769 feat(ssh): use heredoc for stdin prompts to avoid CLI length limits
IMPORTANT: Prompts must be passed via stdin to avoid CLI argument length
limits. Prompts can be huge and contain arbitrary characters that would
break if passed as command-line arguments.

Changes:
- Add stdinInput parameter to buildSshCommandWithStdin for heredoc-based
  prompt delivery
- Use MAESTRO_PROMPT_EOF delimiter with collision detection (appends _N
  suffix if prompt contains the delimiter)
- OpenCode prompts now always sent via stdin heredoc, not CLI args
- Add comprehensive tests for heredoc behavior and delimiter collision
- Add comment in process.ts documenting this requirement to prevent
  regressions

The heredoc approach: exec opencode 'run' <<'MAESTRO_PROMPT_EOF'
ensures prompts of any size with any characters work correctly.
2026-02-03 14:26:25 -06:00
Pedram Amini
3d593719fb fix(ssh): use stdin-based execution to bypass shell escaping issues
This is a complete rewrite of SSH remote command execution that eliminates
all shell escaping issues by sending the entire script via stdin.

Previously, the SSH command was built as:
  ssh host '/bin/bash -c '\''cd /path && VAR='\''value'\'' cmd arg'\'''

This required complex nested escaping that broke with:
- Heredocs (cat << 'EOF')
- Long prompts (command line length limits)
- Special characters in prompts

Now the SSH command is simply:
  ssh host /bin/bash

And the entire script is piped via stdin:
  export PATH="$HOME/.local/bin:..."
  cd '/project/path'
  export OPENCODE_CONFIG_CONTENT='{"permission":...}'
  exec opencode run --format json 'prompt here'

Benefits:
- No shell escaping layers (stdin is binary-safe)
- No command line length limits
- Works with any remote shell (bash, zsh, fish)
- Handles any prompt content (quotes, newlines, $, etc.)
- Much simpler to debug and maintain

Changes:
- Add buildSshCommandWithStdin() in ssh-command-builder.ts
- Update process.ts to use stdin-based SSH for all agents
- Add sshStdinScript to ProcessConfig type
- Update ChildProcessSpawner to send stdin script
- Add comprehensive tests for new function
2026-02-03 14:26:25 -06:00
Pedram Amini
09aa978932 fix(ssh): remove heredoc approach for OpenCode prompts
The heredoc syntax (cat << 'EOF' ... EOF) was breaking when passed
through buildSshCommand's single-quote escaping. The '\'' escape
pattern was being applied to the heredoc delimiters, producing
invalid shell syntax like cat << '\''EOF'\''.

Solution: Embed OpenCode prompts directly as positional arguments.
The prompt will be properly escaped by buildRemoteCommand using
shellEscape(), which handles the single-quote escaping correctly
for bash -c command execution.

This was the root cause of SSH remote execution failures with
OpenCode - the OPENCODE_CONFIG_CONTENT env var escaping was
correct, but the heredoc escaping was not.
2026-02-03 14:26:24 -06:00
Pedram Amini
7be82ce338 fix(tab-bar): ensure full tab visibility when scrolling into view
Changed from centering the tab to using scrollIntoView with 'nearest' option.
This ensures the entire tab including the close button is visible, rather than
potentially cutting off the right edge when near container boundaries.
2026-02-03 14:26:24 -06:00
Pedram Amini
99f4257c17 feat(symphony): add manual contribution credit handler
Add symphony:manualCredit IPC handler to allow crediting contributions
made outside the Symphony workflow (e.g., manual PRs, external
contributors). This enables proper tracking of all contributions
regardless of how they were created.

- Add symphony:manualCredit handler with full validation
- Add preload API for manual credit
- Support all contribution fields (tokens, time, merged status, etc.)
- Prevent duplicate PR credits
- Update contributor stats (streak, repos, totals)
- Add comprehensive tests for validation and success cases
2026-02-03 14:26:24 -06:00
Pedram Amini
81c64d9858 Merge pull request #288 from chr1syy/main
fix(windows): Shell interpration of % in git log format string
2026-02-03 14:25:35 -06:00
Raza Rauf
7d76a5a06d feat: add conservative context growth estimation during multi-tool turns
When Claude Code performs multi-tool turns (many internal API calls),
accumulated token values cause estimateContextUsage to return null,
freezing the context gauge. This adds estimateAccumulatedGrowth which
provides conservative 1-3% per-turn growth estimates so the gauge
keeps moving during tool-heavy sessions.

Safety: App.tsx caps all estimates at yellowThreshold - 5, guaranteeing
that estimates can never trigger compact warnings — only real
measurements from non-accumulated turns can.
2026-02-04 01:20:51 +05:00
Chris
a9e725b9e7 Merge branch 'pedramamini:main' into main 2026-02-03 19:41:00 +01:00
chr1syy
2f5c74480f fix: Windows shell interpretation of % in git log format string
On Windows, when execFile detects 'git' without extension, it enables shell
mode for PATHEXT resolution. However, shell mode interprets '%' characters in
arguments as environment variable expansions, causing 'git log --pretty=format:%an'
to fail with 'Der Befehl "%an" ist entweder falsch geschrieben...'

The fix adds 'git' (and other known .exe commands) to a list of exceptions
that don't require shell mode, allowing the format string to pass through
to git unchanged. This works because these commands have .exe variants on
Windows and don't need PATHEXT resolution.
2026-02-03 19:37:07 +01:00
Pedram Amini
fc7880cc32 feat(ssh): use heredoc for stdin prompts to avoid CLI length limits
IMPORTANT: Prompts must be passed via stdin to avoid CLI argument length
limits. Prompts can be huge and contain arbitrary characters that would
break if passed as command-line arguments.

Changes:
- Add stdinInput parameter to buildSshCommandWithStdin for heredoc-based
  prompt delivery
- Use MAESTRO_PROMPT_EOF delimiter with collision detection (appends _N
  suffix if prompt contains the delimiter)
- OpenCode prompts now always sent via stdin heredoc, not CLI args
- Add comprehensive tests for heredoc behavior and delimiter collision
- Add comment in process.ts documenting this requirement to prevent
  regressions

The heredoc approach: exec opencode 'run' <<'MAESTRO_PROMPT_EOF'
ensures prompts of any size with any characters work correctly.
2026-02-03 12:15:49 -06:00
Pedram Amini
07df61fbcf fix(ssh): use stdin-based execution to bypass shell escaping issues
This is a complete rewrite of SSH remote command execution that eliminates
all shell escaping issues by sending the entire script via stdin.

Previously, the SSH command was built as:
  ssh host '/bin/bash -c '\''cd /path && VAR='\''value'\'' cmd arg'\'''

This required complex nested escaping that broke with:
- Heredocs (cat << 'EOF')
- Long prompts (command line length limits)
- Special characters in prompts

Now the SSH command is simply:
  ssh host /bin/bash

And the entire script is piped via stdin:
  export PATH="$HOME/.local/bin:..."
  cd '/project/path'
  export OPENCODE_CONFIG_CONTENT='{"permission":...}'
  exec opencode run --format json 'prompt here'

Benefits:
- No shell escaping layers (stdin is binary-safe)
- No command line length limits
- Works with any remote shell (bash, zsh, fish)
- Handles any prompt content (quotes, newlines, $, etc.)
- Much simpler to debug and maintain

Changes:
- Add buildSshCommandWithStdin() in ssh-command-builder.ts
- Update process.ts to use stdin-based SSH for all agents
- Add sshStdinScript to ProcessConfig type
- Update ChildProcessSpawner to send stdin script
- Add comprehensive tests for new function
2026-02-03 12:15:49 -06:00
Pedram Amini
3a8dd62a13 fix(ssh): remove heredoc approach for OpenCode prompts
The heredoc syntax (cat << 'EOF' ... EOF) was breaking when passed
through buildSshCommand's single-quote escaping. The '\'' escape
pattern was being applied to the heredoc delimiters, producing
invalid shell syntax like cat << '\''EOF'\''.

Solution: Embed OpenCode prompts directly as positional arguments.
The prompt will be properly escaped by buildRemoteCommand using
shellEscape(), which handles the single-quote escaping correctly
for bash -c command execution.

This was the root cause of SSH remote execution failures with
OpenCode - the OPENCODE_CONFIG_CONTENT env var escaping was
correct, but the heredoc escaping was not.
2026-02-03 12:15:49 -06:00
Pedram Amini
4ae5d86a05 fix(tab-bar): ensure full tab visibility when scrolling into view
Changed from centering the tab to using scrollIntoView with 'nearest' option.
This ensures the entire tab including the close button is visible, rather than
potentially cutting off the right edge when near container boundaries.
2026-02-03 12:15:49 -06:00
Pedram Amini
b4c5f155ed feat(symphony): add manual contribution credit handler
Add symphony:manualCredit IPC handler to allow crediting contributions
made outside the Symphony workflow (e.g., manual PRs, external
contributors). This enables proper tracking of all contributions
regardless of how they were created.

- Add symphony:manualCredit handler with full validation
- Add preload API for manual credit
- Support all contribution fields (tokens, time, merged status, etc.)
- Prevent duplicate PR credits
- Update contributor stats (streak, repos, totals)
- Add comprehensive tests for validation and success cases
2026-02-03 12:15:49 -06:00
Raza Rauf
802ecd52a1 Merge pull request #287 from pedramamini/code-refactor
fix(file-preview): resolve image flickering under heavy parallel agen…
2026-02-03 10:58:43 -06:00
Raza Rauf
6e36f6b63f fix(file-preview): stabilize fileTree prop to complete memoization chain
The fileTree prop was passed as `activeSession?.fileTree || []` which
creates a new array reference on every render, defeating React.memo()
on FilePreview during agent activity. Memoize it with useMemo so the
reference only changes when the actual fileTree changes.
2026-02-03 21:46:07 +05:00
Raza Rauf
2f8a77a65d fix(file-preview): resolve image flickering under heavy parallel agent load
Wrap FilePreview and MarkdownImage with React.memo to prevent unnecessary
re-renders caused by upstream state updates from running agents.
2026-02-03 21:31:34 +05:00
Pedram Amini
2cd882ed7b Merge pull request #286 from chr1syy/main
Add @chr1syy as Windows Contributor and tester
2026-02-03 09:24:34 -06:00
Chris
00016e2342 Add @chr1syy as Windows Contributor and tester 2026-02-03 15:34:37 +01:00
Pedram Amini
2fcd03eb44 Remove duplicate Contributors section
Removed redundant 'Contributors' header from README.
2026-02-03 06:52:54 -06:00
Pedram Amini
afaead2220 Add contributors section to README 2026-02-03 06:52:40 -06:00
Pedram Amini
c1e434e3fe test(tab-naming): fix tests to match extractTabName behavior
Update test expectations to match the actual extractTabName logic:
- Lines > 40 chars are filtered out (not truncated), returning null
- Lines starting with quotes are filtered as example inputs
- Use period separator to test multi-line filtering correctly
- Preamble test uses exact pattern that regex matches
2026-02-03 01:04:05 -06:00
Pedram Amini
92f49af12d fix(header): restore git badge and changes hover overlays
Remove overflow-hidden from parent containers that was clipping the
absolutely positioned tooltip overlays. The responsive text truncation
is now handled by individual element classes (truncate, max-w-[120px])
rather than container-level overflow clipping.

Changes:
- MainPanel.tsx: Remove overflow-hidden from flex containers, add truncate
  to session name, use shrink-0 on git badge container
- GitStatusWidget.tsx: Use shrink-0 instead of overflow-visible
2026-02-03 00:50:43 -06:00
Pedram Amini
9c654819ce fix(header): restore git badge and changes hover overlays
The git branch badge and GitStatusWidget hover overlays were being clipped
by overflow-hidden on their parent containers. Added overflow-visible to
the tooltip container divs while keeping overflow-hidden on the outer
parent containers to preserve responsive truncation behavior.

Changes:
- MainPanel.tsx: Added overflow-visible to git badge's relative container
- GitStatusWidget.tsx: Added overflow-visible to widget's relative container
2026-02-03 00:47:47 -06:00
Pedram Amini
464ccdb83d feat(file-explorer): add Open in Default App context menu option
Add a new context menu option for files that opens them in the system's
default application. The option appears in the top section of the menu,
after Preview and Document Graph, as the third item.
2026-02-03 00:30:28 -06:00
Pedram Amini
42dd005ca1 fix(tab-naming): use stdin for prompt in SSH remote execution
Tab naming was failing with 'zsh:23: unmatched' errors when running
via SSH because the prompt was being passed through multiple layers
of shell escaping (local spawn -> SSH -> remote zsh -> bash -c).

Fix by detecting SSH remote execution and sending the prompt via stdin
with --input-format stream-json instead of embedding it in the command
line. This completely bypasses shell escaping issues.

Changes:
- Add shouldSendPromptViaStdin flag when SSH remote is configured
- Pass useStdin option to buildSshCommand for proper SSH configuration
- Add sendPromptViaStdin to ProcessManager spawn call
- Add test case for SSH remote tab naming
2026-02-03 00:09:48 -06:00
Pedram Amini
f29e767b79 fix(tab-naming): replace unicode arrows with ASCII to prevent shell escaping issues 2026-02-03 00:03:53 -06:00
Pedram Amini
7088a33b1f fix(tab-naming): simplify prompt and improve output extraction
The tab naming prompt was too verbose, causing agents to output full
sentences instead of short 2-4 word names.

Changes:
- Simplified tab-naming.md prompt to be more concise and direct
- Improved extractTabName() to filter out bad output:
  - Removes markdown headers (##, ###)
  - Removes common preamble phrases ("Here's", "Tab name:")
  - Filters lines containing "example", "message:", "rules:"
  - Removes trailing punctuation (periods, colons)
  - Reduced max length from 50 to 40 characters
- Added tests for new extraction behaviors
2026-02-02 23:58:46 -06:00
Pedram Amini
89445f1a55 Remove excessive SSH debug logging in remote-fs
The execRemoteCommand() function was logging every SSH command at
DEBUG level, which created continuous log spam when operating over
SSH connections. This log fired for every remote filesystem operation
(directory listings, file stats, reads, etc.).

The transient error retry logging is preserved so SSH connection
issues are still visible in debug output.
2026-02-02 23:55:52 -06:00
Pedram Amini
9bdbac3818 test(tab-naming): add tests for automatic tab naming in useInputProcessing
Added test suite covering:
- Triggers tab naming for new AI sessions with text messages
- Respects automaticTabNamingEnabled setting
- Skips existing sessions (with agentSessionId)
- Skips tabs with custom names
- Skips terminal mode
- Skips empty/image-only messages
- Sets isGeneratingName flag during naming
- Handles naming failures gracefully
2026-02-02 23:49:06 -06:00
Pedram Amini
0f701e4ebd refactor(tab-naming): trigger immediately on first message send
Moved tab naming logic from onSessionId callback to useInputProcessing
hook. Tab naming now starts immediately when the user sends their first
message, running in parallel with the actual agent request instead of
waiting for the agent to respond with a session ID.

Changes:
- Added automaticTabNamingEnabled prop to UseInputProcessingDeps
- Tab naming triggered in processInput for new AI sessions with text
- Removed ~140 lines of tab naming code from onSessionId handler
- Removed unused automaticTabNamingEnabledRef
2026-02-02 23:47:44 -06:00
Pedram Amini
d15e023ea9 fix(tab-naming): show spinner regardless of tab busy state
The spinner was hidden when tab.state === 'busy', but when a user sends
a message the tab immediately enters busy state. Since tab naming runs
in parallel with the main request, the spinner should show regardless
of the busy state to indicate the naming process is working.
2026-02-02 23:37:58 -06:00
Pedram Amini
3761e0cf14 fix(tab-naming): register IPC handlers for automatic tab naming
The tabNaming:generateTabName IPC handler was defined in registerAllHandlers()
but that function was never called. Instead, handlers are registered individually
in main/index.ts. Added registerTabNamingHandlers import and call with required
dependencies (processManager, agentDetector, agentConfigsStore, settingsStore).

Also removed debug console.log statements that were added during investigation.
2026-02-02 23:32:51 -06:00
Pedram Amini
3e00e81b7a ## CHANGES
- Added detailed console logs to debug automatic tab naming conditions 🧭
- Logged user message discovery and first message preview for naming 📝
- Emitted telemetry for prepared tab-naming payload before AI processing 🔍
- Logged tab-naming trigger state, including feature-flag enablement 🚦
2026-02-02 23:28:23 -06:00
Pedram Amini
c2f4afe2cd fix(tab-naming): cancel automatic naming when manual rename is triggered
When user opens the rename modal, clear isGeneratingName flag to stop
showing the spinner. Also clear the flag when the rename is confirmed
to prevent any race conditions with the automatic naming completing.
2026-02-02 23:23:05 -06:00
Pedram Amini
3a56648fc1 fix(save-markdown): refresh file list after saving chat response to disk
When users save AI chat response content to a markdown file, the file
list in the right panel was not updating to show the new file. This
made it difficult to reference or open the saved file immediately.

Added onFileSaved callback prop to SaveMarkdownModal that triggers the
file tree refresh after a successful save. The callback is passed
through TerminalOutput from MainPanel, which calls refreshFileTree
with the active session ID.
2026-02-02 23:09:56 -06:00
Pedram Amini
64e0a886b9 ## CHANGES
- Toast clicks now always reveal the AI terminal, not file previews 🧠
- Session switching clears active file preview to prevent confusing UI state 🧹
- Toast-driven navigation can target a specific AI tab when available 🎯
- Missing tab IDs fall back gracefully while still entering AI input mode 🛟
- Context usage warnings are less noisy with higher yellow threshold (75%) 🟡
- Red context warnings now trigger later at 90% for calmer workflows 🔴
2026-02-02 22:54:16 -06:00
Pedram Amini
0b97505265 fix(tabs): use performTabClose for unified close history
When closing an AI tab via Cmd+W, the keyboard handler was calling
closeTab() directly which only adds to the legacy closedTabHistory.
This meant AI tabs were not being added to unifiedClosedTabHistory,
so Cmd+Shift+T could not restore them in the correct order with
file preview tabs.

Now uses performTabClose() which properly calls addAiTabToUnifiedHistory()
to ensure both AI tabs and file tabs appear in the unified closed tab
history in the order they were closed.

Fixes tab restore order: closing AI-tab-1, file-preview-A, AI-tab-2
then pressing Cmd+Shift+T three times now correctly restores:
AI-tab-2, file-preview-A, AI-tab-1.
2026-02-02 22:51:17 -06:00