From c4f92f6a0aee3435c56eb8d27d9aa9204284833e Mon Sep 17 00:00:00 2001 From: Ralph Khreish <35776126+Crunchyman-ralph@users.noreply.github.com> Date: Fri, 29 Aug 2025 00:28:00 +0200 Subject: [PATCH] feat: add optional feature flag for code context (#1165) * feat: add featureFlag for codebase analysis * chore: add changeset * chore: run format --- .changeset/sour-coins-lay.md | 11 ++++ apps/extension/package.json | 25 ++------ package.json | 5 +- scripts/modules/config-manager.js | 57 +++++++++++++++++-- scripts/modules/task-manager/add-task.js | 6 +- .../task-manager/analyze-task-complexity.js | 6 +- scripts/modules/task-manager/expand-task.js | 3 +- .../parse-prd/parse-prd-config.js | 2 +- .../task-manager/update-subtask-by-id.js | 6 +- .../modules/task-manager/update-task-by-id.js | 6 +- scripts/modules/task-manager/update-tasks.js | 6 +- tests/unit/config-manager.test.js | 1 + .../analyze-task-complexity.test.js | 1 - .../complexity-report-tag-isolation.test.js | 1 - 14 files changed, 98 insertions(+), 38 deletions(-) create mode 100644 .changeset/sour-coins-lay.md diff --git a/.changeset/sour-coins-lay.md b/.changeset/sour-coins-lay.md new file mode 100644 index 00000000..e7ba6785 --- /dev/null +++ b/.changeset/sour-coins-lay.md @@ -0,0 +1,11 @@ +--- +"task-master-ai": minor +--- + +Add configurable codebase analysis feature flag with multiple configuration sources + +Users can now control whether codebase analysis features (Claude Code and Gemini CLI integration) are enabled through environment variables, MCP configuration, or project config files. + +Priority order: .env > MCP session env > .taskmaster/config.json. + +Set `TASKMASTER_ENABLE_CODEBASE_ANALYSIS=false` in `.env` to disable codebase analysis prompts and tool integration. diff --git a/apps/extension/package.json b/apps/extension/package.json index 8e051c1a..3d0d35ff 100644 --- a/apps/extension/package.json +++ b/apps/extension/package.json @@ -9,17 +9,9 @@ "engines": { "vscode": "^1.93.0" }, - "categories": [ - "AI", - "Visualization", - "Education", - "Other" - ], + "categories": ["AI", "Visualization", "Education", "Other"], "main": "./dist/extension.js", - "activationEvents": [ - "onStartupFinished", - "workspaceContains:.taskmaster/**" - ], + "activationEvents": ["onStartupFinished", "workspaceContains:.taskmaster/**"], "contributes": { "viewsContainers": { "activitybar": [ @@ -147,11 +139,7 @@ }, "taskmaster.ui.theme": { "type": "string", - "enum": [ - "auto", - "light", - "dark" - ], + "enum": ["auto", "light", "dark"], "default": "auto", "description": "UI theme preference" }, @@ -212,12 +200,7 @@ }, "taskmaster.debug.logLevel": { "type": "string", - "enum": [ - "error", - "warn", - "info", - "debug" - ], + "enum": ["error", "warn", "info", "debug"], "default": "info", "description": "Logging level" }, diff --git a/package.json b/package.json index 8b82651e..3148d21a 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,7 @@ "task-master-mcp": "mcp-server/server.js", "task-master-ai": "mcp-server/server.js" }, - "workspaces": [ - "apps/*", - "." - ], + "workspaces": ["apps/*", "."], "scripts": { "test": "node --experimental-vm-modules node_modules/.bin/jest", "test:fails": "node --experimental-vm-modules node_modules/.bin/jest --onlyFailures", diff --git a/scripts/modules/config-manager.js b/scripts/modules/config-manager.js index 600eeecf..08023398 100644 --- a/scripts/modules/config-manager.js +++ b/scripts/modules/config-manager.js @@ -72,7 +72,8 @@ const DEFAULTS = { projectName: 'Task Master', ollamaBaseURL: 'http://localhost:11434/api', bedrockBaseURL: 'https://bedrock.us-east-1.amazonaws.com', - responseLanguage: 'English' + responseLanguage: 'English', + enableCodebaseAnalysis: true }, claudeCode: {} }; @@ -428,15 +429,56 @@ function getResearchProvider(explicitRoot = null) { } /** - * Check if a codebase analysis provider is being used (Claude Code or Gemini CLI) + * Check if codebase analysis feature flag is enabled across all sources + * Priority: .env > MCP env > config.json + * @param {object|null} session - MCP session object (optional) + * @param {string|null} projectRoot - Project root path (optional) + * @returns {boolean} True if codebase analysis is enabled + */ +function isCodebaseAnalysisEnabled(session = null, projectRoot = null) { + // Priority 1: Environment variable + const envFlag = resolveEnvVariable( + 'TASKMASTER_ENABLE_CODEBASE_ANALYSIS', + session, + projectRoot + ); + if (envFlag !== null && envFlag !== undefined && envFlag !== '') { + return envFlag.toLowerCase() === 'true' || envFlag === '1'; + } + + // Priority 2: MCP session environment + if (session?.env?.TASKMASTER_ENABLE_CODEBASE_ANALYSIS) { + const mcpFlag = session.env.TASKMASTER_ENABLE_CODEBASE_ANALYSIS; + return mcpFlag.toLowerCase() === 'true' || mcpFlag === '1'; + } + + // Priority 3: Configuration file + const globalConfig = getGlobalConfig(projectRoot); + return globalConfig.enableCodebaseAnalysis !== false; // Default to true +} + +/** + * Check if codebase analysis is available and enabled * @param {boolean} useResearch - Whether to check research provider or main provider * @param {string|null} projectRoot - Project root path (optional) - * @returns {boolean} True if a codebase analysis provider is the current provider + * @param {object|null} session - MCP session object (optional) + * @returns {boolean} True if codebase analysis is available and enabled */ -function hasCodebaseAnalysis(useResearch = false, projectRoot = null) { +function hasCodebaseAnalysis( + useResearch = false, + projectRoot = null, + session = null +) { + // First check if the feature is enabled + if (!isCodebaseAnalysisEnabled(session, projectRoot)) { + return false; + } + + // Then check if a codebase analysis provider is configured const currentProvider = useResearch ? getResearchProvider(projectRoot) : getMainProvider(projectRoot); + return ( currentProvider === CUSTOM_PROVIDERS.CLAUDE_CODE || currentProvider === CUSTOM_PROVIDERS.GEMINI_CLI @@ -558,6 +600,11 @@ function getResponseLanguage(explicitRoot = null) { return getGlobalConfig(explicitRoot).responseLanguage; } +function getCodebaseAnalysisEnabled(explicitRoot = null) { + // Directly return value from config + return getGlobalConfig(explicitRoot).enableCodebaseAnalysis; +} + /** * Gets model parameters (maxTokens, temperature) for a specific role, * considering model-specific overrides from supported-models.json. @@ -1016,6 +1063,8 @@ export { getAzureBaseURL, getBedrockBaseURL, getResponseLanguage, + getCodebaseAnalysisEnabled, + isCodebaseAnalysisEnabled, getParametersForRole, getUserId, // API Key Checkers (still relevant) diff --git a/scripts/modules/task-manager/add-task.js b/scripts/modules/task-manager/add-task.js index 8c1e709f..ea98f970 100644 --- a/scripts/modules/task-manager/add-task.js +++ b/scripts/modules/task-manager/add-task.js @@ -426,7 +426,11 @@ async function addTask( useResearch, priority: effectivePriority, dependencies: numericDependencies, - hasCodebaseAnalysis: hasCodebaseAnalysis(useResearch, projectRoot), + hasCodebaseAnalysis: hasCodebaseAnalysis( + useResearch, + projectRoot, + session + ), projectRoot: projectRoot } ); diff --git a/scripts/modules/task-manager/analyze-task-complexity.js b/scripts/modules/task-manager/analyze-task-complexity.js index abac9331..af0e97ed 100644 --- a/scripts/modules/task-manager/analyze-task-complexity.js +++ b/scripts/modules/task-manager/analyze-task-complexity.js @@ -419,7 +419,11 @@ async function analyzeTaskComplexity(options, context = {}) { tasks: tasksData.tasks, gatheredContext: gatheredContext || '', useResearch: useResearch, - hasCodebaseAnalysis: hasCodebaseAnalysis(useResearch, projectRoot), + hasCodebaseAnalysis: hasCodebaseAnalysis( + useResearch, + projectRoot, + session + ), projectRoot: projectRoot || '' }; diff --git a/scripts/modules/task-manager/expand-task.js b/scripts/modules/task-manager/expand-task.js index 648976ce..05b33b62 100644 --- a/scripts/modules/task-manager/expand-task.js +++ b/scripts/modules/task-manager/expand-task.js @@ -458,7 +458,8 @@ async function expandTask( // Check if a codebase analysis provider is being used const hasCodebaseAnalysisCapability = hasCodebaseAnalysis( useResearch, - projectRoot + projectRoot, + session ); // Combine all context sources into a single additionalContext parameter diff --git a/scripts/modules/task-manager/parse-prd/parse-prd-config.js b/scripts/modules/task-manager/parse-prd/parse-prd-config.js index 56afb8a8..f28b3650 100644 --- a/scripts/modules/task-manager/parse-prd/parse-prd-config.js +++ b/scripts/modules/task-manager/parse-prd/parse-prd-config.js @@ -77,7 +77,7 @@ export class PrdParseConfig { * Check if codebase analysis is available (Claude Code or Gemini CLI) */ hasCodebaseAnalysis() { - return hasCodebaseAnalysis(this.research, this.projectRoot); + return hasCodebaseAnalysis(this.research, this.projectRoot, this.session); } } diff --git a/scripts/modules/task-manager/update-subtask-by-id.js b/scripts/modules/task-manager/update-subtask-by-id.js index 884bf5ba..68666d35 100644 --- a/scripts/modules/task-manager/update-subtask-by-id.js +++ b/scripts/modules/task-manager/update-subtask-by-id.js @@ -232,7 +232,11 @@ async function updateSubtaskById( updatePrompt: prompt, useResearch: useResearch, gatheredContext: gatheredContext || '', - hasCodebaseAnalysis: hasCodebaseAnalysis(useResearch, projectRoot), + hasCodebaseAnalysis: hasCodebaseAnalysis( + useResearch, + projectRoot, + session + ), projectRoot: projectRoot }; diff --git a/scripts/modules/task-manager/update-task-by-id.js b/scripts/modules/task-manager/update-task-by-id.js index aa94e3a1..1a1612c8 100644 --- a/scripts/modules/task-manager/update-task-by-id.js +++ b/scripts/modules/task-manager/update-task-by-id.js @@ -458,7 +458,11 @@ async function updateTaskById( useResearch: useResearch, currentDetails: taskToUpdate.details || '(No existing details)', gatheredContext: gatheredContext || '', - hasCodebaseAnalysis: hasCodebaseAnalysis(useResearch, projectRoot), + hasCodebaseAnalysis: hasCodebaseAnalysis( + useResearch, + projectRoot, + session + ), projectRoot: projectRoot }; diff --git a/scripts/modules/task-manager/update-tasks.js b/scripts/modules/task-manager/update-tasks.js index d2e0b83c..a1871ce7 100644 --- a/scripts/modules/task-manager/update-tasks.js +++ b/scripts/modules/task-manager/update-tasks.js @@ -436,7 +436,11 @@ async function updateTasks( updatePrompt: prompt, useResearch, projectContext: gatheredContext, - hasCodebaseAnalysis: hasCodebaseAnalysis(useResearch, projectRoot), + hasCodebaseAnalysis: hasCodebaseAnalysis( + useResearch, + projectRoot, + session + ), projectRoot: projectRoot } ); diff --git a/tests/unit/config-manager.test.js b/tests/unit/config-manager.test.js index 157ad98b..34ba70b4 100644 --- a/tests/unit/config-manager.test.js +++ b/tests/unit/config-manager.test.js @@ -145,6 +145,7 @@ const DEFAULT_CONFIG = { projectName: 'Task Master', ollamaBaseURL: 'http://localhost:11434/api', bedrockBaseURL: 'https://bedrock.us-east-1.amazonaws.com', + enableCodebaseAnalysis: true, responseLanguage: 'English' }, claudeCode: {} diff --git a/tests/unit/scripts/modules/task-manager/analyze-task-complexity.test.js b/tests/unit/scripts/modules/task-manager/analyze-task-complexity.test.js index 8da3b8c7..ff08c96f 100644 --- a/tests/unit/scripts/modules/task-manager/analyze-task-complexity.test.js +++ b/tests/unit/scripts/modules/task-manager/analyze-task-complexity.test.js @@ -6,7 +6,6 @@ import { createGetTagAwareFilePathMock, createSlugifyTagForFilePathMock } from './setup.js'; -import { hasCodebaseAnalysis } from '../../../../../scripts/modules/config-manager.js'; // Mock the dependencies before importing the module under test jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({ diff --git a/tests/unit/scripts/modules/task-manager/complexity-report-tag-isolation.test.js b/tests/unit/scripts/modules/task-manager/complexity-report-tag-isolation.test.js index 959d1607..99fb57eb 100644 --- a/tests/unit/scripts/modules/task-manager/complexity-report-tag-isolation.test.js +++ b/tests/unit/scripts/modules/task-manager/complexity-report-tag-isolation.test.js @@ -6,7 +6,6 @@ import { jest } from '@jest/globals'; import fs from 'fs'; import path from 'path'; -import { hasCodebaseAnalysis } from '../../../../../scripts/modules/config-manager.js'; // Mock the dependencies jest.unstable_mockModule('../../../../../src/utils/path-utils.js', () => ({