Conversation
📝 WalkthroughWalkthroughAdds multiple new CLI commands, services, an Ink-based PR UI, AI (Gemini) integration, GitHub integration, conflict-resolution utilities, configuration handling, and a pino logger to enable AI-assisted commits, PR browsing, and automated conflict suggestions. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant PRCmd as pr-command
participant Config as ConfigService
participant Git as GitService
participant GH as GitHubService
participant UI as PRList
participant Handler as SelectionHandler
User->>PRCmd: runPRCommand()
PRCmd->>Config: getConfig()
PRCmd->>Git: git.getRemotes(true)
PRCmd->>Git: validate origin fetch URL
PRCmd->>GH: init(repoUrl)
PRCmd->>UI: render(githubService, onSelect)
UI->>GH: listOpenPRs()
GH-->>UI: PR metadata
User->>UI: navigate & select
UI->>Handler: onSelect(selectedPR)
Handler-->>User: print PR details & unmount
sequenceDiagram
participant User
participant ResolveCmd as resolve-command
participant Config as ConfigService
participant Git as GitService
participant Resolver as ConflictResolver
participant AI as AIService
User->>ResolveCmd: runResolveCommand()
ResolveCmd->>Config: getConfig()
ResolveCmd->>Git: init/getStatus()
ResolveCmd->>AI: initClient()
ResolveCmd->>Resolver: new Resolver(aiService, gitService)
ResolveCmd->>Resolver: getConflicts()
Resolver->>Git: read conflicted files
Git-->>Resolver: file contents
loop per conflict
Resolver->>AI: suggestResolution(conflict)
AI-->>Resolver: resolvedContent
Resolver->>Git: applyResolution(atomically)
end
Resolver-->>ResolveCmd: results
ResolveCmd-->>User: report results
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ❌ 3❌ Failed checks (2 warnings, 1 inconclusive)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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. Comment |
|
@copilot
Error: src/services/AIService.ts(1,53): error TS2307: Cannot find module '@google/generative-ai' or its corresponding type declarations. Run actions/setup-node@v4 |
Co-authored-by: jaseel0 <225665919+jaseel0@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 9
🧹 Nitpick comments (2)
git-ai/src/cli/resolve-command.ts (1)
27-29: Avoid dumping full resolved file content to stdout by default.Line [28] can expose sensitive source in terminal scrollback/log collectors and can overwhelm output for large files. Consider a preview + explicit “show full” option.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@git-ai/src/cli/resolve-command.ts` around lines 27 - 29, The current console.log of the full resolved content (the lines printing suggestion and the header with conflict.file) can leak large or sensitive files; change this to print a short preview instead and require an explicit flag or confirmation to dump the full content. Replace the direct console.log(suggestion) usage with a preview (e.g., first N lines or chars) and add a CLI flag like --show-full (or an interactive prompt) that, when set, prints the entire suggestion; update the code paths around the console.log calls and the suggestion variable handling in resolve-command.ts so the header still references conflict.file but full output is gated behind the new flag/confirmation.git-ai/src/cli/pr-command.ts (1)
19-20: Add a publicgetRemotes()method toGitServiceinstead of bypassing encapsulation withas any.The code at lines 19–20 uses
(gitService as any).git.getRemotes(true)to access the privategitfield, which violates encapsulation and is fragile if internals change. GitService has no publicgetRemotes()wrapper method. Add one:// git-ai/src/core/GitService.ts public async getRemotes(verbose = true) { return await this.git.getRemotes(verbose); }Then replace the call at line 19 with
await gitService.getRemotes(true)to remove theas anycast.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@git-ai/src/cli/pr-command.ts` around lines 19 - 20, Add a public wrapper on the GitService class that exposes the underlying getRemotes call (e.g., add a public async getRemotes(verbose = true) method in GitService that returns this.git.getRemotes(verbose)), then update pr-command.ts to call await gitService.getRemotes(true) instead of using (gitService as any).git.getRemotes(true), removing the as any cast and preserving encapsulation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@git-ai/src/cli/pr-command.ts`:
- Around line 22-24: The error branch that checks for origin (the if block
referencing origin and origin.refs.fetch in pr-command.ts) logs an error but
returns normally; change it to return a non-zero exit status for CLI callers by
exiting with a failure code (e.g., call process.exit(1)) or by throwing an error
so the process terminates with a non-zero status; update the branch inside the
function that contains this check (the origin validation block) to use
process.exit(1) or rethrow instead of simply returning.
- Around line 30-39: The selection handler handleSelect currently calls
process.exit(0) which forces termination; instead obtain the Ink render instance
and call its unmount() so the app can perform a clean teardown and allow
waitUntilExit() to complete; update handleSelect to call
renderInstance.unmount() (and optionally trigger gitService.checkout(pr.branch)
before unmounting), then return so the process exits naturally after
waitUntilExit() finishes.
In `@git-ai/src/index.ts`:
- Around line 8-10: AIService is being instantiated at startup which can crash
CLI bootstrap if config is missing; instead, delay construction until the
ai-commit command runs. Remove the top-level new AIService(configService)
instantiation and instead create a local AIService instance inside the ai-commit
command action (and any other command handlers that currently new AIService,
e.g., the other spots referenced around the same block), passing the existing
ConfigService instance; ensure GitService and ConfigService remain created at
startup but AIService construction is deferred to inside the command handlers to
avoid early crashes.
In `@git-ai/src/services/AIService.ts`:
- Line 1: The project is missing the `@google/generative-ai` dependency referenced
by the import in AIService.ts (GoogleGenerativeAI, GenerativeModel); add
"@google/generative-ai" to the dependencies section of package.json, run the
package manager to update node_modules and the lockfile (npm install or yarn
install), and ensure package.json and the lockfile are committed so the build
can resolve the import.
- Around line 25-39: The constructor/initialization in AIService currently only
handles config.ai.provider === "gemini" and leaves this.model undefined for
other providers; update the initialization logic (referencing
config.ai.provider, this.genAI, this.model) to fail fast for unsupported
providers by adding an explicit else/default branch that throws a clear Error
including the unsupported provider value (e.g., `Unsupported AI provider:
${config.ai.provider}`), or alternatively implement the "openai" branch if
intended; ensure the thrown error occurs during service construction so later
calls cannot proceed with a null model.
In `@git-ai/src/services/ConfigService.ts`:
- Around line 56-59: The saveConfig method currently writes secrets to disk
without restrictive permissions; update saveConfig (and the write path that uses
ConfigService.CONFIG_PATH) to write the file with owner-only permissions (mode
0o600) by passing a mode option to fs.writeFileSync or by writing to a temp file
and fs.renameSync while setting file mode via fs.chmodSync/fchmod to 0o600 so
the resulting config file is readable/writable only by the owner; ensure you
still update this.config with the validated value after a successful write.
In `@git-ai/src/services/ConflictResolver.ts`:
- Around line 55-62: The suggestResolution method currently injects raw
conflict.content (and conflict.file) into the external model prompt which can
leak secrets/PII; implement a sanitization step (e.g., a new sanitizeContent or
redactSecrets function) inside suggestResolution to scan conflict.content for
common secret patterns (API keys, tokens, private key blocks, passwords, emails,
and other sensitive regexes) and either redact/mask them or replace large
sensitive blocks with placeholder text, and limit the payload by extracting only
the conflict hunk around git markers (<<<<<<<, =======, >>>>>>>) rather than the
entire file; ensure the sanitized content is what gets sent to the model and
keep ConflictDetail usage but pass sanitizedContent into the prompt.
- Around line 85-86: The current write path in ConflictResolver is not truly
atomic despite the comment; update the file-write routine in the
ConflictResolver class (the method that currently opens the target with O_TRUNC
and calls write()) to use the atomic-replace pattern: create a uniquely named
temporary file in the same directory (open with O_CREAT|O_EXCL|O_NOFOLLOW),
write the full contents to that temp file, call fsync on the temp file, close
it, call fsync on the directory, then rename(tempPath, targetPath) to atomically
replace the target; on any error ensure the temp file is unlinked and surface
the error. Ensure file mode/ownership are preserved or set appropriately before
rename.
In `@git-ai/src/services/GitHubService.ts`:
- Around line 45-46: The logger.error currently emits the raw remote URL (e.g.,
in GitHubService.ts where logger.error is called), which can leak credentials;
update the code that logs "Could not parse GitHub owner/repo from remote URL"
(and the similar call around lines 50–51) to sanitize the URL before logging by
parsing the URL (e.g., via the URL constructor or equivalent) and stripping any
username/password/userinfo component, then log the redacted/sanitized URL or
only the host/path instead of the raw value; keep the thrown Error message
unchanged but ensure all logger.error calls (the ones referencing the remote
URL) use the sanitized variable.
---
Nitpick comments:
In `@git-ai/src/cli/pr-command.ts`:
- Around line 19-20: Add a public wrapper on the GitService class that exposes
the underlying getRemotes call (e.g., add a public async getRemotes(verbose =
true) method in GitService that returns this.git.getRemotes(verbose)), then
update pr-command.ts to call await gitService.getRemotes(true) instead of using
(gitService as any).git.getRemotes(true), removing the as any cast and
preserving encapsulation.
In `@git-ai/src/cli/resolve-command.ts`:
- Around line 27-29: The current console.log of the full resolved content (the
lines printing suggestion and the header with conflict.file) can leak large or
sensitive files; change this to print a short preview instead and require an
explicit flag or confirmation to dump the full content. Replace the direct
console.log(suggestion) usage with a preview (e.g., first N lines or chars) and
add a CLI flag like --show-full (or an interactive prompt) that, when set,
prints the entire suggestion; update the code paths around the console.log calls
and the suggestion variable handling in resolve-command.ts so the header still
references conflict.file but full output is gated behind the new
flag/confirmation.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
git-ai/src/cli/pr-command.tsgit-ai/src/cli/resolve-command.tsgit-ai/src/core/GitService.tsgit-ai/src/index.tsgit-ai/src/services/AIService.tsgit-ai/src/services/ConfigService.tsgit-ai/src/services/ConflictResolver.tsgit-ai/src/services/GitHubService.tsgit-ai/src/ui/PRList.tsxgit-ai/src/utils/logger.tsgit-ai/tsconfig.json
|
@copilot In Verify each finding against the current code and only fix it if needed. In In Verify each finding against the current code and only fix it if needed. In Verify each finding against the current code and only fix it if needed. In Verify each finding against the current code and only fix it if needed. In Verify each finding against the current code and only fix it if needed. In Verify each finding against the current code and only fix it if needed. In Verify each finding against the current code and only fix it if needed. In |
Fix missing npm dependencies causing TypeScript lint failures
Co-authored-by: jaseel0 <225665919+jaseel0@users.noreply.github.com>
Fix missing dependencies, CLI exit behavior, and security issues
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
git-ai/src/services/ConflictResolver.ts (2)
28-49:⚠️ Potential issue | 🟠 MajorDo not fall back to full file content when no conflict markers exist.
Line [48] returns the entire file when markers are absent, which bypasses the hunk-only minimization and can leak unrelated sensitive data to the model.
♻️ Proposed fix
function extractConflictHunks(content: string): string { @@ - return hunks.length > 0 ? hunks.join('\n\n') : content; + return hunks.length > 0 ? hunks.join('\n\n') : ''; } @@ function sanitizeContent(content: string): string { let sanitized = extractConflictHunks(content); + if (!sanitized) { + return '[NO_CONFLICT_MARKERS_FOUND]'; + } for (const pattern of SECRET_PATTERNS) { sanitized = sanitized.replace(pattern, '[REDACTED]'); } return sanitized; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@git-ai/src/services/ConflictResolver.ts` around lines 28 - 49, The function extractConflictHunks currently returns the entire file when no conflict markers exist, which can leak unrelated data; update extractConflictHunks so it returns only the joined conflict hunks when any are found and returns an empty string (not the full content) when none are found, i.e., replace the final return branch to return hunks.length > 0 ? hunks.join('\n\n') : '' and ensure callers of extractConflictHunks (the code that calls this function) properly handle an empty string result.
145-176:⚠️ Potential issue | 🟠 MajorPreserve target file permissions instead of forcing
0o644.Line [176] always creates the temp file with
0o644. On replace, this can broaden sensitive file permissions or drop executable bits.♻️ Proposed fix
public async applyResolution(file: string, resolvedContent: string): Promise<void> { @@ + let targetMode = 0o644; try { const targetStats = await fs.lstat(targetPath); if (targetStats.isSymbolicLink()) { throw new Error(`Refusing to write to symlink: ${file}`); } + targetMode = targetStats.mode & 0o777; } catch (error: unknown) { @@ - const tempHandle = await fs.open(tempPath, fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY | fs.constants.O_NOFOLLOW, 0o644); + const tempHandle = await fs.open( + tempPath, + fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY | fs.constants.O_NOFOLLOW, + targetMode + );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@git-ai/src/services/ConflictResolver.ts` around lines 145 - 176, The temp file creation currently forces mode 0o644 when opening tempPath; instead reuse the existing target's permission bits if the target existed (use the earlier targetStats.mode & 0o777) and only fall back to a sensible umask-respecting default when targetStats is absent (e.g. (0o666 & ~process.umask())). Replace the hardcoded 0o644 in the fs.open call that creates tempPath with the computed mode variable so we preserve executable bits and avoid widening or dropping permissions.
🧹 Nitpick comments (1)
git-ai/src/cli/pr-command.ts (1)
17-25: Avoid bypassing encapsulation withas anyto access private members.Line 19 uses
(gitService as any).gitto access the privategitinstance, and Line 20 usesr: anywhich loses type safety. This pattern is fragile – ifGitServiceinternals change, this code silently breaks at runtime.Consider exposing a public method on
GitService:♻️ Suggested approach
Add a method to
GitService(ingit-ai/src/core/GitService.ts):public async getRemotes(): Promise<RemoteWithRefs[]> { return await this.git.getRemotes(true); }Then update
pr-command.ts:- const remotes = await (gitService as any).git.getRemotes(true); - const origin = remotes.find((r: any) => r.name === 'origin'); + const remotes = await gitService.getRemotes(); + const origin = remotes.find((r) => r.name === 'origin');🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@git-ai/src/cli/pr-command.ts` around lines 17 - 25, Replace the unsafe casts by adding a public accessor on GitService named getRemotes that returns the typed remotes (e.g., public async getRemotes(): Promise<RemoteWithRefs[]> { return this.git.getRemotes(true); }) and then in the PR command call gitService.getRemotes() (remove (gitService as any).git and r: any) and use the proper RemoteWithRefs type for remotes and origin when finding name === 'origin' so you keep type safety and avoid accessing private members directly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@git-ai/src/services/ConflictResolver.ts`:
- Around line 177-179: The current write via tempHandle.write(...) can perform a
short write and cause truncated resolved files; replace the manual write+sync
sequence in ConflictResolver (the tempHandle.write and tempHandle.sync usage)
with a full-file write that retries until the buffer is written (e.g., use
fs.promises.writeFile or the FileHandle.writeFile helper) to atomically write
the entire buffer to the temporary path, then close the handle and proceed to
the rename; ensure you still close/cleanup tempHandle (and preserve the existing
rename logic) so the temporary file is complete before renaming.
---
Duplicate comments:
In `@git-ai/src/services/ConflictResolver.ts`:
- Around line 28-49: The function extractConflictHunks currently returns the
entire file when no conflict markers exist, which can leak unrelated data;
update extractConflictHunks so it returns only the joined conflict hunks when
any are found and returns an empty string (not the full content) when none are
found, i.e., replace the final return branch to return hunks.length > 0 ?
hunks.join('\n\n') : '' and ensure callers of extractConflictHunks (the code
that calls this function) properly handle an empty string result.
- Around line 145-176: The temp file creation currently forces mode 0o644 when
opening tempPath; instead reuse the existing target's permission bits if the
target existed (use the earlier targetStats.mode & 0o777) and only fall back to
a sensible umask-respecting default when targetStats is absent (e.g. (0o666 &
~process.umask())). Replace the hardcoded 0o644 in the fs.open call that creates
tempPath with the computed mode variable so we preserve executable bits and
avoid widening or dropping permissions.
---
Nitpick comments:
In `@git-ai/src/cli/pr-command.ts`:
- Around line 17-25: Replace the unsafe casts by adding a public accessor on
GitService named getRemotes that returns the typed remotes (e.g., public async
getRemotes(): Promise<RemoteWithRefs[]> { return this.git.getRemotes(true); })
and then in the PR command call gitService.getRemotes() (remove (gitService as
any).git and r: any) and use the proper RemoteWithRefs type for remotes and
origin when finding name === 'origin' so you keep type safety and avoid
accessing private members directly.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
git-ai/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (7)
git-ai/package.jsongit-ai/src/cli/pr-command.tsgit-ai/src/index.tsgit-ai/src/services/AIService.tsgit-ai/src/services/ConfigService.tsgit-ai/src/services/ConflictResolver.tsgit-ai/src/services/GitHubService.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- git-ai/src/index.ts
- git-ai/src/services/ConfigService.ts
|
@copilot In Verify each finding against the current code and only fix it if needed. In |
…esolver Co-authored-by: jaseel0 <225665919+jaseel0@users.noreply.github.com>
fix: install @google/generative-ai and use writeFile for atomic writes in ConflictResolver
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@git-ai/src/services/ConflictResolver.ts`:
- Around line 173-185: The atomic write is using a hardcoded mode 0o644 which
strips execute bits; instead stat the existing target file (use fs.stat or
fs.lstat on the target path) to obtain its mode, mask it with 0o777 and use that
mode when creating/opening the temp file (replace the hardcoded 0o644 passed to
fs.open where tempHandle is created). If the target does not exist, fall back to
0o644; keep the existing error cleanup logic (closing/unlink) intact.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
git-ai/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (1)
git-ai/src/services/ConflictResolver.ts
|
@copilot In |
Co-authored-by: jaseel0 <225665919+jaseel0@users.noreply.github.com>
fix: preserve file permissions in ConflictResolver atomic write
There was a problem hiding this comment.
♻️ Duplicate comments (3)
git-ai/src/services/ConflictResolver.ts (3)
48-48:⚠️ Potential issue | 🟠 MajorAvoid full-file fallback when conflict markers are missing.
Line [48] returns the entire file when no marker block is found, which defeats the hunk-only data minimization path.
🔒 Proposed safer fallback
- return hunks.length > 0 ? hunks.join('\n\n') : content; + if (hunks.length > 0) { + return hunks.join('\n\n'); + } + return '';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@git-ai/src/services/ConflictResolver.ts` at line 48, The current return expression "hunks.length > 0 ? hunks.join('\n\n') : content" in ConflictResolver returns the whole file when no conflict markers are found; change it to avoid full-file fallback by returning an empty string (or null/undefined per project convention) instead of content when hunks.length === 0, and update any callers of the ConflictResolver method that expect a string (e.g., callers of the function containing this return) to handle the empty/no-hunk case appropriately (validate output before using, skip processing or fall back to the hunk-only minimization path).
173-200:⚠️ Potential issue | 🟠 MajorComplete crash-safe atomic replace with directory sync.
Lines [195]-[200] rename the temp file without syncing parent directory metadata. A crash window remains where data is written but rename metadata is not durable.
💾 Proposed durability fix
- // Atomically replace target with temp file - try { - await fs.rename(tempPath, targetPath); + // Atomically replace target with temp file and sync dir metadata + const dirHandle = await fs.open(targetParent, fs.constants.O_RDONLY); + try { + await dirHandle.sync(); + await fs.rename(tempPath, targetPath); + await dirHandle.sync(); } catch (error) { await fs.unlink(tempPath).catch(() => {}); throw error; + } finally { + await dirHandle.close().catch(() => {}); }#!/bin/bash set -euo pipefail FILE="git-ai/src/services/ConflictResolver.ts" echo "=== applyResolution write/rename block ===" cat -n "$FILE" | sed -n '170,210p' echo echo "=== sync/open/rename calls in this file ===" rg -n "fs\\.open\\(|\\.sync\\(|fs\\.rename\\(" "$FILE"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@git-ai/src/services/ConflictResolver.ts` around lines 173 - 200, The write/rename sequence is missing a parent-directory fsync, leaving a durability window; after successfully renaming tempPath to targetPath, open the parent directory (targetParent) with fs.open(..., fs.constants.O_DIRECTORY | fs.constants.O_RDONLY), call dirHandle.sync() (or fsync) to flush the rename metadata, then close the dir handle; ensure this happens in the same try that performs fs.rename and that you still clean up tempPath on errors (references: tempPath, targetParent, targetPath, tempHandle.sync(), fs.rename).
17-23:⚠️ Potential issue | 🟠 MajorExpand redaction coverage before sending content to the model.
Line [18] and Line [23] still allow common sensitive data classes through (notably emails and non-RSA private-key block variants).
🛡️ Proposed hardening
const SECRET_PATTERNS: RegExp[] = [ - /-----BEGIN\s+(?:RSA\s+)?PRIVATE KEY-----[\s\S]*?-----END\s+(?:RSA\s+)?PRIVATE KEY-----/gi, + /-----BEGIN\s+[A-Z ]*PRIVATE KEY-----[\s\S]*?-----END\s+[A-Z ]*PRIVATE KEY-----/g, /(?:api[_\s-]?key|apikey|secret|token|password|passwd|pwd|auth)['":\s=]+['"]?[A-Za-z0-9/+_\-]{16,}['"]?/gi, // Long base64-like strings that resemble encoded tokens (standalone, not part of identifiers) /(?<![A-Za-z0-9])([A-Za-z0-9+/]{40,}={0,2})(?![A-Za-z0-9])/g, /(?<![A-Za-z0-9_])[a-f0-9]{32,64}(?![A-Za-z0-9_])/gi, // hex strings (hashes/keys) + /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, // emails ];🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@git-ai/src/services/ConflictResolver.ts` around lines 17 - 23, SECRET_PATTERNS currently misses common sensitive classes (emails, SSH/PGP/non‑RSA private key block variants, and token/key formats like AWS access keys), so update the SECRET_PATTERNS array in ConflictResolver.ts to include additional regexes that match email addresses, SSH/PGP/private-key blocks (-----BEGIN [A-Z ]*PRIVATE KEY----- with various key names), AWS-style access keys (AKIA[0-9A-Z]{16}), and common token formats (shorter base64-like or dot-separated JWTs), keeping appropriate flags (g, i) and using word-boundary or lookaround anchors similar to existing entries; ensure these new patterns are applied wherever SECRET_PATTERNS is used before sending content to the model (e.g., in any redact/clean function) so redaction covers these classes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@git-ai/src/services/ConflictResolver.ts`:
- Line 48: The current return expression "hunks.length > 0 ? hunks.join('\n\n')
: content" in ConflictResolver returns the whole file when no conflict markers
are found; change it to avoid full-file fallback by returning an empty string
(or null/undefined per project convention) instead of content when hunks.length
=== 0, and update any callers of the ConflictResolver method that expect a
string (e.g., callers of the function containing this return) to handle the
empty/no-hunk case appropriately (validate output before using, skip processing
or fall back to the hunk-only minimization path).
- Around line 173-200: The write/rename sequence is missing a parent-directory
fsync, leaving a durability window; after successfully renaming tempPath to
targetPath, open the parent directory (targetParent) with fs.open(...,
fs.constants.O_DIRECTORY | fs.constants.O_RDONLY), call dirHandle.sync() (or
fsync) to flush the rename metadata, then close the dir handle; ensure this
happens in the same try that performs fs.rename and that you still clean up
tempPath on errors (references: tempPath, targetParent, targetPath,
tempHandle.sync(), fs.rename).
- Around line 17-23: SECRET_PATTERNS currently misses common sensitive classes
(emails, SSH/PGP/non‑RSA private key block variants, and token/key formats like
AWS access keys), so update the SECRET_PATTERNS array in ConflictResolver.ts to
include additional regexes that match email addresses, SSH/PGP/private-key
blocks (-----BEGIN [A-Z ]*PRIVATE KEY----- with various key names), AWS-style
access keys (AKIA[0-9A-Z]{16}), and common token formats (shorter base64-like or
dot-separated JWTs), keeping appropriate flags (g, i) and using word-boundary or
lookaround anchors similar to existing entries; ensure these new patterns are
applied wherever SECRET_PATTERNS is used before sending content to the model
(e.g., in any redact/clean function) so redaction covers these classes.
This pull request introduces a foundational set of features for an AI-powered Git CLI tool, focusing on AI-assisted commit message generation, merge conflict resolution, GitHub PR integration, and robust configuration management. The codebase is organized into modular services for Git, AI, configuration, GitHub, and conflict resolution, and includes an interactive terminal UI for PR selection. Below are the most important changes:
AI Integration and Commit Automation
AIServiceto generate conventional commit messages and analyze merge conflicts using Google Gemini, with robust error handling and prompt engineering. (git-ai/src/services/AIService.ts)ai-commitCLI command to stage changes, generate an AI commit message, and commit via the terminal. (git-ai/src/index.ts)Git and Conflict Resolution Services
GitServicefor core git operations (status, diff, commit, log, branch), abstractingsimple-gitfor use across commands. (git-ai/src/core/GitService.ts)ConflictResolverto detect conflicted files, use AI to suggest resolutions, and safely apply them with atomic writes and symlink protection. (git-ai/src/services/ConflictResolver.ts)git-ai/src/cli/resolve-command.ts)GitHub Pull Request Integration
GitHubServiceto fetch open PRs and merge them using the GitHub API, parsing repo info from git remotes and handling authentication. (git-ai/src/services/GitHubService.ts)PRList) for interactive PR selection, with keyboard navigation and selection callbacks. (git-ai/src/ui/PRList.tsx,git-ai/src/cli/pr-command.ts) [1] [2]Configuration and Logging
ConfigServicefor loading, validating (with Zod), and saving user config from~/.aigitrc, supporting AI, GitHub, git, and UI settings. (git-ai/src/services/ConfigService.ts)pinofor structured, colorized logging across all services. (git-ai/src/utils/logger.ts)Summary by CodeRabbit