From 0246ef6a22d07e6e338b4d99c508bb1ef990758c Mon Sep 17 00:00:00 2001 From: Eric Garcia Date: Tue, 27 Jan 2026 17:21:25 -0500 Subject: [PATCH] fix: add plan_cache to base schema + feature/{slug} branch naming - Add plan_cache table to base SCHEMA so fresh databases have it (was only created via migration, causing "no such table" errors) - Change worktree branch naming from `{title}` to `feature/{slug}` - Add slugify() to handle titles with spaces like "Minimal Job Submission" - Update cleanup handler to use same naming convention Co-Authored-By: Claude Opus 4.5 --- crates/blue-core/src/store.rs | 10 +++ crates/blue-mcp/src/handlers/worktree.rs | 81 +++++++++++++++++++++--- 2 files changed, 83 insertions(+), 8 deletions(-) diff --git a/crates/blue-core/src/store.rs b/crates/blue-core/src/store.rs index 0aae87a..cb2d458 100644 --- a/crates/blue-core/src/store.rs +++ b/crates/blue-core/src/store.rs @@ -222,6 +222,16 @@ const SCHEMA: &str = r#" doc_type, updated_at ) WHERE deleted_at IS NULL; + + -- Plan cache for tracking plan file sync state (RFC 0017) + CREATE TABLE IF NOT EXISTS plan_cache ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + document_id INTEGER NOT NULL UNIQUE, + cache_mtime TEXT NOT NULL, + FOREIGN KEY (document_id) REFERENCES documents(id) ON DELETE CASCADE + ); + + CREATE INDEX IF NOT EXISTS idx_plan_cache_document ON plan_cache(document_id); "#; /// FTS5 schema for full-text search diff --git a/crates/blue-mcp/src/handlers/worktree.rs b/crates/blue-mcp/src/handlers/worktree.rs index cbd2f67..be72c60 100644 --- a/crates/blue-mcp/src/handlers/worktree.rs +++ b/crates/blue-mcp/src/handlers/worktree.rs @@ -3,9 +3,9 @@ //! Handles git worktree operations for isolated feature development. //! //! Branch naming convention (RFC 0007): -//! - RFC file: `NNNN-feature-description.md` -//! - Branch: `feature-description` (number prefix stripped) -//! - Worktree: `feature-description` +//! - RFC file: `NNNN-feature-description.md` or "Feature Description" title +//! - Branch: `feature/{slug}` where slug is lowercase with hyphens +//! - Worktree: `{slug}` directory name use std::path::Path; @@ -95,6 +95,47 @@ pub fn strip_rfc_number_prefix(title: &str) -> (String, Option) { } } +/// Convert a title to a URL-safe slug +/// +/// - Converts to lowercase +/// - Replaces spaces and underscores with hyphens +/// - Removes non-alphanumeric characters (except hyphens) +/// - Collapses multiple hyphens +/// - Trims leading/trailing hyphens +fn slugify(title: &str) -> String { + let slug: String = title + .to_lowercase() + .chars() + .map(|c| { + if c.is_ascii_alphanumeric() { + c + } else if c == ' ' || c == '_' { + '-' + } else { + '-' + } + }) + .collect(); + + // Collapse multiple hyphens and trim + let mut result = String::new(); + let mut prev_hyphen = false; + for c in slug.chars() { + if c == '-' { + if !prev_hyphen && !result.is_empty() { + result.push(c); + } + prev_hyphen = true; + } else { + result.push(c); + prev_hyphen = false; + } + } + + // Trim trailing hyphen + result.trim_end_matches('-').to_string() +} + /// Handle blue_worktree_create pub fn handle_create(state: &ProjectState, args: &Value) -> Result { let title = args @@ -152,10 +193,11 @@ pub fn handle_create(state: &ProjectState, args: &Value) -> Result Result