@@ -37,7 +37,9 @@ import type {
3737 ConversationMessage ,
3838 ExecuteOptions ,
3939 ImageAttachment ,
40+ McpConfig ,
4041 PlanOptions ,
42+ SkillsConfig ,
4143} from '@/core/agent/types' ;
4244import {
4345 DEFAULT_API_HOST ,
@@ -891,6 +893,37 @@ export class ClaudeAgent extends BaseAgent {
891893 } ) ;
892894 }
893895
896+ /**
897+ * Build settingSources based on skillsConfig
898+ * Controls which skill directories are loaded by the Claude Agent SDK
899+ */
900+ private buildSettingSources ( skillsConfig ?: SkillsConfig ) : ( 'user' | 'project' ) [ ] {
901+ // If skillsConfig is not provided or skills are globally disabled, use minimal sources
902+ if ( ! skillsConfig || ! skillsConfig . enabled ) {
903+ logger . info ( '[ClaudeAgent] Skills disabled or no config, using project only' ) ;
904+ return [ 'project' ] ;
905+ }
906+
907+ const sources : ( 'user' | 'project' ) [ ] = [ ] ;
908+
909+ // 'user' source loads skills from ~/.claude/skills
910+ if ( skillsConfig . userDirEnabled ) {
911+ sources . push ( 'user' ) ;
912+ }
913+
914+ // 'project' source loads skills from project directory
915+ // Always include project for project-specific settings
916+ sources . push ( 'project' ) ;
917+
918+ // Note: App directory skills (workspace/skills) are handled separately
919+ // as they are not part of the standard Claude SDK settingSources
920+ if ( skillsConfig . appDirEnabled ) {
921+ logger . info ( '[ClaudeAgent] App directory skills enabled (handled via custom skill loading)' ) ;
922+ }
923+
924+ return sources . length > 0 ? sources : [ 'project' ] ;
925+ }
926+
894927 /**
895928 * Build environment variables for the SDK query
896929 * Supports custom API endpoint and API key (including OpenRouter)
@@ -1123,21 +1156,24 @@ User's request (answer this AFTER reading the images):
11231156 if ( ! claudeCodePath ) {
11241157 yield {
11251158 type : 'error' ,
1126- message :
1127- 'Claude Code is not installed. Please install it with: npm install -g @anthropic-ai/claude-code' ,
1159+ message : '__CLAUDE_CODE_NOT_FOUND__' ,
11281160 } ;
11291161 yield { type : 'done' } ;
11301162 return ;
11311163 }
11321164
1133- // Load user-configured MCP servers from ~/.workany/mcp.json
1134- const userMcpServers = await loadMcpServers ( ) ;
1165+ // Load user-configured MCP servers based on mcpConfig settings
1166+ const userMcpServers = await loadMcpServers ( options ?. mcpConfig as McpConfig | undefined ) ;
11351167
11361168 // Build query options
1137- // Always use ['user', 'project'] to load skills and MCP from user's ~/.claude directory
1169+ // Use settingSources based on skillsConfig to control skill loading
1170+ // - 'user' source loads from ~/.claude directory (User skills)
1171+ // - 'project' source loads from project/.claude directory
11381172 // User's custom API settings from WorkAny settings page are passed via env config
11391173 // which takes priority over ~/.claude/settings.json because we set ANTHROPIC_API_KEY directly
1140- const settingSources : ( 'user' | 'project' ) [ ] = [ 'user' , 'project' ] ;
1174+ const settingSources : ( 'user' | 'project' ) [ ] = this . buildSettingSources ( options ?. skillsConfig ) ;
1175+ logger . info ( `[Claude ${ session . id } ] Skills config:` , options ?. skillsConfig ) ;
1176+ logger . info ( `[Claude ${ session . id } ] Setting sources: ${ settingSources . join ( ', ' ) } ` ) ;
11411177
11421178 const queryOptions : Options = {
11431179 cwd : sessionCwd ,
@@ -1225,13 +1261,31 @@ User's request (answer this AFTER reading the images):
12251261 } ,
12261262 } ) ;
12271263
1228- // Show simple user-friendly error message
1229- // Detailed error info is already logged to file
1230- const logPath = '~/.workany/logs/workany.log' ;
1231- yield {
1232- type : 'error' ,
1233- message : `__INTERNAL_ERROR__|${ logPath } ` ,
1234- } ;
1264+ // Check for API key related errors
1265+ const errorMessage = error instanceof Error ? error . message : String ( error ) ;
1266+ const isApiKeyError =
1267+ errorMessage . includes ( 'Invalid API key' ) ||
1268+ errorMessage . includes ( 'invalid_api_key' ) ||
1269+ errorMessage . includes ( 'API key' ) ||
1270+ errorMessage . includes ( 'authentication' ) ||
1271+ errorMessage . includes ( 'Please run /login' ) ||
1272+ errorMessage . includes ( 'Unauthorized' ) ||
1273+ errorMessage . includes ( '401' ) ;
1274+
1275+ if ( isApiKeyError ) {
1276+ yield {
1277+ type : 'error' ,
1278+ message : '__API_KEY_ERROR__' ,
1279+ } ;
1280+ } else {
1281+ // Show simple user-friendly error message
1282+ // Detailed error info is already logged to file
1283+ const logPath = '~/.workany/logs/workany.log' ;
1284+ yield {
1285+ type : 'error' ,
1286+ message : `__INTERNAL_ERROR__|${ logPath } ` ,
1287+ } ;
1288+ }
12351289 } finally {
12361290 this . sessions . delete ( session . id ) ;
12371291 yield { type : 'done' } ;
@@ -1274,8 +1328,7 @@ If you need to create any files during planning, use this directory.
12741328 if ( ! claudeCodePath ) {
12751329 yield {
12761330 type : 'error' ,
1277- message :
1278- 'Claude Code is not installed. Please install it with: npm install -g @anthropic-ai/claude-code' ,
1331+ message : '__CLAUDE_CODE_NOT_FOUND__' ,
12791332 } ;
12801333 yield { type : 'done' } ;
12811334 return ;
@@ -1427,19 +1480,20 @@ If you need to create any files during planning, use this directory.
14271480 if ( ! claudeCodePath ) {
14281481 yield {
14291482 type : 'error' ,
1430- message :
1431- 'Claude Code is not installed. Please install it with: npm install -g @anthropic-ai/claude-code' ,
1483+ message : '__CLAUDE_CODE_NOT_FOUND__' ,
14321484 } ;
14331485 yield { type : 'done' } ;
14341486 return ;
14351487 }
14361488
1437- // Load user-configured MCP servers from ~/.workany/mcp.json
1438- const userMcpServers = await loadMcpServers ( ) ;
1489+ // Load user-configured MCP servers based on mcpConfig settings
1490+ const userMcpServers = await loadMcpServers ( options . mcpConfig as McpConfig | undefined ) ;
14391491
14401492 // Build query options
1441- // Always use ['user', 'project'] to load skills and MCP from user's ~/.claude directory
1442- const execSettingSources : ( 'user' | 'project' ) [ ] = [ 'user' , 'project' ] ;
1493+ // Use settingSources based on skillsConfig to control skill loading
1494+ const execSettingSources : ( 'user' | 'project' ) [ ] = this . buildSettingSources ( options . skillsConfig ) ;
1495+ logger . info ( `[Claude ${ session . id } ] Execute skills config:` , options . skillsConfig ) ;
1496+ logger . info ( `[Claude ${ session . id } ] Execute setting sources: ${ execSettingSources . join ( ', ' ) } ` ) ;
14431497
14441498 const queryOptions : Options = {
14451499 cwd : sessionCwd ,
0 commit comments