Skip to content

fix(desktop): wrap zsh and bash to enable claude and codex proxies instead of modifying users' paths#187

Merged
saddlepaddle merged 1 commit intomainfrom
golden-ocean-48
Nov 29, 2025
Merged

fix(desktop): wrap zsh and bash to enable claude and codex proxies instead of modifying users' paths#187
saddlepaddle merged 1 commit intomainfrom
golden-ocean-48

Conversation

@saddlepaddle
Copy link
Copy Markdown
Collaborator

@saddlepaddle saddlepaddle commented Nov 29, 2025

…time

The wrapper scripts for Claude Code and Codex were hardcoding absolute paths to binaries when the app first launched. This caused notifications to fail for other users since paths like /Users/satyapatel/.nvm/... don't exist on their machines.

Now the wrappers use which -a at runtime to find the real binary, making them portable across different machines and Node.js installations.

🤖 Generated with Claude Code

Description

Related Issues

Type of Change

  • Bug fix
  • New feature
  • Documentation
  • Refactor
  • Other (please describe):

Testing

Screenshots (if applicable)

Additional Notes

Summary by CodeRabbit

  • Refactor

    • Terminal startup now respects the user’s shell environment and startup files, with added zsh/bash initialization wrappers.
    • Better handling of PATH and shell startup arguments for more reliable command execution.
  • Bug Fixes

    • Improved logging around wrapper creation and more consistent environment propagation to spawned terminals.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link
Copy Markdown

vercel Bot commented Nov 29, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
website Ready Ready Preview Comment Nov 29, 2025 9:33pm

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Nov 29, 2025

Walkthrough

Added shell-aware wrapper scaffolding and APIs: zsh/bash wrapper creators, getShellEnv, getShellArgs, and getSupersetBinDir; replaced the former getSupersetPath-based PATH injection with shell-specific env/args and updated terminal startup to merge shell envs and use shell args.

Changes

Cohort / File(s) Summary
Agent setup & wrapper scaffolding
apps/desktop/src/main/lib/agent-setup.ts
Added ZSH_DIR/BASH_DIR constants and creators (createZshWrapper, createBashWrapper); initialize zsh/bash wrapper directories; added getShellEnv(shell), getShellArgs(shell), and getSupersetBinDir() exports; removed/renamed getSupersetPath; switched to shell-aware env/arg handling and added wrapper creation logging.
Terminal startup integration
apps/desktop/src/main/lib/terminal-manager.ts
Replaced import of getSupersetPath with getShellArgs and getShellEnv; merge shell-specific env from getShellEnv(shell) into process env instead of overriding PATH; obtain shell startup arguments via getShellArgs(shell) when launching shells.

Sequence Diagram(s)

sequenceDiagram
    participant App as Desktop App
    participant AgentSetup as agent-setup module
    participant Terminal as Terminal Manager
    participant Shell as User Shell (zsh/bash)
    Note over App,AgentSetup: Initialization step
    App->>AgentSetup: setupAgentHooks()
    AgentSetup->>AgentSetup: create ZSH_DIR / BASH_DIR
    AgentSetup->>AgentSetup: create zsh/bash wrapper scripts
    AgentSetup-->>App: expose getSupersetBinDir, getShellEnv, getShellArgs
    Note over App,Terminal: When opening a terminal
    App->>Terminal: spawn shell (shell)
    Terminal->>AgentSetup: getShellEnv(shell)
    AgentSetup-->>Terminal: shell-specific env map
    Terminal->>AgentSetup: getShellArgs(shell)
    AgentSetup-->>Terminal: shell startup args
    Terminal->>Shell: launch process with merged env and args
    Shell-->>Terminal: shell runs with wrappers intercepting PATH/bin resolution
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Files to focus on:
    • apps/desktop/src/main/lib/agent-setup.ts — verify correctness of new APIs, wrapper content, and directory initialization.
    • apps/desktop/src/main/lib/terminal-manager.ts — confirm env merge semantics and correct use of getShellArgs.
    • Wrapper scripts created by agent-setup — ensure they correctly prepend bin dir, source user rc, and avoid recursive interception.
  • Check logging and error messaging around wrapper creation and missing binaries.

