Skip to content
Merged
287 changes: 287 additions & 0 deletions Microsoft.PowerShell_profile.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,7 @@ Set-Alias -Name wrh -Value Write-Host
Set-Alias -Name cpwd -Value Set-PWDClipboard
Set-Alias -Name tree -Value Show-DirectoryTree
Set-Alias -Name gemini -Value Invoke-GeminiChat
Set-Alias -Name gcm -Value Invoke-SuggestCommitMessage

# Create aliases only if the original commands exist
if ($Global:OriginalPipPath -and (Test-Path $Global:OriginalPipPath)) {
Expand Down Expand Up @@ -1915,3 +1916,289 @@ Remember: Terminal users value SPEED and CLARITY over detailed explanations. Mak
Write-Host "" # Add a final blank line before exit message
Write-Host "Ending chat." -ForegroundColor Cyan
}

<#
.SYNOPSIS
Suggests a commit message using Gemini AI based on staged changes and commit history.

.DESCRIPTION
This function analyzes your git repository's staged changes, branch name, and commit history
to generate an appropriate commit message using Google Gemini AI. It checks if a git repository
exists and if there are staged changes before proceeding.

The generated message matches the formatting, language, and style of previous commits.

.PARAMETER CommitCount
Number of previous commits to analyze for style and context. Defaults to 100.

.PARAMETER Model
The Gemini model to use for generating the commit message. Defaults to 'gemini-2.5-flash'.

.PARAMETER Force
If specified, automatically commits with the suggested message without prompting for confirmation.

.PARAMETER AdditionalInstructions
Additional instructions to guide the commit message generation (text string).

.PARAMETER InstructionsFile
Path to a file containing additional instructions for commit message generation.

.PARAMETER ResetApiKey
Forces the function to ask for a new API key, replacing the stored one.

.EXAMPLE
Invoke-SuggestCommitMessage
# Generates a commit message based on staged changes and prompts for action

.EXAMPLE
Invoke-SuggestCommitMessage -CommitCount 50 -Model "gemini-2.5-flash"
# Uses the last 50 commits and specified model

.EXAMPLE
Invoke-SuggestCommitMessage -Force
# Automatically commits with the suggested message

.EXAMPLE
Invoke-SuggestCommitMessage -AdditionalInstructions "Use conventional commits format"
# Adds specific instructions for message generation

.EXAMPLE
gcm
# Uses the alias to suggest a commit message
#>
function Invoke-SuggestCommitMessage {
[CmdletBinding()]
param(
[int]$CommitCount = 100,

[string]$Model = "gemini-2.5-flash",

[switch]$Force,

[string]$AdditionalInstructions = "",

[string]$InstructionsFile = "",

[switch]$ResetApiKey
)

# --- Check if we're in a git repository ---
try {
$gitCheck = git rev-parse --is-inside-work-tree 2>&1
if ($LASTEXITCODE -ne 0) {
Write-Host "Error: Not in a git repository." -ForegroundColor Red
return
}
}
catch {
Write-Host "Error: Git is not available or not in a git repository." -ForegroundColor Red
return
}

# --- Check for staged changes ---
$stagedFiles = git diff --cached --name-only
if ([string]::IsNullOrWhiteSpace($stagedFiles)) {
Write-Host "Error: No staged changes found. Use 'git add' to stage files first." -ForegroundColor Yellow
return
}

Write-Host "Analyzing staged changes and commit history..." -ForegroundColor Cyan

# --- Get branch name ---
$branchName = git rev-parse --abbrev-ref HEAD 2>&1
if ($LASTEXITCODE -ne 0) {
$branchName = "unknown"
}

# --- Get commit history ---
$commitHistory = git --no-pager log --oneline -n $CommitCount 2>&1
if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($commitHistory)) {
$commitHistory = "No previous commits available (new repository)"
}

# --- Get staged diff ---
$stagedDiff = git diff --cached
if ([string]::IsNullOrWhiteSpace($stagedDiff)) {
Write-Host "Error: Unable to get staged diff." -ForegroundColor Red
return
}

# --- Load additional instructions from file if provided ---
$additionalInstructionsText = $AdditionalInstructions
if (-not [string]::IsNullOrWhiteSpace($InstructionsFile)) {
if (Test-Path $InstructionsFile) {
$fileContent = Get-Content -Path $InstructionsFile -Raw
$additionalInstructionsText = if ([string]::IsNullOrWhiteSpace($additionalInstructionsText)) {
$fileContent
} else {
"$additionalInstructionsText`n`n$fileContent"
}
}
else {
Write-Warning "Instructions file not found: $InstructionsFile"
}
}

# --- Get or Set API Key ---
$apiKey = $null

if ($ResetApiKey.IsPresent) {
Write-Host "Resetting API key..." -ForegroundColor Yellow
$apiKey = $null
}
else {
$apiKey = Get-SecureApiKey -KeyName "GeminiAPI"
}

if ([string]::IsNullOrEmpty($apiKey)) {
Write-Host "Google Gemini API key not found or reset requested." -ForegroundColor Yellow
Write-Host "Please enter your Google Gemini API key:" -ForegroundColor Cyan
$inputApiKey = Read-Host -AsSecureString

# Convert secure string to plain text for this session
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($inputApiKey)
$apiKey = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)

if ([string]::IsNullOrEmpty($apiKey)) {
Write-Error "API key cannot be empty."
return
}

# Store the API key securely
Set-SecureApiKey -ApiKey $apiKey -KeyName "GeminiAPI"
}

# --- Prepare the prompt for Gemini ---
$promptText = @"
You are a git commit message expert. Your task is to analyze the provided information and generate a concise, meaningful commit message.

CONTEXT:
- Branch: $branchName
- Staged files: $($stagedFiles.Count) file(s)
Comment thread
adrian-cancio marked this conversation as resolved.
Outdated

PREVIOUS COMMITS (last $CommitCount):
$commitHistory

STAGED CHANGES (diff):
$stagedDiff

INSTRUCTIONS:
1. Analyze the staged changes to understand what was modified
2. Review the previous commits to match their style, format, language, and length
3. Generate a commit message that:
- Accurately describes the changes
- Matches the language used in previous commits (English, Spanish, etc.)
- Follows the same formatting style as previous commits
- Is concise but descriptive
- Uses appropriate prefixes if the project uses them (feat:, fix:, docs:, etc.)

$(if (-not [string]::IsNullOrWhiteSpace($additionalInstructionsText)) { "ADDITIONAL INSTRUCTIONS:`n$additionalInstructionsText`n" } else { "" })
Please provide ONLY the commit message, without any explanations or additional text.
"@

# --- API Setup ---
$uri = "https://generativelanguage.googleapis.com/v1beta/models/$($Model):generateContent"

$headers = @{
"Content-Type" = "application/json"
"X-goog-api-key" = $apiKey
}

$body = @{
contents = @(
@{
role = "user"
parts = @(@{ text = $promptText })
}
)
} | ConvertTo-Json -Depth 10

# --- API Call ---
try {
Write-Host "Generating commit message with model '$Model'..." -ForegroundColor Cyan

$response = Invoke-RestMethod -Uri $uri -Method Post -Headers $headers -Body $body -ContentType "application/json"

if ($null -eq $response.candidates) {
Write-Error "The API did not return a valid response. The content may have been blocked."
return
}

$suggestedMessage = $response.candidates[0].content.parts[0].text.Trim()

# Remove any markdown code block markers if present
$suggestedMessage = $suggestedMessage -replace '^```.*\n', '' -replace '\n```$', ''
$suggestedMessage = $suggestedMessage.Trim()

}
catch {
Write-Error "An error occurred while contacting the Gemini API: $($_.Exception.Message)"
if ($_.Exception.Response) {
$errorBody = $_.Exception.Response.GetResponseStream() | ForEach-Object { (New-Object System.IO.StreamReader($_)).ReadToEnd() }
Write-Host "Error body: $errorBody" -ForegroundColor Red
}
return
}

# --- Display the suggested message ---
Write-Host "`n" -NoNewline
Write-Host "═══════════════════════════════════════════" -ForegroundColor Cyan
Write-Host "Suggested Commit Message:" -ForegroundColor Green
Write-Host "═══════════════════════════════════════════" -ForegroundColor Cyan
Write-Host $suggestedMessage -ForegroundColor White
Write-Host "═══════════════════════════════════════════" -ForegroundColor Cyan
Write-Host ""

# --- Handle user action ---
if ($Force.IsPresent) {
# Auto-commit without prompting
try {
git commit -m $suggestedMessage
if ($LASTEXITCODE -eq 0) {
Write-Host "✓ Changes committed successfully!" -ForegroundColor Green
}
else {
Write-Error "Failed to commit changes."
}
}
catch {
Write-Error "Error during commit: $($_.Exception.Message)"
}
}
else {
# Prompt for action
Write-Host "What would you like to do?" -ForegroundColor Yellow
Write-Host " [C] Commit with this message" -ForegroundColor White
Write-Host " [Any other key] Copy to clipboard" -ForegroundColor White
Write-Host ""

$action = Read-Host "Your choice"

if ($action -eq 'C' -or $action -eq 'c' -or $action -eq 'commit') {
Comment thread
adrian-cancio marked this conversation as resolved.
Outdated
try {
git commit -m $suggestedMessage
if ($LASTEXITCODE -eq 0) {
Write-Host "✓ Changes committed successfully!" -ForegroundColor Green
}
else {
Write-Error "Failed to commit changes."
}
}
catch {
Write-Error "Error during commit: $($_.Exception.Message)"
}
}
else {
# Copy to clipboard
try {
Set-Clipboard -Value $suggestedMessage
Write-Host "✓ Commit message copied to clipboard!" -ForegroundColor Green
}
catch {
Write-Warning "Failed to copy to clipboard. Here's the message to copy manually:"
Write-Host $suggestedMessage -ForegroundColor White
}
}
}
}
56 changes: 54 additions & 2 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ A powerful, cross-platform PowerShell profile that enhances your terminal experi

