From 8d6f825c5cb1f1d4164bdfca3a4a0f45c7ee0c39 Mon Sep 17 00:00:00 2001 From: trueheads Date: Thu, 11 Dec 2025 03:40:16 -0600 Subject: [PATCH] Overhaul updates for appspec & feature generation. Added detail back to kanban feature creation --- app/electron/services/feature-loader.js | 40 ++++++++++-- app/electron/services/mcp-server-factory.js | 34 +++++++--- app/electron/services/prompt-builder.js | 18 ++--- .../services/spec-regeneration-service.js | 65 +++++++++++++------ 4 files changed, 115 insertions(+), 42 deletions(-) diff --git a/app/electron/services/feature-loader.js b/app/electron/services/feature-loader.js index 02bb9d5f..67e6f5df 100644 --- a/app/electron/services/feature-loader.js +++ b/app/electron/services/feature-loader.js @@ -384,20 +384,30 @@ class FeatureLoader { * @param {string} projectPath - Path to the project * @param {string} [summary] - Optional summary of what was done * @param {string} [error] - Optional error message if feature errored + * @param {string} [description] - Optional detailed description + * @param {string} [category] - Optional category/phase + * @param {string[]} [steps] - Optional array of implementation steps */ - async updateFeatureStatus(featureId, status, projectPath, summary, error) { + async updateFeatureStatus(featureId, status, projectPath, summary, error, description, category, steps) { // Check if feature exists const existingFeature = await this.get(projectPath, featureId); if (!existingFeature) { - // Feature doesn't exist - create it + // Feature doesn't exist - create it with all required fields console.log(`[FeatureLoader] Feature ${featureId} not found - creating new feature`); const newFeature = { id: featureId, title: featureId.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' '), - description: summary || '', // Use summary as description for display + description: description || summary || '', // Use provided description, fall back to summary + category: category || "Uncategorized", + steps: steps || [], status: status, - summary: summary || '', + images: [], + imagePaths: [], + skipTests: true, + model: "sonnet", + thinkingLevel: "none", + summary: summary || description || '', createdAt: new Date().toISOString(), }; if (error !== undefined) { @@ -405,7 +415,7 @@ class FeatureLoader { } await this.create(projectPath, newFeature); console.log( - `[FeatureLoader] Created feature ${featureId}: status=${status}${ + `[FeatureLoader] Created feature ${featureId}: status=${status}, category=${category || "Uncategorized"}, steps=${steps?.length || 0}${ summary ? `, summary="${summary}"` : "" }` ); @@ -421,6 +431,15 @@ class FeatureLoader { updates.description = summary; } } + if (description !== undefined) { + updates.description = description; + } + if (category !== undefined) { + updates.category = category; + } + if (steps !== undefined && Array.isArray(steps)) { + updates.steps = steps; + } if (error !== undefined) { updates.error = error; } else { @@ -429,10 +448,21 @@ class FeatureLoader { updates.error = undefined; } } + + // Ensure required fields exist (for features created before this fix) + if (!existingFeature.category && !updates.category) updates.category = "Uncategorized"; + if (!existingFeature.steps && !updates.steps) updates.steps = []; + if (!existingFeature.images) updates.images = []; + if (!existingFeature.imagePaths) updates.imagePaths = []; + if (existingFeature.skipTests === undefined) updates.skipTests = true; + if (!existingFeature.model) updates.model = "sonnet"; + if (!existingFeature.thinkingLevel) updates.thinkingLevel = "none"; await this.update(projectPath, featureId, updates); console.log( `[FeatureLoader] Updated feature ${featureId}: status=${status}${ + category ? `, category="${category}"` : "" + }${steps ? `, steps=${steps.length}` : ""}${ summary ? `, summary="${summary}"` : "" }` ); diff --git a/app/electron/services/mcp-server-factory.js b/app/electron/services/mcp-server-factory.js index 8907b59c..8650e926 100644 --- a/app/electron/services/mcp-server-factory.js +++ b/app/electron/services/mcp-server-factory.js @@ -19,15 +19,18 @@ class McpServerFactory { tools: [ tool( "UpdateFeatureStatus", - "Update the status of a feature. Use this tool instead of directly modifying feature files to safely update feature status. IMPORTANT: If the feature has skipTests=true, you should NOT mark it as verified - instead it will automatically go to waiting_approval status for manual review. Always include a summary of what was done.", + "Create or update a feature. Use this tool to create new features with detailed information or update existing feature status. When creating features, provide comprehensive description, category, and implementation steps.", { - featureId: z.string().describe("The ID of the feature to update"), - status: z.enum(["backlog", "in_progress", "verified"]).describe("The new status for the feature. Note: If skipTests=true, verified will be converted to waiting_approval automatically."), - summary: z.string().optional().describe("A brief summary of what was implemented/changed. This will be displayed on the Kanban card. Example: 'Added dark mode toggle. Modified: settings.tsx, theme-provider.tsx'") + featureId: z.string().describe("The ID of the feature (lowercase, hyphens for spaces). Example: 'user-authentication', 'budget-tracking'"), + status: z.enum(["backlog", "todo", "in_progress", "verified"]).describe("The status for the feature. Use 'backlog' or 'todo' for new features."), + summary: z.string().optional().describe("A brief summary of what was implemented/changed or what the feature does."), + description: z.string().optional().describe("A detailed description of the feature. Be comprehensive - explain what the feature does, its purpose, and key functionality."), + category: z.string().optional().describe("The category/phase for this feature. Example: 'Phase 1: Foundation', 'Phase 2: Core Logic', 'Phase 3: Polish', 'Authentication', 'UI/UX'"), + steps: z.array(z.string()).optional().describe("Array of implementation steps. Each step should be a clear, actionable task. Example: ['Set up database schema', 'Create API endpoints', 'Build UI components', 'Add validation']") }, async (args) => { try { - console.log(`[McpServerFactory] UpdateFeatureStatus tool called: featureId=${args.featureId}, status=${args.status}, summary=${args.summary || "(none)"}`); + console.log(`[McpServerFactory] UpdateFeatureStatus tool called: featureId=${args.featureId}, status=${args.status}, summary=${args.summary || "(none)"}, category=${args.category || "(none)"}, steps=${args.steps?.length || 0}`); console.log(`[Feature Creation] Creating/updating feature "${args.featureId}" with status "${args.status}"`); // Load the feature to check skipTests flag @@ -41,17 +44,30 @@ class McpServerFactory { // If agent tries to mark as verified but feature has skipTests=true, convert to waiting_approval let finalStatus = args.status; + // Convert 'todo' to 'backlog' for consistency + if (finalStatus === "todo") { + finalStatus = "backlog"; + } if (feature && args.status === "verified" && feature.skipTests === true) { console.log(`[McpServerFactory] Feature ${args.featureId} has skipTests=true, converting verified -> waiting_approval`); finalStatus = "waiting_approval"; } - // Call the provided callback to update feature status with summary - await updateFeatureStatusCallback(args.featureId, finalStatus, projectPath, args.summary); + // Call the provided callback to update feature status with all parameters + await updateFeatureStatusCallback( + args.featureId, + finalStatus, + projectPath, + args.summary, + undefined, // error + args.description, + args.category, + args.steps + ); const statusMessage = finalStatus !== args.status - ? `Successfully updated feature ${args.featureId} to status "${finalStatus}" (converted from "${args.status}" because skipTests=true)${args.summary ? ` with summary: "${args.summary}"` : ""}` - : `Successfully updated feature ${args.featureId} to status "${finalStatus}"${args.summary ? ` with summary: "${args.summary}"` : ""}`; + ? `Successfully created/updated feature ${args.featureId} to status "${finalStatus}" (converted from "${args.status}")${args.summary ? ` - ${args.summary}` : ""}` + : `Successfully created/updated feature ${args.featureId} to status "${finalStatus}"${args.summary ? ` - ${args.summary}` : ""}`; console.log(`[Feature Creation] ✓ ${statusMessage}`); diff --git a/app/electron/services/prompt-builder.js b/app/electron/services/prompt-builder.js index 2c793403..d2e44d9c 100644 --- a/app/electron/services/prompt-builder.js +++ b/app/electron/services/prompt-builder.js @@ -52,11 +52,11 @@ ${memoryContent} **Current Feature to Implement:** ID: ${feature.id} -Category: ${feature.category} -Description: ${feature.description} +Category: ${feature.category || "Uncategorized"} +Description: ${feature.description || feature.summary || feature.title || "No description provided"} ${skipTestsNote}${imagesNote}${contextFilesPreview} **Steps to Complete:** -${feature.steps.map((step, i) => `${i + 1}. ${step}`).join("\n")} +${(feature.steps || []).map((step, i) => `${i + 1}. ${step}`).join("\n") || "No specific steps provided - implement based on description"} **Your Task:** @@ -195,12 +195,12 @@ ${memoryContent} **Feature to Implement/Verify:** ID: ${feature.id} -Category: ${feature.category} -Description: ${feature.description} +Category: ${feature.category || "Uncategorized"} +Description: ${feature.description || feature.summary || feature.title || "No description provided"} Current Status: ${feature.status} ${skipTestsNote}${imagesNote}${contextFilesPreview} **Steps that should be implemented:** -${feature.steps.map((step, i) => `${i + 1}. ${step}`).join("\n")} +${(feature.steps || []).map((step, i) => `${i + 1}. ${step}`).join("\n") || "No specific steps provided - implement based on description"} **Your Task:** @@ -335,11 +335,11 @@ ${memoryContent} **Current Feature:** ID: ${feature.id} -Category: ${feature.category} -Description: ${feature.description} +Category: ${feature.category || "Uncategorized"} +Description: ${feature.description || feature.summary || feature.title || "No description provided"} ${skipTestsNote}${imagesNote}${contextFilesPreview} **Steps to Complete:** -${feature.steps.map((step, i) => `${i + 1}. ${step}`).join("\n")} +${(feature.steps || []).map((step, i) => `${i + 1}. ${step}`).join("\n") || "No specific steps provided - implement based on description"} **Previous Work Context:** diff --git a/app/electron/services/spec-regeneration-service.js b/app/electron/services/spec-regeneration-service.js index 55fe55a1..632b0a1e 100644 --- a/app/electron/services/spec-regeneration-service.js +++ b/app/electron/services/spec-regeneration-service.js @@ -368,24 +368,42 @@ class SpecRegenerationService { const options = { model: "claude-sonnet-4-20250514", - systemPrompt: `You are a feature management assistant. Your job is to read the app_spec.txt file and create feature entries based on the implementation_roadmap section. + systemPrompt: `You are a feature management assistant. Your job is to read the app_spec.txt file and create DETAILED, COMPREHENSIVE feature entries based on the implementation_roadmap section. **Your Task:** -1. Read the .automaker/app_spec.txt file +1. Read the .automaker/app_spec.txt file thoroughly 2. Parse the implementation_roadmap section (it contains phases with features listed) -3. For each feature listed in the roadmap, use the UpdateFeatureStatus tool to create a feature entry -4. Set the initial status to "todo" for all features -5. Extract a meaningful summary/description for each feature from the roadmap +3. For EACH feature in the roadmap, use the UpdateFeatureStatus tool to create a detailed feature entry +4. Set the initial status to "backlog" for all features + +**IMPORTANT - For each feature you MUST provide:** +- **featureId**: A descriptive ID (lowercase, hyphens for spaces). Example: "user-authentication", "budget-tracking" +- **status**: "backlog" for all new features +- **description**: A DETAILED description (2-4 sentences) explaining what the feature does, its purpose, and key functionality +- **category**: The phase from the roadmap (e.g., "Phase 1: Foundation", "Phase 2: Core Logic", "Phase 3: Polish") +- **steps**: An array of 4-8 clear, actionable implementation steps. Each step should be specific and completable. +- **summary**: A brief one-line summary of the feature + +**Example of a well-defined feature:** +{ + "featureId": "user-authentication", + "status": "backlog", + "description": "Implement secure user authentication system with email/password login, OAuth integration for Google and Facebook, password reset functionality, and session management. This forms the foundation for all user-specific features.", + "category": "Phase 1: Foundation", + "steps": [ + "Set up authentication provider (NextAuth.js or similar)", + "Configure email/password authentication", + "Implement social login (Google, Facebook OAuth)", + "Create login and registration UI components", + "Add password reset flow with email verification", + "Implement session management and token refresh" + ], + "summary": "Secure authentication with email/password and social login" +} **Feature Storage:** Features are stored in .automaker/features/{id}/feature.json - each feature has its own folder. -Use the UpdateFeatureStatus tool to create features. The tool will handle creating the directory structure and feature.json file. - -**Important:** -- Create features ONLY from the implementation_roadmap section -- Use the UpdateFeatureStatus tool for each feature -- Set status to "todo" initially -- Use a descriptive featureId based on the feature name (lowercase, hyphens for spaces)`, +Use the UpdateFeatureStatus tool to create features with ALL the fields above.`, maxTurns: 50, cwd: projectPath, mcpServers: { @@ -400,15 +418,24 @@ Use the UpdateFeatureStatus tool to create features. The tool will handle creati abortController: abortController, }; - const prompt = `Please read the .automaker/app_spec.txt file and create feature entries for all features listed in the implementation_roadmap section. + const prompt = `Please read the .automaker/app_spec.txt file and create DETAILED feature entries for ALL features listed in the implementation_roadmap section. -For each feature in the roadmap: -1. Use the UpdateFeatureStatus tool to create the feature -2. Set status to "todo" -3. Provide a clear summary/description based on what's in the roadmap -4. Use a featureId that's descriptive and follows the pattern: lowercase with hyphens (e.g., "user-authentication", "payment-processing") +**Your workflow:** +1. Read the app_spec.txt file completely +2. Identify ALL features from the implementation_roadmap section +3. For EACH feature, call UpdateFeatureStatus with ALL required fields: -Start by reading the app_spec.txt file to see the implementation roadmap.`; +**Required for each UpdateFeatureStatus call:** +- featureId: Descriptive ID (lowercase, hyphens). Example: "user-authentication" +- status: "backlog" +- description: 2-4 sentences explaining the feature in detail +- category: The phase name (e.g., "Phase 1: Foundation", "Phase 2: Core Logic") +- steps: Array of 4-8 specific implementation steps +- summary: One-line summary + +**Do NOT create features with just a summary - each feature needs description, category, AND steps.** + +Start by reading the app_spec.txt file, then create each feature with full detail.`; const currentQuery = query({ prompt, options }); execution.query = currentQuery;