Skip to content

fix(desktop): improve terminal startup reliability with agent hook wrappers#1659

Closed
Kitenite wants to merge 1 commit intomainfrom
Kitenite/jacket
Closed

fix(desktop): improve terminal startup reliability with agent hook wrappers#1659
Kitenite wants to merge 1 commit intomainfrom
Kitenite/jacket

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Feb 21, 2026

Summary

  • switch desktop startup to non-blocking ensureAgentHooks() warmup
  • ensure new daemon terminal sessions wait (with timeout) for hook wrappers before spawn
  • align terminal-host shell args with shared agent shell wrapper logic
  • keep zsh .zshrc/.zlogin split, add wrapper-env fallback behavior, and remove test-only writer exports
  • restore OpenCode behavior to local plugin only and clean stale global plugin

Validation

  • bun run lint:fix
  • bun test apps/desktop/src/main/lib/agent-setup/agent-wrappers.test.ts apps/desktop/src/main/lib/agent-setup/shell-wrappers.test.ts
  • bun test apps/desktop/src/main/lib/terminal/daemon/daemon-manager.test.ts apps/desktop/src/main/terminal-host/daemon.test.ts

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced agent initialization with improved error handling and timeout protection
    • Accelerated shell configuration setup through parallel operations
  • Bug Fixes

    • Improved reliability of shell integration fallback logic
  • Performance

    • Reduced initialization time by executing shell configuration steps concurrently instead of sequentially

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 21, 2026

📝 Walkthrough

Walkthrough

The PR refactors agent hooks initialization from synchronous to asynchronous, restructures setup logic to execute directory creation and script generation in parallel phases instead of sequentially, and replaces direct file-writing methods with pure content getter functions. Consumers are updated to handle the new async flow.

Changes

Cohort / File(s) Summary
Core API Refactoring
apps/desktop/src/main/index.ts, apps/desktop/src/main/lib/agent-setup/index.ts
Changed from sync setupAgentHooks() to async ensureAgentHooks() returning Promise<void>. Removed deprecated getSupersetBinDir() export.
Initialization Logic Restructuring
apps/desktop/src/main/lib/agent-setup/ensure-agent-hooks.ts
Reorganized directory and script creation into three parallel phases. Added wrappers/plugins for claude, codex, opencode, cursor-agent, gemini, copilot. Replaced sequential writes with Promise.all for concurrent execution. Integrated cleanup of global OpenCode plugin.
Shell Wrapper Refactoring
apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts, shell-wrappers.test.ts
Removed direct file-writing methods (createZshWrapper, createBashWrapper). Added exported content getters (getZshProfileContent, getZshRcContent, getZshLoginContent, getBashRcfileContent) and path getters. Introduced SHELL_WRAPPER_MARKER. Updated tests to use new helpers and added two new test cases for wrapper presence detection.
Daemon Manager Integration
apps/desktop/src/main/lib/terminal/daemon/daemon-manager.ts
Added waitForAgentHooks() method that races ensureAgentHooks() against 2-second timeout. Integrated call before daemon create/attach flow to ensure agent hooks are prepared.
Session Shell Arguments
apps/desktop/src/main/terminal-host/session.ts
Delegated to agent-provided shell args via getShellArgs() with fallback logic. Narrowed login-shell fallback from [zsh, bash, sh, ksh, fish] to [sh, ksh, fish].

Sequence Diagram

sequenceDiagram
    participant Main as Main Process
    participant DaemonMgr as Daemon Manager
    participant AgentSetup as ensureAgentHooks
    participant FSPhase1 as Phase 1:<br/>Dir Creation
    participant FSPhase2 as Phase 2:<br/>Notify + Settings
    participant FSPhase3 as Phase 3:<br/>Scripts + Wrappers

    Main->>DaemonMgr: doCreateOrAttach()
    DaemonMgr->>DaemonMgr: Check if daemon exists
    alt No daemon exists
        DaemonMgr->>DaemonMgr: waitForAgentHooks()
        DaemonMgr->>AgentSetup: ensureAgentHooks()
        par Parallel Phase 1
            AgentSetup->>FSPhase1: Create BIN_DIR, HOOKS_DIR,<br/>ZSH_DIR, BASH_DIR, etc.
        and
            AgentSetup->>AgentSetup: cleanupGlobalOpenCodePlugin()
        end
        par Parallel Phase 2
            AgentSetup->>FSPhase2: Queue notify script creation
        and
            AgentSetup->>FSPhase2: Queue Claude settings
        end
        par Parallel Phase 3
            AgentSetup->>FSPhase3: Create all wrappers<br/>(claude, codex, cursor, etc.)
        and
            AgentSetup->>FSPhase3: Create hooks<br/>(Cursor, Gemini, Copilot)
        and
            AgentSetup->>FSPhase3: Create plugins
        end
        AgentSetup-->>DaemonMgr: Promise resolves
    end
    DaemonMgr->>DaemonMgr: Create shell env
    DaemonMgr->>DaemonMgr: Attach daemon
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

Poem

🐰 Hops with glee through async dreams,
Parallel scripts and gleaming themes,
No more waiting, walls of time,
Phase by phase, in perfect rhyme,
Agent hooks now swift and true!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.65% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: improving terminal startup reliability by implementing agent hook wrappers, which aligns with the comprehensive refactoring across the agent setup and daemon terminal management system.
Description check ✅ Passed The description provides a clear summary of changes organized by objective, includes validation steps with specific test files, and covers all major modifications without requiring template sections.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch Kitenite/jacket

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.

🧹 Nitpick comments (2)
apps/desktop/src/main/terminal-host/session.ts (1)

14-14: Consider using the path alias main/lib/agent-setup instead of a relative path.

The daemon-manager.ts imports from "main/lib/agent-setup" (alias), while this file uses a relative path. If the terminal-host files intentionally avoid aliases (all existing imports here are relative), this is fine — but it's inconsistent with the convention in other main-process files. As per coding guidelines: "Use alias as defined in tsconfig.json when possible."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/main/terminal-host/session.ts` at line 14, The import in
session.ts uses a relative path for getShellArgs (imported as getAgentShellArgs)
which is inconsistent with other main-process files; update the import to use
the path alias main/lib/agent-setup (matching daemon-manager.ts) so the symbol
getShellArgs (getAgentShellArgs) is imported via the alias and conforms to
tsconfig.json aliasing conventions.
apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts (1)

6-9: Path constants are duplicated between module-level consts and exported getter functions.

Lines 6–9 define ZSH_PROFILE, ZSH_RC, ZSH_LOGIN, and BASH_RCFILE as module-level constants, while lines 42–56 define getter functions that recompute the same path.join(...) expressions. The getters should return the existing constants to avoid drift.

♻️ Proposed fix — return existing constants from getters
 export function getZshProfilePath(): string {
-	return path.join(ZSH_DIR, ".zprofile");
+	return ZSH_PROFILE;
 }
 
 export function getZshRcPath(): string {
-	return path.join(ZSH_DIR, ".zshrc");
+	return ZSH_RC;
 }
 
 export function getZshLoginPath(): string {
-	return path.join(ZSH_DIR, ".zlogin");
+	return ZSH_LOGIN;
 }
 
 export function getBashRcfilePath(): string {
-	return path.join(BASH_DIR, "rcfile");
+	return BASH_RCFILE;
 }

Also applies to: 42-56

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts` around lines 6 - 9,
The module defines path constants ZSH_PROFILE, ZSH_RC, ZSH_LOGIN, and
BASH_RCFILE but the exported getter functions later recompute the same
path.join(...) expressions; update those exported getters to simply return the
existing constants (ZSH_PROFILE, ZSH_RC, ZSH_LOGIN, BASH_RCFILE) instead of
recalculating to avoid drift and duplication.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts`:
- Around line 6-9: The module defines path constants ZSH_PROFILE, ZSH_RC,
ZSH_LOGIN, and BASH_RCFILE but the exported getter functions later recompute the
same path.join(...) expressions; update those exported getters to simply return
the existing constants (ZSH_PROFILE, ZSH_RC, ZSH_LOGIN, BASH_RCFILE) instead of
recalculating to avoid drift and duplication.

In `@apps/desktop/src/main/terminal-host/session.ts`:
- Line 14: The import in session.ts uses a relative path for getShellArgs
(imported as getAgentShellArgs) which is inconsistent with other main-process
files; update the import to use the path alias main/lib/agent-setup (matching
daemon-manager.ts) so the symbol getShellArgs (getAgentShellArgs) is imported
via the alias and conforms to tsconfig.json aliasing conventions.

@Kitenite Kitenite closed this Feb 22, 2026
@Kitenite Kitenite deleted the Kitenite/jacket branch February 22, 2026 05:52
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