mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-31 06:42:03 +00:00
feat: implement ideation feature for brainstorming and idea management
- Introduced a new IdeationService to manage brainstorming sessions, including idea creation, analysis, and conversion to features. - Added RESTful API routes for ideation, including session management, idea CRUD operations, and suggestion generation. - Created UI components for the ideation dashboard, prompt selection, and category grid to enhance user experience. - Integrated keyboard shortcuts and navigation for the ideation feature, improving accessibility and workflow. - Updated state management with Zustand to handle ideation-specific data and actions. - Added necessary types and paths for ideation functionality, ensuring type safety and clarity in the codebase.
This commit is contained in:
@@ -58,6 +58,8 @@ import { createMCPRoutes } from './routes/mcp/index.js';
|
||||
import { MCPTestService } from './services/mcp-test-service.js';
|
||||
import { createPipelineRoutes } from './routes/pipeline/index.js';
|
||||
import { pipelineService } from './services/pipeline-service.js';
|
||||
import { createIdeationRoutes } from './routes/ideation/index.js';
|
||||
import { IdeationService } from './services/ideation-service.js';
|
||||
|
||||
// Load environment variables
|
||||
dotenv.config();
|
||||
@@ -162,6 +164,7 @@ const featureLoader = new FeatureLoader();
|
||||
const autoModeService = new AutoModeService(events, settingsService);
|
||||
const claudeUsageService = new ClaudeUsageService();
|
||||
const mcpTestService = new MCPTestService(settingsService);
|
||||
const ideationService = new IdeationService(events, settingsService, featureLoader);
|
||||
|
||||
// Initialize services
|
||||
(async () => {
|
||||
@@ -215,6 +218,7 @@ app.use('/api/context', createContextRoutes(settingsService));
|
||||
app.use('/api/backlog-plan', createBacklogPlanRoutes(events, settingsService));
|
||||
app.use('/api/mcp', createMCPRoutes(mcpTestService));
|
||||
app.use('/api/pipeline', createPipelineRoutes(pipelineService));
|
||||
app.use('/api/ideation', createIdeationRoutes(ideationService, featureLoader));
|
||||
|
||||
// Create HTTP server
|
||||
const server = createServer(app);
|
||||
|
||||
@@ -89,7 +89,7 @@ export class ClaudeProvider extends BaseProvider {
|
||||
...(allowedTools && shouldRestrictTools && { allowedTools }),
|
||||
...(!allowedTools && shouldRestrictTools && { allowedTools: defaultTools }),
|
||||
// When MCP servers are configured and auto-approve is enabled, use bypassPermissions
|
||||
permissionMode: shouldBypassPermissions ? 'bypassPermissions' : 'default',
|
||||
permissionMode: shouldBypassPermissions ? 'bypassPermissions' : 'acceptEdits',
|
||||
// Required when using bypassPermissions mode
|
||||
...(shouldBypassPermissions && { allowDangerouslySkipPermissions: true }),
|
||||
abortController,
|
||||
|
||||
12
apps/server/src/routes/ideation/common.ts
Normal file
12
apps/server/src/routes/ideation/common.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Common utilities for ideation routes
|
||||
*/
|
||||
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { getErrorMessage as getErrorMessageShared, createLogError } from '../common.js';
|
||||
|
||||
const logger = createLogger('Ideation');
|
||||
|
||||
// Re-export shared utilities
|
||||
export { getErrorMessageShared as getErrorMessage };
|
||||
export const logError = createLogError(logger);
|
||||
99
apps/server/src/routes/ideation/index.ts
Normal file
99
apps/server/src/routes/ideation/index.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Ideation routes - HTTP API for brainstorming and idea management
|
||||
*/
|
||||
|
||||
import { Router } from 'express';
|
||||
import { validatePathParams } from '../../middleware/validate-paths.js';
|
||||
import type { IdeationService } from '../../services/ideation-service.js';
|
||||
import type { FeatureLoader } from '../../services/feature-loader.js';
|
||||
|
||||
// Route handlers
|
||||
import { createSessionStartHandler } from './routes/session-start.js';
|
||||
import { createSessionMessageHandler } from './routes/session-message.js';
|
||||
import { createSessionStopHandler } from './routes/session-stop.js';
|
||||
import { createSessionGetHandler } from './routes/session-get.js';
|
||||
import { createIdeasListHandler } from './routes/ideas-list.js';
|
||||
import { createIdeasCreateHandler } from './routes/ideas-create.js';
|
||||
import { createIdeasGetHandler } from './routes/ideas-get.js';
|
||||
import { createIdeasUpdateHandler } from './routes/ideas-update.js';
|
||||
import { createIdeasDeleteHandler } from './routes/ideas-delete.js';
|
||||
import { createAnalyzeHandler, createGetAnalysisHandler } from './routes/analyze.js';
|
||||
import { createConvertHandler } from './routes/convert.js';
|
||||
import { createPromptsHandler, createPromptsByCategoryHandler } from './routes/prompts.js';
|
||||
import { createSuggestionsGenerateHandler } from './routes/suggestions-generate.js';
|
||||
|
||||
export function createIdeationRoutes(
|
||||
ideationService: IdeationService,
|
||||
featureLoader: FeatureLoader
|
||||
): Router {
|
||||
const router = Router();
|
||||
|
||||
// Session management
|
||||
router.post(
|
||||
'/session/start',
|
||||
validatePathParams('projectPath'),
|
||||
createSessionStartHandler(ideationService)
|
||||
);
|
||||
router.post('/session/message', createSessionMessageHandler(ideationService));
|
||||
router.post('/session/stop', createSessionStopHandler(ideationService));
|
||||
router.post(
|
||||
'/session/get',
|
||||
validatePathParams('projectPath'),
|
||||
createSessionGetHandler(ideationService)
|
||||
);
|
||||
|
||||
// Ideas CRUD
|
||||
router.post(
|
||||
'/ideas/list',
|
||||
validatePathParams('projectPath'),
|
||||
createIdeasListHandler(ideationService)
|
||||
);
|
||||
router.post(
|
||||
'/ideas/create',
|
||||
validatePathParams('projectPath'),
|
||||
createIdeasCreateHandler(ideationService)
|
||||
);
|
||||
router.post(
|
||||
'/ideas/get',
|
||||
validatePathParams('projectPath'),
|
||||
createIdeasGetHandler(ideationService)
|
||||
);
|
||||
router.post(
|
||||
'/ideas/update',
|
||||
validatePathParams('projectPath'),
|
||||
createIdeasUpdateHandler(ideationService)
|
||||
);
|
||||
router.post(
|
||||
'/ideas/delete',
|
||||
validatePathParams('projectPath'),
|
||||
createIdeasDeleteHandler(ideationService)
|
||||
);
|
||||
|
||||
// Project analysis
|
||||
router.post('/analyze', validatePathParams('projectPath'), createAnalyzeHandler(ideationService));
|
||||
router.post(
|
||||
'/analysis',
|
||||
validatePathParams('projectPath'),
|
||||
createGetAnalysisHandler(ideationService)
|
||||
);
|
||||
|
||||
// Convert to feature
|
||||
router.post(
|
||||
'/convert',
|
||||
validatePathParams('projectPath'),
|
||||
createConvertHandler(ideationService, featureLoader)
|
||||
);
|
||||
|
||||
// Guided prompts (no validation needed - static data)
|
||||
router.get('/prompts', createPromptsHandler(ideationService));
|
||||
router.get('/prompts/:category', createPromptsByCategoryHandler(ideationService));
|
||||
|
||||
// Generate suggestions (structured output)
|
||||
router.post(
|
||||
'/suggestions/generate',
|
||||
validatePathParams('projectPath'),
|
||||
createSuggestionsGenerateHandler(ideationService)
|
||||
);
|
||||
|
||||
return router;
|
||||
}
|
||||
49
apps/server/src/routes/ideation/routes/analyze.ts
Normal file
49
apps/server/src/routes/ideation/routes/analyze.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* POST /analyze - Analyze project and generate suggestions
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { IdeationService } from '../../../services/ideation-service.js';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createAnalyzeHandler(ideationService: IdeationService) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath } = req.body as { projectPath: string };
|
||||
|
||||
if (!projectPath) {
|
||||
res.status(400).json({ success: false, error: 'projectPath is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Start analysis - results come via WebSocket events
|
||||
ideationService.analyzeProject(projectPath).catch((error) => {
|
||||
logError(error, 'Analyze project failed (async)');
|
||||
});
|
||||
|
||||
res.json({ success: true, message: 'Analysis started' });
|
||||
} catch (error) {
|
||||
logError(error, 'Analyze project failed');
|
||||
res.status(500).json({ success: false, error: getErrorMessage(error) });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createGetAnalysisHandler(ideationService: IdeationService) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath } = req.body as { projectPath: string };
|
||||
|
||||
if (!projectPath) {
|
||||
res.status(400).json({ success: false, error: 'projectPath is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await ideationService.getCachedAnalysis(projectPath);
|
||||
res.json({ success: true, result });
|
||||
} catch (error) {
|
||||
logError(error, 'Get analysis failed');
|
||||
res.status(500).json({ success: false, error: getErrorMessage(error) });
|
||||
}
|
||||
};
|
||||
}
|
||||
61
apps/server/src/routes/ideation/routes/convert.ts
Normal file
61
apps/server/src/routes/ideation/routes/convert.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* POST /convert - Convert an idea to a feature
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { IdeationService } from '../../../services/ideation-service.js';
|
||||
import type { FeatureLoader } from '../../../services/feature-loader.js';
|
||||
import type { ConvertToFeatureOptions } from '@automaker/types';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createConvertHandler(
|
||||
ideationService: IdeationService,
|
||||
featureLoader: FeatureLoader
|
||||
) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, ideaId, keepIdea, column, dependencies, tags } = req.body as {
|
||||
projectPath: string;
|
||||
ideaId: string;
|
||||
} & ConvertToFeatureOptions;
|
||||
|
||||
if (!projectPath) {
|
||||
res.status(400).json({ success: false, error: 'projectPath is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ideaId) {
|
||||
res.status(400).json({ success: false, error: 'ideaId is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert idea to feature structure
|
||||
const featureData = await ideationService.convertToFeature(projectPath, ideaId);
|
||||
|
||||
// Apply any options from the request
|
||||
if (column) {
|
||||
featureData.status = column;
|
||||
}
|
||||
if (dependencies && dependencies.length > 0) {
|
||||
featureData.dependencies = dependencies;
|
||||
}
|
||||
if (tags && tags.length > 0) {
|
||||
featureData.tags = tags;
|
||||
}
|
||||
|
||||
// Create the feature using FeatureLoader
|
||||
const feature = await featureLoader.create(projectPath, featureData);
|
||||
|
||||
// Delete the idea unless keepIdea is explicitly true
|
||||
if (!keepIdea) {
|
||||
await ideationService.deleteIdea(projectPath, ideaId);
|
||||
}
|
||||
|
||||
// Return featureId as expected by the frontend API interface
|
||||
res.json({ success: true, featureId: feature.id });
|
||||
} catch (error) {
|
||||
logError(error, 'Convert to feature failed');
|
||||
res.status(500).json({ success: false, error: getErrorMessage(error) });
|
||||
}
|
||||
};
|
||||
}
|
||||
43
apps/server/src/routes/ideation/routes/ideas-create.ts
Normal file
43
apps/server/src/routes/ideation/routes/ideas-create.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* POST /ideas/create - Create a new idea
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { IdeationService } from '../../../services/ideation-service.js';
|
||||
import type { CreateIdeaInput } from '@automaker/types';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createIdeasCreateHandler(ideationService: IdeationService) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, idea } = req.body as {
|
||||
projectPath: string;
|
||||
idea: CreateIdeaInput;
|
||||
};
|
||||
|
||||
if (!projectPath) {
|
||||
res.status(400).json({ success: false, error: 'projectPath is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!idea) {
|
||||
res.status(400).json({ success: false, error: 'idea is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!idea.title || !idea.description || !idea.category) {
|
||||
res.status(400).json({
|
||||
success: false,
|
||||
error: 'idea must have title, description, and category',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const created = await ideationService.createIdea(projectPath, idea);
|
||||
res.json({ success: true, idea: created });
|
||||
} catch (error) {
|
||||
logError(error, 'Create idea failed');
|
||||
res.status(500).json({ success: false, error: getErrorMessage(error) });
|
||||
}
|
||||
};
|
||||
}
|
||||
34
apps/server/src/routes/ideation/routes/ideas-delete.ts
Normal file
34
apps/server/src/routes/ideation/routes/ideas-delete.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* POST /ideas/delete - Delete an idea
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { IdeationService } from '../../../services/ideation-service.js';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createIdeasDeleteHandler(ideationService: IdeationService) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, ideaId } = req.body as {
|
||||
projectPath: string;
|
||||
ideaId: string;
|
||||
};
|
||||
|
||||
if (!projectPath) {
|
||||
res.status(400).json({ success: false, error: 'projectPath is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ideaId) {
|
||||
res.status(400).json({ success: false, error: 'ideaId is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
await ideationService.deleteIdea(projectPath, ideaId);
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
logError(error, 'Delete idea failed');
|
||||
res.status(500).json({ success: false, error: getErrorMessage(error) });
|
||||
}
|
||||
};
|
||||
}
|
||||
39
apps/server/src/routes/ideation/routes/ideas-get.ts
Normal file
39
apps/server/src/routes/ideation/routes/ideas-get.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* POST /ideas/get - Get a single idea
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { IdeationService } from '../../../services/ideation-service.js';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createIdeasGetHandler(ideationService: IdeationService) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, ideaId } = req.body as {
|
||||
projectPath: string;
|
||||
ideaId: string;
|
||||
};
|
||||
|
||||
if (!projectPath) {
|
||||
res.status(400).json({ success: false, error: 'projectPath is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ideaId) {
|
||||
res.status(400).json({ success: false, error: 'ideaId is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const idea = await ideationService.getIdea(projectPath, ideaId);
|
||||
if (!idea) {
|
||||
res.status(404).json({ success: false, error: 'Idea not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ success: true, idea });
|
||||
} catch (error) {
|
||||
logError(error, 'Get idea failed');
|
||||
res.status(500).json({ success: false, error: getErrorMessage(error) });
|
||||
}
|
||||
};
|
||||
}
|
||||
26
apps/server/src/routes/ideation/routes/ideas-list.ts
Normal file
26
apps/server/src/routes/ideation/routes/ideas-list.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* POST /ideas/list - List all ideas for a project
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { IdeationService } from '../../../services/ideation-service.js';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createIdeasListHandler(ideationService: IdeationService) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath } = req.body as { projectPath: string };
|
||||
|
||||
if (!projectPath) {
|
||||
res.status(400).json({ success: false, error: 'projectPath is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const ideas = await ideationService.getIdeas(projectPath);
|
||||
res.json({ success: true, ideas });
|
||||
} catch (error) {
|
||||
logError(error, 'List ideas failed');
|
||||
res.status(500).json({ success: false, error: getErrorMessage(error) });
|
||||
}
|
||||
};
|
||||
}
|
||||
46
apps/server/src/routes/ideation/routes/ideas-update.ts
Normal file
46
apps/server/src/routes/ideation/routes/ideas-update.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* POST /ideas/update - Update an idea
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { IdeationService } from '../../../services/ideation-service.js';
|
||||
import type { UpdateIdeaInput } from '@automaker/types';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createIdeasUpdateHandler(ideationService: IdeationService) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, ideaId, updates } = req.body as {
|
||||
projectPath: string;
|
||||
ideaId: string;
|
||||
updates: UpdateIdeaInput;
|
||||
};
|
||||
|
||||
if (!projectPath) {
|
||||
res.status(400).json({ success: false, error: 'projectPath is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ideaId) {
|
||||
res.status(400).json({ success: false, error: 'ideaId is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!updates) {
|
||||
res.status(400).json({ success: false, error: 'updates is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const idea = await ideationService.updateIdea(projectPath, ideaId, updates);
|
||||
if (!idea) {
|
||||
res.status(404).json({ success: false, error: 'Idea not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ success: true, idea });
|
||||
} catch (error) {
|
||||
logError(error, 'Update idea failed');
|
||||
res.status(500).json({ success: false, error: getErrorMessage(error) });
|
||||
}
|
||||
};
|
||||
}
|
||||
42
apps/server/src/routes/ideation/routes/prompts.ts
Normal file
42
apps/server/src/routes/ideation/routes/prompts.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* GET /prompts - Get all guided prompts
|
||||
* GET /prompts/:category - Get prompts for a specific category
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { IdeationService } from '../../../services/ideation-service.js';
|
||||
import type { IdeaCategory } from '@automaker/types';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createPromptsHandler(ideationService: IdeationService) {
|
||||
return async (_req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const prompts = ideationService.getAllPrompts();
|
||||
const categories = ideationService.getPromptCategories();
|
||||
res.json({ success: true, prompts, categories });
|
||||
} catch (error) {
|
||||
logError(error, 'Get prompts failed');
|
||||
res.status(500).json({ success: false, error: getErrorMessage(error) });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createPromptsByCategoryHandler(ideationService: IdeationService) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { category } = req.params as { category: string };
|
||||
|
||||
const validCategories: IdeaCategory[] = ['feature', 'ux-ui', 'dx', 'growth', 'technical'];
|
||||
if (!validCategories.includes(category as IdeaCategory)) {
|
||||
res.status(400).json({ success: false, error: 'Invalid category' });
|
||||
return;
|
||||
}
|
||||
|
||||
const prompts = ideationService.getPromptsByCategory(category as IdeaCategory);
|
||||
res.json({ success: true, prompts });
|
||||
} catch (error) {
|
||||
logError(error, 'Get prompts by category failed');
|
||||
res.status(500).json({ success: false, error: getErrorMessage(error) });
|
||||
}
|
||||
};
|
||||
}
|
||||
45
apps/server/src/routes/ideation/routes/session-get.ts
Normal file
45
apps/server/src/routes/ideation/routes/session-get.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* POST /session/get - Get an ideation session with messages
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { IdeationService } from '../../../services/ideation-service.js';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createSessionGetHandler(ideationService: IdeationService) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, sessionId } = req.body as {
|
||||
projectPath: string;
|
||||
sessionId: string;
|
||||
};
|
||||
|
||||
if (!projectPath) {
|
||||
res.status(400).json({ success: false, error: 'projectPath is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sessionId) {
|
||||
res.status(400).json({ success: false, error: 'sessionId is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const session = await ideationService.getSession(projectPath, sessionId);
|
||||
if (!session) {
|
||||
res.status(404).json({ success: false, error: 'Session not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
const isRunning = ideationService.isSessionRunning(sessionId);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
session: { ...session, isRunning },
|
||||
messages: session.messages,
|
||||
});
|
||||
} catch (error) {
|
||||
logError(error, 'Get session failed');
|
||||
res.status(500).json({ success: false, error: getErrorMessage(error) });
|
||||
}
|
||||
};
|
||||
}
|
||||
40
apps/server/src/routes/ideation/routes/session-message.ts
Normal file
40
apps/server/src/routes/ideation/routes/session-message.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* POST /session/message - Send a message in an ideation session
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { IdeationService } from '../../../services/ideation-service.js';
|
||||
import type { SendMessageOptions } from '@automaker/types';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createSessionMessageHandler(ideationService: IdeationService) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { sessionId, message, options } = req.body as {
|
||||
sessionId: string;
|
||||
message: string;
|
||||
options?: SendMessageOptions;
|
||||
};
|
||||
|
||||
if (!sessionId) {
|
||||
res.status(400).json({ success: false, error: 'sessionId is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!message) {
|
||||
res.status(400).json({ success: false, error: 'message is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
// This is async but we don't await - responses come via WebSocket
|
||||
ideationService.sendMessage(sessionId, message, options).catch((error) => {
|
||||
logError(error, 'Send message failed (async)');
|
||||
});
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
logError(error, 'Send message failed');
|
||||
res.status(500).json({ success: false, error: getErrorMessage(error) });
|
||||
}
|
||||
};
|
||||
}
|
||||
30
apps/server/src/routes/ideation/routes/session-start.ts
Normal file
30
apps/server/src/routes/ideation/routes/session-start.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* POST /session/start - Start a new ideation session
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { IdeationService } from '../../../services/ideation-service.js';
|
||||
import type { StartSessionOptions } from '@automaker/types';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createSessionStartHandler(ideationService: IdeationService) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, options } = req.body as {
|
||||
projectPath: string;
|
||||
options?: StartSessionOptions;
|
||||
};
|
||||
|
||||
if (!projectPath) {
|
||||
res.status(400).json({ success: false, error: 'projectPath is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
const session = await ideationService.startSession(projectPath, options);
|
||||
res.json({ success: true, session });
|
||||
} catch (error) {
|
||||
logError(error, 'Start session failed');
|
||||
res.status(500).json({ success: false, error: getErrorMessage(error) });
|
||||
}
|
||||
};
|
||||
}
|
||||
26
apps/server/src/routes/ideation/routes/session-stop.ts
Normal file
26
apps/server/src/routes/ideation/routes/session-stop.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* POST /session/stop - Stop an ideation session
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { IdeationService } from '../../../services/ideation-service.js';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
export function createSessionStopHandler(ideationService: IdeationService) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { sessionId } = req.body as { sessionId: string };
|
||||
|
||||
if (!sessionId) {
|
||||
res.status(400).json({ success: false, error: 'sessionId is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
await ideationService.stopSession(sessionId);
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
logError(error, 'Stop session failed');
|
||||
res.status(500).json({ success: false, error: getErrorMessage(error) });
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Generate suggestions route - Returns structured AI suggestions for a prompt
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { IdeationService } from '../../../services/ideation-service.js';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
|
||||
const logger = createLogger('ideation:suggestions-generate');
|
||||
|
||||
export function createSuggestionsGenerateHandler(ideationService: IdeationService) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, promptId, category, count } = req.body;
|
||||
|
||||
if (!projectPath) {
|
||||
res.status(400).json({ success: false, error: 'projectPath is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!promptId) {
|
||||
res.status(400).json({ success: false, error: 'promptId is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!category) {
|
||||
res.status(400).json({ success: false, error: 'category is required' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Default to 10 suggestions, allow 1-20
|
||||
const suggestionCount = Math.min(Math.max(count || 10, 1), 20);
|
||||
|
||||
logger.info(`Generating ${suggestionCount} suggestions for prompt: ${promptId}`);
|
||||
|
||||
const suggestions = await ideationService.generateSuggestions(
|
||||
projectPath,
|
||||
promptId,
|
||||
category,
|
||||
suggestionCount
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
suggestions,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Failed to generate suggestions:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: (error as Error).message,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
1679
apps/server/src/services/ideation-service.ts
Normal file
1679
apps/server/src/services/ideation-service.ts
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user