mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-03 21:03:08 +00:00
Overhaul updates for appspec & feature generation. Added detail back to kanban feature creation
This commit is contained in:
@@ -384,20 +384,30 @@ class FeatureLoader {
|
|||||||
* @param {string} projectPath - Path to the project
|
* @param {string} projectPath - Path to the project
|
||||||
* @param {string} [summary] - Optional summary of what was done
|
* @param {string} [summary] - Optional summary of what was done
|
||||||
* @param {string} [error] - Optional error message if feature errored
|
* @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
|
// Check if feature exists
|
||||||
const existingFeature = await this.get(projectPath, featureId);
|
const existingFeature = await this.get(projectPath, featureId);
|
||||||
|
|
||||||
if (!existingFeature) {
|
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`);
|
console.log(`[FeatureLoader] Feature ${featureId} not found - creating new feature`);
|
||||||
const newFeature = {
|
const newFeature = {
|
||||||
id: featureId,
|
id: featureId,
|
||||||
title: featureId.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' '),
|
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,
|
status: status,
|
||||||
summary: summary || '',
|
images: [],
|
||||||
|
imagePaths: [],
|
||||||
|
skipTests: true,
|
||||||
|
model: "sonnet",
|
||||||
|
thinkingLevel: "none",
|
||||||
|
summary: summary || description || '',
|
||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
if (error !== undefined) {
|
if (error !== undefined) {
|
||||||
@@ -405,7 +415,7 @@ class FeatureLoader {
|
|||||||
}
|
}
|
||||||
await this.create(projectPath, newFeature);
|
await this.create(projectPath, newFeature);
|
||||||
console.log(
|
console.log(
|
||||||
`[FeatureLoader] Created feature ${featureId}: status=${status}${
|
`[FeatureLoader] Created feature ${featureId}: status=${status}, category=${category || "Uncategorized"}, steps=${steps?.length || 0}${
|
||||||
summary ? `, summary="${summary}"` : ""
|
summary ? `, summary="${summary}"` : ""
|
||||||
}`
|
}`
|
||||||
);
|
);
|
||||||
@@ -421,6 +431,15 @@ class FeatureLoader {
|
|||||||
updates.description = summary;
|
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) {
|
if (error !== undefined) {
|
||||||
updates.error = error;
|
updates.error = error;
|
||||||
} else {
|
} else {
|
||||||
@@ -429,10 +448,21 @@ class FeatureLoader {
|
|||||||
updates.error = undefined;
|
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);
|
await this.update(projectPath, featureId, updates);
|
||||||
console.log(
|
console.log(
|
||||||
`[FeatureLoader] Updated feature ${featureId}: status=${status}${
|
`[FeatureLoader] Updated feature ${featureId}: status=${status}${
|
||||||
|
category ? `, category="${category}"` : ""
|
||||||
|
}${steps ? `, steps=${steps.length}` : ""}${
|
||||||
summary ? `, summary="${summary}"` : ""
|
summary ? `, summary="${summary}"` : ""
|
||||||
}`
|
}`
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -19,15 +19,18 @@ class McpServerFactory {
|
|||||||
tools: [
|
tools: [
|
||||||
tool(
|
tool(
|
||||||
"UpdateFeatureStatus",
|
"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"),
|
featureId: z.string().describe("The ID of the feature (lowercase, hyphens for spaces). Example: 'user-authentication', 'budget-tracking'"),
|
||||||
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", "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. This will be displayed on the Kanban card. Example: 'Added dark mode toggle. Modified: settings.tsx, theme-provider.tsx'")
|
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) => {
|
async (args) => {
|
||||||
try {
|
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}"`);
|
console.log(`[Feature Creation] Creating/updating feature "${args.featureId}" with status "${args.status}"`);
|
||||||
|
|
||||||
// Load the feature to check skipTests flag
|
// 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
|
// If agent tries to mark as verified but feature has skipTests=true, convert to waiting_approval
|
||||||
let finalStatus = args.status;
|
let finalStatus = args.status;
|
||||||
|
// Convert 'todo' to 'backlog' for consistency
|
||||||
|
if (finalStatus === "todo") {
|
||||||
|
finalStatus = "backlog";
|
||||||
|
}
|
||||||
if (feature && args.status === "verified" && feature.skipTests === true) {
|
if (feature && args.status === "verified" && feature.skipTests === true) {
|
||||||
console.log(`[McpServerFactory] Feature ${args.featureId} has skipTests=true, converting verified -> waiting_approval`);
|
console.log(`[McpServerFactory] Feature ${args.featureId} has skipTests=true, converting verified -> waiting_approval`);
|
||||||
finalStatus = "waiting_approval";
|
finalStatus = "waiting_approval";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the provided callback to update feature status with summary
|
// Call the provided callback to update feature status with all parameters
|
||||||
await updateFeatureStatusCallback(args.featureId, finalStatus, projectPath, args.summary);
|
await updateFeatureStatusCallback(
|
||||||
|
args.featureId,
|
||||||
|
finalStatus,
|
||||||
|
projectPath,
|
||||||
|
args.summary,
|
||||||
|
undefined, // error
|
||||||
|
args.description,
|
||||||
|
args.category,
|
||||||
|
args.steps
|
||||||
|
);
|
||||||
|
|
||||||
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)${args.summary ? ` with summary: "${args.summary}"` : ""}`
|
? `Successfully created/updated feature ${args.featureId} to status "${finalStatus}" (converted from "${args.status}")${args.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}"${args.summary ? ` - ${args.summary}` : ""}`;
|
||||||
|
|
||||||
console.log(`[Feature Creation] ✓ ${statusMessage}`);
|
console.log(`[Feature Creation] ✓ ${statusMessage}`);
|
||||||
|
|
||||||
|
|||||||
@@ -52,11 +52,11 @@ ${memoryContent}
|
|||||||
**Current Feature to Implement:**
|
**Current Feature to Implement:**
|
||||||
|
|
||||||
ID: ${feature.id}
|
ID: ${feature.id}
|
||||||
Category: ${feature.category}
|
Category: ${feature.category || "Uncategorized"}
|
||||||
Description: ${feature.description}
|
Description: ${feature.description || feature.summary || feature.title || "No description provided"}
|
||||||
${skipTestsNote}${imagesNote}${contextFilesPreview}
|
${skipTestsNote}${imagesNote}${contextFilesPreview}
|
||||||
**Steps to Complete:**
|
**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:**
|
**Your Task:**
|
||||||
|
|
||||||
@@ -195,12 +195,12 @@ ${memoryContent}
|
|||||||
**Feature to Implement/Verify:**
|
**Feature to Implement/Verify:**
|
||||||
|
|
||||||
ID: ${feature.id}
|
ID: ${feature.id}
|
||||||
Category: ${feature.category}
|
Category: ${feature.category || "Uncategorized"}
|
||||||
Description: ${feature.description}
|
Description: ${feature.description || feature.summary || feature.title || "No description provided"}
|
||||||
Current Status: ${feature.status}
|
Current Status: ${feature.status}
|
||||||
${skipTestsNote}${imagesNote}${contextFilesPreview}
|
${skipTestsNote}${imagesNote}${contextFilesPreview}
|
||||||
**Steps that should be implemented:**
|
**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:**
|
**Your Task:**
|
||||||
|
|
||||||
@@ -335,11 +335,11 @@ ${memoryContent}
|
|||||||
**Current Feature:**
|
**Current Feature:**
|
||||||
|
|
||||||
ID: ${feature.id}
|
ID: ${feature.id}
|
||||||
Category: ${feature.category}
|
Category: ${feature.category || "Uncategorized"}
|
||||||
Description: ${feature.description}
|
Description: ${feature.description || feature.summary || feature.title || "No description provided"}
|
||||||
${skipTestsNote}${imagesNote}${contextFilesPreview}
|
${skipTestsNote}${imagesNote}${contextFilesPreview}
|
||||||
**Steps to Complete:**
|
**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:**
|
**Previous Work Context:**
|
||||||
|
|
||||||
|
|||||||
@@ -368,24 +368,42 @@ class SpecRegenerationService {
|
|||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
model: "claude-sonnet-4-20250514",
|
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:**
|
**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)
|
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
|
3. For EACH feature in the roadmap, use the UpdateFeatureStatus tool to create a detailed feature entry
|
||||||
4. Set the initial status to "todo" for all features
|
4. Set the initial status to "backlog" for all features
|
||||||
5. Extract a meaningful summary/description for each feature from the roadmap
|
|
||||||
|
**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:**
|
**Feature Storage:**
|
||||||
Features are stored in .automaker/features/{id}/feature.json - each feature has its own folder.
|
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.
|
Use the UpdateFeatureStatus tool to create features with ALL the fields above.`,
|
||||||
|
|
||||||
**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)`,
|
|
||||||
maxTurns: 50,
|
maxTurns: 50,
|
||||||
cwd: projectPath,
|
cwd: projectPath,
|
||||||
mcpServers: {
|
mcpServers: {
|
||||||
@@ -400,15 +418,24 @@ Use the UpdateFeatureStatus tool to create features. The tool will handle creati
|
|||||||
abortController: abortController,
|
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:
|
**Your workflow:**
|
||||||
1. Use the UpdateFeatureStatus tool to create the feature
|
1. Read the app_spec.txt file completely
|
||||||
2. Set status to "todo"
|
2. Identify ALL features from the implementation_roadmap section
|
||||||
3. Provide a clear summary/description based on what's in the roadmap
|
3. For EACH feature, call UpdateFeatureStatus with ALL required fields:
|
||||||
4. Use a featureId that's descriptive and follows the pattern: lowercase with hyphens (e.g., "user-authentication", "payment-processing")
|
|
||||||
|
|
||||||
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 });
|
const currentQuery = query({ prompt, options });
|
||||||
execution.query = currentQuery;
|
execution.query = currentQuery;
|
||||||
|
|||||||
Reference in New Issue
Block a user