Files
automaker/apps/server/src/routes/suggestions.ts
SuperComboGamer 4b9bd2641f chore: update project management and API integration
- Added new scripts for server development and full application startup in package.json.
- Enhanced project management by checking for existing projects to avoid duplicates.
- Improved API integration with better error handling and connection checks in the Electron API.
- Updated UI components to reflect changes in project and session management.
- Refactored authentication status display to include more detailed information on methods used.
2025-12-12 00:23:43 -05:00

193 lines
5.7 KiB
TypeScript

/**
* Suggestions routes - HTTP API for AI-powered feature suggestions
*/
import { Router, type Request, type Response } from "express";
import { query, type Options } from "@anthropic-ai/claude-agent-sdk";
import type { EventEmitter } from "../lib/events.js";
let isRunning = false;
let currentAbortController: AbortController | null = null;
export function createSuggestionsRoutes(events: EventEmitter): Router {
const router = Router();
// Generate suggestions
router.post("/generate", async (req: Request, res: Response) => {
try {
const { projectPath, suggestionType = "features" } = req.body as {
projectPath: string;
suggestionType?: string;
};
if (!projectPath) {
res.status(400).json({ success: false, error: "projectPath required" });
return;
}
if (isRunning) {
res.json({ success: false, error: "Suggestions generation is already running" });
return;
}
isRunning = true;
currentAbortController = new AbortController();
// Start generation in background
generateSuggestions(projectPath, suggestionType, events, currentAbortController)
.catch((error) => {
console.error("[Suggestions] Error:", error);
events.emit("suggestions:event", {
type: "suggestions_error",
error: error.message,
});
})
.finally(() => {
isRunning = false;
currentAbortController = null;
});
res.json({ success: true });
} catch (error) {
const message = error instanceof Error ? error.message : "Unknown error";
res.status(500).json({ success: false, error: message });
}
});
// Stop suggestions generation
router.post("/stop", async (_req: Request, res: Response) => {
try {
if (currentAbortController) {
currentAbortController.abort();
}
isRunning = false;
res.json({ success: true });
} catch (error) {
const message = error instanceof Error ? error.message : "Unknown error";
res.status(500).json({ success: false, error: message });
}
});
// Get status
router.get("/status", async (_req: Request, res: Response) => {
try {
res.json({ success: true, isRunning });
} catch (error) {
const message = error instanceof Error ? error.message : "Unknown error";
res.status(500).json({ success: false, error: message });
}
});
return router;
}
async function generateSuggestions(
projectPath: string,
suggestionType: string,
events: EventEmitter,
abortController: AbortController
) {
const typePrompts: Record<string, string> = {
features: "Analyze this project and suggest new features that would add value.",
refactoring: "Analyze this project and identify refactoring opportunities.",
security: "Analyze this project for security vulnerabilities and suggest fixes.",
performance: "Analyze this project for performance issues and suggest optimizations.",
};
const prompt = `${typePrompts[suggestionType] || typePrompts.features}
Look at the codebase and provide 3-5 concrete suggestions.
For each suggestion, provide:
1. A category (e.g., "User Experience", "Security", "Performance")
2. A clear description of what to implement
3. Concrete steps to implement it
4. Priority (1=high, 2=medium, 3=low)
5. Brief reasoning for why this would help
Format your response as JSON:
{
"suggestions": [
{
"id": "suggestion-123",
"category": "Category",
"description": "What to implement",
"steps": ["Step 1", "Step 2"],
"priority": 1,
"reasoning": "Why this helps"
}
]
}`;
events.emit("suggestions:event", {
type: "suggestions_progress",
content: `Starting ${suggestionType} analysis...\n`,
});
const options: Options = {
model: "claude-opus-4-5-20251101",
maxTurns: 5,
cwd: projectPath,
allowedTools: ["Read", "Glob", "Grep"],
permissionMode: "acceptEdits",
abortController,
};
const stream = query({ prompt, options });
let responseText = "";
for await (const msg of stream) {
if (msg.type === "assistant" && msg.message.content) {
for (const block of msg.message.content) {
if (block.type === "text") {
responseText = block.text;
events.emit("suggestions:event", {
type: "suggestions_progress",
content: block.text,
});
} else if (block.type === "tool_use") {
events.emit("suggestions:event", {
type: "suggestions_tool",
tool: block.name,
input: block.input,
});
}
}
} else if (msg.type === "result" && msg.subtype === "success") {
responseText = msg.result || responseText;
}
}
// Parse suggestions from response
try {
const jsonMatch = responseText.match(/\{[\s\S]*"suggestions"[\s\S]*\}/);
if (jsonMatch) {
const parsed = JSON.parse(jsonMatch[0]);
events.emit("suggestions:event", {
type: "suggestions_complete",
suggestions: parsed.suggestions.map((s: Record<string, unknown>, i: number) => ({
...s,
id: s.id || `suggestion-${Date.now()}-${i}`,
})),
});
} else {
throw new Error("No valid JSON found in response");
}
} catch (error) {
// Return generic suggestions if parsing fails
events.emit("suggestions:event", {
type: "suggestions_complete",
suggestions: [
{
id: `suggestion-${Date.now()}-0`,
category: "Analysis",
description: "Review the AI analysis output for insights",
steps: ["Review the generated analysis"],
priority: 1,
reasoning: "The AI provided analysis but suggestions need manual review",
},
],
});
}
}