/** * Branch Naming Utility * * Pure functions for computing deterministic branch names * in the initiative → phase → task branch hierarchy. */ /** * Task categories that run on the project's default branch (no initiative branch needed). */ export const PLANNING_CATEGORIES = ['research', 'discuss', 'plan', 'detail', 'refine'] as const; /** * Task categories that require an initiative branch. */ export const EXECUTION_CATEGORIES = ['execute', 'verify', 'merge', 'review'] as const; /** * Check if a task category is a planning category (runs on default branch). */ export function isPlanningCategory(category: string): boolean { return (PLANNING_CATEGORIES as readonly string[]).includes(category); } /** * Convert a name to a URL/branch-safe slug. * Lowercase, replace non-alphanumeric runs with single hyphens, trim hyphens. */ export function slugify(name: string): string { return name .toLowerCase() .replace(/[^a-z0-9]+/g, '-') .replace(/^-|-$/g, ''); } /** * Generate an initiative branch name from the initiative name. * Format: `cw/` */ export function generateInitiativeBranch(name: string): string { return `cw/${slugify(name)}`; } /** * Compute the initiative branch name. * Returns the branch as-is if set, or null if unset. */ export function initiativeBranchName(branch: string | null): string | null { return branch; } /** * Compute a phase branch name. * Format: `-phase-` */ export function phaseBranchName(initiativeBranch: string, phaseName: string): string { return `${initiativeBranch}-phase-${slugify(phaseName)}`; } /** * Compute a task branch name. * Format: `-task-` * Uses the raw task ID (already unique) to avoid collisions. */ export function taskBranchName(initiativeBranch: string, taskId: string): string { return `${initiativeBranch}-task-${taskId}`; }