Skip to content

Commit 35210c2

Browse files
committed
feat(prompts): add configurable commit message styles with custom template support
1 parent d01e12e commit 35210c2

8 files changed

Lines changed: 390 additions & 64 deletions

File tree

‎README.md‎

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ You're already investing in Claude Code – whether it's Pro, Max ×5, or Max ×
1616

1717
- **One-click commit message generation**: The sparkle button ✨ you know and love, right in VS Code's Source Control panel
1818
- **Powered by your Claude CLI**: Uses your existing Claude installation – no extra API keys or subscriptions needed
19-
- **Context-aware analysis**: Understands your git diff to generate meaningful, conventional commit messages
19+
- **Context-aware analysis**: Understands your git diff to generate meaningful commit messages
20+
- **Flexible commit styles**: Choose from conventional commits, prefix-only, simple descriptions, or create your own custom template
21+
- **Custom prompt templates**: Full control over AI prompts with `{diff}` and `{stats}` template variables
2022
- **Edit with feedback**: Not satisfied? Click "Edit with feedback" to refine the message with AI assistance
2123
- **Multi-line commit support**: Generate detailed commits with body and footer for complex changes
2224
- **Model selection**: Choose between Haiku (fast), Sonnet (balanced), or Opus (most capable)
@@ -77,6 +79,8 @@ This extension keeps it simple with optional settings:
7779
* `claudeCommit.keepCoAuthoredBy`: Keep Co-Authored-By signature in commit message (only works in Claude Code managed mode) – defaults to `false`
7880
* `claudeCommit.messageAutoCloseSeconds`: Auto-close timeout for success message in seconds (0 to disable) – defaults to `5`
7981
* `claudeCommit.privacyMode`: Restrict temporary prompt file permissions to owner-only on Linux/macOS – defaults to `false`
82+
* `claudeCommit.commitStyle`: Commit message style format (`conventional`, `prefix`, `default`, or `custom`) – defaults to `conventional`
83+
* `claudeCommit.customPromptTemplate`: Custom prompt template with `{diff}` and `{stats}` variables (only used when commitStyle is `custom`) – defaults to empty
8084

8185
## Configuration Examples
8286

