Skip to content

Commit 10311f6

Browse files
centdixclaude
andauthored
feat: enforce 40-char max on auto-generated branch names (#108)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 64a877a commit 10311f6

2 files changed

Lines changed: 35 additions & 4 deletions

File tree

backend/src/__tests__/auto-name-service.test.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ describe("AutoNameService", () => {
2727
"--system-prompt", "Generate a branch name",
2828
"--output-format", "text",
2929
"--no-session-persistence",
30-
"Task description:\nFix the login flow",
30+
"Here is the task description: Fix the login flow. You MUST return the branch name only, no other text or comments. Be fast, make it simple, and concise.",
3131
]);
3232
});
3333

@@ -72,7 +72,7 @@ describe("AutoNameService", () => {
7272
"-c", 'developer_instructions="Generate a branch name"',
7373
"exec",
7474
"--ephemeral",
75-
"Task description:\nImprove search ranking",
75+
"Here is the task description: Improve search ranking. You MUST return the branch name only, no other text or comments. Be fast, make it simple, and concise.",
7676
]);
7777
});
7878

@@ -151,6 +151,33 @@ describe("AutoNameService", () => {
151151
).rejects.toThrow("claude returned empty output");
152152
});
153153

154+
it("truncates branch names longer than 40 characters", async () => {
155+
const { spawnImpl } = fakeSpawn("this-is-a-very-long-branch-name-that-exceeds-the-forty-character-limit");
156+
const service = new AutoNameService({ spawnImpl });
157+
158+
const branch = await service.generateBranchName(
159+
{ provider: "claude" },
160+
"A very long task description",
161+
);
162+
163+
expect(branch.length).toBeLessThanOrEqual(40);
164+
expect(branch).toBe("this-is-a-very-long-branch-name-that-exc");
165+
});
166+
167+
it("removes trailing hyphens after truncation", async () => {
168+
// 40th char lands right after a hyphen: "a]b-c" → truncate at 40 → trailing hyphen
169+
const { spawnImpl } = fakeSpawn("add-feature-to-handle-user-authentication-flow");
170+
const service = new AutoNameService({ spawnImpl });
171+
172+
const branch = await service.generateBranchName(
173+
{ provider: "claude" },
174+
"Some task",
175+
);
176+
177+
expect(branch.length).toBeLessThanOrEqual(40);
178+
expect(branch).not.toMatch(/-$/);
179+
});
180+
154181
it("escapes special characters in system prompt for codex TOML config", async () => {
155182
const { calls, spawnImpl } = fakeSpawn("fix-bug");
156183
const service = new AutoNameService({ spawnImpl });

backend/src/services/auto-name-service.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ interface SpawnResult {
99

1010
type SpawnLike = (args: string[]) => Promise<SpawnResult>;
1111

12+
const MAX_BRANCH_LENGTH = 40;
13+
1214
const DEFAULT_SYSTEM_PROMPT = [
1315
"Generate a concise git branch name from the task description.",
1416
"Return only the branch name.",
1517
"Use lowercase kebab-case.",
18+
`Maximum ${MAX_BRANCH_LENGTH} characters.`,
1619
"Do not include quotes, code fences, or prefixes like feature/ or fix/.",
1720
].join(" ");
1821

@@ -27,6 +30,7 @@ function normalizeGeneratedBranchName(raw: string): string {
2730
branch = branch.replace(/[/.]+/g, "-");
2831
branch = branch.replace(/-+/g, "-");
2932
branch = branch.replace(/^-+|-+$/g, "");
33+
branch = branch.slice(0, MAX_BRANCH_LENGTH).replace(/-+$/, "");
3034

3135
if (!branch) {
3236
throw new Error("Auto-name model returned an empty branch name");
@@ -65,7 +69,7 @@ function buildClaudeArgs(model: string | undefined, systemPrompt: string, prompt
6569
if (model) {
6670
args.push("--model", model);
6771
}
68-
args.push(`Here is the task description: ${prompt}. You MUST return the branch name only, no other text or comments.`);
72+
args.push(prompt);
6973
return args;
7074
}
7175

@@ -87,7 +91,7 @@ function buildCodexArgs(model: string | undefined, systemPrompt: string, prompt:
8791
if (model) {
8892
args.push("-m", model);
8993
}
90-
args.push(`Here is the task description: ${prompt}. You MUST return the branch name only, no other text or comments.`);
94+
args.push(prompt);
9195
return args;
9296
}
9397

0 commit comments

Comments
 (0)