eat(models): Add MCP support for models command and improve configuration docs
This commit implements several related improvements to the models command and configuration system: - Added MCP support for the models command: - Created new direct function implementation in models.js - Registered modelsDirect in task-master-core.js for proper export - Added models tool registration in tools/index.js - Ensured project name replacement when copying .taskmasterconfig in init.js - Improved .taskmasterconfig copying during project initialization: - Added copyTemplateFile() call in createProjectStructure() - Ensured project name is properly replaced in the config - Restructured tool registration in logical workflow groups: - Organized registration into 6 functional categories - Improved command ordering to follow typical workflow - Added clear group comments for maintainability - Enhanced documentation in cursor rules: - Updated dev_workflow.mdc with clearer config management instructions - Added comprehensive models command reference to taskmaster.mdc - Clarified CLI vs MCP usage patterns and options - Added warning against manual .taskmasterconfig editing
This commit is contained in:
File diff suppressed because it is too large
Load Diff
386
scripts/modules/task-manager/models.js
Normal file
386
scripts/modules/task-manager/models.js
Normal file
@@ -0,0 +1,386 @@
|
||||
/**
|
||||
* models.js
|
||||
* Core functionality for managing AI model configurations
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import {
|
||||
getMainModelId,
|
||||
getResearchModelId,
|
||||
getFallbackModelId,
|
||||
getAvailableModels,
|
||||
VALID_PROVIDERS,
|
||||
getMainProvider,
|
||||
getResearchProvider,
|
||||
getFallbackProvider,
|
||||
isApiKeySet,
|
||||
getMcpApiKeyStatus,
|
||||
getConfig,
|
||||
writeConfig,
|
||||
isConfigFilePresent
|
||||
} from '../config-manager.js';
|
||||
|
||||
/**
|
||||
* Get the current model configuration
|
||||
* @param {Object} [options] - Options for the operation
|
||||
* @param {Object} [options.session] - Session object containing environment variables (for MCP)
|
||||
* @param {Function} [options.mcpLog] - MCP logger object (for MCP)
|
||||
* @param {string} [options.projectRoot] - Project root directory
|
||||
* @returns {Object} RESTful response with current model configuration
|
||||
*/
|
||||
async function getModelConfiguration(options = {}) {
|
||||
const { mcpLog, projectRoot } = options;
|
||||
|
||||
const report = (level, ...args) => {
|
||||
if (mcpLog && typeof mcpLog[level] === 'function') {
|
||||
mcpLog[level](...args);
|
||||
}
|
||||
};
|
||||
|
||||
// Check if configuration file exists using provided project root
|
||||
let configPath;
|
||||
let configExists = false;
|
||||
|
||||
if (projectRoot) {
|
||||
configPath = path.join(projectRoot, '.taskmasterconfig');
|
||||
configExists = fs.existsSync(configPath);
|
||||
report(
|
||||
'info',
|
||||
`Checking for .taskmasterconfig at: ${configPath}, exists: ${configExists}`
|
||||
);
|
||||
} else {
|
||||
configExists = isConfigFilePresent();
|
||||
report(
|
||||
'info',
|
||||
`Checking for .taskmasterconfig using isConfigFilePresent(), exists: ${configExists}`
|
||||
);
|
||||
}
|
||||
|
||||
if (!configExists) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: 'CONFIG_MISSING',
|
||||
message:
|
||||
'The .taskmasterconfig file is missing. Run "task-master models --setup" to create it.'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
// Get current settings - these should use the config from the found path automatically
|
||||
const mainProvider = getMainProvider(projectRoot);
|
||||
const mainModelId = getMainModelId(projectRoot);
|
||||
const researchProvider = getResearchProvider(projectRoot);
|
||||
const researchModelId = getResearchModelId(projectRoot);
|
||||
const fallbackProvider = getFallbackProvider(projectRoot);
|
||||
const fallbackModelId = getFallbackModelId(projectRoot);
|
||||
|
||||
// Check API keys
|
||||
const mainCliKeyOk = isApiKeySet(mainProvider);
|
||||
const mainMcpKeyOk = getMcpApiKeyStatus(mainProvider);
|
||||
const researchCliKeyOk = isApiKeySet(researchProvider);
|
||||
const researchMcpKeyOk = getMcpApiKeyStatus(researchProvider);
|
||||
const fallbackCliKeyOk = fallbackProvider
|
||||
? isApiKeySet(fallbackProvider)
|
||||
: true;
|
||||
const fallbackMcpKeyOk = fallbackProvider
|
||||
? getMcpApiKeyStatus(fallbackProvider)
|
||||
: true;
|
||||
|
||||
// Get available models to find detailed info
|
||||
const availableModels = getAvailableModels(projectRoot);
|
||||
|
||||
// Find model details
|
||||
const mainModelData = availableModels.find((m) => m.id === mainModelId);
|
||||
const researchModelData = availableModels.find(
|
||||
(m) => m.id === researchModelId
|
||||
);
|
||||
const fallbackModelData = fallbackModelId
|
||||
? availableModels.find((m) => m.id === fallbackModelId)
|
||||
: null;
|
||||
|
||||
// Return structured configuration data
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
activeModels: {
|
||||
main: {
|
||||
provider: mainProvider,
|
||||
modelId: mainModelId,
|
||||
sweScore: mainModelData?.swe_score || null,
|
||||
cost: mainModelData?.cost_per_1m_tokens || null,
|
||||
keyStatus: {
|
||||
cli: mainCliKeyOk,
|
||||
mcp: mainMcpKeyOk
|
||||
}
|
||||
},
|
||||
research: {
|
||||
provider: researchProvider,
|
||||
modelId: researchModelId,
|
||||
sweScore: researchModelData?.swe_score || null,
|
||||
cost: researchModelData?.cost_per_1m_tokens || null,
|
||||
keyStatus: {
|
||||
cli: researchCliKeyOk,
|
||||
mcp: researchMcpKeyOk
|
||||
}
|
||||
},
|
||||
fallback: fallbackProvider
|
||||
? {
|
||||
provider: fallbackProvider,
|
||||
modelId: fallbackModelId,
|
||||
sweScore: fallbackModelData?.swe_score || null,
|
||||
cost: fallbackModelData?.cost_per_1m_tokens || null,
|
||||
keyStatus: {
|
||||
cli: fallbackCliKeyOk,
|
||||
mcp: fallbackMcpKeyOk
|
||||
}
|
||||
}
|
||||
: null
|
||||
},
|
||||
message: 'Successfully retrieved current model configuration'
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
report('error', `Error getting model configuration: ${error.message}`);
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: 'CONFIG_ERROR',
|
||||
message: error.message
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available models not currently in use
|
||||
* @param {Object} [options] - Options for the operation
|
||||
* @param {Object} [options.session] - Session object containing environment variables (for MCP)
|
||||
* @param {Function} [options.mcpLog] - MCP logger object (for MCP)
|
||||
* @param {string} [options.projectRoot] - Project root directory
|
||||
* @returns {Object} RESTful response with available models
|
||||
*/
|
||||
async function getAvailableModelsList(options = {}) {
|
||||
const { mcpLog, projectRoot } = options;
|
||||
|
||||
const report = (level, ...args) => {
|
||||
if (mcpLog && typeof mcpLog[level] === 'function') {
|
||||
mcpLog[level](...args);
|
||||
}
|
||||
};
|
||||
|
||||
// Check if configuration file exists using provided project root
|
||||
let configPath;
|
||||
let configExists = false;
|
||||
|
||||
if (projectRoot) {
|
||||
configPath = path.join(projectRoot, '.taskmasterconfig');
|
||||
configExists = fs.existsSync(configPath);
|
||||
report(
|
||||
'info',
|
||||
`Checking for .taskmasterconfig at: ${configPath}, exists: ${configExists}`
|
||||
);
|
||||
} else {
|
||||
configExists = isConfigFilePresent();
|
||||
report(
|
||||
'info',
|
||||
`Checking for .taskmasterconfig using isConfigFilePresent(), exists: ${configExists}`
|
||||
);
|
||||
}
|
||||
|
||||
if (!configExists) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: 'CONFIG_MISSING',
|
||||
message:
|
||||
'The .taskmasterconfig file is missing. Run "task-master models --setup" to create it.'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
// Get all available models
|
||||
const allAvailableModels = getAvailableModels(projectRoot);
|
||||
|
||||
if (!allAvailableModels || allAvailableModels.length === 0) {
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
models: [],
|
||||
message: 'No available models found'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Get currently used model IDs
|
||||
const mainModelId = getMainModelId(projectRoot);
|
||||
const researchModelId = getResearchModelId(projectRoot);
|
||||
const fallbackModelId = getFallbackModelId(projectRoot);
|
||||
|
||||
// Filter out placeholder models and active models
|
||||
const activeIds = [mainModelId, researchModelId, fallbackModelId].filter(
|
||||
Boolean
|
||||
);
|
||||
const otherAvailableModels = allAvailableModels.map((model) => ({
|
||||
provider: model.provider || 'N/A',
|
||||
modelId: model.id,
|
||||
sweScore: model.swe_score || null,
|
||||
cost: model.cost_per_1m_tokens || null,
|
||||
allowedRoles: model.allowed_roles || []
|
||||
}));
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
models: otherAvailableModels,
|
||||
message: `Successfully retrieved ${otherAvailableModels.length} available models`
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
report('error', `Error getting available models: ${error.message}`);
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: 'MODELS_LIST_ERROR',
|
||||
message: error.message
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a specific model in the configuration
|
||||
* @param {string} role - The model role to update ('main', 'research', 'fallback')
|
||||
* @param {string} modelId - The model ID to set for the role
|
||||
* @param {Object} [options] - Options for the operation
|
||||
* @param {Object} [options.session] - Session object containing environment variables (for MCP)
|
||||
* @param {Function} [options.mcpLog] - MCP logger object (for MCP)
|
||||
* @param {string} [options.projectRoot] - Project root directory
|
||||
* @returns {Object} RESTful response with result of update operation
|
||||
*/
|
||||
async function setModel(role, modelId, options = {}) {
|
||||
const { mcpLog, projectRoot } = options;
|
||||
|
||||
const report = (level, ...args) => {
|
||||
if (mcpLog && typeof mcpLog[level] === 'function') {
|
||||
mcpLog[level](...args);
|
||||
}
|
||||
};
|
||||
|
||||
// Check if configuration file exists using provided project root
|
||||
let configPath;
|
||||
let configExists = false;
|
||||
|
||||
if (projectRoot) {
|
||||
configPath = path.join(projectRoot, '.taskmasterconfig');
|
||||
configExists = fs.existsSync(configPath);
|
||||
report(
|
||||
'info',
|
||||
`Checking for .taskmasterconfig at: ${configPath}, exists: ${configExists}`
|
||||
);
|
||||
} else {
|
||||
configExists = isConfigFilePresent();
|
||||
report(
|
||||
'info',
|
||||
`Checking for .taskmasterconfig using isConfigFilePresent(), exists: ${configExists}`
|
||||
);
|
||||
}
|
||||
|
||||
if (!configExists) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: 'CONFIG_MISSING',
|
||||
message:
|
||||
'The .taskmasterconfig file is missing. Run "task-master models --setup" to create it.'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Validate role
|
||||
if (!['main', 'research', 'fallback'].includes(role)) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: 'INVALID_ROLE',
|
||||
message: `Invalid role: ${role}. Must be one of: main, research, fallback.`
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Validate model ID
|
||||
if (typeof modelId !== 'string' || modelId.trim() === '') {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: 'INVALID_MODEL_ID',
|
||||
message: `Invalid model ID: ${modelId}. Must be a non-empty string.`
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const availableModels = getAvailableModels(projectRoot);
|
||||
const currentConfig = getConfig(projectRoot);
|
||||
|
||||
// Find the model data
|
||||
const modelData = availableModels.find((m) => m.id === modelId);
|
||||
if (!modelData || !modelData.provider) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: 'MODEL_NOT_FOUND',
|
||||
message: `Model ID "${modelId}" not found or invalid in available models.`
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Update configuration
|
||||
currentConfig.models[role] = {
|
||||
...currentConfig.models[role], // Keep existing params like maxTokens
|
||||
provider: modelData.provider,
|
||||
modelId: modelId
|
||||
};
|
||||
|
||||
// Write updated configuration
|
||||
const writeResult = writeConfig(currentConfig, projectRoot);
|
||||
if (!writeResult) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: 'WRITE_ERROR',
|
||||
message: 'Error writing updated configuration to .taskmasterconfig'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
report(
|
||||
'info',
|
||||
`Set ${role} model to: ${modelId} (Provider: ${modelData.provider})`
|
||||
);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
role,
|
||||
provider: modelData.provider,
|
||||
modelId,
|
||||
message: `Successfully set ${role} model to ${modelId} (Provider: ${modelData.provider})`
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
report('error', `Error setting ${role} model: ${error.message}`);
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
code: 'SET_MODEL_ERROR',
|
||||
message: error.message
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export { getModelConfiguration, getAvailableModelsList, setModel };
|
||||
@@ -21,13 +21,8 @@ import fs from 'fs';
|
||||
import { findNextTask, analyzeTaskComplexity } from './task-manager.js';
|
||||
import {
|
||||
getProjectName,
|
||||
getDefaultSubtasks,
|
||||
getMainModelId,
|
||||
getMainMaxTokens,
|
||||
getMainTemperature,
|
||||
getDebugFlag,
|
||||
getLogLevel,
|
||||
getDefaultPriority
|
||||
getDefaultSubtasks
|
||||
} from './config-manager.js';
|
||||
|
||||
// Create a color gradient for the banner
|
||||
@@ -386,6 +381,9 @@ function formatDependenciesWithStatus(
|
||||
function displayHelp() {
|
||||
displayBanner();
|
||||
|
||||
// Get terminal width - moved to top of function to make it available throughout
|
||||
const terminalWidth = process.stdout.columns || 100; // Default to 100 if can't detect
|
||||
|
||||
console.log(
|
||||
boxen(chalk.white.bold('Task Master CLI'), {
|
||||
padding: 1,
|
||||
@@ -397,6 +395,42 @@ function displayHelp() {
|
||||
|
||||
// Command categories
|
||||
const commandCategories = [
|
||||
{
|
||||
title: 'Project Setup & Configuration',
|
||||
color: 'blue',
|
||||
commands: [
|
||||
{
|
||||
name: 'init',
|
||||
args: '[--name=<name>] [--description=<desc>] [-y]',
|
||||
desc: 'Initialize a new project with Task Master structure'
|
||||
},
|
||||
{
|
||||
name: 'models',
|
||||
args: '',
|
||||
desc: 'View current AI model configuration and available models'
|
||||
},
|
||||
{
|
||||
name: 'models --setup',
|
||||
args: '',
|
||||
desc: 'Run interactive setup to configure AI models'
|
||||
},
|
||||
{
|
||||
name: 'models --set-main',
|
||||
args: '<model_id>',
|
||||
desc: 'Set the primary model for task generation'
|
||||
},
|
||||
{
|
||||
name: 'models --set-research',
|
||||
args: '<model_id>',
|
||||
desc: 'Set the model for research operations'
|
||||
},
|
||||
{
|
||||
name: 'models --set-fallback',
|
||||
args: '<model_id>',
|
||||
desc: 'Set the fallback model (optional)'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Task Generation',
|
||||
color: 'cyan',
|
||||
@@ -430,7 +464,17 @@ function displayHelp() {
|
||||
{
|
||||
name: 'update',
|
||||
args: '--from=<id> --prompt="<context>"',
|
||||
desc: 'Update tasks based on new requirements'
|
||||
desc: 'Update multiple tasks based on new requirements'
|
||||
},
|
||||
{
|
||||
name: 'update-task',
|
||||
args: '--id=<id> --prompt="<context>"',
|
||||
desc: 'Update a single specific task with new information'
|
||||
},
|
||||
{
|
||||
name: 'update-subtask',
|
||||
args: '--id=<parentId.subtaskId> --prompt="<context>"',
|
||||
desc: 'Append additional information to a subtask'
|
||||
},
|
||||
{
|
||||
name: 'add-task',
|
||||
@@ -438,20 +482,46 @@ function displayHelp() {
|
||||
desc: 'Add a new task using AI'
|
||||
},
|
||||
{
|
||||
name: 'add-dependency',
|
||||
args: '--id=<id> --depends-on=<id>',
|
||||
desc: 'Add a dependency to a task'
|
||||
},
|
||||
{
|
||||
name: 'remove-dependency',
|
||||
args: '--id=<id> --depends-on=<id>',
|
||||
desc: 'Remove a dependency from a task'
|
||||
name: 'remove-task',
|
||||
args: '--id=<id> [-y]',
|
||||
desc: 'Permanently remove a task or subtask'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Task Analysis & Detail',
|
||||
title: 'Subtask Management',
|
||||
color: 'yellow',
|
||||
commands: [
|
||||
{
|
||||
name: 'add-subtask',
|
||||
args: '--parent=<id> --title="<title>" [--description="<desc>"]',
|
||||
desc: 'Add a new subtask to a parent task'
|
||||
},
|
||||
{
|
||||
name: 'add-subtask',
|
||||
args: '--parent=<id> --task-id=<id>',
|
||||
desc: 'Convert an existing task into a subtask'
|
||||
},
|
||||
{
|
||||
name: 'remove-subtask',
|
||||
args: '--id=<parentId.subtaskId> [--convert]',
|
||||
desc: 'Remove a subtask (optionally convert to standalone task)'
|
||||
},
|
||||
{
|
||||
name: 'clear-subtasks',
|
||||
args: '--id=<id>',
|
||||
desc: 'Remove all subtasks from specified tasks'
|
||||
},
|
||||
{
|
||||
name: 'clear-subtasks --all',
|
||||
args: '',
|
||||
desc: 'Remove subtasks from all tasks'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Task Analysis & Breakdown',
|
||||
color: 'magenta',
|
||||
commands: [
|
||||
{
|
||||
name: 'analyze-complexity',
|
||||
@@ -472,17 +542,12 @@ function displayHelp() {
|
||||
name: 'expand --all',
|
||||
args: '[--force] [--research]',
|
||||
desc: 'Expand all pending tasks with subtasks'
|
||||
},
|
||||
{
|
||||
name: 'clear-subtasks',
|
||||
args: '--id=<id>',
|
||||
desc: 'Remove subtasks from specified tasks'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Task Navigation & Viewing',
|
||||
color: 'magenta',
|
||||
color: 'cyan',
|
||||
commands: [
|
||||
{
|
||||
name: 'next',
|
||||
@@ -500,6 +565,16 @@ function displayHelp() {
|
||||
title: 'Dependency Management',
|
||||
color: 'blue',
|
||||
commands: [
|
||||
{
|
||||
name: 'add-dependency',
|
||||
args: '--id=<id> --depends-on=<id>',
|
||||
desc: 'Add a dependency to a task'
|
||||
},
|
||||
{
|
||||
name: 'remove-dependency',
|
||||
args: '--id=<id> --depends-on=<id>',
|
||||
desc: 'Remove a dependency from a task'
|
||||
},
|
||||
{
|
||||
name: 'validate-dependencies',
|
||||
args: '',
|
||||
@@ -525,8 +600,13 @@ function displayHelp() {
|
||||
})
|
||||
);
|
||||
|
||||
// Calculate dynamic column widths - adjust ratios as needed
|
||||
const nameWidth = Math.max(25, Math.floor(terminalWidth * 0.2)); // 20% of width but min 25
|
||||
const argsWidth = Math.max(40, Math.floor(terminalWidth * 0.35)); // 35% of width but min 40
|
||||
const descWidth = Math.max(45, Math.floor(terminalWidth * 0.45) - 10); // 45% of width but min 45, minus some buffer
|
||||
|
||||
const commandTable = new Table({
|
||||
colWidths: [25, 40, 45],
|
||||
colWidths: [nameWidth, argsWidth, descWidth],
|
||||
chars: {
|
||||
top: '',
|
||||
'top-mid': '',
|
||||
@@ -544,7 +624,8 @@ function displayHelp() {
|
||||
'right-mid': '',
|
||||
middle: ' '
|
||||
},
|
||||
style: { border: [], 'padding-left': 4 }
|
||||
style: { border: [], 'padding-left': 4 },
|
||||
wordWrap: true
|
||||
});
|
||||
|
||||
category.commands.forEach((cmd, index) => {
|
||||
@@ -559,9 +640,9 @@ function displayHelp() {
|
||||
console.log('');
|
||||
});
|
||||
|
||||
// Display environment variables section
|
||||
// Display configuration section
|
||||
console.log(
|
||||
boxen(chalk.cyan.bold('Environment Variables'), {
|
||||
boxen(chalk.cyan.bold('Configuration'), {
|
||||
padding: { left: 2, right: 2, top: 0, bottom: 0 },
|
||||
margin: { top: 1, bottom: 0 },
|
||||
borderColor: 'cyan',
|
||||
@@ -569,8 +650,19 @@ function displayHelp() {
|
||||
})
|
||||
);
|
||||
|
||||
const envTable = new Table({
|
||||
colWidths: [30, 50, 30],
|
||||
// Get terminal width if not already defined
|
||||
const configTerminalWidth = terminalWidth || process.stdout.columns || 100;
|
||||
|
||||
// Calculate dynamic column widths for config table
|
||||
const configKeyWidth = Math.max(30, Math.floor(configTerminalWidth * 0.25));
|
||||
const configDescWidth = Math.max(50, Math.floor(configTerminalWidth * 0.45));
|
||||
const configValueWidth = Math.max(
|
||||
30,
|
||||
Math.floor(configTerminalWidth * 0.3) - 10
|
||||
);
|
||||
|
||||
const configTable = new Table({
|
||||
colWidths: [configKeyWidth, configDescWidth, configValueWidth],
|
||||
chars: {
|
||||
top: '',
|
||||
'top-mid': '',
|
||||
@@ -588,69 +680,59 @@ function displayHelp() {
|
||||
'right-mid': '',
|
||||
middle: ' '
|
||||
},
|
||||
style: { border: [], 'padding-left': 4 }
|
||||
style: { border: [], 'padding-left': 4 },
|
||||
wordWrap: true
|
||||
});
|
||||
|
||||
envTable.push(
|
||||
configTable.push(
|
||||
[
|
||||
`${chalk.yellow('ANTHROPIC_API_KEY')}${chalk.reset('')}`,
|
||||
`${chalk.white('Your Anthropic API key')}${chalk.reset('')}`,
|
||||
`${chalk.dim('Required')}${chalk.reset('')}`
|
||||
`${chalk.yellow('.taskmasterconfig')}${chalk.reset('')}`,
|
||||
`${chalk.white('AI model configuration file (project root)')}${chalk.reset('')}`,
|
||||
`${chalk.dim('Managed by models cmd')}${chalk.reset('')}`
|
||||
],
|
||||
[
|
||||
`${chalk.yellow('MODEL')}${chalk.reset('')}`,
|
||||
`${chalk.white('Claude model to use')}${chalk.reset('')}`,
|
||||
`${chalk.dim(`Default: ${getMainModelId()}`)}${chalk.reset('')}`
|
||||
`${chalk.yellow('API Keys (.env)')}${chalk.reset('')}`,
|
||||
`${chalk.white('API keys for AI providers (ANTHROPIC_API_KEY, etc.)')}${chalk.reset('')}`,
|
||||
`${chalk.dim('Required in .env file')}${chalk.reset('')}`
|
||||
],
|
||||
[
|
||||
`${chalk.yellow('MAX_TOKENS')}${chalk.reset('')}`,
|
||||
`${chalk.white('Maximum tokens for responses')}${chalk.reset('')}`,
|
||||
`${chalk.dim(`Default: ${getMainMaxTokens()}`)}${chalk.reset('')}`
|
||||
],
|
||||
[
|
||||
`${chalk.yellow('TEMPERATURE')}${chalk.reset('')}`,
|
||||
`${chalk.white('Temperature for model responses')}${chalk.reset('')}`,
|
||||
`${chalk.dim(`Default: ${getMainTemperature()}`)}${chalk.reset('')}`
|
||||
],
|
||||
[
|
||||
`${chalk.yellow('PERPLEXITY_API_KEY')}${chalk.reset('')}`,
|
||||
`${chalk.white('Perplexity API key for research')}${chalk.reset('')}`,
|
||||
`${chalk.dim('Optional')}${chalk.reset('')}`
|
||||
],
|
||||
[
|
||||
`${chalk.yellow('PERPLEXITY_MODEL')}${chalk.reset('')}`,
|
||||
`${chalk.white('Perplexity model to use')}${chalk.reset('')}`,
|
||||
`${chalk.dim('Default: sonar-pro')}${chalk.reset('')}`
|
||||
],
|
||||
[
|
||||
`${chalk.yellow('DEBUG')}${chalk.reset('')}`,
|
||||
`${chalk.white('Enable debug logging')}${chalk.reset('')}`,
|
||||
`${chalk.dim(`Default: ${getDebugFlag()}`)}${chalk.reset('')}`
|
||||
],
|
||||
[
|
||||
`${chalk.yellow('LOG_LEVEL')}${chalk.reset('')}`,
|
||||
`${chalk.white('Console output level (debug,info,warn,error)')}${chalk.reset('')}`,
|
||||
`${chalk.dim(`Default: ${getLogLevel()}`)}${chalk.reset('')}`
|
||||
],
|
||||
[
|
||||
`${chalk.yellow('DEFAULT_SUBTASKS')}${chalk.reset('')}`,
|
||||
`${chalk.white('Default number of subtasks to generate')}${chalk.reset('')}`,
|
||||
`${chalk.dim(`Default: ${getDefaultSubtasks()}`)}${chalk.reset('')}`
|
||||
],
|
||||
[
|
||||
`${chalk.yellow('DEFAULT_PRIORITY')}${chalk.reset('')}`,
|
||||
`${chalk.white('Default task priority')}${chalk.reset('')}`,
|
||||
`${chalk.dim(`Default: ${getDefaultPriority()}`)}${chalk.reset('')}`
|
||||
],
|
||||
[
|
||||
`${chalk.yellow('PROJECT_NAME')}${chalk.reset('')}`,
|
||||
`${chalk.white('Project name displayed in UI')}${chalk.reset('')}`,
|
||||
`${chalk.dim(`Default: ${getProjectName()}`)}${chalk.reset('')}`
|
||||
`${chalk.yellow('MCP Keys (mcp.json)')}${chalk.reset('')}`,
|
||||
`${chalk.white('API keys for Cursor integration')}${chalk.reset('')}`,
|
||||
`${chalk.dim('Required in .cursor/')}${chalk.reset('')}`
|
||||
]
|
||||
);
|
||||
|
||||
console.log(envTable.toString());
|
||||
console.log(configTable.toString());
|
||||
console.log('');
|
||||
|
||||
// Show helpful hints
|
||||
console.log(
|
||||
boxen(
|
||||
chalk.white.bold('Quick Start:') +
|
||||
'\n\n' +
|
||||
chalk.cyan('1. Create Project: ') +
|
||||
chalk.white('task-master init') +
|
||||
'\n' +
|
||||
chalk.cyan('2. Setup Models: ') +
|
||||
chalk.white('task-master models --setup') +
|
||||
'\n' +
|
||||
chalk.cyan('3. Parse PRD: ') +
|
||||
chalk.white('task-master parse-prd --input=<prd-file>') +
|
||||
'\n' +
|
||||
chalk.cyan('4. List Tasks: ') +
|
||||
chalk.white('task-master list') +
|
||||
'\n' +
|
||||
chalk.cyan('5. Find Next Task: ') +
|
||||
chalk.white('task-master next'),
|
||||
{
|
||||
padding: 1,
|
||||
borderColor: 'yellow',
|
||||
borderStyle: 'round',
|
||||
margin: { top: 1 },
|
||||
width: Math.min(configTerminalWidth - 10, 100) // Limit width to terminal width minus padding, max 100
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user