@@ -177,6 +181,41 @@ Set to `0` to disable auto-close and keep the success message visible until manu
177181
```
178182
Restricts temporary prompt file permissions to owner-only (0600) on Linux/macOS. Windows ignores this setting.
179183

184+
### Commit message styles
185+
186+
#### Conventional Commits (default)
187+
```json
188+
{
189+
"claudeCommit.commitStyle": "conventional"
190+
}
191+
```
192+
Generates: `feat(auth): added user login`
193+
194+
#### Prefix only (without scope)
195+
```json
196+
{
197+
"claudeCommit.commitStyle": "prefix"
198+
}
199+
```
200+
Generates: `feat: added user login`
201+
202+
#### Simple description (no prefix)
203+
```json
204+
{
205+
"claudeCommit.commitStyle": "default"
206+
}
207+
```
208+
Generates: `added user login`
209+
210+
#### Custom prompt template
211+
```json
212+
{
213+
"claudeCommit.commitStyle": "custom",
214+
"claudeCommit.customPromptTemplate": "Generate a concise commit message following our team's style.\n\nChanges:\n{stats}\n\nDiff (first 6000 chars):\n{diff}\n\nFormat: <category>: <description>\nCategories: feature, bugfix, refactor, docs, test, chore\nReturn only the commit message."
215+
}
216+
```
217+
Use `{diff}` for git diff content (automatically limited to first 6000 characters) and `{stats}` for change statistics. This allows complete control over the prompt sent to Claude.
218+
180219
## Troubleshooting
181220

182221
### Claude CLI not found

‎package.json‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,31 @@
152152
"default": false,
153153
"markdownDescription": "Privacy mode: Restrict temporary prompt file permissions to owner-only (0600). When disabled, uses default permissions (0644). **Note: This option only takes effect on Linux/macOS. On Windows, file permissions are managed by the OS and this setting is ignored.**",
154154
"order": 11
155+
},
156+
"claudeCommit.commitStyle": {
157+
"type": "string",
158+
"enum": [
159+
"conventional",
160+
"prefix",
161+
"default",
162+
"custom"
163+
],
164+
"default": "conventional",
165+
"enumDescriptions": [
166+
"Conventional Commits with scope - feat(auth): added user login",
167+
"Type prefix only - feat: added user login",
168+
"Simple description - added user login",
169+
"Custom template using {diff} and {stats} variables"
170+
],
171+
"markdownDescription": "Commit message style format. Choose 'custom' to use your own prompt template.",
172+
"order": 12
173+
},
174+
"claudeCommit.customPromptTemplate": {
175+
"type": "string",
176+
"default": "",
177+
"markdownDescription": "Custom prompt template. Use `{diff}` for diff content and `{stats}` for change statistics. Only used when commitStyle is set to 'custom'. Example: `Generate a commit message for:\n\n{stats}\n\n{diff}`",
178+
"editPresentation": "multilineText",
179+
"order": 13
155180
}
156181
}
157182
}

‎src/generators/commit.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ export async function generateCommitMessage(
6464
}
6565

6666
const multiLine = config.get<boolean>("multiLineCommit", false);
67+
const commitStyle = config.get<string>("commitStyle", "conventional");
68+
const customTemplate = config.get<string>("customPromptTemplate", "");
6769

68-
const prompt = createGenerationPrompt(diff, stats, language, multiLine);
70+
const prompt = createGenerationPrompt(diff, stats, language, multiLine, commitStyle, customTemplate);
6971

7072
let commitMessage: string | undefined;
7173
let cliNotFound = false;

‎src/prompts/en.ts‎

Lines changed: 103 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,44 @@
11
export function getGenerationPrompt(
22
diff: string,
33
stats: string,
4-
multiLine: boolean
4+
multiLine: boolean,
5+
commitStyle: string = "conventional"
56
): string {
7+
const diffContent = diff.slice(0, 6000);
8+
9+
const styleInstructions = getStyleInstructions(commitStyle, multiLine);
10+
611
if (multiLine) {
7-
return `Analyze git changes and generate detailed commit message in conventional commits format.
12+
return `Analyze git changes and generate detailed commit message.
13+
14+
Change statistics:
15+
${stats}
16+
17+
Diff (first 6000 characters):
18+
${diffContent}
19+
20+
${styleInstructions}
21+
22+
Return ONLY the commit message in the specified format, no explanations.`;
23+
}
24+
25+
return `Analyze git changes and generate commit message.
826
927
Change statistics:
1028
${stats}
1129
1230
Diff (first 6000 characters):
13-
${diff.slice(0, 6000)}
31+
${diffContent}
1432
15-
RESPONSE FORMAT:
33+
${styleInstructions}
34+
35+
Return ONLY the commit message (one line), no explanations.`;
36+
}
37+
38+
function getStyleInstructions(style: string, multiLine: boolean): string {
39+
switch (style) {
40+
case "conventional":
41+
return multiLine ? `RESPONSE FORMAT:
1642
<type>(<scope>): <subject>
1743
1844
<body>
@@ -33,20 +59,7 @@ Implemented authentication via Google OAuth 2.0.
3359
Added token handling and refresh mechanism.
3460
Updated configuration to support new providers.
3561
36-
Closes #123
37-
38-
Return ONLY the commit message in the specified format, no explanations.`;
39-
}
40-
41-
return `Analyze git changes and generate commit message in conventional commits format.
42-
43-
Change statistics:
44-
${stats}
45-
46-
Diff (first 6000 characters):
47-
${diff.slice(0, 6000)}
48-
49-
STRICT RULES:
62+
Closes #123` : `STRICT RULES:
5063
- Format: <type>(<scope>): <subject>
5164
- Type: feat/fix/refactor/docs/style/test/chore/perf
5265
- Subject in PAST TENSE (what WAS DONE), max 50 characters, no period
@@ -58,9 +71,79 @@ Examples:
5871
feat(auth): added Google OAuth provider
5972
fix(api): fixed validation error in user endpoint
6073
refactor(store): optimized cart state management
61-
docs(readme): updated installation instructions
74+
docs(readme): updated installation instructions`;
6275

63-
Return ONLY the commit message (one line), no explanations.`;
76+
case "prefix":
77+
return multiLine ? `RESPONSE FORMAT:
78+
<type>: <subject>
79+
80+
<body>
81+
82+
<footer>
83+
84+
RULES:
85+
- Subject: PAST TENSE, max 50 characters, no period
86+
- Body: detailed description of changes (what and why)
87+
- Footer: Breaking changes, issue references
88+
- Type: feat/fix/refactor/docs/style/test/chore/perf
89+
- Use verbs: added, fixed, updated, removed, refactored
90+
- NO SCOPE in parentheses
91+
92+
Example:
93+
feat: added Google OAuth provider
94+
95+
Implemented authentication via Google OAuth 2.0.
96+
Added token handling and refresh mechanism.
97+
98+
Closes #123` : `STRICT RULES:
99+
- Format: <type>: <subject>
100+
- Type: feat/fix/refactor/docs/style/test/chore/perf
101+
- Subject in PAST TENSE (what WAS DONE), max 50 characters, no period
102+
- Use verbs like: added, fixed, updated, removed, refactored
103+
- NO SCOPE in parentheses
104+
105+
Examples:
106+
feat: added Google OAuth provider
107+
fix: fixed validation error in user endpoint
108+
refactor: optimized cart state management
109+
docs: updated installation instructions`;
110+
111+
case "default":
112+
return multiLine ? `RESPONSE FORMAT:
113+
<subject>
114+
115+
<body>
116+
117+
<footer>
118+
119+
RULES:
120+
- Subject: PAST TENSE, clear description, max 50 characters, no period
121+
- Body: detailed description of changes (what and why)
122+
- Footer: Breaking changes, issue references
123+
- Use verbs: added, fixed, updated, removed, refactored
124+
- NO TYPE prefix, NO SCOPE
125+
126+
Example:
127+
added Google OAuth provider
128+
129+
Implemented authentication via Google OAuth 2.0.
130+
Added token handling and refresh mechanism.
131+
132+
Closes #123` : `STRICT RULES:
133+
- Format: simple description without type/scope prefix
134+
- Subject in PAST TENSE (what WAS DONE), max 50 characters, no period
135+
- Use verbs like: added, fixed, updated, removed, refactored
136+
- NO TYPE prefix (feat/fix/etc), NO SCOPE
137+
138+
Examples:
139+
added Google OAuth provider
140+
fixed validation error in user endpoint
141+
optimized cart state management
142+
updated installation instructions`;
143+
144+
default:
145+
return getStyleInstructions("conventional", multiLine);
146+
}
64147
}
65148

66149
export function getManagedPrompt(keepCoAuthoredBy: boolean, multiline: boolean, diffSource: string, customPrompt: string): string {

‎src/prompts/generation.ts‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,19 @@ export function createGenerationPrompt(
99
diff: string,
1010
stats: string,
1111
lang: Language,
12-
multiLine = false
12+
multiLine = false,
13+
commitStyle = "conventional",
14+
customTemplate?: string
1315
): string {
16+
// If custom style and template provided, use it
17+
if (commitStyle === "custom" && customTemplate) {
18+
return customTemplate
19+
.replace(/\{diff\}/g, diff.slice(0, 6000))
20+
.replace(/\{stats\}/g, stats);
21+
}
22+
1423
const module = promptModules[lang];
15-
return module.getGenerationPrompt(diff, stats, multiLine);
24+
return module.getGenerationPrompt(diff, stats, multiLine, commitStyle);
1625
}
1726

1827
export function createManagedPrompt(lang: Language, keepCoAuthoredBy: boolean, multiline: boolean, diffSource: string, customPrompt: string): string {

0 commit comments

Comments
 (0)