From 9ab85edf1ae920661dc46ff23284b070d074a5fb Mon Sep 17 00:00:00 2001 From: Neo Date: Tue, 10 Feb 2026 08:13:41 +0700 Subject: [PATCH 1/9] refactor(git): improve file staging for split commits --- src/extension.ts | 127 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 102 insertions(+), 25 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 292d8fb..526b7d3 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,4 +1,5 @@ import * as vscode from 'vscode'; +import * as path from 'path'; import { execFileSync } from 'child_process'; import { minimatch } from 'minimatch'; import { @@ -58,10 +59,23 @@ interface GitAPI { repositories: Repository[]; } +interface RepositoryState { + indexChanges: GitChange[]; + workingTreeChanges: GitChange[]; +} + +interface GitChange { + uri: vscode.Uri; + originalUri: vscode.Uri; + renameUri: vscode.Uri | undefined; + status: number; +} + interface Repository { inputBox: { value: string }; diff(staged: boolean): Promise; rootUri: vscode.Uri; + state: RepositoryState; } interface ExtensionConfig { @@ -338,6 +352,47 @@ function parseDiffSections(diff: string): Map { return sections; } +/** + * Get relative paths of all staged files from the VS Code Git API + */ +function getStagedRelativePaths(repo: Repository): string[] { + return repo.state.indexChanges.map(change => + path.relative(repo.rootUri.fsPath, change.uri.fsPath).replace(/\\/g, '/') + ); +} + +/** + * Match AI-suggested file paths against actual staged files. + * Handles exact match and case-insensitive match (for Windows). + */ +function resolveAiFilesToStaged( + aiFiles: string[], + stagedFiles: string[] +): { matched: string[]; unmatched: string[] } { + const matched: string[] = []; + const unmatched: string[] = []; + + for (const aiFile of aiFiles) { + const normalized = aiFile.replace(/\\/g, '/'); + + const exact = stagedFiles.find(f => f === normalized); + if (exact) { + matched.push(exact); + continue; + } + + const caseMatch = stagedFiles.find(f => f.toLowerCase() === normalized.toLowerCase()); + if (caseMatch) { + matched.push(caseMatch); + continue; + } + + unmatched.push(aiFile); + } + + return { matched, unmatched }; +} + /** * Filter diff to remove sensitive files based on exclude patterns */ @@ -368,16 +423,18 @@ function filterSensitiveDiff( } /** - * Unstage all files, then stage only the files for the selected commit + * Selectively unstage files not belonging to the selected commit. + * Uses VS Code Git API to read staged state, validates AI paths against it, + * then only unstages the complement (files NOT in the selected commit). */ async function stageFilesForCommit( - workspaceRoot: vscode.Uri, + repo: Repository, filesToStage: string[] ): Promise { - const cwd = workspaceRoot.fsPath; - logDebug('Staging files', { cwd, filesToStage }); + const cwd = repo.rootUri.fsPath; + logDebug('Smart staging files', { cwd, filesToStage }); - // Validate and filter paths to prevent path traversal attacks + // Validate paths to prevent path traversal from AI responses const validFiles = filesToStage.filter(f => { if (!isValidRelativePath(f)) { logDebug(`Rejected invalid file path: ${f}`); @@ -390,34 +447,54 @@ async function stageFilesForCommit( throw new Error('No valid file paths to stage'); } - logDebug('Valid files to stage', { validFiles }); + // Read currently staged files from VS Code Git API + const stagedFiles = getStagedRelativePaths(repo); + logDebug('Currently staged files (from Git API)', { stagedFiles }); - // Step 1: Unstage all currently staged files - try { - execFileSync('git', ['reset', 'HEAD'], { cwd, encoding: 'utf-8', stdio: 'pipe' }); - logDebug('Unstaged all files'); - } catch (err) { - logDebug('Failed to unstage files (may be initial commit)', err); + // Match AI-suggested files against actual staged files + const { matched, unmatched } = resolveAiFilesToStaged(validFiles, stagedFiles); + + if (unmatched.length > 0) { + logDebug('AI suggested files not found in staged changes', { unmatched }); } - // Step 2: Stage only the files for the selected commit - for (const relativePath of validFiles) { - try { - // Use execFileSync to prevent command injection from AI-generated paths - execFileSync('git', ['add', '--', relativePath], { cwd, encoding: 'utf-8', stdio: 'pipe' }); - logDebug(`Staged file: ${relativePath}`); - } catch (err) { - logDebug(`Failed to stage file: ${relativePath}`, err); - } + if (matched.length === 0) { + throw new Error('None of the suggested files match currently staged changes'); + } + + logDebug('Matched files to keep staged', { matched }); + + // Compute files to unstage (staged files NOT in the selected commit) + const matchedSet = new Set(matched); + const filesToUnstage = stagedFiles.filter(f => !matchedSet.has(f)); + + if (filesToUnstage.length === 0) { + logDebug('All staged files belong to selected commit, no unstaging needed'); + return; + } + + logDebug('Selectively unstaging files', { filesToUnstage }); + + // Selectively unstage only the files not in the selected commit + // (VS Code Git API does not expose an unstage method, so we use git reset) + try { + execFileSync('git', ['reset', 'HEAD', '--', ...filesToUnstage], { + cwd, + encoding: 'utf-8', + stdio: 'pipe' + }); + logDebug('Selectively unstaged files', { count: filesToUnstage.length }); + } catch (err) { + logDebug('Failed to selectively unstage files', err); + throw new Error('Failed to update staging area'); } } /** * Handle the split commit workflow: * 1. Show QuickPick for user to select one commit - * 2. Unstage all files - * 3. Stage only files for selected commit - * 4. Return the commit message, or undefined if cancelled + * 2. Selectively unstage files not in the selected commit + * 3. Return the commit message, or undefined if cancelled */ async function handleSplitCommit( repo: Repository, @@ -444,7 +521,7 @@ async function handleSplitCommit( cancellable: false }, async () => { - await stageFilesForCommit(repo.rootUri, selectedCommit.files); + await stageFilesForCommit(repo, selectedCommit.files); } ); From c3539571d0f719e79ed15bca0c2d024b25049b1e Mon Sep 17 00:00:00 2001 From: Neo Date: Tue, 10 Feb 2026 08:19:15 +0700 Subject: [PATCH 2/9] docs: remove rule about grouping related changes --- src/extension.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/extension.ts b/src/extension.ts index 526b7d3..0d6224c 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -23,7 +23,6 @@ const DEFAULT_SYSTEM_PROMPT = `You are a Git commit message generator. Analyze t 3. Scope: Infer from semantic context; use file paths as hints when unclear (e.g., src/auth/ → auth). Omit if no clear scope. 4. Description: imperative mood, lowercase, no period, keep under 72 characters for the first line 5. No emojis -6. Group related changes into a single commit when same type and scope ## Split Detection If the diff contains multiple unrelated changes (different features, fixes, or concerns), set suggest_split: true and provide separate commit messages. From cda2739ba570bfc54007aeb1af78594ad3b4359b Mon Sep 17 00:00:00 2001 From: Neo Date: Tue, 10 Feb 2026 10:39:50 +0700 Subject: [PATCH 3/9] docs: update split detection description in system prompt --- src/extension.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extension.ts b/src/extension.ts index 0d6224c..290de13 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -25,7 +25,7 @@ const DEFAULT_SYSTEM_PROMPT = `You are a Git commit message generator. Analyze t 5. No emojis ## Split Detection -If the diff contains multiple unrelated changes (different features, fixes, or concerns), set suggest_split: true and provide separate commit messages. +If the diff contains multiple unrelated changes (different features, fixes, or concerns, .. etc), set suggest_split: true and provide separate commit messages. ## Output JSON You MUST respond with valid JSON only, no other text: From 190f0f8367c21f0ddbd991981e9103b09e28dd37 Mon Sep 17 00:00:00 2001 From: Neo Date: Tue, 10 Feb 2026 10:59:54 +0700 Subject: [PATCH 4/9] feat(commit-assistant): add split commit workflow --- package.json | 4 + src/extension.ts | 262 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 243 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index ef540e2..67d6913 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,10 @@ "command": "claude-commit.generate", "title": "Generate Commit Message with AI", "icon": "$(wand)" + }, + { + "command": "claude-commit.nextSplitCommit", + "title": "Advance to Next Split Commit" } ], "menus": { diff --git a/src/extension.ts b/src/extension.ts index 290de13..f054c7a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -14,6 +14,17 @@ import { // Output channel for debug logging let outputChannel: vscode.OutputChannel; +// Split session state for step-by-step commit workflow +interface SplitSession { + repo: Repository; + commits: CommitSuggestion[]; + currentIndex: number; + statusBarItem: vscode.StatusBarItem; + commitListener: vscode.Disposable; +} + +let activeSplitSession: SplitSession | null = null; + // Default system prompt for commit message generation const DEFAULT_SYSTEM_PROMPT = `You are a Git commit message generator. Analyze the provided diff and generate commit messages following Conventional Commits specification. @@ -47,9 +58,15 @@ const DEFAULT_USER_PROMPT = 'Analyze this git diff and generate commit message(s * Extended QuickPickItem for commit suggestions */ interface CommitQuickPickItem extends vscode.QuickPickItem { - commit: CommitSuggestion; + commit?: CommitSuggestion; + isStageAll?: boolean; } +type SplitPickerResult = + | { mode: 'single'; commit: CommitSuggestion } + | { mode: 'all' } + | undefined; + interface GitExtension { getAPI(version: number): GitAPI; } @@ -75,6 +92,7 @@ interface Repository { diff(staged: boolean): Promise; rootUri: vscode.Uri; state: RepositoryState; + onDidCommit: vscode.Event; } interface ExtensionConfig { @@ -132,7 +150,15 @@ export function activate(context: vscode.ExtensionContext) { outputChannel = vscode.window.createOutputChannel('Claude Commit Assistant'); context.subscriptions.push(outputChannel); + const nextSplitCommand = vscode.commands.registerCommand('claude-commit.nextSplitCommit', () => { + advanceSplitSession(); + }); + context.subscriptions.push(nextSplitCommand); + const command = vscode.commands.registerCommand('claude-commit.generate', async () => { + // Cancel any active split session when re-generating + cancelSplitSession(); + const gitExt = vscode.extensions.getExtension('vscode.git'); if (!gitExt) { vscode.window.showErrorMessage('Git extension not found'); @@ -221,7 +247,7 @@ export function activate(context: vscode.ExtensionContext) { if (result.splitSuggested && result.commits.length > 1) { // Handle split commit flow - const selectedMessage = await handleSplitCommit(repo, result.commits); + const selectedMessage = await handleSplitCommit(repo, result.commits, context); if (selectedMessage) { repo.inputBox.value = selectedMessage; } @@ -266,27 +292,49 @@ function logDebug(message: string, data?: unknown): void { } /** - * Show a QuickPick dialog for split commit suggestions - * Returns the selected commit, or undefined if cancelled + * Show a QuickPick dialog for split commit suggestions. + * Returns the selected commit, 'all' mode for step-by-step, or undefined if cancelled. */ async function showSplitCommitPicker( commits: CommitSuggestion[] -): Promise { - const items: CommitQuickPickItem[] = commits.map((commit) => ({ +): Promise { + const stageAllItem: CommitQuickPickItem = { + label: `$(list-ordered) Stage all commits step by step`, + description: `(${commits.length} commits)`, + isStageAll: true + }; + + const separator: CommitQuickPickItem = { + label: '', + kind: vscode.QuickPickItemKind.Separator + }; + + const commitItems: CommitQuickPickItem[] = commits.map((commit) => ({ label: `$(git-commit) ${commit.message}`, description: `${commit.files.length} file${commit.files.length !== 1 ? 's' : ''}`, detail: commit.files.join(', '), commit: commit })); - const selected = await vscode.window.showQuickPick(items, { - title: 'Select a commit to stage', - placeHolder: 'Claude suggests splitting into multiple commits. Pick one to stage:', - matchOnDescription: true, - matchOnDetail: true - }); + const selected = await vscode.window.showQuickPick( + [stageAllItem, separator, ...commitItems], + { + title: 'Select a commit to stage', + placeHolder: 'Split into multiple commits. Pick one, or stage all step by step:', + matchOnDescription: true, + matchOnDetail: true + } + ); + + if (!selected) { + return undefined; + } + + if (selected.isStageAll) { + return { mode: 'all' }; + } - return selected?.commit; + return { mode: 'single', commit: selected.commit! }; } /** @@ -489,28 +537,194 @@ async function stageFilesForCommit( } } +/** + * Stage files by running `git add` for the given paths. + * Used during step-by-step split sessions (commits 2+) where files are unstaged. + */ +function stageFiles(repo: Repository, files: string[]): void { + const cwd = repo.rootUri.fsPath; + const validFiles = files.filter(f => { + if (!isValidRelativePath(f)) { + logDebug(`Rejected invalid file path: ${f}`); + return false; + } + return true; + }); + + if (validFiles.length === 0) { + throw new Error('No valid file paths to stage'); + } + + try { + execFileSync('git', ['add', '--', ...validFiles], { + cwd, + encoding: 'utf-8', + stdio: 'pipe' + }); + logDebug('Staged files', { files: validFiles }); + } catch (err) { + logDebug('Failed to stage files', err); + throw new Error('Failed to stage files'); + } +} + +/** + * Update the status bar item to show current split session progress. + */ +function updateSplitStatusBar(session: SplitSession): void { + const { commits, currentIndex, statusBarItem } = session; + const current = currentIndex + 1; + const total = commits.length; + + if (currentIndex < commits.length - 1) { + const nextMsg = commits[currentIndex + 1].message; + const truncated = nextMsg.length > 40 ? nextMsg.substring(0, 37) + '...' : nextMsg; + statusBarItem.text = `$(git-commit) Split ${current}/${total} | Next: ${truncated}`; + statusBarItem.tooltip = `Commit ${current} of ${total}. Click to advance to next commit.\nNext: ${nextMsg}`; + } else { + statusBarItem.text = `$(git-commit) Split ${current}/${total} (last)`; + statusBarItem.tooltip = `Last commit (${current} of ${total}). Commit to finish.`; + } +} + +/** + * Start a step-by-step split commit session. + * Stages the first commit and sets up auto-advance on commit. + */ +async function startSplitSession( + repo: Repository, + commits: CommitSuggestion[], + context: vscode.ExtensionContext +): Promise { + cancelSplitSession(); + + const statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100); + statusBarItem.command = 'claude-commit.nextSplitCommit'; + context.subscriptions.push(statusBarItem); + + const commitListener = repo.onDidCommit(() => { + advanceSplitSession(); + }); + context.subscriptions.push(commitListener); + + activeSplitSession = { + repo, + commits, + currentIndex: 0, + statusBarItem, + commitListener + }; + + // Stage first commit using selective unstage (same as single-pick flow) + await stageFilesForCommit(repo, commits[0].files); + repo.inputBox.value = commits[0].message; + + updateSplitStatusBar(activeSplitSession); + statusBarItem.show(); + + logDebug('Split session started', { totalCommits: commits.length }); +} + +/** + * Advance to the next commit in the split session. + * Called automatically on commit or manually via status bar click. + */ +function advanceSplitSession(): void { + if (!activeSplitSession) { + return; + } + + const session = activeSplitSession; + session.currentIndex++; + + if (session.currentIndex >= session.commits.length) { + // All commits done + cancelSplitSession(); + vscode.window.showInformationMessage('Split commits complete!'); + logDebug('Split session complete'); + return; + } + + const commit = session.commits[session.currentIndex]; + + // For commits 2+, files are unstaged (they were unstaged in step 1). + // Just stage the next batch directly. + try { + stageFiles(session.repo, commit.files); + } catch (err) { + const msg = err instanceof Error ? err.message : 'Unknown error'; + vscode.window.showErrorMessage(`Failed to stage files for next commit: ${msg}`); + cancelSplitSession(); + return; + } + + session.repo.inputBox.value = commit.message; + updateSplitStatusBar(session); + + logDebug('Advanced split session', { + index: session.currentIndex, + message: commit.message + }); +} + +/** + * Cancel and clean up any active split session. + */ +function cancelSplitSession(): void { + if (!activeSplitSession) { + return; + } + + activeSplitSession.statusBarItem.hide(); + activeSplitSession.statusBarItem.dispose(); + activeSplitSession.commitListener.dispose(); + activeSplitSession = null; + + logDebug('Split session cancelled/cleaned up'); +} + /** * Handle the split commit workflow: - * 1. Show QuickPick for user to select one commit - * 2. Selectively unstage files not in the selected commit + * 1. Show QuickPick for user to select one commit or stage all step by step + * 2. Selectively unstage/stage files as needed * 3. Return the commit message, or undefined if cancelled */ async function handleSplitCommit( repo: Repository, - commits: CommitSuggestion[] + commits: CommitSuggestion[], + context: vscode.ExtensionContext ): Promise { logDebug('Split suggested', { commitCount: commits.length }); - const selectedCommit = await showSplitCommitPicker(commits); + const result = await showSplitCommitPicker(commits); - if (!selectedCommit) { + if (!result) { logDebug('User cancelled split commit selection'); return undefined; } + if (result.mode === 'all') { + logDebug('User selected stage all step by step'); + + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: 'Staging files for first commit...', + cancellable: false + }, + async () => { + await startSplitSession(repo, commits, context); + } + ); + + // First commit message is already set by startSplitSession + return undefined; + } + + // Single commit mode logDebug('User selected commit', { - message: selectedCommit.message, - files: selectedCommit.files + message: result.commit.message, + files: result.commit.files }); await vscode.window.withProgress( @@ -520,11 +734,13 @@ async function handleSplitCommit( cancellable: false }, async () => { - await stageFilesForCommit(repo, selectedCommit.files); + await stageFilesForCommit(repo, result.commit.files); } ); - return selectedCommit.message; + return result.commit.message; } -export function deactivate() {} +export function deactivate() { + cancelSplitSession(); +} From e3c1d2c88f8abab22dfb12bf1e900c866f1b2f2c Mon Sep 17 00:00:00 2001 From: Neo Date: Tue, 10 Feb 2026 11:09:13 +0700 Subject: [PATCH 5/9] docs: update CLAUDE.md with split commit workflow details --- CLAUDE.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 332807e..4f58214 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -39,8 +39,9 @@ This is a VS Code extension that generates git commit messages using AI provider 6. Filters sensitive files based on exclude patterns 7. Calls `provider.generateCommitMessage()` with prompt + diff 8. Parses JSON response via Zod schemas -9. If split suggested: shows QuickPick, stages selected files -10. Inserts message into commit input box +9. If split suggested: shows QuickPick with "Stage all step by step" option + individual commits +10. Single pick: stages selected files, inserts message +11. Step-by-step: starts a split session that auto-advances through commits via `onDidCommit` **Providers:** - `ClaudeProvider` - Uses Claude Agent SDK, requires Claude Code CLI From c3e82544364beddae0bba430e708ae57b8c2af14 Mon Sep 17 00:00:00 2001 From: Neo Date: Tue, 10 Feb 2026 11:09:19 +0700 Subject: [PATCH 6/9] docs(readme): add split commits workflow explanation --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index d43b615..f97ff8e 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,18 @@ Then press F5 in VS Code to launch Extension Development Host. 3. Wait for AI to generate a commit message 4. Review and commit +### Split Commits + +When the AI detects unrelated changes, it suggests splitting into multiple commits. You can: + +- **Pick a single commit** to stage just that commit's files +- **Stage all step by step** to walk through each commit sequentially: + 1. The first commit's files are staged and its message is set + 2. A status bar item shows your progress (e.g., "Split 1/3 | Next: fix(api)...") + 3. After you commit, the next commit is automatically staged + 4. Click the status bar item to manually advance if needed + 5. Repeat until all commits are done + The extension generates conventional commit messages in the format: ``` type(scope): description @@ -57,6 +69,7 @@ To use VS Code Language Models instead of Claude: - **Multi-provider support**: Use Claude Code CLI or VS Code Language Models - **Model selection**: Choose between Haiku (fast), Sonnet, or Opus for Claude - **Split commit detection**: Suggests splitting unrelated changes into atomic commits +- **Step-by-step split commits**: Walk through all suggested commits sequentially with auto-advance - **Smart staging**: Auto-stages only relevant files for selected commit - **Sensitive file filtering**: Excludes .env, keys, and credentials from AI - **Customizable prompts**: Adjust system/user prompts for your team's conventions From 213992f3a4123a8b71e281cb0e281425ff3fe290 Mon Sep 17 00:00:00 2001 From: Neo Date: Tue, 10 Feb 2026 11:09:22 +0700 Subject: [PATCH 7/9] docs(feature-spec): update user stories and workflow for split commits --- documents/FEATURE_SPEC.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/documents/FEATURE_SPEC.md b/documents/FEATURE_SPEC.md index 91a6d00..8f3da42 100644 --- a/documents/FEATURE_SPEC.md +++ b/documents/FEATURE_SPEC.md @@ -61,6 +61,12 @@ This problem affects all developers using VS Code with Git, occurring multiple t - **As a developer**, I want the extension to automatically stage only the relevant files for my selected commit so that I don't have to manually unstage/stage files. +- **As a developer**, I want a "Stage all step by step" option that walks through each suggested commit sequentially so that I can commit all splits without re-running generation. + +- **As a developer**, I want the extension to auto-advance to the next commit after I commit so that the step-by-step flow is seamless. + +- **As a developer**, I want a status bar item showing my progress (e.g., "Split 1/3") so that I know where I am in the split workflow. + ### Configuration - **As a developer**, I want to customize the system prompt so that I can adjust the style of generated messages to my team's conventions. @@ -111,6 +117,7 @@ This problem affects all developers using VS Code with Git, occurring multiple t | Cross-platform support | Works on Windows, macOS, and Linux | **Done** | | Split commit detection | When diff contains unrelated changes, suggest splitting into multiple commits | **Done** | | Smart staging workflow | QuickPick UI to select a commit; auto-stage only relevant files | **Done** | +| Step-by-step split commits | "Stage all step by step" option walks through each commit sequentially with auto-advance | **Done** | ### Must-Have (P0) - **v1.1.0 Multi-Provider** @@ -207,8 +214,9 @@ This problem affects all developers using VS Code with Git, occurring multiple t -> [Build prompt with system instructions + diff] -> [Call provider.generateCommitMessage()] -> [Parse JSON response via Zod schemas] - -> [If split suggested: show QuickPick -> stage selected files] - -> [Insert message into repo.inputBox.value] + -> [If split suggested: show QuickPick with "Stage all step by step" + individual commits] + -> [Single pick: stage selected files -> insert message] + -> [Stage all: start split session -> auto-advance via onDidCommit] ``` ### File Structure From 0142783f0f9509ebdfd9b167cc65efd1f6767c63 Mon Sep 17 00:00:00 2001 From: Neo Date: Tue, 10 Feb 2026 11:09:24 +0700 Subject: [PATCH 8/9] docs(roadmap): mark step-by-step split commits as done --- documents/ROADMAP.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/documents/ROADMAP.md b/documents/ROADMAP.md index 63dc1af..274a72e 100644 --- a/documents/ROADMAP.md +++ b/documents/ROADMAP.md @@ -8,7 +8,7 @@ | Status | Count | |--------|-------| -| **Done** | 24 items | +| **Done** | 25 items | | **Now** | 0 items | | **Next** | 3 items | | **Later** | 4 items | @@ -63,6 +63,7 @@ Items shipped in previous releases. | **VS Code Language Model provider** | Add VS Code LM API as alternative AI backend; user can configure provider in settings | 1.1.0 | **Done** | | **Provider abstraction layer** | Create unified interface for AI providers to enable seamless switching | 1.1.0 | **Done** | | **Model selection** | Allow users to choose model (Claude: Haiku/Sonnet/Opus, VS Code LM: any available) | 1.1.0 | **Done** | +| **Step-by-step split commits** | "Stage all step by step" option to walk through each suggested commit sequentially with auto-advance on commit | 1.2.0 | **Done** | | **Configurable timeout** | User can adjust timeout for slow network conditions | 0.0.7 | **Done** | | **Configurable system prompt** | User can customize the system prompt for different conventions | 0.0.7 | **Done** | | **Configurable user prompt** | User can customize how diff is presented to Claude | 0.0.7 | **Done** | From 713f9a31a05682625ff647ff17c814931683d1c2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 10 Feb 2026 04:13:42 +0000 Subject: [PATCH 9/9] chore(release): 1.2.0 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c30ba34..2b4ab17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.2.0](https://github.com/neoz/vscode-commit-assistant/compare/v1.1.0...v1.2.0) (2026-02-10) + + +### Features + +* **commit-assistant:** add split commit workflow ([190f0f8](https://github.com/neoz/vscode-commit-assistant/commit/190f0f8367c21f0ddbd991981e9103b09e28dd37)) + ## [1.1.0](https://github.com/neoz/vscode-commit-assistant/compare/v1.0.0...v1.1.0) (2026-02-05) diff --git a/package-lock.json b/package-lock.json index 42852b9..bae1ebd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "claude-commit", - "version": "1.1.0", + "version": "1.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "claude-commit", - "version": "1.1.0", + "version": "1.2.0", "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.1.0", "minimatch": "^10.1.2", diff --git a/package.json b/package.json index 67d6913..864009a 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "publisher": "neoz", "displayName": "Claude Commit Message", "description": "Generate commit messages using Claude Code", - "version": "1.1.0", + "version": "1.2.0", "repository": { "type": "git", "url": "https://github.com/neoz/vscode-commit-assistant.git"