Skip to content

Commit 0c136d6

Browse files
authored
Merge pull request #3 from yamork779/feat/claude_message_enhance
Feat/claude message enhance
2 parents 0059140 + 26e646f commit 0c136d6

10 files changed

Lines changed: 159 additions & 13 deletions

File tree

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
node_modules
22
.vscode-test/
3+
.vscode/
34
*.vsix
45
dist/
56
out/

‎package.json‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,18 @@
121121
],
122122
"description": "Which changes to use for generating commit messages",
123123
"order": 7
124+
},
125+
"claudeCommit.claudeCodeManaged": {
126+
"type": "boolean",
127+
"default": false,
128+
"markdownDescription": "Claude Code managed mode: Let Claude Code's haiku model generate commit messages with minimal intervention (only language hint provided). **Only works when preferredMethod is 'cli'**",
129+
"order": 8
130+
},
131+
"claudeCommit.keepCoAuthoredBy": {
132+
"type": "boolean",
133+
"default": false,
134+
"markdownDescription": "Keep Co-Authored-By signature in commit message. **Only works in Claude Code managed mode**",
135+
"order": 9
124136
}
125137
}
126138
}

‎src/cli/execution.ts‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,69 @@ export async function generateWithCLI(
109109
}
110110
}
111111

112+
export async function generateWithCLIManaged(
113+
prompt: string,
114+
repoPath: string,
115+
progressCallback: ProgressCallback | null = null
116+
): Promise<string> {
117+
const cliPath = await findClaudeCliPath();
118+
119+
if (!cliPath) {
120+
throw new Error("Claude CLI path not found");
121+
}
122+
123+
const escapedCliPath = cliPath.includes(" ") ? `"${cliPath}"` : cliPath;
124+
125+
const tmpDir = os.tmpdir();
126+
const promptFile = path.join(
127+
tmpDir,
128+
`claude-commit-prompt-${Date.now()}.txt`
129+
);
130+
131+
try {
132+
await fs.promises.writeFile(promptFile, prompt, "utf-8");
133+
134+
if (progressCallback) {
135+
progressCallback("Using haiku model (managed mode)...");
136+
}
137+
138+
const command =
139+
process.platform === "win32"
140+
? `type "${promptFile}" | ${escapedCliPath} -p --model haiku`
141+
: `cat "${promptFile}" | ${escapedCliPath} -p --model haiku`;
142+
143+
const { stdout, stderr } = await execAsync(command, {
144+
shell: process.platform === "win32" ? "cmd.exe" : "/bin/bash",
145+
maxBuffer: 10 * 1024 * 1024,
146+
timeout: 120000,
147+
cwd: repoPath,
148+
});
149+
150+
if (stderr && !stdout) {
151+
throw new Error(`CLI error output: ${stderr.trim()}`);
152+
}
153+
154+
return stdout.trim() || "chore: update code";
155+
} catch (error) {
156+
const err = error as NodeJS.ErrnoException & { killed?: boolean };
157+
if (err.killed) {
158+
throw new Error(
159+
"CLI process timed out after 2 minutes. Try a smaller diff or check your connection."
160+
);
161+
}
162+
if (err.code === "ENOENT") {
163+
throw new Error(`CLI executable not found at: ${cliPath}`);
164+
}
165+
throw error;
166+
} finally {
167+
try {
168+
await fs.promises.unlink(promptFile);
169+
} catch {
170+
// Ignore deletion errors
171+
}
172+
}
173+
}
174+
112175
export async function generateWithAPI(
113176
prompt: string,
114177
progressCallback: ProgressCallback | null = null

‎src/extension.ts‎

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,21 @@ export function activate(context: vscode.ExtensionContext): void {
2323

2424
const repo = git.repositories[0] as GitRepository;
2525

26-
if (
27-
repo.state.indexChanges.length === 0 &&
28-
repo.state.workingTreeChanges.length === 0
29-
) {
30-
vscode.window.showWarningMessage(
31-
"No changes to commit. Stage files first."
32-
);
33-
return;
26+
// Skip change check in Claude Code managed mode (Claude Code will detect changes itself)
27+
const config = vscode.workspace.getConfiguration("claudeCommit");
28+
const claudeCodeManaged = config.get<boolean>("claudeCodeManaged", false);
29+
const preferredMethod = config.get<string>("preferredMethod", "auto");
30+
31+
if (!(claudeCodeManaged && preferredMethod === "cli")) {
32+
if (
33+
repo.state.indexChanges.length === 0 &&
34+
repo.state.workingTreeChanges.length === 0
35+
) {
36+
vscode.window.showWarningMessage(
37+
"No changes to commit. Stage files first."
38+
);
39+
return;
40+
}
3441
}
3542

3643
let commitMessage: string | null = null;

‎src/generators/commit.ts‎

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,47 @@ import {
77
DiffSource,
88
} from "../types";
99
import { getDiff } from "../utils/git";
10-
import { createGenerationPrompt, createEditPrompt } from "../prompts/generation";
10+
import { createGenerationPrompt, createEditPrompt, createManagedPrompt } from "../prompts/generation";
1111
import {
1212
hasClaudeCodeCLI,
1313
promptForCliPath,
1414
} from "../cli/detection";
15-
import { generateWithCLI, generateWithAPI } from "../cli/execution";
15+
import { generateWithCLI, generateWithCLIManaged, generateWithAPI } from "../cli/execution";
1616

1717
export async function generateCommitMessage(
1818
repo: GitRepository,
1919
language: Language = "en",
2020
progressCallback: ProgressCallback | null = null
2121
): Promise<string> {
2222
const repoPath = repo.rootUri.fsPath;
23+
const config = vscode.workspace.getConfiguration("claudeCommit");
24+
25+
const preferredMethod = config.get<GenerationMethod>("preferredMethod", "auto");
26+
27+
// Claude Code managed mode: minimal prompt, let Claude Code handle everything
28+
// Only effective when preferredMethod is "cli"
29+
const claudeCodeManaged = config.get<boolean>("claudeCodeManaged", false);
30+
31+
if (claudeCodeManaged && preferredMethod === "cli") {
32+
if (progressCallback) {
33+
progressCallback("Claude Code managed mode...");
34+
}
35+
36+
if (!(await hasClaudeCodeCLI())) {
37+
throw new Error(
38+
"Claude Code managed mode requires Claude Code CLI. Please install it or disable managed mode."
39+
);
40+
}
41+
42+
const keepCoAuthoredBy = config.get<boolean>("keepCoAuthoredBy", false);
43+
const prompt = createManagedPrompt(language, keepCoAuthoredBy);
44+
return await generateWithCLIManaged(prompt, repoPath, progressCallback);
45+
}
2346

2447
if (progressCallback) {
2548
progressCallback("Getting git diff...");
2649
}
2750

28-
const config = vscode.workspace.getConfiguration("claudeCommit");
2951
const diffSource = config.get<DiffSource>("diffSource", "auto");
3052

3153
const { diff, stats } = await getDiff(repoPath, diffSource);
@@ -42,8 +64,6 @@ export async function generateCommitMessage(
4264

4365
const prompt = createGenerationPrompt(diff, stats, language, multiLine);
4466

45-
const preferredMethod = config.get<GenerationMethod>("preferredMethod", "auto");
46-
4767
let commitMessage: string | undefined;
4868
let cliNotFound = false;
4969

‎src/prompts/en.ts‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,18 @@ docs(readme): updated installation instructions
6363
Return ONLY the commit message (one line), no explanations.`;
6464
}
6565

66+
export function getManagedPrompt(keepCoAuthoredBy: boolean): string {
67+
let prompt = `Generate a git commit message for current changes, in English, output only the commit message, no other text.`;
68+
if (keepCoAuthoredBy) {
69+
prompt += `
70+
71+
Keep at the end of commit message:
72+
🤖 Generated with Claude Code
73+
Co-Authored-By: Claude <noreply@anthropic.com>`;
74+
}
75+
return prompt;
76+
}
77+
6678
export function getEditPrompt(
6779
currentMessage: string,
6880
userFeedback: string,

‎src/prompts/generation.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ export function createGenerationPrompt(
1515
return module.getGenerationPrompt(diff, stats, multiLine);
1616
}
1717

18+
export function createManagedPrompt(lang: Language, keepCoAuthoredBy: boolean): string {
19+
const module = promptModules[lang];
20+
return module.getManagedPrompt(keepCoAuthoredBy);
21+
}
22+
1823
export function createEditPrompt(
1924
currentMessage: string,
2025
userFeedback: string,

‎src/prompts/ua.ts‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,18 @@ docs(readme): оновлено інструкції встановлення
6363
Поверни ТІЛЬКИ commit message (один рядок), без пояснень.`;
6464
}
6565

66+
export function getManagedPrompt(keepCoAuthoredBy: boolean): string {
67+
let prompt = `Згенеруй git commit message для поточних змін, українською мовою, лише commit message, без іншого тексту.`;
68+
if (keepCoAuthoredBy) {
69+
prompt += `
70+
71+
В кінці commit message додай:
72+
🤖 Generated with Claude Code
73+
Co-Authored-By: Claude <noreply@anthropic.com>`;
74+
}
75+
return prompt;
76+
}
77+
6678
export function getEditPrompt(
6779
currentMessage: string,
6880
userFeedback: string,

‎src/prompts/zh.ts‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,18 @@ docs(readme): 更新了安装说明
6363
仅返回 commit message(一行),不要有任何解释。`;
6464
}
6565

66+
export function getManagedPrompt(keepCoAuthoredBy: boolean): string {
67+
let prompt = `为当前改动生成git commit message,使用中文,仅输出commit message内容,不要有其他多余输出。`;
68+
if (keepCoAuthoredBy) {
69+
prompt += `
70+
71+
commit message 末尾保留:
72+
🤖 Generated with Claude Code
73+
Co-Authored-By: Claude <noreply@anthropic.com>`;
74+
}
75+
return prompt;
76+
}
77+
6678
export function getEditPrompt(
6779
currentMessage: string,
6880
userFeedback: string,

‎src/types/index.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ export interface ClaudeCommitConfig {
2424
language: "en" | "ua" | "zh";
2525
multiLineCommit: boolean;
2626
diffSource: "staged" | "all" | "auto";
27+
claudeCodeManaged: boolean;
28+
keepCoAuthoredBy: boolean;
2729
}
2830

2931
export type ProgressCallback = (message: string) => void;

0 commit comments

Comments
 (0)