mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-30 06:12:03 +00:00
feat: integrate settings service for auto-load CLAUDE.md functionality
- Updated API routes to accept an optional settings service for loading the autoLoadClaudeMd setting. - Introduced a new settings helper utility for retrieving project-specific settings. - Enhanced feature generation and spec generation processes to utilize the autoLoadClaudeMd setting. - Refactored relevant route handlers to support the new settings integration across various endpoints.
This commit is contained in:
@@ -149,17 +149,17 @@ app.use('/api/enhance-prompt', createEnhancePromptRoutes());
|
||||
app.use('/api/worktree', createWorktreeRoutes());
|
||||
app.use('/api/git', createGitRoutes());
|
||||
app.use('/api/setup', createSetupRoutes());
|
||||
app.use('/api/suggestions', createSuggestionsRoutes(events));
|
||||
app.use('/api/suggestions', createSuggestionsRoutes(events, settingsService));
|
||||
app.use('/api/models', createModelsRoutes());
|
||||
app.use('/api/spec-regeneration', createSpecRegenerationRoutes(events));
|
||||
app.use('/api/spec-regeneration', createSpecRegenerationRoutes(events, settingsService));
|
||||
app.use('/api/running-agents', createRunningAgentsRoutes(autoModeService));
|
||||
app.use('/api/workspace', createWorkspaceRoutes());
|
||||
app.use('/api/templates', createTemplatesRoutes());
|
||||
app.use('/api/terminal', createTerminalRoutes());
|
||||
app.use('/api/settings', createSettingsRoutes(settingsService));
|
||||
app.use('/api/claude', createClaudeRoutes(claudeUsageService));
|
||||
app.use('/api/github', createGitHubRoutes(events));
|
||||
app.use('/api/context', createContextRoutes());
|
||||
app.use('/api/github', createGitHubRoutes(events, settingsService));
|
||||
app.use('/api/context', createContextRoutes(settingsService));
|
||||
|
||||
// Create HTTP server
|
||||
const server = createServer(app);
|
||||
|
||||
45
apps/server/src/lib/settings-helpers.ts
Normal file
45
apps/server/src/lib/settings-helpers.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Helper utilities for loading settings across different parts of the server
|
||||
*/
|
||||
|
||||
import type { SettingsService } from '../services/settings-service.js';
|
||||
|
||||
/**
|
||||
* Get the autoLoadClaudeMd setting, with project settings taking precedence over global.
|
||||
* Returns false if settings service is not available.
|
||||
*
|
||||
* @param projectPath - Path to the project
|
||||
* @param settingsService - Optional settings service instance
|
||||
* @param logPrefix - Prefix for log messages (e.g., '[DescribeImage]')
|
||||
* @returns Promise resolving to the autoLoadClaudeMd setting value
|
||||
*/
|
||||
export async function getAutoLoadClaudeMdSetting(
|
||||
projectPath: string,
|
||||
settingsService?: SettingsService,
|
||||
logPrefix = '[SettingsHelper]'
|
||||
): Promise<boolean> {
|
||||
if (!settingsService) {
|
||||
console.log(`${logPrefix} SettingsService not available, autoLoadClaudeMd disabled`);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// Check project settings first (takes precedence)
|
||||
const projectSettings = await settingsService.getProjectSettings(projectPath);
|
||||
if (projectSettings.autoLoadClaudeMd !== undefined) {
|
||||
console.log(
|
||||
`${logPrefix} autoLoadClaudeMd from project settings: ${projectSettings.autoLoadClaudeMd}`
|
||||
);
|
||||
return projectSettings.autoLoadClaudeMd;
|
||||
}
|
||||
|
||||
// Fall back to global settings
|
||||
const globalSettings = await settingsService.getGlobalSettings();
|
||||
const result = globalSettings.autoLoadClaudeMd ?? false;
|
||||
console.log(`${logPrefix} autoLoadClaudeMd from global settings: ${result}`);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error(`${logPrefix} Failed to load autoLoadClaudeMd setting:`, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import { createFeatureGenerationOptions } from '../../lib/sdk-options.js';
|
||||
import { logAuthStatus } from './common.js';
|
||||
import { parseAndCreateFeatures } from './parse-and-create-features.js';
|
||||
import { getAppSpecPath } from '@automaker/platform';
|
||||
import type { SettingsService } from '../../services/settings-service.js';
|
||||
import { getAutoLoadClaudeMdSetting } from '../../lib/settings-helpers.js';
|
||||
|
||||
const logger = createLogger('SpecRegeneration');
|
||||
|
||||
@@ -19,7 +21,8 @@ export async function generateFeaturesFromSpec(
|
||||
projectPath: string,
|
||||
events: EventEmitter,
|
||||
abortController: AbortController,
|
||||
maxFeatures?: number
|
||||
maxFeatures?: number,
|
||||
settingsService?: SettingsService
|
||||
): Promise<void> {
|
||||
const featureCount = maxFeatures ?? DEFAULT_MAX_FEATURES;
|
||||
logger.debug('========== generateFeaturesFromSpec() started ==========');
|
||||
@@ -91,9 +94,17 @@ IMPORTANT: Do not ask for clarification. The specification is provided above. Ge
|
||||
projectPath: projectPath,
|
||||
});
|
||||
|
||||
// Load autoLoadClaudeMd setting
|
||||
const autoLoadClaudeMd = await getAutoLoadClaudeMdSetting(
|
||||
projectPath,
|
||||
settingsService,
|
||||
'[FeatureGeneration]'
|
||||
);
|
||||
|
||||
const options = createFeatureGenerationOptions({
|
||||
cwd: projectPath,
|
||||
abortController,
|
||||
autoLoadClaudeMd,
|
||||
});
|
||||
|
||||
logger.debug('SDK Options:', JSON.stringify(options, null, 2));
|
||||
|
||||
@@ -17,6 +17,8 @@ import { createSpecGenerationOptions } from '../../lib/sdk-options.js';
|
||||
import { logAuthStatus } from './common.js';
|
||||
import { generateFeaturesFromSpec } from './generate-features-from-spec.js';
|
||||
import { ensureAutomakerDir, getAppSpecPath } from '@automaker/platform';
|
||||
import type { SettingsService } from '../../services/settings-service.js';
|
||||
import { getAutoLoadClaudeMdSetting } from '../../lib/settings-helpers.js';
|
||||
|
||||
const logger = createLogger('SpecRegeneration');
|
||||
|
||||
@@ -27,7 +29,8 @@ export async function generateSpec(
|
||||
abortController: AbortController,
|
||||
generateFeatures?: boolean,
|
||||
analyzeProject?: boolean,
|
||||
maxFeatures?: number
|
||||
maxFeatures?: number,
|
||||
settingsService?: SettingsService
|
||||
): Promise<void> {
|
||||
logger.info('========== generateSpec() started ==========');
|
||||
logger.info('projectPath:', projectPath);
|
||||
@@ -83,9 +86,17 @@ ${getStructuredSpecPromptInstruction()}`;
|
||||
content: 'Starting spec generation...\n',
|
||||
});
|
||||
|
||||
// Load autoLoadClaudeMd setting
|
||||
const autoLoadClaudeMd = await getAutoLoadClaudeMdSetting(
|
||||
projectPath,
|
||||
settingsService,
|
||||
'[SpecRegeneration]'
|
||||
);
|
||||
|
||||
const options = createSpecGenerationOptions({
|
||||
cwd: projectPath,
|
||||
abortController,
|
||||
autoLoadClaudeMd,
|
||||
outputFormat: {
|
||||
type: 'json_schema',
|
||||
schema: specOutputSchema,
|
||||
@@ -269,7 +280,13 @@ ${getStructuredSpecPromptInstruction()}`;
|
||||
// Create a new abort controller for feature generation
|
||||
const featureAbortController = new AbortController();
|
||||
try {
|
||||
await generateFeaturesFromSpec(projectPath, events, featureAbortController, maxFeatures);
|
||||
await generateFeaturesFromSpec(
|
||||
projectPath,
|
||||
events,
|
||||
featureAbortController,
|
||||
maxFeatures,
|
||||
settingsService
|
||||
);
|
||||
// Final completion will be emitted by generateFeaturesFromSpec -> parseAndCreateFeatures
|
||||
} catch (featureError) {
|
||||
logger.error('Feature generation failed:', featureError);
|
||||
|
||||
@@ -9,13 +9,17 @@ import { createGenerateHandler } from './routes/generate.js';
|
||||
import { createGenerateFeaturesHandler } from './routes/generate-features.js';
|
||||
import { createStopHandler } from './routes/stop.js';
|
||||
import { createStatusHandler } from './routes/status.js';
|
||||
import type { SettingsService } from '../../services/settings-service.js';
|
||||
|
||||
export function createSpecRegenerationRoutes(events: EventEmitter): Router {
|
||||
export function createSpecRegenerationRoutes(
|
||||
events: EventEmitter,
|
||||
settingsService?: SettingsService
|
||||
): Router {
|
||||
const router = Router();
|
||||
|
||||
router.post('/create', createCreateHandler(events));
|
||||
router.post('/generate', createGenerateHandler(events));
|
||||
router.post('/generate-features', createGenerateFeaturesHandler(events));
|
||||
router.post('/generate', createGenerateHandler(events, settingsService));
|
||||
router.post('/generate-features', createGenerateFeaturesHandler(events, settingsService));
|
||||
router.post('/stop', createStopHandler());
|
||||
router.get('/status', createStatusHandler());
|
||||
|
||||
|
||||
@@ -13,10 +13,14 @@ import {
|
||||
getErrorMessage,
|
||||
} from '../common.js';
|
||||
import { generateFeaturesFromSpec } from '../generate-features-from-spec.js';
|
||||
import type { SettingsService } from '../../../services/settings-service.js';
|
||||
|
||||
const logger = createLogger('SpecRegeneration');
|
||||
|
||||
export function createGenerateFeaturesHandler(events: EventEmitter) {
|
||||
export function createGenerateFeaturesHandler(
|
||||
events: EventEmitter,
|
||||
settingsService?: SettingsService
|
||||
) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
logger.info('========== /generate-features endpoint called ==========');
|
||||
logger.debug('Request body:', JSON.stringify(req.body, null, 2));
|
||||
@@ -49,7 +53,7 @@ export function createGenerateFeaturesHandler(events: EventEmitter) {
|
||||
setRunningState(true, abortController);
|
||||
logger.info('Starting background feature generation task...');
|
||||
|
||||
generateFeaturesFromSpec(projectPath, events, abortController, maxFeatures)
|
||||
generateFeaturesFromSpec(projectPath, events, abortController, maxFeatures, settingsService)
|
||||
.catch((error) => {
|
||||
logError(error, 'Feature generation failed with error');
|
||||
events.emit('spec-regeneration:event', {
|
||||
|
||||
@@ -13,10 +13,11 @@ import {
|
||||
getErrorMessage,
|
||||
} from '../common.js';
|
||||
import { generateSpec } from '../generate-spec.js';
|
||||
import type { SettingsService } from '../../../services/settings-service.js';
|
||||
|
||||
const logger = createLogger('SpecRegeneration');
|
||||
|
||||
export function createGenerateHandler(events: EventEmitter) {
|
||||
export function createGenerateHandler(events: EventEmitter, settingsService?: SettingsService) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
logger.info('========== /generate endpoint called ==========');
|
||||
logger.debug('Request body:', JSON.stringify(req.body, null, 2));
|
||||
@@ -67,7 +68,8 @@ export function createGenerateHandler(events: EventEmitter) {
|
||||
abortController,
|
||||
generateFeatures,
|
||||
analyzeProject,
|
||||
maxFeatures
|
||||
maxFeatures,
|
||||
settingsService
|
||||
)
|
||||
.catch((error) => {
|
||||
logError(error, 'Generation failed with error');
|
||||
|
||||
@@ -8,17 +8,19 @@
|
||||
import { Router } from 'express';
|
||||
import { createDescribeImageHandler } from './routes/describe-image.js';
|
||||
import { createDescribeFileHandler } from './routes/describe-file.js';
|
||||
import type { SettingsService } from '../../services/settings-service.js';
|
||||
|
||||
/**
|
||||
* Create the context router
|
||||
*
|
||||
* @param settingsService - Optional settings service for loading autoLoadClaudeMd setting
|
||||
* @returns Express router with context endpoints
|
||||
*/
|
||||
export function createContextRoutes(): Router {
|
||||
export function createContextRoutes(settingsService?: SettingsService): Router {
|
||||
const router = Router();
|
||||
|
||||
router.post('/describe-image', createDescribeImageHandler());
|
||||
router.post('/describe-file', createDescribeFileHandler());
|
||||
router.post('/describe-image', createDescribeImageHandler(settingsService));
|
||||
router.post('/describe-file', createDescribeFileHandler(settingsService));
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ import { PathNotAllowedError } from '@automaker/platform';
|
||||
import { createCustomOptions } from '../../../lib/sdk-options.js';
|
||||
import * as secureFs from '../../../lib/secure-fs.js';
|
||||
import * as path from 'path';
|
||||
import type { SettingsService } from '../../../services/settings-service.js';
|
||||
import { getAutoLoadClaudeMdSetting } from '../../../lib/settings-helpers.js';
|
||||
|
||||
const logger = createLogger('DescribeFile');
|
||||
|
||||
@@ -72,9 +74,12 @@ async function extractTextFromStream(
|
||||
/**
|
||||
* Create the describe-file request handler
|
||||
*
|
||||
* @param settingsService - Optional settings service for loading autoLoadClaudeMd setting
|
||||
* @returns Express request handler for file description
|
||||
*/
|
||||
export function createDescribeFileHandler(): (req: Request, res: Response) => Promise<void> {
|
||||
export function createDescribeFileHandler(
|
||||
settingsService?: SettingsService
|
||||
): (req: Request, res: Response) => Promise<void> {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { filePath } = req.body as DescribeFileRequestBody;
|
||||
@@ -165,6 +170,13 @@ File: ${fileName}${truncated ? ' (truncated)' : ''}`;
|
||||
// Use the file's directory as the working directory
|
||||
const cwd = path.dirname(resolvedPath);
|
||||
|
||||
// Load autoLoadClaudeMd setting
|
||||
const autoLoadClaudeMd = await getAutoLoadClaudeMdSetting(
|
||||
cwd,
|
||||
settingsService,
|
||||
'[DescribeFile]'
|
||||
);
|
||||
|
||||
// Use centralized SDK options with proper cwd validation
|
||||
// No tools needed since we're passing file content directly
|
||||
const sdkOptions = createCustomOptions({
|
||||
@@ -172,6 +184,7 @@ File: ${fileName}${truncated ? ' (truncated)' : ''}`;
|
||||
model: CLAUDE_MODEL_MAP.haiku,
|
||||
maxTurns: 1,
|
||||
allowedTools: [],
|
||||
autoLoadClaudeMd,
|
||||
sandbox: { enabled: true, autoAllowBashIfSandboxed: true },
|
||||
});
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ import { CLAUDE_MODEL_MAP } from '@automaker/types';
|
||||
import { createCustomOptions } from '../../../lib/sdk-options.js';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import type { SettingsService } from '../../../services/settings-service.js';
|
||||
import { getAutoLoadClaudeMdSetting } from '../../../lib/settings-helpers.js';
|
||||
|
||||
const logger = createLogger('DescribeImage');
|
||||
|
||||
@@ -226,9 +228,12 @@ async function extractTextFromStream(
|
||||
* Uses Claude SDK query with multi-part content blocks to include the image (base64),
|
||||
* matching the agent runner behavior.
|
||||
*
|
||||
* @param settingsService - Optional settings service for loading autoLoadClaudeMd setting
|
||||
* @returns Express request handler for image description
|
||||
*/
|
||||
export function createDescribeImageHandler(): (req: Request, res: Response) => Promise<void> {
|
||||
export function createDescribeImageHandler(
|
||||
settingsService?: SettingsService
|
||||
): (req: Request, res: Response) => Promise<void> {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
const requestId = `describe-image-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
||||
const startedAt = Date.now();
|
||||
@@ -325,12 +330,20 @@ export function createDescribeImageHandler(): (req: Request, res: Response) => P
|
||||
const cwd = path.dirname(actualPath);
|
||||
logger.info(`[${requestId}] Using cwd=${cwd}`);
|
||||
|
||||
// Load autoLoadClaudeMd setting
|
||||
const autoLoadClaudeMd = await getAutoLoadClaudeMdSetting(
|
||||
cwd,
|
||||
settingsService,
|
||||
'[DescribeImage]'
|
||||
);
|
||||
|
||||
// Use the same centralized option builder used across the server (validates cwd)
|
||||
const sdkOptions = createCustomOptions({
|
||||
cwd,
|
||||
model: CLAUDE_MODEL_MAP.haiku,
|
||||
maxTurns: 1,
|
||||
allowedTools: [],
|
||||
autoLoadClaudeMd,
|
||||
sandbox: { enabled: true, autoAllowBashIfSandboxed: true },
|
||||
});
|
||||
|
||||
|
||||
@@ -16,8 +16,12 @@ import {
|
||||
createDeleteValidationHandler,
|
||||
createMarkViewedHandler,
|
||||
} from './routes/validation-endpoints.js';
|
||||
import type { SettingsService } from '../../services/settings-service.js';
|
||||
|
||||
export function createGitHubRoutes(events: EventEmitter): Router {
|
||||
export function createGitHubRoutes(
|
||||
events: EventEmitter,
|
||||
settingsService?: SettingsService
|
||||
): Router {
|
||||
const router = Router();
|
||||
|
||||
router.post('/check-remote', validatePathParams('projectPath'), createCheckGitHubRemoteHandler());
|
||||
@@ -26,7 +30,7 @@ export function createGitHubRoutes(events: EventEmitter): Router {
|
||||
router.post(
|
||||
'/validate-issue',
|
||||
validatePathParams('projectPath'),
|
||||
createValidateIssueHandler(events)
|
||||
createValidateIssueHandler(events, settingsService)
|
||||
);
|
||||
|
||||
// Validation management endpoints
|
||||
|
||||
@@ -23,6 +23,8 @@ import {
|
||||
logError,
|
||||
logger,
|
||||
} from './validation-common.js';
|
||||
import type { SettingsService } from '../../../services/settings-service.js';
|
||||
import { getAutoLoadClaudeMdSetting } from '../../../lib/settings-helpers.js';
|
||||
|
||||
/** Valid model values for validation */
|
||||
const VALID_MODELS: readonly AgentModel[] = ['opus', 'sonnet', 'haiku'] as const;
|
||||
@@ -54,7 +56,8 @@ async function runValidation(
|
||||
issueLabels: string[] | undefined,
|
||||
model: AgentModel,
|
||||
events: EventEmitter,
|
||||
abortController: AbortController
|
||||
abortController: AbortController,
|
||||
settingsService?: SettingsService
|
||||
): Promise<void> {
|
||||
// Emit start event
|
||||
const startEvent: IssueValidationEvent = {
|
||||
@@ -76,12 +79,20 @@ async function runValidation(
|
||||
// Build the prompt
|
||||
const prompt = buildValidationPrompt(issueNumber, issueTitle, issueBody, issueLabels);
|
||||
|
||||
// Load autoLoadClaudeMd setting
|
||||
const autoLoadClaudeMd = await getAutoLoadClaudeMdSetting(
|
||||
projectPath,
|
||||
settingsService,
|
||||
'[ValidateIssue]'
|
||||
);
|
||||
|
||||
// Create SDK options with structured output and abort controller
|
||||
const options = createSuggestionsOptions({
|
||||
cwd: projectPath,
|
||||
model,
|
||||
systemPrompt: ISSUE_VALIDATION_SYSTEM_PROMPT,
|
||||
abortController,
|
||||
autoLoadClaudeMd,
|
||||
outputFormat: {
|
||||
type: 'json_schema',
|
||||
schema: issueValidationSchema as Record<string, unknown>,
|
||||
@@ -190,7 +201,10 @@ async function runValidation(
|
||||
* - System prompt guiding the validation process
|
||||
* - Async execution with event emission
|
||||
*/
|
||||
export function createValidateIssueHandler(events: EventEmitter) {
|
||||
export function createValidateIssueHandler(
|
||||
events: EventEmitter,
|
||||
settingsService?: SettingsService
|
||||
) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const {
|
||||
@@ -256,7 +270,8 @@ export function createValidateIssueHandler(events: EventEmitter) {
|
||||
issueLabels,
|
||||
model,
|
||||
events,
|
||||
abortController
|
||||
abortController,
|
||||
settingsService
|
||||
)
|
||||
.catch((error) => {
|
||||
// Error is already handled inside runValidation (event emitted)
|
||||
|
||||
@@ -9,6 +9,8 @@ import { createSuggestionsOptions } from '../../lib/sdk-options.js';
|
||||
import { FeatureLoader } from '../../services/feature-loader.js';
|
||||
import { getAppSpecPath } from '@automaker/platform';
|
||||
import * as secureFs from '../../lib/secure-fs.js';
|
||||
import type { SettingsService } from '../../services/settings-service.js';
|
||||
import { getAutoLoadClaudeMdSetting } from '../../lib/settings-helpers.js';
|
||||
|
||||
const logger = createLogger('Suggestions');
|
||||
|
||||
@@ -125,7 +127,8 @@ export async function generateSuggestions(
|
||||
projectPath: string,
|
||||
suggestionType: string,
|
||||
events: EventEmitter,
|
||||
abortController: AbortController
|
||||
abortController: AbortController,
|
||||
settingsService?: SettingsService
|
||||
): Promise<void> {
|
||||
const typePrompts: Record<string, string> = {
|
||||
features: 'Analyze this project and suggest new features that would add value.',
|
||||
@@ -154,9 +157,17 @@ The response will be automatically formatted as structured JSON.`;
|
||||
// Don't send initial message - let the agent output speak for itself
|
||||
// The first agent message will be captured as an info entry
|
||||
|
||||
// Load autoLoadClaudeMd setting
|
||||
const autoLoadClaudeMd = await getAutoLoadClaudeMdSetting(
|
||||
projectPath,
|
||||
settingsService,
|
||||
'[Suggestions]'
|
||||
);
|
||||
|
||||
const options = createSuggestionsOptions({
|
||||
cwd: projectPath,
|
||||
abortController,
|
||||
autoLoadClaudeMd,
|
||||
outputFormat: {
|
||||
type: 'json_schema',
|
||||
schema: suggestionsSchema,
|
||||
|
||||
@@ -8,11 +8,19 @@ import { validatePathParams } from '../../middleware/validate-paths.js';
|
||||
import { createGenerateHandler } from './routes/generate.js';
|
||||
import { createStopHandler } from './routes/stop.js';
|
||||
import { createStatusHandler } from './routes/status.js';
|
||||
import type { SettingsService } from '../../services/settings-service.js';
|
||||
|
||||
export function createSuggestionsRoutes(events: EventEmitter): Router {
|
||||
export function createSuggestionsRoutes(
|
||||
events: EventEmitter,
|
||||
settingsService?: SettingsService
|
||||
): Router {
|
||||
const router = Router();
|
||||
|
||||
router.post('/generate', validatePathParams('projectPath'), createGenerateHandler(events));
|
||||
router.post(
|
||||
'/generate',
|
||||
validatePathParams('projectPath'),
|
||||
createGenerateHandler(events, settingsService)
|
||||
);
|
||||
router.post('/stop', createStopHandler());
|
||||
router.get('/status', createStatusHandler());
|
||||
|
||||
|
||||
@@ -7,10 +7,11 @@ import type { EventEmitter } from '../../../lib/events.js';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { getSuggestionsStatus, setRunningState, getErrorMessage, logError } from '../common.js';
|
||||
import { generateSuggestions } from '../generate-suggestions.js';
|
||||
import type { SettingsService } from '../../../services/settings-service.js';
|
||||
|
||||
const logger = createLogger('Suggestions');
|
||||
|
||||
export function createGenerateHandler(events: EventEmitter) {
|
||||
export function createGenerateHandler(events: EventEmitter, settingsService?: SettingsService) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, suggestionType = 'features' } = req.body as {
|
||||
@@ -37,7 +38,7 @@ export function createGenerateHandler(events: EventEmitter) {
|
||||
setRunningState(true, abortController);
|
||||
|
||||
// Start generation in background
|
||||
generateSuggestions(projectPath, suggestionType, events, abortController)
|
||||
generateSuggestions(projectPath, suggestionType, events, abortController, settingsService)
|
||||
.catch((error) => {
|
||||
logError(error, 'Generate suggestions failed (background)');
|
||||
events.emit('suggestions:event', {
|
||||
|
||||
@@ -25,7 +25,11 @@ import { promisify } from 'util';
|
||||
import path from 'path';
|
||||
import * as secureFs from '../lib/secure-fs.js';
|
||||
import type { EventEmitter } from '../lib/events.js';
|
||||
import { createAutoModeOptions, validateWorkingDirectory } from '../lib/sdk-options.js';
|
||||
import {
|
||||
createAutoModeOptions,
|
||||
createCustomOptions,
|
||||
validateWorkingDirectory,
|
||||
} from '../lib/sdk-options.js';
|
||||
import { FeatureLoader } from './feature-loader.js';
|
||||
import type { SettingsService } from './settings-service.js';
|
||||
|
||||
@@ -1068,11 +1072,6 @@ Address the follow-up instructions above. Review the previous work and make the
|
||||
* Analyze project to gather context
|
||||
*/
|
||||
async analyzeProject(projectPath: string): Promise<void> {
|
||||
// Validate project path before proceeding
|
||||
// This is called here because analyzeProject builds ExecuteOptions directly
|
||||
// without using a factory function from sdk-options.ts
|
||||
validateWorkingDirectory(projectPath);
|
||||
|
||||
const abortController = new AbortController();
|
||||
|
||||
const analysisFeatureId = `analysis-${Date.now()}`;
|
||||
@@ -1100,13 +1099,27 @@ Format your response as a structured markdown document.`;
|
||||
const analysisModel = resolveModelString(undefined, DEFAULT_MODELS.claude);
|
||||
const provider = ProviderFactory.getProviderForModel(analysisModel);
|
||||
|
||||
const options: ExecuteOptions = {
|
||||
prompt,
|
||||
// Load autoLoadClaudeMd setting
|
||||
const autoLoadClaudeMd = await this.getAutoLoadClaudeMdSetting(projectPath);
|
||||
|
||||
// Use createCustomOptions for centralized SDK configuration with CLAUDE.md support
|
||||
const sdkOptions = createCustomOptions({
|
||||
cwd: projectPath,
|
||||
model: analysisModel,
|
||||
maxTurns: 5,
|
||||
cwd: projectPath,
|
||||
allowedTools: ['Read', 'Glob', 'Grep'],
|
||||
abortController,
|
||||
autoLoadClaudeMd,
|
||||
});
|
||||
|
||||
const options: ExecuteOptions = {
|
||||
prompt,
|
||||
model: sdkOptions.model ?? analysisModel,
|
||||
cwd: sdkOptions.cwd ?? projectPath,
|
||||
maxTurns: sdkOptions.maxTurns,
|
||||
allowedTools: sdkOptions.allowedTools as string[],
|
||||
abortController,
|
||||
settingSources: sdkOptions.settingSources,
|
||||
};
|
||||
|
||||
const stream = provider.executeQuery(options);
|
||||
|
||||
@@ -19,6 +19,15 @@ export interface ConversationMessage {
|
||||
content: string | Array<{ type: string; text?: string; source?: object }>;
|
||||
}
|
||||
|
||||
/**
|
||||
* System prompt preset configuration for CLAUDE.md auto-loading
|
||||
*/
|
||||
export interface SystemPromptPreset {
|
||||
type: 'preset';
|
||||
preset: 'claude_code';
|
||||
append?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for executing a query via a provider
|
||||
*/
|
||||
@@ -26,13 +35,14 @@ export interface ExecuteOptions {
|
||||
prompt: string | Array<{ type: string; text?: string; source?: object }>;
|
||||
model: string;
|
||||
cwd: string;
|
||||
systemPrompt?: string;
|
||||
systemPrompt?: string | SystemPromptPreset;
|
||||
maxTurns?: number;
|
||||
allowedTools?: string[];
|
||||
mcpServers?: Record<string, unknown>;
|
||||
abortController?: AbortController;
|
||||
conversationHistory?: ConversationMessage[]; // Previous messages for context
|
||||
sdkSessionId?: string; // Claude SDK session ID for resuming conversations
|
||||
settingSources?: Array<'user' | 'project' | 'local'>; // Sources for CLAUDE.md loading
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user