feat(kanban): add feature summary display and agent context info

Enhance Kanban cards to show comprehensive feature information:
- Add feature summary field to display completed work details
- Show agent context info (model, progress, tasks) on cards
- Display tool usage and token consumption metrics
- Add expandable summary dialog for detailed view
- Update prompts to require summary when marking features complete
- Improve UI for waiting_approval and verified states

Modified: kanban-card.tsx, board-view.tsx, feature-loader.js,
mcp-server-factory.js, prompt-builder.js, app-store.ts
Created: agent-context-parser.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
This commit is contained in:
Kacper
2025-12-09 23:25:27 +01:00
parent 5ff7e3791a
commit ef0519adf9
8 changed files with 597 additions and 33 deletions

View File

@@ -53,12 +53,12 @@
"status": "verified" "status": "verified"
}, },
{ {
"id": "feature-1765316742659-rll51tb62", "id": "feature-1765318148517-715isvwwb",
"category": "Kanban", "category": "Kanban",
"description": "We implemented the follow up prompt and waiting approval column its work well but when we click commit button its commiting with the title of follow up prompt i dont like this i would prefer the convencional commit that u as agent is creating when skip automated testing mode is off and u commit it in nice way look how we generate commit / handle it when automated testing is enabled and see how we do it when its disabled and its waiting for our approval and commit button how its handle it", "description": "When agent finish work the cards is moved either to waiting approval or into verified one But mostly its include some type of summary at the end i want you to modify our prompts and ui so when its in both states we can see the feature summary of what was done / modified instead of relying on going to code editor to see what got changed etc.",
"steps": [], "steps": [],
"status": "waiting_approval", "status": "verified",
"startedAt": "2025-12-09T21:56:25.922Z", "startedAt": "2025-12-09T22:09:13.684Z",
"imagePaths": [], "imagePaths": [],
"skipTests": true "skipTests": true
} }

View File

