Skip to content

feat(git): offer git init on create + auto-detect repo transitions#1027

Merged
pedramamini merged 3 commits into
RunMaestro:rcfrom
chr1syy:feat/ack-git
May 26, 2026
Merged

feat(git): offer git init on create + auto-detect repo transitions#1027
pedramamini merged 3 commits into
RunMaestro:rcfrom
chr1syy:feat/ack-git

Conversation

@chr1syy
Copy link
Copy Markdown
Contributor

@chr1syy chr1syy commented May 20, 2026

Summary

  • Adds an inline "Initialize as Git Repository" button to both the Onboarding Wizard (Directory Selection screen) and the New Agent modal so users can git init the working directory without leaving the create-agent flow.
  • Auto-detects when a session's working dir becomes a git repo after agent creation (git init from terminal, cloning into the dir, etc.). The useGitStatusPolling loop now re-checks non-git sessions and flips isGitRepo on transition, unlocking worktree creation and other git-gated features within one poll tick (~30–90s) — no restart required.
  • New SSH-aware git:init IPC handler routed through the existing execGit helper, so the offer works for both local and SSH-remote working directories.

Why

Today, if you create an agent on a non-git folder and later git init it, Maestro keeps session.isGitRepo === false until you restart the app, so "Create Worktree" never appears in the context menu or Quick Actions. This PR closes that gap and also surfaces an init offer at agent-create time so the user can opt in upfront.

Changes

  • Main: new git:init handler in src/main/ipc/handlers/git.ts (SSH-aware).
  • Preload / types: src/main/preload/git.ts, src/renderer/global.d.ts expose window.maestro.git.init().
  • Renderer service: gitService.init() in src/renderer/services/git.ts.
  • Polling: src/renderer/hooks/git/useGitStatusPolling.ts — new detectGitRepoTransitions() runs alongside the main poll for non-git sessions; on transition it calls updateSessionWith and warms gitBranches / gitTags.
  • Wizard: src/renderer/components/Wizard/screens/DirectorySelectionScreen.tsx — replaced the "you can initialize one later" copy with an inline button + error state.
  • New Agent modal: src/renderer/components/NewInstanceModal/NewInstanceModal.tsx — added debounced git.isRepo detection on the working-dir field and an offer panel when the directory isn't a repo. Gated on remotePathValidation.valid for SSH paths.
  • Tests: src/__tests__/main/ipc/handlers/git.test.ts — bumped registered-handler count to 27 and added 'git:init' to the expected channel list.

Test plan

  • Create a new agent (via the Wizard) on a non-git folder → "Initialize as Git Repository" button shown under "Regular Directory" → click → folder is now a repo, panel flips to "Git Repository Detected".
  • Create a new agent (via manual New Agent modal) on a non-git folder → offer panel appears under the working directory → click init → panel disappears.
  • Create an agent on a non-git folder, then run git init from a terminal in that folder → within ~30–90s the worktree action appears in the Quick Actions modal and session context menu without restarting Maestro.
  • Same flow but with an SSH remote selected: confirm init runs over SSH and the panel updates correctly.
  • Verify the offer does not appear when the directory is already a git repo.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Initialize a selected directory as a Git repository from the New Instance modal and Directory Selection wizard, with SSH-remote support and clear progress/error UI.
    • Exposed a Git "init" operation to the renderer API and added a renderer-side service method for invoking it.
    • App now detects when non-Git directories become Git repositories and refreshes refs/status automatically.
  • Tests

    • IPC handler tests updated to account for the added Git init handler.

Review Change Stack

…r creation

Two changes that remove the "restart Maestro" workaround when a working
directory becomes a git repo after agent creation:

