Files
automaker/apps/server/src/services/auto-mode/project-analyzer.ts
Kacper 85dc631250 refactor: consolidate shared packages and eliminate code duplication
- Update 26+ files to import secureFs from @automaker/platform
- Create shared type files: github.ts, worktree.ts, claude.ts in libs/types
- Create exec-utils.ts for cross-platform shell execution
- Delete redundant wrapper files: secure-fs.ts, stream-processor.ts, enhancement-prompts.ts
- Update GitHub routes to use createLogError pattern
- Add isENOENT helper to routes/common.ts
- Fix test imports to use @automaker/prompts and @automaker/platform

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 00:31:23 +01:00

110 lines
3.4 KiB
TypeScript

/**
* Project Analyzer - Analyzes project structure and context
*
* Provides project analysis functionality using Claude to understand
* codebase architecture, patterns, and conventions.
*/
import type { ExecuteOptions } from '@automaker/types';
import { createLogger, classifyError, processStream } from '@automaker/utils';
import { resolveModelString, DEFAULT_MODELS } from '@automaker/model-resolver';
import { getAutomakerDir, secureFs } from '@automaker/platform';
import { ProviderFactory } from '../../providers/provider-factory.js';
import { validateWorkingDirectory } from '../../lib/sdk-options.js';
import path from 'path';
import type { EventEmitter } from '../../lib/events.js';
const logger = createLogger('ProjectAnalyzer');
const ANALYSIS_PROMPT = `Analyze this project and provide a summary of:
1. Project structure and architecture
2. Main technologies and frameworks used
3. Key components and their responsibilities
4. Build and test commands
5. Any existing conventions or patterns
Format your response as a structured markdown document.`;
export class ProjectAnalyzer {
private events: EventEmitter;
constructor(events: EventEmitter) {
this.events = events;
}
/**
* Analyze project to gather context
*/
async analyze(projectPath: string): Promise<void> {
validateWorkingDirectory(projectPath);
const abortController = new AbortController();
const analysisFeatureId = `analysis-${Date.now()}`;
this.emitEvent('auto_mode_feature_start', {
featureId: analysisFeatureId,
projectPath,
feature: {
id: analysisFeatureId,
title: 'Project Analysis',
description: 'Analyzing project structure',
},
});
try {
const analysisModel = resolveModelString(undefined, DEFAULT_MODELS.claude);
const provider = ProviderFactory.getProviderForModel(analysisModel);
const options: ExecuteOptions = {
prompt: ANALYSIS_PROMPT,
model: analysisModel,
maxTurns: 5,
cwd: projectPath,
allowedTools: ['Read', 'Glob', 'Grep'],
abortController,
};
const stream = provider.executeQuery(options);
let analysisResult = '';
const result = await processStream(stream, {
onText: (text) => {
analysisResult += text;
this.emitEvent('auto_mode_progress', {
featureId: analysisFeatureId,
content: text,
projectPath,
});
},
});
analysisResult = result.text || analysisResult;
// Save analysis
const automakerDir = getAutomakerDir(projectPath);
const analysisPath = path.join(automakerDir, 'project-analysis.md');
await secureFs.mkdir(automakerDir, { recursive: true });
await secureFs.writeFile(analysisPath, analysisResult);
this.emitEvent('auto_mode_feature_complete', {
featureId: analysisFeatureId,
passes: true,
message: 'Project analysis completed',
projectPath,
});
} catch (error) {
const errorInfo = classifyError(error);
this.emitEvent('auto_mode_error', {
featureId: analysisFeatureId,
error: errorInfo.message,
errorType: errorInfo.type,
projectPath,
});
}
}
private emitEvent(eventType: string, data: Record<string, unknown>): void {
this.events.emit('auto-mode:event', { type: eventType, ...data });
}
}