@@ -32,8 +32,12 @@ class FeatureLoader {
/** /**
* Update feature status in .automaker/feature_list.json * Update feature status in .automaker/feature_list.json
* @param {string} featureId - The ID of the feature to update
* @param {string} status - The new status
* @param {string} projectPath - Path to the project
* @param {string} [summary] - Optional summary of what was done
*/ */
async updateFeatureStatus(featureId, status, projectPath) { async updateFeatureStatus(featureId, status, projectPath, summary) {
const features = await this.loadFeatures(projectPath); const features = await this.loadFeatures(projectPath);
const feature = features.find((f) => f.id === featureId); const feature = features.find((f) => f.id === featureId);
@@ -45,6 +49,11 @@ class FeatureLoader {
// Update the status field // Update the status field
feature.status = status; feature.status = status;
// Update the summary field if provided
if (summary) {
feature.summary = summary;
}
// Save back to file // Save back to file
const featuresPath = path.join( const featuresPath = path.join(
projectPath, projectPath,
@@ -72,11 +81,14 @@ class FeatureLoader {
if (f.startedAt !== undefined) { if (f.startedAt !== undefined) {
featureData.startedAt = f.startedAt; featureData.startedAt = f.startedAt;
} }
if (f.summary !== undefined) {
featureData.summary = f.summary;
}
return featureData; return featureData;
}); });
await fs.writeFile(featuresPath, JSON.stringify(toSave, null, 2), "utf-8"); await fs.writeFile(featuresPath, JSON.stringify(toSave, null, 2), "utf-8");
console.log(`[FeatureLoader] Updated feature ${featureId}: status=${status}`); console.log(`[FeatureLoader] Updated feature ${featureId}: status=${status}${summary ? `, summary="${summary}"` : ""}`);
} }
/** /**

View File

@@ -19,14 +19,15 @@ class McpServerFactory {
tools: [ tools: [
tool( tool(
"UpdateFeatureStatus", "UpdateFeatureStatus",
"Update the status of a feature in the feature list. Use this tool instead of directly modifying feature_list.json 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.", "Update the status of a feature in the feature list. Use this tool instead of directly modifying feature_list.json 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.",
{ {
featureId: z.string().describe("The ID of the feature to update"), 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.") 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'")
}, },
async (args) => { async (args) => {
try { try {
console.log(`[McpServerFactory] UpdateFeatureStatus tool called: featureId=${args.featureId}, status=${args.status}`); console.log(`[McpServerFactory] UpdateFeatureStatus tool called: featureId=${args.featureId}, status=${args.status}, summary=${args.summary || "(none)"}`);
// Load the feature to check skipTests flag // Load the feature to check skipTests flag
const features = await featureLoader.loadFeatures(projectPath); const features = await featureLoader.loadFeatures(projectPath);
@@ -43,12 +44,12 @@ class McpServerFactory {
finalStatus = "waiting_approval"; finalStatus = "waiting_approval";
} }
// Call the provided callback to update feature status // Call the provided callback to update feature status with summary
await updateFeatureStatusCallback(args.featureId, finalStatus, projectPath); await updateFeatureStatusCallback(args.featureId, finalStatus, projectPath, args.summary);
const statusMessage = finalStatus !== args.status const statusMessage = finalStatus !== args.status
? `Successfully updated feature ${args.featureId} to status "${finalStatus}" (converted from "${args.status}" because skipTests=true)` ? `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}"`; : `Successfully updated feature ${args.featureId} to status "${finalStatus}"${args.summary ? ` with summary: "${args.summary}"` : ""}`;
return { return {
content: [{ content: [{

View File

@@ -6,7 +6,7 @@ class PromptBuilder {
* Build the prompt for implementing a specific feature * Build the prompt for implementing a specific feature
*/ */
buildFeaturePrompt(feature) { buildFeaturePrompt(feature) {
const skipTestsNote = feature.skipTests const skipTestsNote = feature.skipTests
? `\n**⚠️ IMPORTANT - Manual Testing Mode:**\nThis feature has skipTests=true, which means:\n- DO NOT commit changes automatically\n- DO NOT mark as verified - it will automatically go to "waiting_approval" status\n- The user will manually review and commit the changes\n- Just implement the feature and mark it as verified (it will be converted to waiting_approval)\n` ? `\n**⚠️ IMPORTANT - Manual Testing Mode:**\nThis feature has skipTests=true, which means:\n- DO NOT commit changes automatically\n- DO NOT mark as verified - it will automatically go to "waiting_approval" status\n- The user will manually review and commit the changes\n- Just implement the feature and mark it as verified (it will be converted to waiting_approval)\n`
: ""; : "";
@@ -25,11 +25,11 @@ ${feature.steps.map((step, i) => `${i + 1}. ${step}`).join("\n")}
1. Read the project files to understand the current codebase structure 1. Read the project files to understand the current codebase structure
2. Implement the feature according to the description and steps 2. Implement the feature according to the description and steps
${feature.skipTests ${feature.skipTests
? "3. Test the implementation manually (no automated tests needed for skipTests features)" ? "3. Test the implementation manually (no automated tests needed for skipTests features)"
: "3. Write Playwright tests to verify the feature works correctly\n4. Run the tests and ensure they pass\n5. **DELETE the test file(s) you created** - tests are only for immediate verification"} : "3. Write Playwright tests to verify the feature works correctly\n4. Run the tests and ensure they pass\n5. **DELETE the test file(s) you created** - tests are only for immediate verification"}
${feature.skipTests ? "4" : "6"}. **CRITICAL: Use the UpdateFeatureStatus tool to mark this feature as verified** - DO NOT manually edit .automaker/feature_list.json ${feature.skipTests ? "4" : "6"}. **CRITICAL: Use the UpdateFeatureStatus tool to mark this feature as verified** - DO NOT manually edit .automaker/feature_list.json
${feature.skipTests ${feature.skipTests
? "5. **DO NOT commit changes** - the user will review and commit manually" ? "5. **DO NOT commit changes** - the user will review and commit manually"
: "7. Commit your changes with git"} : "7. Commit your changes with git"}
@@ -37,20 +37,36 @@ ${feature.skipTests
When you have completed the feature${feature.skipTests ? "" : " and all tests pass"}, you MUST use the \`mcp__automaker-tools__UpdateFeatureStatus\` tool to update the feature status: When you have completed the feature${feature.skipTests ? "" : " and all tests pass"}, you MUST use the \`mcp__automaker-tools__UpdateFeatureStatus\` tool to update the feature status:
- Call the tool with: featureId="${feature.id}" and status="verified" - Call the tool with: featureId="${feature.id}" and status="verified"
- **You can also include a summary parameter** to describe what was done: summary="Brief summary of changes"
- **DO NOT manually edit the .automaker/feature_list.json file** - this can cause race conditions - **DO NOT manually edit the .automaker/feature_list.json file** - this can cause race conditions
- The UpdateFeatureStatus tool safely updates the feature status without risk of corrupting other data - The UpdateFeatureStatus tool safely updates the feature status without risk of corrupting other data
- **If skipTests=true, the tool will automatically convert "verified" to "waiting_approval"** - this is correct behavior - **If skipTests=true, the tool will automatically convert "verified" to "waiting_approval"** - this is correct behavior
**IMPORTANT - Feature Summary (REQUIRED):**
When calling UpdateFeatureStatus, you MUST include a summary parameter that describes:
- What files were modified/created
- What functionality was added or changed
- Any notable implementation decisions
Example:
\`\`\`
UpdateFeatureStatus(featureId="${feature.id}", status="verified", summary="Added dark mode toggle to settings. Modified: settings.tsx, theme-provider.tsx. Created new useTheme hook.")
\`\`\`
The summary will be displayed on the Kanban card so the user can see what was done without checking the code.
**Important Guidelines:** **Important Guidelines:**
- Focus ONLY on implementing this specific feature - Focus ONLY on implementing this specific feature
- Write clean, production-quality code - Write clean, production-quality code
- Add proper error handling - Add proper error handling
${feature.skipTests ${feature.skipTests
? "- Skip automated testing (skipTests=true) - user will manually verify" ? "- Skip automated testing (skipTests=true) - user will manually verify"
: "- Write comprehensive Playwright tests\n- Ensure all existing tests still pass\n- Mark the feature as passing only when all tests are green\n- **CRITICAL: Delete test files after verification** - tests accumulate and become brittle"} : "- Write comprehensive Playwright tests\n- Ensure all existing tests still pass\n- Mark the feature as passing only when all tests are green\n- **CRITICAL: Delete test files after verification** - tests accumulate and become brittle"}
- **CRITICAL: Use UpdateFeatureStatus tool instead of editing feature_list.json directly** - **CRITICAL: Use UpdateFeatureStatus tool instead of editing feature_list.json directly**
${feature.skipTests - **CRITICAL: Always include a summary when marking feature as verified**
${feature.skipTests
? "- **DO NOT commit changes** - user will review and commit manually" ? "- **DO NOT commit changes** - user will review and commit manually"
: "- Make a git commit when complete"} : "- Make a git commit when complete"}
@@ -83,7 +99,7 @@ Begin by reading the project structure and then implementing the feature.`;
* Build the prompt for verifying a specific feature * Build the prompt for verifying a specific feature
*/ */
buildVerificationPrompt(feature) { buildVerificationPrompt(feature) {
const skipTestsNote = feature.skipTests const skipTestsNote = feature.skipTests
? `\n**⚠️ IMPORTANT - Manual Testing Mode:**\nThis feature has skipTests=true, which means:\n- DO NOT commit changes automatically\n- DO NOT mark as verified - it will automatically go to "waiting_approval" status\n- The user will manually review and commit the changes\n- Just implement the feature and mark it as verified (it will be converted to waiting_approval)\n` ? `\n**⚠️ IMPORTANT - Manual Testing Mode:**\nThis feature has skipTests=true, which means:\n- DO NOT commit changes automatically\n- DO NOT mark as verified - it will automatically go to "waiting_approval" status\n- The user will manually review and commit the changes\n- Just implement the feature and mark it as verified (it will be converted to waiting_approval)\n`
: ""; : "";
@@ -103,7 +119,7 @@ ${feature.steps.map((step, i) => `${i + 1}. ${step}`).join("\n")}
1. Read the project files to understand the current implementation 1. Read the project files to understand the current implementation
2. If the feature is not fully implemented, continue implementing it 2. If the feature is not fully implemented, continue implementing it
${feature.skipTests ${feature.skipTests
? "3. Test the implementation manually (no automated tests needed for skipTests features)" ? "3. Test the implementation manually (no automated tests needed for skipTests features)"
: `3. Write or update Playwright tests to verify the feature works correctly : `3. Write or update Playwright tests to verify the feature works correctly
4. Run the Playwright tests: npx playwright test tests/[feature-name].spec.ts 4. Run the Playwright tests: npx playwright test tests/[feature-name].spec.ts
@@ -117,7 +133,7 @@ ${feature.skipTests
7. **If ALL tests pass:** 7. **If ALL tests pass:**
- **DELETE the test file(s) for this feature** - tests are only for immediate verification`} - **DELETE the test file(s) for this feature** - tests are only for immediate verification`}
${feature.skipTests ? "4" : "8"}. **CRITICAL: Use the UpdateFeatureStatus tool to mark this feature as verified** - DO NOT manually edit .automaker/feature_list.json ${feature.skipTests ? "4" : "8"}. **CRITICAL: Use the UpdateFeatureStatus tool to mark this feature as verified** - DO NOT manually edit .automaker/feature_list.json
${feature.skipTests ${feature.skipTests
? "5. **DO NOT commit changes** - the user will review and commit manually" ? "5. **DO NOT commit changes** - the user will review and commit manually"
: "9. Explain what was implemented/fixed and that all tests passed\n10. Commit your changes with git"} : "9. Explain what was implemented/fixed and that all tests passed\n10. Commit your changes with git"}
@@ -125,10 +141,25 @@ ${feature.skipTests
When you have completed the feature${feature.skipTests ? "" : " and all tests pass"}, you MUST use the \`mcp__automaker-tools__UpdateFeatureStatus\` tool to update the feature status: When you have completed the feature${feature.skipTests ? "" : " and all tests pass"}, you MUST use the \`mcp__automaker-tools__UpdateFeatureStatus\` tool to update the feature status:
- Call the tool with: featureId="${feature.id}" and status="verified" - Call the tool with: featureId="${feature.id}" and status="verified"
- **You can also include a summary parameter** to describe what was done: summary="Brief summary of changes"
- **DO NOT manually edit the .automaker/feature_list.json file** - this can cause race conditions - **DO NOT manually edit the .automaker/feature_list.json file** - this can cause race conditions
- The UpdateFeatureStatus tool safely updates the feature status without risk of corrupting other data - The UpdateFeatureStatus tool safely updates the feature status without risk of corrupting other data
- **If skipTests=true, the tool will automatically convert "verified" to "waiting_approval"** - this is correct behavior - **If skipTests=true, the tool will automatically convert "verified" to "waiting_approval"** - this is correct behavior
**IMPORTANT - Feature Summary (REQUIRED):**
When calling UpdateFeatureStatus, you MUST include a summary parameter that describes:
- What files were modified/created
- What functionality was added or changed
- Any notable implementation decisions
Example:
\`\`\`
UpdateFeatureStatus(featureId="${feature.id}", status="verified", summary="Added dark mode toggle to settings. Modified: settings.tsx, theme-provider.tsx. Created new useTheme hook.")
\`\`\`
The summary will be displayed on the Kanban card so the user can see what was done without checking the code.
**Testing Utilities:** **Testing Utilities:**
- Check if tests/utils.ts exists and is being used - Check if tests/utils.ts exists and is being used
- If utilities are outdated due to functionality changes, update them - If utilities are outdated due to functionality changes, update them
@@ -142,10 +173,11 @@ rm tests/[feature-name].spec.ts
\`\`\` \`\`\`
**Important:** **Important:**
${feature.skipTests ${feature.skipTests
? "- Skip automated testing (skipTests=true) - user will manually verify\n- **DO NOT commit changes** - user will review and commit manually" ? "- Skip automated testing (skipTests=true) - user will manually verify\n- **DO NOT commit changes** - user will review and commit manually"
: "- **CONTINUE IMPLEMENTING until all tests pass** - don't stop at the first failure\n- Only mark as verified if Playwright tests pass\n- **CRITICAL: Delete test files after they pass** - tests should not accumulate\n- Update test utilities if functionality changed\n- Make a git commit when the feature is complete\n- Be thorough and persistent in fixing issues"} : "- **CONTINUE IMPLEMENTING until all tests pass** - don't stop at the first failure\n- Only mark as verified if Playwright tests pass\n- **CRITICAL: Delete test files after they pass** - tests should not accumulate\n- Update test utilities if functionality changed\n- Make a git commit when the feature is complete\n- Be thorough and persistent in fixing issues"}
- **CRITICAL: Use UpdateFeatureStatus tool instead of editing feature_list.json directly** - **CRITICAL: Use UpdateFeatureStatus tool instead of editing feature_list.json directly**
- **CRITICAL: Always include a summary when marking feature as verified**
Begin by reading the project structure and understanding what needs to be implemented or fixed.`; Begin by reading the project structure and understanding what needs to be implemented or fixed.`;
} }
@@ -154,7 +186,7 @@ Begin by reading the project structure and understanding what needs to be implem
* Build prompt for resuming feature with previous context * Build prompt for resuming feature with previous context
*/ */
buildResumePrompt(feature, previousContext) { buildResumePrompt(feature, previousContext) {
const skipTestsNote = feature.skipTests const skipTestsNote = feature.skipTests
? `\n**⚠️ IMPORTANT - Manual Testing Mode:**\nThis feature has skipTests=true, which means:\n- DO NOT commit changes automatically\n- DO NOT mark as verified - it will automatically go to "waiting_approval" status\n- The user will manually review and commit the changes\n- Just implement the feature and mark it as verified (it will be converted to waiting_approval)\n` ? `\n**⚠️ IMPORTANT - Manual Testing Mode:**\nThis feature has skipTests=true, which means:\n- DO NOT commit changes automatically\n- DO NOT mark as verified - it will automatically go to "waiting_approval" status\n- The user will manually review and commit the changes\n- Just implement the feature and mark it as verified (it will be converted to waiting_approval)\n`
: ""; : "";
@@ -179,11 +211,11 @@ Continue where you left off and complete the feature implementation:
1. Review the previous work context above to understand what has been done 1. Review the previous work context above to understand what has been done
2. Continue implementing the feature according to the description and steps 2. Continue implementing the feature according to the description and steps
${feature.skipTests ${feature.skipTests
? "3. Test the implementation manually (no automated tests needed for skipTests features)" ? "3. Test the implementation manually (no automated tests needed for skipTests features)"
: "3. Write Playwright tests to verify the feature works correctly (if not already done)\n4. Run the tests and ensure they pass\n5. **DELETE the test file(s) you created** - tests are only for immediate verification"} : "3. Write Playwright tests to verify the feature works correctly (if not already done)\n4. Run the tests and ensure they pass\n5. **DELETE the test file(s) you created** - tests are only for immediate verification"}
${feature.skipTests ? "4" : "6"}. **CRITICAL: Use the UpdateFeatureStatus tool to mark this feature as verified** - DO NOT manually edit .automaker/feature_list.json ${feature.skipTests ? "4" : "6"}. **CRITICAL: Use the UpdateFeatureStatus tool to mark this feature as verified** - DO NOT manually edit .automaker/feature_list.json
${feature.skipTests ${feature.skipTests
? "5. **DO NOT commit changes** - the user will review and commit manually" ? "5. **DO NOT commit changes** - the user will review and commit manually"
: "7. Commit your changes with git"} : "7. Commit your changes with git"}
@@ -191,20 +223,36 @@ ${feature.skipTests
When you have completed the feature${feature.skipTests ? "" : " and all tests pass"}, you MUST use the \`mcp__automaker-tools__UpdateFeatureStatus\` tool to update the feature status: When you have completed the feature${feature.skipTests ? "" : " and all tests pass"}, you MUST use the \`mcp__automaker-tools__UpdateFeatureStatus\` tool to update the feature status:
- Call the tool with: featureId="${feature.id}" and status="verified" - Call the tool with: featureId="${feature.id}" and status="verified"
- **You can also include a summary parameter** to describe what was done: summary="Brief summary of changes"
- **DO NOT manually edit the .automaker/feature_list.json file** - this can cause race conditions - **DO NOT manually edit the .automaker/feature_list.json file** - this can cause race conditions
- The UpdateFeatureStatus tool safely updates the feature status without risk of corrupting other data - The UpdateFeatureStatus tool safely updates the feature status without risk of corrupting other data
- **If skipTests=true, the tool will automatically convert "verified" to "waiting_approval"** - this is correct behavior - **If skipTests=true, the tool will automatically convert "verified" to "waiting_approval"** - this is correct behavior
**IMPORTANT - Feature Summary (REQUIRED):**
When calling UpdateFeatureStatus, you MUST include a summary parameter that describes:
- What files were modified/created
- What functionality was added or changed
- Any notable implementation decisions
Example:
\`\`\`
UpdateFeatureStatus(featureId="${feature.id}", status="verified", summary="Added dark mode toggle to settings. Modified: settings.tsx, theme-provider.tsx. Created new useTheme hook.")
\`\`\`
The summary will be displayed on the Kanban card so the user can see what was done without checking the code.
**Important Guidelines:** **Important Guidelines:**
- Review what was already done in the previous context - Review what was already done in the previous context
- Don't redo work that's already complete - continue from where it left off - Don't redo work that's already complete - continue from where it left off
- Focus on completing any remaining tasks - Focus on completing any remaining tasks
${feature.skipTests ${feature.skipTests
? "- Skip automated testing (skipTests=true) - user will manually verify" ? "- Skip automated testing (skipTests=true) - user will manually verify"
: "- Write comprehensive Playwright tests if not already done\n- Ensure all tests pass before marking as verified\n- **CRITICAL: Delete test files after verification**"} : "- Write comprehensive Playwright tests if not already done\n- Ensure all tests pass before marking as verified\n- **CRITICAL: Delete test files after verification**"}
- **CRITICAL: Use UpdateFeatureStatus tool instead of editing feature_list.json directly** - **CRITICAL: Use UpdateFeatureStatus tool instead of editing feature_list.json directly**
${feature.skipTests - **CRITICAL: Always include a summary when marking feature as verified**
${feature.skipTests
? "- **DO NOT commit changes** - user will review and commit manually" ? "- **DO NOT commit changes** - user will review and commit manually"
: "- Make a git commit when complete"} : "- Make a git commit when complete"}
@@ -305,6 +353,7 @@ Your role is to:
- Ensure all tests pass before marking features complete (only if skipTests is false) - Ensure all tests pass before marking features complete (only if skipTests is false)
- **DELETE test files after successful verification** - tests are only for immediate feature verification (only if skipTests is false) - **DELETE test files after successful verification** - tests are only for immediate feature verification (only if skipTests is false)
- **Use the UpdateFeatureStatus tool to mark features as verified** - NEVER manually edit feature_list.json - **Use the UpdateFeatureStatus tool to mark features as verified** - NEVER manually edit feature_list.json
- **Always include a summary parameter when calling UpdateFeatureStatus** - describe what was done
- Commit working code to git (only if skipTests is false - skipTests features require manual review) - Commit working code to git (only if skipTests is false - skipTests features require manual review)
- Be thorough and detail-oriented - Be thorough and detail-oriented
@@ -316,12 +365,22 @@ If a feature has skipTests=true:
- The user will manually verify and commit the changes - The user will manually verify and commit the changes
**IMPORTANT - UpdateFeatureStatus Tool:** **IMPORTANT - UpdateFeatureStatus Tool:**
You have access to the \`mcp__automaker-tools__UpdateFeatureStatus\` tool. When the feature is complete${""} (and all tests pass if skipTests is false), use this tool to update the feature status: You have access to the \`mcp__automaker-tools__UpdateFeatureStatus\` tool. When the feature is complete (and all tests pass if skipTests is false), use this tool to update the feature status:
- Call with featureId and status="verified" - Call with featureId, status="verified", and summary="Description of what was done"
- **DO NOT manually edit .automaker/feature_list.json** - this can cause race conditions and restore old state - **DO NOT manually edit .automaker/feature_list.json** - this can cause race conditions and restore old state
- The tool safely updates the status without corrupting other feature data - The tool safely updates the status without corrupting other feature data
- **If skipTests=true, the tool will automatically convert "verified" to "waiting_approval"** - this is correct - **If skipTests=true, the tool will automatically convert "verified" to "waiting_approval"** - this is correct
**IMPORTANT - Feature Summary (REQUIRED):**
When calling UpdateFeatureStatus, you MUST include a summary parameter that describes:
- What files were modified/created
- What functionality was added or changed
- Any notable implementation decisions
Example: summary="Added dark mode toggle. Modified: settings.tsx, theme-provider.tsx. Created useTheme hook."
The summary will be displayed on the Kanban card so the user can quickly see what was done.
**Testing Utilities (CRITICAL):** **Testing Utilities (CRITICAL):**
- **Create and maintain tests/utils.ts** with helper functions for finding elements and common operations - **Create and maintain tests/utils.ts** with helper functions for finding elements and common operations
- **Always use utilities in tests** instead of repeating selectors - **Always use utilities in tests** instead of repeating selectors
@@ -366,6 +425,7 @@ Your role is to:
- Continue rerunning tests and fixing issues until ALL tests pass (only if skipTests is false) - Continue rerunning tests and fixing issues until ALL tests pass (only if skipTests is false)
- **DELETE test files after successful verification** - tests are only for immediate feature verification (only if skipTests is false) - **DELETE test files after successful verification** - tests are only for immediate feature verification (only if skipTests is false)
- **Use the UpdateFeatureStatus tool to mark features as verified** - NEVER manually edit feature_list.json - **Use the UpdateFeatureStatus tool to mark features as verified** - NEVER manually edit feature_list.json
- **Always include a summary parameter when calling UpdateFeatureStatus** - describe what was done
- **Update test utilities (tests/utils.ts) if functionality changed** - keep helpers in sync with code (only if skipTests is false) - **Update test utilities (tests/utils.ts) if functionality changed** - keep helpers in sync with code (only if skipTests is false)
- Commit working code to git (only if skipTests is false - skipTests features require manual review) - Commit working code to git (only if skipTests is false - skipTests features require manual review)
@@ -377,12 +437,22 @@ If a feature has skipTests=true:
- The user will manually verify and commit the changes - The user will manually verify and commit the changes
**IMPORTANT - UpdateFeatureStatus Tool:** **IMPORTANT - UpdateFeatureStatus Tool:**
You have access to the \`mcp__automaker-tools__UpdateFeatureStatus\` tool. When the feature is complete${""} (and all tests pass if skipTests is false), use this tool to update the feature status: You have access to the \`mcp__automaker-tools__UpdateFeatureStatus\` tool. When the feature is complete (and all tests pass if skipTests is false), use this tool to update the feature status:
- Call with featureId and status="verified" - Call with featureId, status="verified", and summary="Description of what was done"
- **DO NOT manually edit .automaker/feature_list.json** - this can cause race conditions and restore old state - **DO NOT manually edit .automaker/feature_list.json** - this can cause race conditions and restore old state
- The tool safely updates the status without corrupting other feature data - The tool safely updates the status without corrupting other feature data
- **If skipTests=true, the tool will automatically convert "verified" to "waiting_approval"** - this is correct - **If skipTests=true, the tool will automatically convert "verified" to "waiting_approval"** - this is correct
**IMPORTANT - Feature Summary (REQUIRED):**
When calling UpdateFeatureStatus, you MUST include a summary parameter that describes:
- What files were modified/created
- What functionality was added or changed
- Any notable implementation decisions
Example: summary="Fixed login validation. Modified: auth.ts, login-form.tsx. Added password strength check."
The summary will be displayed on the Kanban card so the user can quickly see what was done.
**Testing Utilities:** **Testing Utilities:**
- Check if tests/utils.ts needs updates based on code changes - Check if tests/utils.ts needs updates based on code changes
- If a component's selectors or behavior changed, update the corresponding utility functions - If a component's selectors or behavior changed, update the corresponding utility functions
@@ -405,7 +475,7 @@ You have access to:
- Make git commits - Make git commits
- **UpdateFeatureStatus tool** (mcp__automaker-tools__UpdateFeatureStatus) - Use this to update feature status - **UpdateFeatureStatus tool** (mcp__automaker-tools__UpdateFeatureStatus) - Use this to update feature status
**CRITICAL:** Be persistent and thorough - keep iterating on the implementation until all tests pass. Don't give up after the first failure. Always delete tests after they pass, use the UpdateFeatureStatus tool, and commit your work.`; **CRITICAL:** Be persistent and thorough - keep iterating on the implementation until all tests pass. Don't give up after the first failure. Always delete tests after they pass, use the UpdateFeatureStatus tool with a summary, and commit your work.`;
} }
/** /**

View File

@@ -404,6 +404,7 @@ export function BoardView() {
startedAt: f.startedAt, startedAt: f.startedAt,
imagePaths: f.imagePaths, imagePaths: f.imagePaths,
skipTests: f.skipTests, skipTests: f.skipTests,
summary: f.summary,
})); }));
await api.writeFile( await api.writeFile(
`${currentProject.path}/.automaker/feature_list.json`, `${currentProject.path}/.automaker/feature_list.json`,

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { useState } from "react"; import { useState, useEffect } from "react";
import { useSortable } from "@dnd-kit/sortable"; import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities"; import { CSS } from "@dnd-kit/utilities";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
@@ -36,8 +36,20 @@ import {
ArrowLeft, ArrowLeft,
MessageSquare, MessageSquare,
GitCommit, GitCommit,
Cpu,
Wrench,
ListTodo,
Sparkles,
Expand,
} from "lucide-react"; } from "lucide-react";
import { CountUpTimer } from "@/components/ui/count-up-timer"; import { CountUpTimer } from "@/components/ui/count-up-timer";
import { getElectronAPI } from "@/lib/electron";
import {
parseAgentContext,
AgentTaskInfo,
formatModelName,
DEFAULT_MODEL,
} from "@/lib/agent-context-parser";
interface KanbanCardProps { interface KanbanCardProps {
feature: Feature; feature: Feature;
@@ -54,6 +66,10 @@ interface KanbanCardProps {
hasContext?: boolean; hasContext?: boolean;
isCurrentAutoTask?: boolean; isCurrentAutoTask?: boolean;
shortcutKey?: string; shortcutKey?: string;
/** Context content for extracting progress info */
contextContent?: string;
/** Feature summary from agent completion */
summary?: string;
} }
export function KanbanCard({ export function KanbanCard({
@@ -71,8 +87,56 @@ export function KanbanCard({
hasContext, hasContext,
isCurrentAutoTask, isCurrentAutoTask,
shortcutKey, shortcutKey,
contextContent,
summary,
}: KanbanCardProps) { }: KanbanCardProps) {
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
const [isSummaryDialogOpen, setIsSummaryDialogOpen] = useState(false);
const [agentInfo, setAgentInfo] = useState<AgentTaskInfo | null>(null);
// Load context file for in_progress, waiting_approval, and verified features
useEffect(() => {
const loadContext = async () => {
// Use provided context or load from file
if (contextContent) {
const info = parseAgentContext(contextContent);
setAgentInfo(info);
return;
}
// Only load for non-backlog features
if (feature.status === "backlog") {
setAgentInfo(null);
return;
}
try {
const api = getElectronAPI();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const currentProject = (window as any).__currentProject;
if (!currentProject?.path) return;
const contextPath = `${currentProject.path}/.automaker/agents-context/${feature.id}.md`;
const result = await api.readFile(contextPath);
if (result.success && result.content) {
const info = parseAgentContext(result.content);
setAgentInfo(info);
}
} catch {
// Context file might not exist
console.debug("[KanbanCard] No context file for feature:", feature.id);
}
};
loadContext();
// Reload context periodically while feature is running
if (isCurrentAutoTask) {
const interval = setInterval(loadContext, 3000);
return () => clearInterval(interval);
}
}, [feature.id, feature.status, contextContent, isCurrentAutoTask]);
const handleDeleteClick = (e: React.MouseEvent) => { const handleDeleteClick = (e: React.MouseEvent) => {
e.stopPropagation(); e.stopPropagation();
@@ -220,6 +284,141 @@ export function KanbanCard({
</div> </div>
)} )}
{/* Agent Info Panel - shows for in_progress, waiting_approval, verified */}
{feature.status !== "backlog" && agentInfo && (
<div className="mb-3 space-y-2">
{/* Model & Progress Bar */}
<div className="flex items-center gap-2 text-xs">
<div className="flex items-center gap-1 text-cyan-400">
<Cpu className="w-3 h-3" />
<span className="font-medium">{formatModelName(DEFAULT_MODEL)}</span>
</div>
{agentInfo.currentPhase && (
<div className={cn(
"px-1.5 py-0.5 rounded text-[10px] font-medium",
agentInfo.currentPhase === "planning" && "bg-blue-500/20 text-blue-400",
agentInfo.currentPhase === "action" && "bg-amber-500/20 text-amber-400",
agentInfo.currentPhase === "verification" && "bg-green-500/20 text-green-400"
)}>
{agentInfo.currentPhase}
</div>
)}
</div>
{/* Progress Indicator */}
{(isCurrentAutoTask || feature.status === "in_progress") && (
<div className="space-y-1">
<div className="w-full h-1.5 bg-zinc-800 rounded-full overflow-hidden">
<div
className="w-full h-full bg-primary transition-transform duration-500 ease-out origin-left"
style={{ transform: `translateX(${agentInfo.progressPercentage - 100}%)` }}
/>
</div>
<div className="flex items-center justify-between text-[10px] text-muted-foreground">
<div className="flex items-center gap-2">
<span className="flex items-center gap-1">
<Wrench className="w-2.5 h-2.5" />
{agentInfo.toolCallCount} tools
</span>
{agentInfo.lastToolUsed && (
<span className="text-zinc-500 truncate max-w-[80px]" title={agentInfo.lastToolUsed}>
{agentInfo.lastToolUsed}
</span>
)}
</div>
<span>{Math.round(agentInfo.progressPercentage)}%</span>
</div>
</div>
)}
{/* Task List Progress (if todos found) */}
{agentInfo.todos.length > 0 && (
<div className="space-y-1">
<div className="flex items-center gap-1 text-[10px] text-muted-foreground">
<ListTodo className="w-3 h-3" />
<span>
{agentInfo.todos.filter(t => t.status === "completed").length}/{agentInfo.todos.length} tasks
</span>
</div>
<div className="space-y-0.5 max-h-16 overflow-y-auto">
{agentInfo.todos.slice(0, 3).map((todo, idx) => (
<div
key={idx}
className="flex items-center gap-1.5 text-[10px]"
>
{todo.status === "completed" ? (
<CheckCircle2 className="w-2.5 h-2.5 text-green-500 shrink-0" />
) : todo.status === "in_progress" ? (
<Loader2 className="w-2.5 h-2.5 text-amber-400 animate-spin shrink-0" />
) : (
<Circle className="w-2.5 h-2.5 text-zinc-500 shrink-0" />
)}
<span className={cn(
"truncate",
todo.status === "completed" && "text-zinc-500 line-through",
todo.status === "in_progress" && "text-amber-400",
todo.status === "pending" && "text-zinc-400"
)}>
{todo.content}
</span>
</div>
))}
{agentInfo.todos.length > 3 && (
<p className="text-[10px] text-muted-foreground pl-4">
+{agentInfo.todos.length - 3} more
</p>
)}
</div>
</div>
)}
{/* Summary for waiting_approval and verified - prioritize feature.summary from UpdateFeatureStatus */}
{(feature.status === "waiting_approval" || feature.status === "verified") && (
<>
{(feature.summary || summary || agentInfo.summary) && (
<div className="space-y-1 pt-1 border-t border-white/5">
<div className="flex items-center justify-between">
<div className="flex items-center gap-1 text-[10px] text-green-400">
<Sparkles className="w-3 h-3" />
<span>Summary</span>
</div>
<button
onClick={(e) => {
e.stopPropagation();
setIsSummaryDialogOpen(true);
}}
className="p-0.5 rounded hover:bg-white/10 transition-colors text-zinc-500 hover:text-zinc-300"
title="View full summary"
data-testid={`expand-summary-${feature.id}`}
>
<Expand className="w-3 h-3" />
</button>
</div>
<p className="text-[10px] text-zinc-400 line-clamp-3">
{feature.summary || summary || agentInfo.summary}
</p>
</div>
)}
{/* Show tool count even without summary */}
{!feature.summary && !summary && !agentInfo.summary && agentInfo.toolCallCount > 0 && (
<div className="flex items-center gap-2 text-[10px] text-muted-foreground pt-1 border-t border-white/5">
<span className="flex items-center gap-1">
<Wrench className="w-2.5 h-2.5" />
{agentInfo.toolCallCount} tool calls
</span>
{agentInfo.todos.length > 0 && (
<span className="flex items-center gap-1">
<CheckCircle2 className="w-2.5 h-2.5 text-green-500" />
{agentInfo.todos.filter(t => t.status === "completed").length} tasks done
</span>
)}
</div>
)}
</>
)}
</div>
)}
{/* Actions */} {/* Actions */}
<div className="flex gap-2"> <div className="flex gap-2">
{isCurrentAutoTask && ( {isCurrentAutoTask && (
@@ -471,6 +670,40 @@ export function KanbanCard({
</DialogFooter> </DialogFooter>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
{/* Summary Modal */}
<Dialog open={isSummaryDialogOpen} onOpenChange={setIsSummaryDialogOpen}>
<DialogContent
className="max-w-2xl max-h-[80vh] overflow-hidden flex flex-col"
data-testid={`summary-dialog-${feature.id}`}
>
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<Sparkles className="w-5 h-5 text-green-400" />
Implementation Summary
</DialogTitle>
<DialogDescription className="text-sm">
{feature.description}
</DialogDescription>
</DialogHeader>
<div className="flex-1 overflow-y-auto">
<div className="prose prose-sm prose-invert max-w-none">
<pre className="whitespace-pre-wrap text-sm text-zinc-300 bg-zinc-900/50 p-4 rounded-lg border border-white/10">
{feature.summary || summary || agentInfo?.summary || "No summary available"}
</pre>
</div>
</div>
<DialogFooter>
<Button
variant="ghost"
onClick={() => setIsSummaryDialogOpen(false)}
data-testid="close-summary-button"
>
Close
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</Card> </Card>
); );
} }

View File

@@ -0,0 +1,246 @@
/**
* Agent Context Parser
* Extracts useful information from agent context files for display in kanban cards
*/
export interface AgentTaskInfo {
// Task list extracted from TodoWrite tool calls
todos: {
content: string;
status: "pending" | "in_progress" | "completed";
}[];
// Progress stats
toolCallCount: number;
lastToolUsed?: string;
// Phase info
currentPhase?: "planning" | "action" | "verification";
// Summary (if feature is completed)
summary?: string;
// Estimated progress percentage based on phase and tool calls
progressPercentage: number;
}
/**
* Default model used by the feature executor
*/
export const DEFAULT_MODEL = "claude-opus-4-5-20251101";
/**
* Formats a model name for display
*/
export function formatModelName(model: string): string {
if (model.includes("opus")) return "Opus 4.5";
if (model.includes("sonnet")) return "Sonnet 4";
if (model.includes("haiku")) return "Haiku 3.5";
return model.split("-").slice(1, 3).join(" ");
}
/**
* Extracts todos from the context content
* Looks for TodoWrite tool calls in the format:
* TodoWrite: [{"content": "...", "status": "..."}]
*/
function extractTodos(content: string): AgentTaskInfo["todos"] {
const todos: AgentTaskInfo["todos"] = [];
// Look for TodoWrite tool inputs
const todoMatches = content.matchAll(/TodoWrite.*?(?:"todos"\s*:\s*)?(\[[\s\S]*?\](?=\s*(?:\}|$|🔧|📋|⚡|✅|❌)))/g);
for (const match of todoMatches) {
try {
// Try to find JSON array in the match
const jsonStr = match[1] || match[0];
const arrayMatch = jsonStr.match(/\[[\s\S]*?\]/);
if (arrayMatch) {
const parsed = JSON.parse(arrayMatch[0]);
if (Array.isArray(parsed)) {
for (const item of parsed) {
if (item.content && item.status) {
// Check if this todo already exists (avoid duplicates)
if (!todos.some(t => t.content === item.content)) {
todos.push({
content: item.content,
status: item.status,
});
}
}
}
}
}
} catch {
// Ignore parse errors
}
}
// Also try to extract from markdown task lists
const markdownTodos = content.matchAll(/- \[([ xX])\] (.+)/g);
for (const match of markdownTodos) {
const isCompleted = match[1].toLowerCase() === "x";
const content = match[2].trim();
if (!todos.some(t => t.content === content)) {
todos.push({
content,
status: isCompleted ? "completed" : "pending",
});
}
}
return todos;
}
/**
* Counts tool calls in the content
*/
function countToolCalls(content: string): number {
const matches = content.match(/🔧\s*Tool:/g);
return matches?.length || 0;
}
/**
* Gets the last tool used
*/
function getLastToolUsed(content: string): string | undefined {
const matches = [...content.matchAll(/🔧\s*Tool:\s*(\S+)/g)];
if (matches.length > 0) {
return matches[matches.length - 1][1];
}
return undefined;
}
/**
* Determines the current phase from the content
*/
function getCurrentPhase(content: string): "planning" | "action" | "verification" | undefined {
// Find the last phase marker
const planningIndex = content.lastIndexOf("📋");
const actionIndex = content.lastIndexOf("⚡");
const verificationIndex = content.lastIndexOf("✅");
const maxIndex = Math.max(planningIndex, actionIndex, verificationIndex);
if (maxIndex === -1) return undefined;
if (maxIndex === verificationIndex) return "verification";
if (maxIndex === actionIndex) return "action";
return "planning";
}
/**
* Extracts a summary from completed feature context
*/
function extractSummary(content: string): string | undefined {
// Look for completion markers and extract surrounding text
const completionMatch = content.match(/✓ (?:Feature|Verification|Task) (?:successfully|completed|verified)[^\n]*(?:\n[^\n]{1,200})?/i);
if (completionMatch) {
return completionMatch[0].trim();
}
// Look for summary sections
const summaryMatch = content.match(/## Summary[^\n]*\n([\s\S]{1,500}?)(?=\n##|\n🔧|$)/i);
if (summaryMatch) {
return summaryMatch[1].trim();
}
// Look for "What was done" type sections
const whatWasDoneMatch = content.match(/(?:What was done|Changes made|Implemented)[^\n]*\n([\s\S]{1,500}?)(?=\n##|\n🔧|$)/i);
if (whatWasDoneMatch) {
return whatWasDoneMatch[1].trim();
}
return undefined;
}
/**
* Calculates progress percentage based on phase and context
* Uses a more dynamic approach that better reflects actual progress
*/
function calculateProgress(phase: AgentTaskInfo["currentPhase"], toolCallCount: number, todos: AgentTaskInfo["todos"]): number {
// If we have todos, primarily use them for progress calculation
if (todos.length > 0) {
const completedCount = todos.filter(t => t.status === "completed").length;
const inProgressCount = todos.filter(t => t.status === "in_progress").length;
// Weight: completed = 1, in_progress = 0.5, pending = 0
const progress = ((completedCount + inProgressCount * 0.5) / todos.length) * 90;
// Add a small base amount and cap at 95%
return Math.min(5 + progress, 95);
}
// Fallback: use phase-based progress with tool call scaling
let phaseProgress = 0;
switch (phase) {
case "planning":
// Planning phase: 5-25%
phaseProgress = 5 + Math.min(toolCallCount * 1, 20);
break;
case "action":
// Action phase: 25-75% based on tool calls (logarithmic scaling)
phaseProgress = 25 + Math.min(Math.log2(toolCallCount + 1) * 10, 50);
break;
case "verification":
// Verification phase: 75-95%
phaseProgress = 75 + Math.min(toolCallCount * 0.5, 20);
break;
default:
// Starting: just use tool calls
phaseProgress = Math.min(toolCallCount * 0.5, 10);
}
return Math.min(Math.round(phaseProgress), 95);
}
/**
* Parses agent context content and extracts useful information
*/
export function parseAgentContext(content: string): AgentTaskInfo {
if (!content || !content.trim()) {
return {
todos: [],
toolCallCount: 0,
progressPercentage: 0,
};
}
const todos = extractTodos(content);
const toolCallCount = countToolCalls(content);
const lastToolUsed = getLastToolUsed(content);
const currentPhase = getCurrentPhase(content);
const summary = extractSummary(content);
const progressPercentage = calculateProgress(currentPhase, toolCallCount, todos);
return {
todos,
toolCallCount,
lastToolUsed,
currentPhase,
summary,
progressPercentage,
};
}
/**
* Quick stats for display in card badges
*/
export interface QuickStats {
toolCalls: number;
completedTasks: number;
totalTasks: number;
phase?: string;
}
/**
* Extracts quick stats from context for compact display
*/
export function getQuickStats(content: string): QuickStats {
const info = parseAgentContext(content);
return {
toolCalls: info.toolCallCount,
completedTasks: info.todos.filter(t => t.status === "completed").length,
totalTasks: info.todos.length,
phase: info.currentPhase,
};
}

View File

@@ -61,6 +61,7 @@ export interface Feature {
imagePaths?: FeatureImagePath[]; // Paths to temp files for agent context imagePaths?: FeatureImagePath[]; // Paths to temp files for agent context
startedAt?: string; // ISO timestamp for when the card moved to in_progress startedAt?: string; // ISO timestamp for when the card moved to in_progress
skipTests?: boolean; // When true, skip TDD approach and require manual verification skipTests?: boolean; // When true, skip TDD approach and require manual verification
summary?: string; // Summary of what was done/modified by the agent
} }
export interface AppState { export interface AppState {