- 🎨 **Customizable Prompt**: 11 different color schemes including dynamic themes
- 🤖 **AI Integration**: Google Gemini chat with terminal-optimized responses
- 💬 **Smart Commit Messages**: AI-powered commit message suggestions based on staged changes
- 🧮 **Mathematical Functions**: Complete set of trigonometric and mathematical operations
- **Smart Pip Wrappers**: Intelligent warnings for global package installations
- 🐙 **GitHub Copilot**: Built-in command suggestions and explanations
- 🐍 **Smart Pip Wrappers**: Intelligent warnings for global package installations
- 🐙 **GitHub Copilot**: Built-in command suggestions and explanations
- 🔒 **Secure Storage**: Cross-platform encrypted API key management
- 📁 **Smart File Operations**: Directory trees with .gitignore support
- ⚙️ **JSON Configuration**: Persistent settings with easy customization
Expand Down Expand Up @@ -86,6 +87,15 @@ pip install package-name --global # Skips warning
# Start Gemini chat (English)
gemini "how to find large files in PowerShell"

# Suggest commit message based on staged changes
gcm # or Invoke-SuggestCommitMessage
# Analyzes staged changes and previous commits to generate a commit message

# Use with custom options
Invoke-SuggestCommitMessage -CommitCount 50 -Model "gemini-2.5-flash"
Invoke-SuggestCommitMessage -Force # Auto-commit without prompting
Invoke-SuggestCommitMessage -AdditionalInstructions "Use conventional commits format"

# GitHub Copilot suggestions
ghcs "compress a folder"

Expand Down Expand Up @@ -225,6 +235,46 @@ Show-DirectoryTree -Path "C:\Projects" -IncludeFiles -RespectGitIgnore
Get-ContentRecursiveIgnore -Path "C:\Projects" -UseMarkdownFence $true
```

### AI-Powered Git Commit Messages

The profile includes an intelligent commit message generator using Gemini AI:

```powershell
# Basic usage - analyzes staged changes and suggests a commit message
gcm
# or
Invoke-SuggestCommitMessage

# Customize the number of previous commits to analyze (default: 100)
Invoke-SuggestCommitMessage -CommitCount 50

# Use a specific Gemini model
Invoke-SuggestCommitMessage -Model "gemini-2.5-flash"

# Auto-commit without prompting for confirmation
Invoke-SuggestCommitMessage -Force

# Add specific instructions for the commit message
Invoke-SuggestCommitMessage -AdditionalInstructions "Use conventional commits format with emoji"

# Load instructions from a file
Invoke-SuggestCommitMessage -InstructionsFile "commit-guidelines.txt"
```

**Features:**
- 🔍 **Analyzes staged changes**: Examines git diff to understand modifications
- 📚 **Learns from history**: Reviews previous commits to match style and language
- 🌐 **Language detection**: Generates messages in the same language as your commit history
- 🎯 **Smart formatting**: Matches existing commit message patterns and conventions
- ⚡ **Quick workflow**: Choose to commit immediately or copy to clipboard
- 🎨 **Customizable**: Supports additional instructions and different AI models

**Workflow:**
1. Stage your changes: `git add .`
2. Run: `gcm`
3. Review the AI-generated commit message
4. Choose action: Press `C` to commit or any other key to copy to clipboard

## 🛠️ System Requirements

### Core Requirements
Expand Down Expand Up @@ -284,6 +334,7 @@ Get-ContentRecursiveIgnore -Path "C:\Projects" -UseMarkdownFence $true

### AI Integration Functions
- `Invoke-GeminiChat` (`gemini`) - Google Gemini AI chat
- `Invoke-SuggestCommitMessage` (`gcm`) - AI-powered commit message suggestions
- `Format-GeminiText` - Process Gemini formatting commands
- `Test-PowerShellCodeRisk` - Analyze code for security risks
- `Invoke-SafePowerShellCode` - Execute code with safety checks
Expand All @@ -301,6 +352,7 @@ Get-ContentRecursiveIgnore -Path "C:\Projects" -UseMarkdownFence $true
| `cpwd` | `Set-PWDClipboard` | Copy working directory |
| `tree` | `Show-DirectoryTree` | Directory tree display |
| `gemini` | `Invoke-GeminiChat` | AI chat |
| `gcm` | `Invoke-SuggestCommitMessage` | AI commit message suggestions |
| `wrh` | `Write-Host` | Write to host |

## 🤝 Contributing
Expand Down