Poem

🐇 I dug new paths for shells to find,

Zsh and Bash with wrappers lined,
Env and args now dance in tune,
Binaries found beneath the moon,
Hopping code and cheer — hooray, we’re online!

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The description begins with a relevant explanation but is incomplete, leaving most required template sections unchecked or blank (Type of Change, Testing, and Related Issues). Complete the PR description by checking the appropriate Type of Change box, adding testing steps/verification details, and linking any related issues if applicable.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: switching from static path wrapping to runtime resolution using which -a for the zsh and bash wrappers.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch golden-ocean-48

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d5927b and 4ec3117.

📒 Files selected for processing (2)
  • apps/desktop/src/main/lib/agent-setup.ts (3 hunks)
  • apps/desktop/src/main/lib/terminal-manager.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
apps/desktop/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc

Files:

  • apps/desktop/src/main/lib/terminal-manager.ts
  • apps/desktop/src/main/lib/agent-setup.ts
apps/desktop/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx}: Please use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary

Files:

  • apps/desktop/src/main/lib/terminal-manager.ts
  • apps/desktop/src/main/lib/agent-setup.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid using any type - use explicit types instead for type safety
Use camelCase for variable and function names following existing codebase patterns
Keep diffs minimal with targeted edits only - avoid unnecessary changes when making modifications
Follow existing patterns and match the codebase style when writing new code

Files:

  • apps/desktop/src/main/lib/terminal-manager.ts
  • apps/desktop/src/main/lib/agent-setup.ts
apps/desktop/src/main/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Node.js modules (fs, path, os, net, etc.) can be used in main process code only

Files:

  • apps/desktop/src/main/lib/terminal-manager.ts
  • apps/desktop/src/main/lib/agent-setup.ts
🧠 Learnings (4)
📚 Learning: 2025-11-28T01:03:47.951Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T01:03:47.951Z
Learning: Applies to apps/desktop/src/main/index.ts : Load `.env` file with `override: true` at the start of the main process before any imports

Applied to files:

  • apps/desktop/src/main/lib/terminal-manager.ts
📚 Learning: 2025-11-24T21:32:21.713Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/CLAUDE.md:0-0
Timestamp: 2025-11-24T21:32:21.713Z
Learning: Applies to apps/desktop/**/AGENTS.md : Document agent responsibilities, capabilities, and interaction patterns in AGENTS.md

Applied to files:

  • apps/desktop/src/main/lib/agent-setup.ts
📚 Learning: 2025-11-28T01:03:47.951Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T01:03:47.951Z
Learning: Applies to **/*.{ts,tsx} : Keep diffs minimal with targeted edits only - avoid unnecessary changes when making modifications

Applied to files:

  • apps/desktop/src/main/lib/agent-setup.ts
📚 Learning: 2025-11-28T01:03:47.951Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T01:03:47.951Z
Learning: Applies to apps/desktop/src/main/**/*.{ts,tsx} : Node.js modules (fs, path, os, net, etc.) can be used in main process code only

Applied to files:

  • apps/desktop/src/main/lib/agent-setup.ts
🧬 Code graph analysis (2)
apps/desktop/src/main/lib/terminal-manager.ts (1)
apps/desktop/src/main/lib/agent-setup.ts (2)
  • getShellEnv (196-205)
  • getShellArgs (210-221)
apps/desktop/src/main/lib/agent-setup.ts (2)
apps/desktop/src/main/lib/app-environment.ts (1)
  • SUPERSET_HOME_DIR (8-8)
apps/desktop/src/shared/constants.ts (1)
  • SUPERSET_DIR_NAME (21-23)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build
🔇 Additional comments (7)
apps/desktop/src/main/lib/terminal-manager.ts (1)

5-5: LGTM! Clean integration with centralized shell handling.

The refactoring correctly delegates shell initialization to the new agent-setup module. Environment variables and startup arguments are now determined by shell type, making the terminal spawning logic cleaner and more maintainable.

Also applies to: 90-93, 118-118

apps/desktop/src/main/lib/agent-setup.ts (6)

3-3: LGTM! Constants follow existing patterns.

The os import is needed for getShellEnv, and the new directory constants follow the established structure.

Also applies to: 10-11


109-131: LGTM! Zsh wrapper correctly intercepts shell initialization.

The wrapper properly preserves the original ZDOTDIR, sources the user's .zshrc, and prepends the Superset bin to PATH. The template literal interpolation and shell variable escaping are correct.


133-166: LGTM! Bash wrapper follows standard startup conventions.

The wrapper correctly sources system and user configurations in the proper order (profile hierarchy, then bashrc) before prepending the Superset bin to PATH. File existence checks are in place.


172-191: LGTM! Initialization sequence is correct.

Directory creation and wrapper generation follow the proper order. Using recursive: true prevents errors if directories already exist.


207-221: LGTM! Shell arguments correctly configured.

  • Zsh uses -l for login shell behavior, working with the ZDOTDIR environment variable set by getShellEnv.
  • Bash uses --rcfile to point to the custom initialization file that sources user configurations.
  • The default empty array handles unsupported shells gracefully.

193-205: I'll verify the Windows shell handling concern by investigating the codebase. Let me start by understanding the context of this function and checking if Windows support exists elsewhere.

#!/bin/bash

1. Check for Windows platform handling in agent-setup and related files

rg -n -C5 'win32|windows|platform|powershell|COMSPEC' apps/desktop/src/main/ --type ts --type tsx

2. Look for shell detection patterns

rg -n 'shell.' apps/desktop/src/main/lib/ --type ts -A2 -B2


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/desktop/src/main/lib/agent-setup.ts (1)

42-91: Consider extracting common wrapper logic to reduce duplication.

The Claude and Codex wrapper functions share ~80% of their logic (runtime resolution, error handling, exec pattern). Consider extracting a helper function to reduce maintenance burden:

function createAgentWrapper(
  binaryName: string,
  settingsOrFlags: string
): void {
  const wrapperPath = path.join(BIN_DIR, binaryName);
  const script = `#!/bin/bash
# Superset wrapper for ${binaryName}
# Injects notification hook settings

# Find the real ${binaryName} binary at runtime, excluding our wrapper
REAL_BINARY=$(which -a ${binaryName} 2>/dev/null | grep -F -v "${BIN_DIR}" | head -1)

if [ -z "$REAL_BINARY" ]; then
  echo "Error: ${binaryName} not found in PATH" >&2
  exit 1
fi

exec "$REAL_BINARY" ${settingsOrFlags} "$@"
`;
  fs.writeFileSync(wrapperPath, script, { mode: 0o755 });
  console.log(\`[agent-setup] Created \${binaryName} wrapper\`);
}

Then call it with agent-specific settings:

createAgentWrapper("claude", '--settings "$SUPERSET_CLAUDE_SETTINGS"');
createAgentWrapper("codex", '-c \'notify=["bash","~/\${SUPERSET_DIR_NAME}/hooks/notify.sh"]\'');
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4b4935d and 3d5927b.

📒 Files selected for processing (1)
  • apps/desktop/src/main/lib/agent-setup.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
apps/desktop/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc

Files:

  • apps/desktop/src/main/lib/agent-setup.ts
apps/desktop/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx}: Please use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary

Files:

  • apps/desktop/src/main/lib/agent-setup.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid using any type - use explicit types instead for type safety
Use camelCase for variable and function names following existing codebase patterns
Keep diffs minimal with targeted edits only - avoid unnecessary changes when making modifications
Follow existing patterns and match the codebase style when writing new code

Files:

  • apps/desktop/src/main/lib/agent-setup.ts
apps/desktop/src/main/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Node.js modules (fs, path, os, net, etc.) can be used in main process code only

Files:

  • apps/desktop/src/main/lib/agent-setup.ts
🧠 Learnings (2)
📚 Learning: 2025-11-24T21:32:21.713Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/CLAUDE.md:0-0
Timestamp: 2025-11-24T21:32:21.713Z
Learning: Applies to apps/desktop/**/AGENTS.md : Document agent responsibilities, capabilities, and interaction patterns in AGENTS.md

Applied to files:

  • apps/desktop/src/main/lib/agent-setup.ts
📚 Learning: 2025-11-28T01:03:47.951Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-28T01:03:47.951Z
Learning: Applies to apps/desktop/src/main/**/*.{ts,tsx} : Node.js modules (fs, path, os, net, etc.) can be used in main process code only

Applied to files:

  • apps/desktop/src/main/lib/agent-setup.ts
🧬 Code graph analysis (1)
apps/desktop/src/main/lib/agent-setup.ts (1)
apps/desktop/src/shared/constants.ts (1)
  • SUPERSET_DIR_NAME (21-23)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build

Comment on lines +51 to +52
# Find the real claude binary at runtime, excluding our wrapper
REAL_CLAUDE=$(which -a claude 2>/dev/null | grep -v "${BIN_DIR}" | head -1)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use grep -F for fixed-string matching to avoid regex interpretation.

The BIN_DIR path is used as a grep pattern, but it contains characters like . that are regex metacharacters. While typical paths are unlikely to cause issues, paths with special regex characters (e.g., [, +, *) could lead to incorrect filtering.

Apply this diff:

-# Find the real claude binary at runtime, excluding our wrapper
-REAL_CLAUDE=$(which -a claude 2>/dev/null | grep -v "${BIN_DIR}" | head -1)
+# Find the real claude binary at runtime, excluding our wrapper
+REAL_CLAUDE=$(which -a claude 2>/dev/null | grep -F -v "${BIN_DIR}" | head -1)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Find the real claude binary at runtime, excluding our wrapper
REAL_CLAUDE=$(which -a claude 2>/dev/null | grep -v "${BIN_DIR}" | head -1)
# Find the real claude binary at runtime, excluding our wrapper
REAL_CLAUDE=$(which -a claude 2>/dev/null | grep -F -v "${BIN_DIR}" | head -1)
🤖 Prompt for AI Agents
In apps/desktop/src/main/lib/agent-setup.ts around lines 51 to 52, the grep used
to filter out our wrapper path treats BIN_DIR as a regex which can misfilter
paths containing regex metacharacters; change the grep invocation to use
fixed-string matching (grep -F) when excluding BIN_DIR (i.e., use grep -F -v
with the BIN_DIR variable) so the path is treated literally and filtering is
reliable.

Comment on lines +79 to +80
# Find the real codex binary at runtime, excluding our wrapper
REAL_CODEX=$(which -a codex 2>/dev/null | grep -v "${BIN_DIR}" | head -1)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use grep -F for fixed-string matching to avoid regex interpretation.

Same issue as in the Claude wrapper: BIN_DIR should be matched as a fixed string, not a regex pattern.

Apply this diff:

-# Find the real codex binary at runtime, excluding our wrapper
-REAL_CODEX=$(which -a codex 2>/dev/null | grep -v "${BIN_DIR}" | head -1)
+# Find the real codex binary at runtime, excluding our wrapper
+REAL_CODEX=$(which -a codex 2>/dev/null | grep -F -v "${BIN_DIR}" | head -1)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Find the real codex binary at runtime, excluding our wrapper
REAL_CODEX=$(which -a codex 2>/dev/null | grep -v "${BIN_DIR}" | head -1)
# Find the real codex binary at runtime, excluding our wrapper
REAL_CODEX=$(which -a codex 2>/dev/null | grep -F -v "${BIN_DIR}" | head -1)
🤖 Prompt for AI Agents
In apps/desktop/src/main/lib/agent-setup.ts around lines 79 to 80, the current
grep call uses the default (regex) mode to exclude BIN_DIR which can
misinterpret special characters; change the grep invocation to use fixed-string
matching (e.g., add the -F flag) when excluding "${BIN_DIR}" so the exclusion is
treated as a literal string, ensuring the real codex binary is found reliably.

@saddlepaddle saddlepaddle changed the title fix(desktop): resolve agent binary paths at runtime instead of build … fix(desktop): wrap zsh and bash to enable claude and codex proxies instead of modifying users' paths Nov 29, 2025
@saddlepaddle saddlepaddle merged commit bcf4056 into main Nov 29, 2025
6 of 7 checks passed
@Kitenite Kitenite deleted the golden-ocean-48 branch December 1, 2025 00:45
@coderabbitai coderabbitai Bot mentioned this pull request Dec 1, 2025
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant