Skip to content

feat(worktrees): run a post-create setup script in new worktrees - #1306

Open
pedramamini wants to merge 1 commit into
mainfrom
feat/409-worktree-post-create-setup-script
Open

feat(worktrees): run a post-create setup script in new worktrees#1306
pedramamini wants to merge 1 commit into
mainfrom
feat/409-worktree-post-create-setup-script

Conversation

@pedramamini

@pedramamini pedramamini commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

Closes #409

Problem

A fresh worktree only contains what git tracks. Anything gitignored - .env.local, generated config, installed dependencies - is missing until you recreate it by hand, every single time. Issue #409 asked for a hook to run an OS-specific script after worktree creation, and the workaround people landed on was a shell script that wraps git worktree add entirely, which means giving up Maestro's worktree UI.

What this adds

A per-agent Setup Script in the Worktree Configuration modal. It runs inside each worktree Maestro creates, with the new worktree as its working directory.

Available to the script:

Variable Value
MAESTRO_WORKTREE_PATH Absolute path of the new worktree (also the cwd)
MAESTRO_WORKTREE_BRANCH Branch checked out in the new worktree
MAESTRO_MAIN_REPO_PATH Absolute path of the main repository
MAESTRO_BASE_BRANCH Branch the new branch was based on, when specified

So the two use cases from the issue become:

cp "$MAESTRO_MAIN_REPO_PATH/.env.local" .
cp "$MAESTRO_MAIN_REPO_PATH/.env.local" . && ./scripts/setup.sh

OS-specific logic stays in a checked-in script that the field points at, so it lives with the repo rather than in app config.

Implementation

  • git:worktreeRunSetup IPC (src/main/utils/worktree-setup-script.ts) runs the command through cmd.exe /d /s /c on Windows and the login shell elsewhere, with a 10 minute cap and stdout/stderr truncated to a 4k tail.
  • Local runs inherit the login-shell PATH (same treatment git:createPR gives gh), so GUI-launched Electron on macOS doesn't lose node/npm.
  • SSH remote agents run the script on the remote host via a new exported execShellRemote in remote-git.ts; the private execRemoteShellCommand now delegates to it.
  • Wired into all four creation paths - config modal, create-worktree modal, Auto Run spawn (worktreeSpawn.ts), batch runner (useWorktreeManager) - through one renderer helper, gated on result.created so reused or re-attached worktrees never re-run it.
  • Failures raise a toast and are swallowed: the worktree and its agent are already usable, so a broken script must not abort the spawn flow.
  • execFileNoThrow's ExecOptions form now accepts env alongside timeout (previously mutually exclusive), which the runner needs.

Design notes

The script is stored per parent agent rather than read from a file in the repo. Auto-executing a checked-in script on git worktree add would mean any cloned repo could run code the moment you make a worktree; requiring the user to type the command keeps that surface closed while still letting the command be ./scripts/setup.sh.

Notes for review

useWorktreeHandlers.ts shows ~85 lines of reindentation: shortening the handleSaveWorktreeConfig parameter type let Prettier collapse the useCallback( wrapper onto one line. git diff -w on that file is 27 insertions / 8 deletions.

Testing

  • src/__tests__/main/utils/worktree-setup-script.test.ts - 13 tests: no-op paths, env exposure, local vs SSH dispatch, exit-code/timeout reporting, output truncation, PATH-probe failure
  • src/__tests__/renderer/utils/worktreeSetupScript.test.ts - 7 tests: script resolution by session and by repo path, child-agent exclusion, toast surfaces, IPC rejection handling
  • Full suite green locally: 31,674 passed / 108 skipped across 1,109 files
  • npm run lint (all three configs) and prettier --check clean on the changed files

Summary by CodeRabbit

  • New Features

    • Added optional setup scripts for newly created Git worktrees.
    • Setup scripts run locally or over SSH before the worktree agent starts.
    • Added environment variables, platform-specific shell support, and execution output reporting.
    • Added a 10-minute timeout; failures show a notification without blocking worktree creation.
  • Documentation

    • Documented worktree setup scripts, configuration, environment variables, and Git integration APIs.
  • Tests

    • Added coverage for local and remote execution, error handling, configuration, and worktree creation flows.

A fresh worktree only contains what git tracks, so gitignored files
(.env.local, generated config, installed deps) have to be recreated by
hand every time. Add a per-agent "Setup Script" that runs inside each
worktree Maestro creates.

- Worktree Configuration modal gains a Setup Script field, stored on the
  parent agent's worktreeConfig
- New git:worktreeRunSetup IPC runs the command with the new worktree as
  cwd, exposing MAESTRO_WORKTREE_PATH / _WORKTREE_BRANCH / _MAIN_REPO_PATH
  / _BASE_BRANCH, with a 10 minute cap and truncated output
- Runs on the remote host over SSH when the parent agent uses SSH remote
  execution
- Wired into all four creation paths (config modal, create-worktree modal,
  Auto Run spawn, batch runner), gated on a freshly created worktree so
  reused/re-attached worktrees don't re-run it
- Failures surface as a toast and never block worktree creation

execFileNoThrow's ExecOptions form now accepts env alongside timeout, so
the runner can inherit the login-shell PATH and still be bounded.

Closes #409
Copilot AI review requested due to automatic review settings July 25, 2026 20:51
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds per-agent worktree setup scripts with UI configuration, local and SSH execution, environment variables, timeout handling, IPC contracts, and invocation after newly created worktrees are prepared.

Changes

Worktree setup script

Layer / File(s) Summary
Configuration and shared contracts
CLAUDE-IPC.md, docs/git-worktrees.md, src/renderer/types/index.ts, src/renderer/components/AppModals/*, src/renderer/components/WorktreeConfigModal.tsx
Adds setupScript to worktree configuration, exposes it in the modal, preserves it during quick creation, and documents execution timing, variables, platform examples, timeout, and failure behavior.
Setup script execution backend
src/main/utils/worktree-setup-script.ts, src/main/utils/execFile.ts, src/main/utils/remote-git.ts, src/main/preload/git.ts, src/main/ipc/handlers/git.ts, src/__tests__/main/*
Adds typed setup execution contracts, local/SSH shell execution, environment propagation, timeout and output handling, and the git:worktreeRunSetup IPC channel with tests.
Fresh-worktree orchestration
src/renderer/utils/worktreeSetupScript.ts, src/renderer/utils/worktreeSpawn.ts, src/renderer/hooks/worktree/useWorktreeHandlers.ts, src/renderer/hooks/batch/useWorktreeManager.ts, src/renderer/global.d.ts, src/__tests__/renderer/utils/*
Runs the configured script only when a worktree is newly created, resolves the owning parent session, reports outcomes with toasts, and wires the typed API through creation flows with renderer tests.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant WorktreeCreation
  participant SetupRunner
  participant GitIPC
  participant Shell
  WorktreeCreation->>SetupRunner: run setup after worktree creation
  SetupRunner->>GitIPC: worktreeRunSetup(script, context, sshRemoteId)
  GitIPC->>Shell: execute locally or over SSH
  Shell-->>GitIPC: return status and output
  GitIPC-->>SetupRunner: return setup result
Loading

Possibly related PRs

Suggested reviewers: copilot, reachrazamair, chr1syy

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main change: running a post-create setup script in new worktrees.
Linked Issues check ✅ Passed The PR satisfies #409 by adding a configurable setup script that runs only for newly created worktrees.
Out of Scope Changes check ✅ Passed The changes are focused on the worktree setup-script feature and its supporting plumbing, tests, and docs.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/409-worktree-post-create-setup-script

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.

@greptile-apps

greptile-apps Bot commented Jul 25, 2026

Copy link
Copy Markdown

Greptile Summary

Adds configurable post-create setup scripts for newly created local and SSH worktrees.

  • Persists a setup command in each parent agent’s worktree configuration.
  • Runs the command before starting worktree agents across interactive, Auto Run, and batch creation paths.
  • Exposes worktree context through MAESTRO_* environment variables and reports failures without aborting worktree creation.
  • Adds IPC/preload support, timeout and output limits, documentation, and focused tests.

Confidence Score: 4/5

The batch setup path needs correction before merging because it can run the wrong agent’s setup command when parent agents share a repository.

The batch manager identifies setup configuration only by repository path, while the lookup returns the first matching parent session; per-agent scripts therefore lose their ownership boundary for duplicate repository sessions.

Files Needing Attention: src/renderer/utils/worktreeSetupScript.ts and src/renderer/hooks/batch/useWorktreeManager.ts

Important Files Changed

Filename Overview
src/main/utils/worktree-setup-script.ts Implements bounded local and remote setup-script execution with worktree context variables and output truncation.
src/main/ipc/handlers/git.ts Registers the setup-script IPC handler and resolves optional SSH configuration before dispatch.
src/main/utils/remote-git.ts Exports a reusable remote shell executor supporting cwd, environment variables, and timeout.
src/main/utils/execFile.ts Extends execution options to support environment variables alongside input and timeout.
src/renderer/utils/worktreeSetupScript.ts Resolves setup configuration by repository path, which can select the wrong parent when multiple agents share a repository.
src/renderer/hooks/worktree/useWorktreeHandlers.ts Runs setup for newly created interactive worktrees and preserves the configured script during session updates.
src/renderer/utils/worktreeSpawn.ts Runs setup before creating and dispatching Auto Run worktree agents.
src/renderer/hooks/batch/useWorktreeManager.ts Runs setup before batch processing but relies on repository-path lookup to identify the owning parent configuration.
src/renderer/components/WorktreeConfigModal.tsx Adds the per-agent setup-script field and persists its trimmed value with worktree configuration.

Sequence Diagram

sequenceDiagram
    participant User
    participant Renderer
    participant GitIPC as Git IPC
    participant Git
    participant Runner as Setup Runner
    participant Shell as Local/SSH Shell
    User->>Renderer: Create worktree
    Renderer->>GitIPC: worktreeSetup(...)
    GitIPC->>Git: git worktree add
    Git-->>GitIPC: "created=true"
    GitIPC-->>Renderer: Setup result
    Renderer->>GitIPC: worktreeRunSetup(script, context)
    GitIPC->>Runner: runWorktreeSetupScript(...)
    Runner->>Shell: Execute with cwd, env, timeout
    Shell-->>Runner: stdout, stderr, exit code
    Runner-->>Renderer: Truncated result
    Renderer->>Renderer: Create and start child agent
Loading

Reviews (1): Last reviewed commit: "feat(worktrees): run a post-create setup..." | Re-trigger Greptile

Copilot AI left a comment

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.

Pull request overview

This PR adds a per-agent "Setup Script" hook that runs immediately after Maestro creates a new git worktree, so repo-local bootstrap steps (copying gitignored env files, generating config, installing deps) can be automated without wrapping git worktree add outside the app. It introduces a new git:worktreeRunSetup IPC that executes locally (OS-specific shell) or over SSH, exposes a small MAESTRO_* env context to the script, and wires the runner into all worktree creation flows.

Changes:

  • Add a Worktree Config modal field to persist a per-agent setup command and run it only for freshly created worktrees.
  • Implement git:worktreeRunSetup IPC with local and SSH execution, runtime caps, and output truncation.
  • Expand types, preload surface, and tests to cover setup-script behavior end to end.

Reviewed changes

Copilot reviewed 18 out of 19 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/renderer/utils/worktreeSpawn.ts Runs setup script after worktree creation in the Auto Run spawn path.
src/renderer/utils/worktreeSetupScript.ts New renderer helper that resolves the owning parent agent and invokes the IPC, surfacing toasts.
src/renderer/types/index.ts Adds SessionWorktreeConfig (including setupScript) and wires it into Session.
src/renderer/hooks/worktree/useWorktreeHandlers.ts Runs setup script after create flows and preserves setupScript when auto-filling basePath.
src/renderer/hooks/batch/useWorktreeManager.ts Runs setup script before starting a batch run in a newly created worktree.
src/renderer/global.d.ts Extends window.maestro.git typing with worktreeRunSetup and related types.
src/renderer/components/WorktreeConfigModal.tsx Adds UI for editing the setup script and saving it into the agent worktree config.
src/renderer/components/AppModals/AppWorktreeModals.tsx Updates modal prop typing to use SessionWorktreeConfig.
src/renderer/components/AppModals/AppModals.tsx Threads SessionWorktreeConfig type into AppModals props.
src/main/utils/worktree-setup-script.ts New main-process runner for local or SSH setup-script execution, env injection, timeouts, output tailing.
src/main/utils/remote-git.ts Exports execShellRemote and adds options for cwd/env/timeout.
src/main/utils/execFile.ts Extends ExecOptions to support env alongside timeout and plumbs env to spawn-with-stdin path.
src/main/preload/git.ts Adds new preload API and types for worktreeRunSetup.
src/main/ipc/handlers/git.ts Registers git:worktreeRunSetup handler and resolves SSH remotes for it.
src/tests/renderer/utils/worktreeSetupScript.test.ts Adds renderer tests for script resolution, no-op behavior, and toast surfaces.
src/tests/main/utils/worktree-setup-script.test.ts Adds main-process tests for env exposure, local vs SSH execution, timeout and truncation behavior.
src/tests/main/ipc/handlers/git.test.ts Updates IPC handler registry expectations to include the new channel.
docs/git-worktrees.md Documents setup scripts, env vars, and Windows usage notes.
CLAUDE-IPC.md Updates IPC surface documentation to include worktreeRunSetup.
Comments suppressed due to low confidence (2)

src/renderer/hooks/worktree/useWorktreeHandlers.ts:383

  • This comment uses an em-dash character, which the repo style guide explicitly forbids (see CLAUDE.md). Please replace it with a normal hyphen or punctuation.
					// Fresh worktree on disk — bootstrap it with the agent's setup script.

src/renderer/hooks/worktree/useWorktreeHandlers.ts:509

  • This comment uses an em-dash character, which the repo style guide explicitly forbids (see CLAUDE.md). Please replace it with a normal hyphen or punctuation.
				// Fresh worktree on disk — bootstrap it with the agent's setup script.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


if (options) {
if ('input' in options || 'timeout' in options) {
if ('input' in options || 'timeout' in options || 'env' in options) {
Comment on lines +114 to +115
// Fresh worktree on disk — run the parent agent's setup script before the
// agent spawns so .env files and generated config are already in place.
Comment on lines +268 to +269
// Fresh worktree on disk — run the owning agent's setup script before the
// batch run starts, so generated env files exist for the first prompt.
@@ -381,6 +379,15 @@ export function useWorktreeHandlers(): WorktreeHandlersReturn {
// avoid re-marking — there was nothing newly created on disk to race with.
Comment on lines +42 to +46
.getState()
.sessions.find(
(s) => !s.parentSessionId && s.worktreeConfig && normalizePath(s.cwd) === normalized
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Setup script owner is ambiguous

When multiple parent agents use the same repository with different worktree setup scripts, this lookup selects the first matching session rather than the agent starting the batch. The batch path can therefore execute another agent’s setup command in the new worktree, producing the wrong generated files or dependencies.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/renderer/hooks/worktree/useWorktreeHandlers.ts (1)

1-1: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Em-dash used in new comments across all four worktree-setup call sites.

Each of the four newly-added "run the setup script" call sites uses the same comment template containing an em-dash (), which violates the repository guideline against em-dashes/en-dashes in authored text.

  • src/renderer/hooks/worktree/useWorktreeHandlers.ts#L382-391: replace // Fresh worktree on disk — bootstrap it with the agent's setup script. with a plain-hyphen or colon phrasing (e.g. // Fresh worktree on disk: bootstrap it with the agent's setup script.).
  • src/renderer/hooks/worktree/useWorktreeHandlers.ts#L508-518: same fix for the duplicate comment in handleCreateWorktree.
  • src/renderer/hooks/batch/useWorktreeManager.ts#L268-279: same fix for // Fresh worktree on disk — run the owning agent's setup script before the batch run starts, ....
  • src/renderer/utils/worktreeSpawn.ts#L113-124: same fix for // Fresh worktree on disk — run the parent agent's setup script before the agent spawns ....
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/hooks/worktree/useWorktreeHandlers.ts` at line 1, Replace the
em-dash in all four newly added “Fresh worktree on disk” comments across the
worktree setup call sites with a colon or plain hyphen, preserving the existing
comment wording and intent.

Source: Coding guidelines

🧹 Nitpick comments (2)
src/renderer/components/WorktreeConfigModal.tsx (1)

334-363: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Apply the modal text-selection classes to the new script editor.

This is a click-driven modal. Add select-none to its root container and select-text to this textarea and the other editable controls so text selection remains intentional.

As per coding guidelines, click-driven TSX modals must use select-none on the root and select-text on nested content-driven areas.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/components/WorktreeConfigModal.tsx` around lines 334 - 363,
Update the WorktreeConfigModal root container to include select-none, then add
select-text to the setup-script textarea and every other editable content-driven
control in the modal. Preserve selection behavior so modal text is
non-selectable by default while inputs and textareas remain selectable.

Source: Coding guidelines

src/main/ipc/handlers/git.ts (1)

798-822: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse WorktreeSetupContext instead of redeclaring the shape inline.

The context parameter type here duplicates WorktreeSetupContext (exported from worktree-setup-script.ts). Importing it keeps the IPC contract and the execution utility's type in sync if the shape changes later.

♻️ Proposed refactor
-import { runWorktreeSetupScript } from '../../utils/worktree-setup-script';
+import { runWorktreeSetupScript, type WorktreeSetupContext } from '../../utils/worktree-setup-script';
...
 			async (
 				script: string,
-				context: {
-					worktreePath: string;
-					branchName: string;
-					mainRepoPath: string;
-					baseBranch?: string;
-				},
+				context: WorktreeSetupContext,
 				sshRemoteId?: string
 			) => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/ipc/handlers/git.ts` around lines 798 - 822, Update the
git:worktreeRunSetup handler to import and use the exported WorktreeSetupContext
type for its context parameter instead of redeclaring the object shape inline.
Keep the existing handler behavior and runWorktreeSetupScript invocation
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/git-worktrees.md`:
- Around line 117-123: Update the Windows setup guidance around the
`MAESTRO_MAIN_REPO_PATH` command to reference a checked-in `.cmd` or `.bat`
script executable by `cmd.exe`, rather than `./scripts/setup.sh`; keep the setup
field as a one-liner and retain the Windows-specific environment-variable
syntax.

In `@src/main/utils/worktree-setup-script.ts`:
- Around line 78-93: Update resolveSetupShell for Windows so multiline setup
scripts are converted into cmd.exe-compatible command separators or executed
through a temporary .bat/.cmd file instead of being passed raw inline. Preserve
the existing ComSpec selection and /d /s /c invocation behavior for single-line
scripts and keep non-Windows shell handling unchanged.

In `@src/renderer/utils/worktreeSetupScript.ts`:
- Around line 68-100: Report the caught worktreeRunSetup IPC exception to Sentry
before showing the error toast and returning false. Update the catch block in
the worktree setup flow to call the existing captureException utility with err,
following the pattern used by createPR in useWorktreeManager.ts, while
preserving the current user-facing error handling.

---

Outside diff comments:
In `@src/renderer/hooks/worktree/useWorktreeHandlers.ts`:
- Line 1: Replace the em-dash in all four newly added “Fresh worktree on disk”
comments across the worktree setup call sites with a colon or plain hyphen,
preserving the existing comment wording and intent.

---

Nitpick comments:
In `@src/main/ipc/handlers/git.ts`:
- Around line 798-822: Update the git:worktreeRunSetup handler to import and use
the exported WorktreeSetupContext type for its context parameter instead of
redeclaring the object shape inline. Keep the existing handler behavior and
runWorktreeSetupScript invocation unchanged.

In `@src/renderer/components/WorktreeConfigModal.tsx`:
- Around line 334-363: Update the WorktreeConfigModal root container to include
select-none, then add select-text to the setup-script textarea and every other
editable content-driven control in the modal. Preserve selection behavior so
modal text is non-selectable by default while inputs and textareas remain
selectable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a4270b1a-94ff-4856-a1a1-3043e10da627

📥 Commits

Reviewing files that changed from the base of the PR and between d2085a0 and 664f894.

📒 Files selected for processing (19)
  • CLAUDE-IPC.md
  • docs/git-worktrees.md
  • src/__tests__/main/ipc/handlers/git.test.ts
  • src/__tests__/main/utils/worktree-setup-script.test.ts
  • src/__tests__/renderer/utils/worktreeSetupScript.test.ts
  • src/main/ipc/handlers/git.ts
  • src/main/preload/git.ts
  • src/main/utils/execFile.ts
  • src/main/utils/remote-git.ts
  • src/main/utils/worktree-setup-script.ts
  • src/renderer/components/AppModals/AppModals.tsx
  • src/renderer/components/AppModals/AppWorktreeModals.tsx
  • src/renderer/components/WorktreeConfigModal.tsx
  • src/renderer/global.d.ts
  • src/renderer/hooks/batch/useWorktreeManager.ts
  • src/renderer/hooks/worktree/useWorktreeHandlers.ts
  • src/renderer/types/index.ts
  • src/renderer/utils/worktreeSetupScript.ts
  • src/renderer/utils/worktreeSpawn.ts

Comment thread docs/git-worktrees.md
Comment on lines +117 to +123
On Windows the command runs through `cmd.exe`, so reference the variables as `%MAESTRO_MAIN_REPO_PATH%`:

```bat
copy "%MAESTRO_MAIN_REPO_PATH%\.env.local" . && npm install
```

Keep the platform-specific logic in a checked-in script (`./scripts/setup.sh`) and point the field at it - that way the setup steps live with the repo and the field stays a one-liner.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Make the Windows setup-script guidance shell-compatible.

The docs say Windows runs through cmd.exe but then recommend pointing the field at ./scripts/setup.sh, which cmd.exe cannot execute by default. Recommend a .cmd or .bat script for Windows, or explicitly invoke Bash when it is guaranteed to exist.

Suggested wording
-On Windows the command runs through `cmd.exe`, so reference the variables as `%MAESTRO_MAIN_REPO_PATH%`:
+On Windows the command runs through `cmd.exe`. Use a `.cmd` or `.bat` script, or explicitly invoke Bash if it is installed:
...
-Keep the platform-specific logic in a checked-in script (`./scripts/setup.sh`) and point the field at it - that way the setup steps live with the repo and the field stays a one-liner.
+Keep platform-specific logic in a checked-in script matching the target shell, such as `./scripts/setup.cmd` on Windows or `./scripts/setup.sh` on POSIX systems.
📝 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
On Windows the command runs through `cmd.exe`, so reference the variables as `%MAESTRO_MAIN_REPO_PATH%`:
```bat
copy "%MAESTRO_MAIN_REPO_PATH%\.env.local" . && npm install
```
Keep the platform-specific logic in a checked-in script (`./scripts/setup.sh`) and point the field at it - that way the setup steps live with the repo and the field stays a one-liner.
On Windows the command runs through `cmd.exe`. Use a `.cmd` or `.bat` script, or explicitly invoke Bash if it is installed:
copy "%MAESTRO_MAIN_REPO_PATH%\.env.local" . && npm install
Keep platform-specific logic in a checked-in script matching the target shell, such as `./scripts/setup.cmd` on Windows or `./scripts/setup.sh` on POSIX systems.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/git-worktrees.md` around lines 117 - 123, Update the Windows setup
guidance around the `MAESTRO_MAIN_REPO_PATH` command to reference a checked-in
`.cmd` or `.bat` script executable by `cmd.exe`, rather than
`./scripts/setup.sh`; keep the setup field as a one-liner and retain the
Windows-specific environment-variable syntax.

Comment on lines +78 to +93
/**
* Shell used to interpret the configured command. `cmd.exe /d /s /c` on Windows,
* the user's login shell (falling back to `/bin/sh`) everywhere else.
*/
export function resolveSetupShell(): { command: string; args: (script: string) => string[] } {
if (isWindows()) {
return {
command: process.env.ComSpec || 'cmd.exe',
args: (script) => ['/d', '/s', '/c', script],
};
}
return {
command: process.env.SHELL || '/bin/sh',
args: (script) => ['-c', script],
};
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -i WorktreeConfigModal
rg -n -A5 -B5 'setupScript' -g 'WorktreeConfigModal*'

Repository: RunMaestro/Maestro

Length of output: 204


🏁 Script executed:

#!/bin/bash
set -e

echo "== files =="
git ls-files | rg '(^|/)WorktreeConfigModal\.tsx$|worktree-setup-script\.ts$|worktree' | sed -n '1,120p'

echo
echo "== WorktreeConfigModal outline =="
ast-grep outline src/renderer/components/WorktreeConfigModal.tsx --view compact 2>/dev/null || true

echo
echo "== setupScript references in WorktreeConfigModal =="
rg -n -C 4 'setupScript|multiline|textarea|multi' src/renderer/components/WorktreeConfigModal.tsx

echo
echo "== worktree setup script relevant lines =="
sed -n '1,180p' src/main/utils/worktree-setup-script.ts

echo
echo "== imports and setupScript data model =="
rg -n -C 3 'setupScript|Worktree|worktreeSetup|setup-script' src -g '*.ts' -g '*.tsx' | sed -n '1,240p'

Repository: RunMaestro/Maestro

Length of output: 28826


🌐 Web query:

cmd.exe /c multi-line command newline behavior CreateProcess argv embedded newline

💡 Result:

The cmd.exe /c command processor does not support passing literal multi-line commands directly [1][2]. When cmd.exe /c is invoked, it treats the provided string as a single command line and strictly ignores or truncates any embedded newline characters [1]. Key technical constraints and behaviors: 1. CMD Parsing Logic: When using /c or /k, cmd.exe processes the remainder of the command line after the switch [3][4]. If this string contains newline characters, they are not interpreted as command separators; instead, the command line is terminated or broken at the newline, effectively causing the parser to ignore subsequent lines [1]. 2. CreateProcess argv Handling: CreateProcess accepts a command-line string (lpCommandLine) [5]. While the Windows API technically allows null characters within a string, cmd.exe itself is fundamentally designed around line-based processing [1]. Even if you successfully pass a string with an embedded newline character via the CreateProcess API, cmd.exe will truncate execution at the first newline it encounters [1]. 3. Workarounds for Multi-line Commands: - Use Command Separators: Multiple commands can be executed in one line by using the && or | operators [6][7]. - Use Temporary Batch Files: For complex scripts, write the commands to a temporary.bat or.cmd file and then invoke that file using cmd.exe /c [2]. - Leverage Escaping for Line Continuation: In some specific contexts, using the caret (^) character followed by a newline allows for visual multi-line formatting in batch files, but this is a pre-processing feature of the batch parser, not a mechanism to pass multi-line strings through the cmd /c argument [2]. - PowerShell Alternative: If you are attempting to run multi-line code, consider using powershell -Command or powershell -EncodedCommand, which support more robust handling of multi-line input when properly quoted or encoded [1][2].

Citations:


Handle multiline setup scripts before passing them to cmd.exe.

WorktreeConfigModal reads the raw setupScript from a multiline <textarea> and sends it to resolveSetupShell(). On Windows, cmd.exe /d /s /c "<script>" does not treat embedded newlines as command separators, so a valid multiline POSIX script can stop after the first line or fail. Use Windows command separators (&&/&) or a temp .bat/.cmd invocation instead of passing the raw multiline string inline.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/utils/worktree-setup-script.ts` around lines 78 - 93, Update
resolveSetupShell for Windows so multiline setup scripts are converted into
cmd.exe-compatible command separators or executed through a temporary .bat/.cmd
file instead of being passed raw inline. Preserve the existing ComSpec selection
and /d /s /c invocation behavior for single-line scripts and keep non-Windows
shell handling unchanged.

Comment on lines +68 to +100
try {
const result = await window.maestro.git.worktreeRunSetup(
script,
{ worktreePath, branchName, mainRepoPath, baseBranch },
sshRemoteId
);

if (!result.ran) return false;

if (!result.success) {
notifyToast({
type: 'error',
title: 'Worktree Setup Script Failed',
message: result.error || 'Setup script exited with an error',
});
return false;
}

notifyToast({
type: 'success',
title: 'Worktree Setup Complete',
message: `Setup script finished for ${branchName}`,
});
return true;
} catch (err) {
notifyToast({
type: 'error',
title: 'Worktree Setup Script Failed',
message: err instanceof Error ? err.message : String(err),
});
return false;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Report the swallowed IPC exception to Sentry.

The catch block here intentionally swallows the worktreeRunSetup IPC failure (shows a toast, returns false) but never calls captureException. Per the coding guideline for .ts/.tsx files, intentional catches should still go through the Sentry reporting utilities — otherwise a regressed IPC channel or main-process crash here would be invisible in Sentry. Note the same PR already does this correctly elsewhere (useWorktreeManager.ts's createPR, which calls captureException for its own "nice-to-have" git.log failure).

🩹 Proposed fix
+import { captureException } from '../services/sentry'; // adjust to the actual Sentry utility import path
...
 	} catch (err) {
+		captureException(err, { extra: { worktreePath, branchName, mainRepoPath } });
 		notifyToast({
 			type: 'error',
 			title: 'Worktree Setup Script Failed',
 			message: err instanceof Error ? err.message : String(err),
 		});
 		return false;
 	}
📝 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
try {
const result = await window.maestro.git.worktreeRunSetup(
script,
{ worktreePath, branchName, mainRepoPath, baseBranch },
sshRemoteId
);
if (!result.ran) return false;
if (!result.success) {
notifyToast({
type: 'error',
title: 'Worktree Setup Script Failed',
message: result.error || 'Setup script exited with an error',
});
return false;
}
notifyToast({
type: 'success',
title: 'Worktree Setup Complete',
message: `Setup script finished for ${branchName}`,
});
return true;
} catch (err) {
notifyToast({
type: 'error',
title: 'Worktree Setup Script Failed',
message: err instanceof Error ? err.message : String(err),
});
return false;
}
}
try {
const result = await window.maestro.git.worktreeRunSetup(
script,
{ worktreePath, branchName, mainRepoPath, baseBranch },
sshRemoteId
);
if (!result.ran) return false;
if (!result.success) {
notifyToast({
type: 'error',
title: 'Worktree Setup Script Failed',
message: result.error || 'Setup script exited with an error',
});
return false;
}
notifyToast({
type: 'success',
title: 'Worktree Setup Complete',
message: `Setup script finished for ${branchName}`,
});
return true;
} catch (err) {
captureException(err, { extra: { worktreePath, branchName, mainRepoPath } });
notifyToast({
type: 'error',
title: 'Worktree Setup Script Failed',
message: err instanceof Error ? err.message : String(err),
});
return false;
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/utils/worktreeSetupScript.ts` around lines 68 - 100, Report the
caught worktreeRunSetup IPC exception to Sentry before showing the error toast
and returning false. Update the catch block in the worktree setup flow to call
the existing captureException utility with err, following the pattern used by
createPR in useWorktreeManager.ts, while preserving the current user-facing
error handling.

Source: Path instructions

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.

[feature] new worktree creation setup script

2 participants