fix(ui): preserve original task description after spec creation (#536)
* fix(ui): preserve original task description after spec creation Task descriptions were being replaced with AI-generated content from spec.md after spec creation completed. The description extraction in project-store.ts prioritized spec.md Overview section over the user's original description stored in implementation_plan.json. Reordered priority: plan.json → requirements.json → spec.md (fallback) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(pr-review): add input validation and timeouts to subprocess calls Address CodeRabbit findings: 1. Import and use _validate_git_ref for head_sha validation before passing to subprocess (security) 2. Add timeout=60 to git worktree add subprocess call to prevent indefinite hangs on slow/corrupted repos 3. Add timeout=30 to git worktree remove, list, and prune calls for consistent timeout handling 4. Remove head_branch fallback - only use head_sha for worktree creation to ensure consistent semantics 5. Fix potential IndexError in worktree list parsing by checking split result length before accessing index 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -346,29 +346,13 @@ export class ProjectStore {
|
||||
}
|
||||
}
|
||||
|
||||
// Try to read spec file for description
|
||||
// PRIORITY 1: Read description from implementation_plan.json (user's original)
|
||||
let description = '';
|
||||
if (existsSync(specFilePath)) {
|
||||
try {
|
||||
const content = readFileSync(specFilePath, 'utf-8');
|
||||
// Extract full Overview section until next heading or end of file
|
||||
// Use \n#{1,6}\s to match valid markdown headings (# to ######) with required space
|
||||
// This avoids truncating at # in code blocks (e.g., Python comments)
|
||||
const overviewMatch = content.match(/## Overview\s*\n+([\s\S]*?)(?=\n#{1,6}\s|$)/);
|
||||
if (overviewMatch) {
|
||||
description = overviewMatch[1].trim();
|
||||
}
|
||||
} catch {
|
||||
// Ignore read errors
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: read description from implementation_plan.json if not found in spec.md
|
||||
if (!description && plan?.description) {
|
||||
if (plan?.description) {
|
||||
description = plan.description;
|
||||
}
|
||||
|
||||
// Fallback: read description from requirements.json if still not found
|
||||
// PRIORITY 2: Fallback to requirements.json
|
||||
if (!description) {
|
||||
const requirementsPath = path.join(specPath, AUTO_BUILD_PATHS.REQUIREMENTS);
|
||||
if (existsSync(requirementsPath)) {
|
||||
@@ -404,6 +388,22 @@ export class ProjectStore {
|
||||
}
|
||||
}
|
||||
|
||||
// PRIORITY 3: Final fallback to spec.md Overview (AI-synthesized content)
|
||||
if (!description && existsSync(specFilePath)) {
|
||||
try {
|
||||
const content = readFileSync(specFilePath, 'utf-8');
|
||||
// Extract full Overview section until next heading or end of file
|
||||
// Use \n#{1,6}\s to match valid markdown headings (# to ######) with required space
|
||||
// This avoids truncating at # in code blocks (e.g., Python comments)
|
||||
const overviewMatch = content.match(/## Overview\s*\n+([\s\S]*?)(?=\n#{1,6}\s|$)/);
|
||||
if (overviewMatch) {
|
||||
description = overviewMatch[1].trim();
|
||||
}
|
||||
} catch {
|
||||
// Ignore read errors
|
||||
}
|
||||
}
|
||||
|
||||
// Try to read task metadata
|
||||
const metadataPath = path.join(specPath, 'task_metadata.json');
|
||||
let metadata: TaskMetadata | undefined;
|
||||
|
||||
Reference in New Issue
Block a user