1. New `git:init` IPC handler (SSH-aware via the existing execGit helper),
   exposed through the preload bridge, global.d.ts typing, and a
   `gitService.init()` wrapper. Surfaced as an inline "Initialize as
   Git Repository" button in the wizard's "Regular Directory" panel and
   under the working-directory field in NewInstanceModal (with debounced
   isRepo detection so the offer only shows when the directory exists
   and isn't already a repo).

2. `useGitStatusPolling` now re-checks non-git sessions on each poll tick
   via a new `detectGitRepoTransitions()` helper. When a session's
   working dir flips to a real repo, `isGitRepo` is updated through
   `updateSessionWith` and branches/tags are cached, so worktree
   creation and other git-gated features unlock without an app restart.

Tests updated: git handler registration count bumped to 27 and `'git:init'`
added to the expected channel list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

📝 Walkthrough

Walkthrough

Adds end-to-end git init: a new git:init IPC handler and preload API, a renderer service and UI to initialize non-git dirs, background detection for post-init transitions, a types update, and the test adjusted to expect the new handler via the expectedChannels array.

Changes

Git Repository Initialization

Layer / File(s) Summary
IPC Handler & Preload API
src/main/ipc/handlers/git.ts, src/main/preload/git.ts, src/__tests__/main/ipc/handlers/git.test.ts
New git:init IPC endpoint executes git init with SSH/remote working-directory support; preload exposes it as window.maestro.git.init; handler registration test updated to include 'git:init' and assert handlers.size === expectedChannels.length.
Type Definitions
src/renderer/global.d.ts
Adds MaestroAPI.git.init(cwd, sshRemoteId?, remoteCwd?) returning { success: boolean; error?: string }.
Service Layer
src/renderer/services/git.ts
Adds gitService.init that calls the preload API via IPC with error context and a failure default result.
Component UI Integration
src/renderer/components/NewInstanceModal/NewInstanceModal.tsx, src/renderer/components/Wizard/screens/DirectorySelectionScreen.tsx
Components track git repo status with debounced checks, show “Initialize as Git Repository” buttons for non-git dirs, handle init progress/errors, and announce success for accessibility.
Background Repository Transition Detection
src/renderer/hooks/git/useGitStatusPolling.ts
Adds detectGitRepoTransitions to re-check non-git sessions, fetch branches/tags on transition, update session state, and warm refs cache without blocking main polling flow.
sequenceDiagram
  participant Renderer as Renderer
  participant Preload as Preload
  participant Main as MainProcess
  participant GitExec as execGit
  Renderer->>Preload: git.init(cwd, sshRemoteId?, remoteCwd?)
  Preload->>Main: invoke 'git:init'
  Main->>GitExec: execGit(['init'], effectiveCwd)
  GitExec-->>Main: { exitCode, stderr }
  Main-->>Preload: { success, error? }
  Preload-->>Renderer: resolve { success, error? }
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • RunMaestro/Maestro#925: Related work that extends isGitRepo detection and warms gitRefsCacheTime when repositories are discovered.

🐰 I found a path, a directory bare,
I whispered "git init" into the air,
Buttons press, a repo is born,
Polling wakes at early morn,
Hops of joy — commits to share.

🚥 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 accurately describes the primary changes: adding a git init feature to the create flow and implementing runtime detection for repository transitions.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@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: 5

🧹 Nitpick comments (2)
src/__tests__/main/ipc/handlers/git.test.ts (1)

168-199: ⚡ Quick win

Derive handler-count assertion from expectedChannels to avoid drift.

Use expectedChannels.length instead of duplicating 27 in the assertion.

Suggested refactor
-		it('should register all 27 git handlers', () => {
+		it('should register all git handlers', () => {
 			const expectedChannels = [
 				'git:status',
 				'git:diff',
 				'git:isRepo',
 				'git:init',
@@
 				'git:removeWorktree',
 				'git:createGist',
 			];

-			expect(handlers.size).toBe(27);
+			expect(handlers.size).toBe(expectedChannels.length);
 			for (const channel of expectedChannels) {
 				expect(handlers.has(channel)).toBe(true);
 			}
 		});
🤖 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/__tests__/main/ipc/handlers/git.test.ts` around lines 168 - 199, Replace
the hard-coded numeric assertion with a derived one so it cannot drift: in the
test where you build expectedChannels and assert handlers.size, change the
assertion from expect(handlers.size).toBe(27) to
expect(handlers.size).toBe(expectedChannels.length); locate the assertion near
the expectedChannels array and update it to use expectedChannels.length
(reference symbols: expectedChannels and handlers.size).
src/renderer/hooks/git/useGitStatusPolling.ts (1)

180-209: ⚡ Quick win

Don't blanket-swallow transition errors here.

gitService.isRepo/getBranches/getTags already absorb IPC failures and return defaults, so this catch {} mostly hides unexpected bugs in the transition path itself. If you need per-session isolation, use Promise.allSettled or narrow the catch to the specific recoverable step and report anything else.

Based on learnings, gitService methods implemented via createIpcMethod swallow IPC failures internally and already trigger captureException.

🤖 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/git/useGitStatusPolling.ts` around lines 180 - 209, The
current per-session try/catch silently swallows all errors from the transition
path (sessions.map block), hiding unexpected bugs; change to use
Promise.allSettled over the sessions.map so each session is isolated and then
for each settled result: onFulfilled apply the existing logic (calling
gitService.isRepo/getBranches/getTags and updateSessionWith), and onRejected
call the global error reporter (e.g., captureException or processLogger.error)
with the thrown error and session.id so failures are visible; alternatively, if
you prefer narrower handling, limit the try/catch to just the recoverable
IPC-returning calls (gitService.isRepo/getBranches/getTags) and rethrow/log any
other unexpected exceptions instead of swallowing them.
🤖 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 `@src/main/ipc/handlers/git.ts`:
- Around line 165-168: If sshRemoteId is passed but
getSshRemoteById(sshRemoteId) returns undefined, do not fall back to running
execGit locally; instead fail fast and return/throw an error. Update the handler
logic around sshRemoteId/sshRemote (where sshRemote is set using
getSshRemoteById) to detect that sshRemoteId was provided yet sshRemote is falsy
and respond with a clear error (e.g., reject the IPC request or return an error
result) before calling execGit(['init'], ...). Ensure effectiveRemoteCwd remains
computed only when a valid sshRemote exists.

In `@src/renderer/components/NewInstanceModal/NewInstanceModal.tsx`:
- Around line 316-322: Replace direct IPC calls to window.maestro.git in
NewInstanceModal (e.g., window.maestro.git.isRepo and any
window.maestro.git.init usages around the same block) with the renderer wrapper
methods on gitService (gitService.isRepo and gitService.init) so IPC errors are
handled and reported consistently; keep the existing cancelled check and
setGitRepoStatus('is-repo'|'not-repo'|'unknown') behavior but call gitService
methods instead of window.maestro.git, and remove any local try/catch that was
suppressing errors so the gitService error-handling/captureException behavior is
relied upon.
- Around line 296-329: The debounced git repo detection useEffect (the block
that reads workingDir, isSshEnabled, remotePathValidation.valid,
effectiveSshRemoteId and calls window.maestro.git.isRepo) should reset the
repo-init state immediately when starting a new check: call
setGitRepoStatus('unknown') and setInitRepoError(null) before scheduling the
setTimeout so the UI doesn't show 'not-repo' during the 500ms debounce; keep the
existing cancelled flag/timeout cleanup and the try/catch that sets the final
status after the async isRepo call.

In `@src/renderer/components/Wizard/screens/DirectorySelectionScreen.tsx`:
- Around line 364-381: Replace the direct preload IPC call in handleInitRepo
with the renderer-side gitService wrapper: instead of calling
window.maestro.git.init(state.directoryPath, sshRemoteId) use
gitService.init(state.directoryPath, sshRemoteId) so IPC failures are handled
centrally; keep the surrounding logic (checking result.success, setting
setInitRepoError, setIsGitRepo, setAnnouncement, and logger usage) the same but
remove the need to manually handle IPC fallbacks because gitService.init already
returns the fallback result and captures exceptions.
- Around line 774-805: The "Initialize as Git Repository" button can run against
a stale path because validation is debounced; update the UI to wait for the
latest validation before allowing initialization by gating the button on a
validation-in-flight flag. Add or reuse a boolean like isValidatingDirectory
(set true at the start of the async/debounced validateDirectory call and false
when it completes) and include it in the button's disabled prop alongside
isInitializingRepo (i.e. disabled={isInitializingRepo ||
isValidatingDirectory}), and ensure handleInitRepo reads state.directoryPath
only after validation completes; also prevent showing initRepoError until
validation finishes if relevant.

---

Nitpick comments:
In `@src/__tests__/main/ipc/handlers/git.test.ts`:
- Around line 168-199: Replace the hard-coded numeric assertion with a derived
one so it cannot drift: in the test where you build expectedChannels and assert
handlers.size, change the assertion from expect(handlers.size).toBe(27) to
expect(handlers.size).toBe(expectedChannels.length); locate the assertion near
the expectedChannels array and update it to use expectedChannels.length
(reference symbols: expectedChannels and handlers.size).

In `@src/renderer/hooks/git/useGitStatusPolling.ts`:
- Around line 180-209: The current per-session try/catch silently swallows all
errors from the transition path (sessions.map block), hiding unexpected bugs;
change to use Promise.allSettled over the sessions.map so each session is
isolated and then for each settled result: onFulfilled apply the existing logic
(calling gitService.isRepo/getBranches/getTags and updateSessionWith), and
onRejected call the global error reporter (e.g., captureException or
processLogger.error) with the thrown error and session.id so failures are
visible; alternatively, if you prefer narrower handling, limit the try/catch to
just the recoverable IPC-returning calls (gitService.isRepo/getBranches/getTags)
and rethrow/log any other unexpected exceptions instead of swallowing them.
🪄 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

Run ID: 7ba1c9ec-e95e-4d02-b1af-297cb2c63033

📥 Commits

Reviewing files that changed from the base of the PR and between a2d61ed and 43a57a4.

📒 Files selected for processing (8)
  • src/__tests__/main/ipc/handlers/git.test.ts
  • src/main/ipc/handlers/git.ts
  • src/main/preload/git.ts
  • src/renderer/components/NewInstanceModal/NewInstanceModal.tsx
  • src/renderer/components/Wizard/screens/DirectorySelectionScreen.tsx
  • src/renderer/global.d.ts
  • src/renderer/hooks/git/useGitStatusPolling.ts
  • src/renderer/services/git.ts

Comment thread src/main/ipc/handlers/git.ts
Comment thread src/renderer/components/NewInstanceModal/NewInstanceModal.tsx
Comment thread src/renderer/components/NewInstanceModal/NewInstanceModal.tsx Outdated
Comment thread src/renderer/components/Wizard/screens/DirectorySelectionScreen.tsx Outdated
Comment thread src/renderer/components/Wizard/screens/DirectorySelectionScreen.tsx
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 20, 2026

Greptile Summary

This PR adds a "Initialize as Git Repository" button to both the Onboarding Wizard and the New Agent modal, and adds auto-detection of git init transitions in the existing polling hook so git-gated features (worktree creation, Quick Actions) unlock without an app restart.

  • git:init IPC handler (src/main/ipc/handlers/git.ts, preload, service, types): new SSH-aware handler that mirrors the existing git:isRepo pattern and returns a structured { success, error? } result.
  • detectGitRepoTransitions (useGitStatusPolling.ts): fire-and-forget per-tick check on non-git sessions; flips isGitRepo and warms branch/tag caches when a transition is detected.
  • UI offer panels (NewInstanceModal.tsx, DirectorySelectionScreen.tsx): debounced isRepo detection on the working-dir field with an inline init button and error state.

Confidence Score: 3/5

The IPC layer and polling logic are solid, but both UI entry points have a state management gap that renders misleading error messages from a prior directory's failed git init on a new directory's offer panel.

The main process handler, preload, service layer, and polling transition detection are all well-implemented. The two renderer components share the same flaw: initRepoError is not cleared when the user changes the working directory to a new non-empty path, so a previous failed-init error can surface for an unrelated directory. Both affected components are on the critical agent-creation paths, making the misleading state visible to users during a key workflow.

src/renderer/components/NewInstanceModal/NewInstanceModal.tsx and src/renderer/components/Wizard/screens/DirectorySelectionScreen.tsx — both need state resets when the working directory changes.

Important Files Changed

Filename Overview
src/main/ipc/handlers/git.ts New git:init IPC handler added; correctly mirrors the git:isRepo pattern with SSH-aware execGit and exit-code checking — no issues found.
src/main/preload/git.ts Preload exposes git.init consistent with existing git.isRepo shape; types and signature are correct.
src/renderer/global.d.ts Type declaration for init added to MaestroAPI.git; matches the preload and handler signatures exactly.
src/renderer/services/git.ts gitService.init wraps the IPC call through createIpcMethod with a safe defaultValue; consistent with all other service methods.
src/renderer/hooks/git/useGitStatusPolling.ts detectGitRepoTransitions correctly fire-and-forgets per-session checks and uses updateSessionWith idempotently; getBranches/getTags have safe defaultValue: [] so empty repos won't block the flip.
src/renderer/components/NewInstanceModal/NewInstanceModal.tsx Debounced isRepo detection and handleInitRepo are well-structured, but initRepoError and gitRepoStatus are not reset when workingDir changes to a new non-empty path, causing stale error messages to appear on the new directory's offer panel.
src/renderer/components/Wizard/screens/DirectorySelectionScreen.tsx handleInitRepo is correctly guarded and updates accessibility state on success, but validateDirectory never clears initRepoError, so a stale error from a prior failed init persists when the user navigates to a different non-repo directory.
src/tests/main/ipc/handlers/git.test.ts Handler count bumped to 27 and git:init added to the expected channel list; registration test is correct.

Sequence Diagram

sequenceDiagram
    participant UI as NewInstanceModal / Wizard
    participant Renderer as Renderer (gitService)
    participant IPC as IPC (git:init / git:isRepo)
    participant Git as git binary (local/SSH)

    UI->>Renderer: workingDir change (debounced 500ms)
    Renderer->>IPC: git:isRepo(cwd, sshRemoteId)
    IPC->>Git: git rev-parse --is-inside-work-tree
    Git-->>IPC: exitCode 0/128
    IPC-->>Renderer: true / false
    Renderer-->>UI: "setGitRepoStatus('is-repo'|'not-repo')"

    UI->>Renderer: handleInitRepo()
    Renderer->>IPC: git:init(cwd, sshRemoteId)
    IPC->>Git: git init
    Git-->>IPC: exitCode 0 / stderr
    IPC-->>Renderer: "{success, error?}"
    Renderer-->>UI: setGitRepoStatus('is-repo') OR setInitRepoError(msg)

    Note over Renderer: Poll tick (30-90s)
    Renderer->>IPC: detectGitRepoTransitions(nonGitSessions)
    IPC->>Git: git:isRepo per session
    Git-->>IPC: true (transitioned)
    IPC->>Git: git:branches + git:tags
    Git-->>IPC: branches[], tags[]
    IPC-->>Renderer: updateSessionWith(isGitRepo:true, branches, tags)
Loading

Comments Outside Diff (1)

  1. src/renderer/components/Wizard/screens/DirectorySelectionScreen.tsx, line 220-226 (link)

    P1 initRepoError is never cleared when the directory path changes. After a failed git init on one directory, if the user types or browses to a different non-repo directory, the old error is still shown inside the "Regular Directory" panel alongside the new init offer — misleading the user into thinking the new path also failed to initialize.

Reviews (1): Last reviewed commit: "feat(git): offer git init on agent creat..." | Re-trigger Greptile

Comment thread src/renderer/components/NewInstanceModal/NewInstanceModal.tsx
@pedramamini
Copy link
Copy Markdown
Collaborator

Thanks for the contribution, @chr1syy! 🎻 This is a nice quality-of-life improvement — the auto-detect of git init transitions without an app restart is especially welcome.

Both Greptile and CodeRabbit flagged a consistent set of issues, and a couple of them are worth addressing before we merge:

1. SSH remote must fail loudly (src/main/ipc/handlers/git.ts) — When sshRemoteId is provided but can't be resolved, sshRemote falls back to undefined and git init runs against the local directory. Per our SSH guidelines in CLAUDE.md, when the user explicitly opts into SSH we must fail loudly rather than silently run locally. Please throw/return an error when sshRemoteId is set but getSshRemoteById() returns nothing.

2. Stale initRepoError / gitRepoStatus across directory changes — Flagged by both bots (P1) in NewInstanceModal.tsx and DirectorySelectionScreen.tsx. After a failed git init on directory A, switching to directory B keeps showing A's error. Reset gitRepoStatus to 'unknown' and initRepoError to null at the start of the debounced check / on directory-path change.

3. Debounce race on the init buttondirectoryPath updates immediately while the repo check stays debounced (~500ms), so the "Initialize as Git Repository" CTA can fire against an unvalidated path. Please gate the button on a fresh validation (disable it while a check is in flight).

4. (Nice-to-have) Route through gitService — The components call window.maestro.git.isRepo/init directly, bypassing the gitService wrapper that centralizes error handling + Sentry reporting. Using gitService.isRepo() / gitService.init() keeps that contract consistent.

Items 1–3 are the blockers; #4 is a cleanup we'd appreciate but won't hold the PR on. Once those are in, ping me for another pass. Thanks again! 🙏

chr1syy added 2 commits May 23, 2026 10:05
- git.ts: reject IPC requests with an unresolvable sshRemoteId so we
  never silently fall back to running `git init` on the wrong local
  directory.
- NewInstanceModal: reset gitRepoStatus/initRepoError immediately when
  the working dir changes so the stale "Initialize as Git Repository"
  panel can't render (and run init) against an unvalidated path during
  the 500ms debounce; route both isRepo and init through gitService for
  centralized renderer-side error reporting.
- DirectorySelectionScreen: route init through gitService.init; flip
  isValidating true at the start of the 800ms debounce in handlePathChange
  so the (stale) git status panel is hidden during the debounce window,
  and add isValidating to the Init button's disabled gate as defense in
  depth.
- useGitStatusPolling: replace the blanket `try {} catch {}` with
  Promise.allSettled so per-session failures are isolated; report
  rejected promises to Sentry via captureException — gitService already
  swallows IPC errors, so anything that reaches here is a real bug.
- git.test.ts: derive the handler-count assertion from
  expectedChannels.length so it cannot drift when new handlers are added.
Copy link
Copy Markdown

@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 (1)
src/__tests__/main/ipc/handlers/git.test.ts (1)

168-199: ⚡ Quick win

Add targeted git:init behavior tests, not just registration.

This hunk verifies channel presence, but it doesn’t lock the new fail-fast contract (sshRemoteId unresolved must not execute local git init). Please add focused handler tests for success and invalid-remote behavior.

Suggested test additions
+	describe('git:init', () => {
+		it('should initialize a repository locally on success', async () => {
+			vi.mocked(execFile.execFileNoThrow).mockResolvedValue({
+				stdout: 'Initialized empty Git repository',
+				stderr: '',
+				exitCode: 0,
+			});
+
+			const handler = handlers.get('git:init');
+			const result = await handler!({} as any, '/test/repo');
+
+			expect(execFile.execFileNoThrow).toHaveBeenCalledWith('git', ['init'], '/test/repo');
+			expect(result).toEqual({ success: true });
+		});
+
+		it('should fail fast when sshRemoteId is provided but not found', async () => {
+			mockSettingsStore.get.mockReturnValue([]);
+
+			const handler = handlers.get('git:init');
+			const result = await handler!({} as any, '/test/repo', 'missing-remote');
+
+			expect(result).toEqual({
+				success: false,
+				error: 'SSH remote not found: missing-remote',
+			});
+			expect(execFile.execFileNoThrow).not.toHaveBeenCalled();
+		});
+	});
🤖 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/__tests__/main/ipc/handlers/git.test.ts` around lines 168 - 199, Add
focused tests for the 'git:init' handler (not just presence in handlers) to
enforce the fail-fast contract: write one test that invokes the registered
handler for 'git:init' with a valid sshRemoteId (or no sshRemoteId) and asserts
it runs the local git init flow and returns success, and another test that
invokes the handler with an unresolved/invalid sshRemoteId and asserts the local
git init command is NOT executed and the handler returns the expected
error/failure; locate the handler via the handlers Map used in the test suite
(handlers.get('git:init')) and stub/mock the git execution utilities (or the
function that performs init) to assert call/no-call and to simulate
success/failure responses.
🤖 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.

Nitpick comments:
In `@src/__tests__/main/ipc/handlers/git.test.ts`:
- Around line 168-199: Add focused tests for the 'git:init' handler (not just
presence in handlers) to enforce the fail-fast contract: write one test that
invokes the registered handler for 'git:init' with a valid sshRemoteId (or no
sshRemoteId) and asserts it runs the local git init flow and returns success,
and another test that invokes the handler with an unresolved/invalid sshRemoteId
and asserts the local git init command is NOT executed and the handler returns
the expected error/failure; locate the handler via the handlers Map used in the
test suite (handlers.get('git:init')) and stub/mock the git execution utilities
(or the function that performs init) to assert call/no-call and to simulate
success/failure responses.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0d2abd1e-e1d9-4099-9b0a-f8d2bcfcfe84

📥 Commits

Reviewing files that changed from the base of the PR and between 73594c3 and cc4c22f.

📒 Files selected for processing (5)
  • src/__tests__/main/ipc/handlers/git.test.ts
  • src/main/ipc/handlers/git.ts
  • src/renderer/components/NewInstanceModal/NewInstanceModal.tsx
  • src/renderer/components/Wizard/screens/DirectorySelectionScreen.tsx
  • src/renderer/hooks/git/useGitStatusPolling.ts

@chr1syy chr1syy added the ready to merge This PR is ready to merge label May 24, 2026
@pedramamini pedramamini merged commit d2f358d into RunMaestro:rc May 26, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready to merge This PR is ready to merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants