fix(vscode): sanitize custom worktree names into valid git branch names (#6246)

* fix(vscode): sanitize custom worktree names into valid git branch names

* chore: revert unintended package.json reordering
This commit is contained in:
Marius
2026-02-24 14:30:03 +00:00
committed by GitHub
parent 8acb463b2e
commit e140802ff2
3 changed files with 59 additions and 7 deletions
@@ -10,7 +10,7 @@ import * as path from "path"
import * as fs from "fs"
import * as cp from "child_process"
import simpleGit, { type SimpleGit } from "simple-git"
import { generateBranchName } from "./branch-name"
import { generateBranchName, sanitizeBranchName } from "./branch-name"
import {
parsePRUrl,
localBranchName,
@@ -91,7 +91,8 @@ export class WorktreeManager {
}
}
let branch = params.existingBranch ?? params.branchName ?? generateBranchName(params.prompt || "agent-task")
const sanitized = params.branchName ? sanitizeBranchName(params.branchName) : undefined
let branch = params.existingBranch ?? (sanitized || undefined) ?? generateBranchName(params.prompt || "agent-task")
if (params.existingBranch) {
const exists = await this.branchExists(branch)
@@ -1,14 +1,21 @@
/**
* Generate a valid git branch name from a prompt.
* Sanitize a string into a valid git branch name segment.
* Keeps lowercase alphanumeric chars and hyphens, collapses runs, strips edges.
*/
export function generateBranchName(prompt: string): string {
const sanitized = prompt
.slice(0, 50)
export function sanitizeBranchName(name: string, maxLength = 50): string {
return name
.slice(0, maxLength)
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "")
.replace(/-+/g, "-")
}
/**
* Generate a valid git branch name from a prompt.
*/
export function generateBranchName(prompt: string): string {
const sanitized = sanitizeBranchName(prompt)
return `${sanitized || "kilo"}-${Date.now()}`
}
@@ -3,7 +3,7 @@ import os from "node:os"
import path from "node:path"
import fs from "node:fs/promises"
import { WorktreeManager } from "../../src/agent-manager/WorktreeManager"
import { generateBranchName, versionedName } from "../../src/agent-manager/branch-name"
import { generateBranchName, sanitizeBranchName, versionedName } from "../../src/agent-manager/branch-name"
import { WorktreeStateManager } from "../../src/agent-manager/WorktreeStateManager"
import simpleGit from "simple-git"
@@ -90,6 +90,50 @@ describe("generateBranchName", () => {
})
})
// ---------------------------------------------------------------------------
// sanitizeBranchName
// ---------------------------------------------------------------------------
describe("sanitizeBranchName", () => {
it("replaces spaces with hyphens", () => {
expect(sanitizeBranchName("model comparison")).toBe("model-comparison")
})
it("lowercases input", () => {
expect(sanitizeBranchName("My Feature")).toBe("my-feature")
})
it("strips special characters", () => {
expect(sanitizeBranchName("fix bug #123 & add feature!")).toBe("fix-bug-123-add-feature")
})
it("collapses consecutive hyphens", () => {
expect(sanitizeBranchName("one two three")).toBe("one-two-three")
})
it("strips leading and trailing hyphens", () => {
expect(sanitizeBranchName("---hello---")).toBe("hello")
})
it("truncates to maxLength", () => {
const result = sanitizeBranchName("a".repeat(100))
expect(result.length).toBeLessThanOrEqual(50)
})
it("returns empty string for whitespace-only input", () => {
expect(sanitizeBranchName(" ")).toBe("")
})
it("returns empty string for empty input", () => {
expect(sanitizeBranchName("")).toBe("")
})
it("handles custom maxLength", () => {
const result = sanitizeBranchName("abcdefghij", 5)
expect(result).toBe("abcde")
})
})
// ---------------------------------------------------------------------------
// versionedName
// ---------------------------------------------------------------------------