chore: passes tests and linting
This commit is contained in:
@@ -1,33 +1,33 @@
|
|||||||
{
|
{
|
||||||
"models": {
|
"models": {
|
||||||
"main": {
|
"main": {
|
||||||
"provider": "anthropic",
|
"provider": "anthropic",
|
||||||
"modelId": "claude-sonnet-4-20250514",
|
"modelId": "claude-sonnet-4-20250514",
|
||||||
"maxTokens": 50000,
|
"maxTokens": 50000,
|
||||||
"temperature": 0.2
|
"temperature": 0.2
|
||||||
},
|
},
|
||||||
"research": {
|
"research": {
|
||||||
"provider": "perplexity",
|
"provider": "perplexity",
|
||||||
"modelId": "sonar-pro",
|
"modelId": "sonar-pro",
|
||||||
"maxTokens": 8700,
|
"maxTokens": 8700,
|
||||||
"temperature": 0.1
|
"temperature": 0.1
|
||||||
},
|
},
|
||||||
"fallback": {
|
"fallback": {
|
||||||
"provider": "anthropic",
|
"provider": "anthropic",
|
||||||
"modelId": "claude-3-7-sonnet-20250219",
|
"modelId": "claude-3-7-sonnet-20250219",
|
||||||
"maxTokens": 128000,
|
"maxTokens": 128000,
|
||||||
"temperature": 0.2
|
"temperature": 0.2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"global": {
|
"global": {
|
||||||
"logLevel": "info",
|
"logLevel": "info",
|
||||||
"debug": false,
|
"debug": false,
|
||||||
"defaultSubtasks": 5,
|
"defaultSubtasks": 5,
|
||||||
"defaultPriority": "medium",
|
"defaultPriority": "medium",
|
||||||
"projectName": "Taskmaster",
|
"projectName": "Taskmaster",
|
||||||
"ollamaBaseURL": "http://localhost:11434/api",
|
"ollamaBaseURL": "http://localhost:11434/api",
|
||||||
"bedrockBaseURL": "https://bedrock.us-east-1.amazonaws.com",
|
"bedrockBaseURL": "https://bedrock.us-east-1.amazonaws.com",
|
||||||
"userId": "1234567890",
|
"userId": "1234567890",
|
||||||
"azureBaseURL": "https://your-endpoint.azure.com/"
|
"azureBaseURL": "https://your-endpoint.azure.com/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,427 +1,427 @@
|
|||||||
{
|
{
|
||||||
"anthropic": [
|
"anthropic": [
|
||||||
{
|
{
|
||||||
"id": "claude-sonnet-4-20250514",
|
"id": "claude-sonnet-4-20250514",
|
||||||
"swe_score": 0.727,
|
"swe_score": 0.727,
|
||||||
"cost_per_1m_tokens": { "input": 3.0, "output": 15.0 },
|
"cost_per_1m_tokens": { "input": 3.0, "output": 15.0 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 64000
|
"max_tokens": 64000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "claude-opus-4-20250514",
|
"id": "claude-opus-4-20250514",
|
||||||
"swe_score": 0.725,
|
"swe_score": 0.725,
|
||||||
"cost_per_1m_tokens": { "input": 15.0, "output": 75.0 },
|
"cost_per_1m_tokens": { "input": 15.0, "output": 75.0 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 32000
|
"max_tokens": 32000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "claude-3-7-sonnet-20250219",
|
"id": "claude-3-7-sonnet-20250219",
|
||||||
"swe_score": 0.623,
|
"swe_score": 0.623,
|
||||||
"cost_per_1m_tokens": { "input": 3.0, "output": 15.0 },
|
"cost_per_1m_tokens": { "input": 3.0, "output": 15.0 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 120000
|
"max_tokens": 120000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "claude-3-5-sonnet-20241022",
|
"id": "claude-3-5-sonnet-20241022",
|
||||||
"swe_score": 0.49,
|
"swe_score": 0.49,
|
||||||
"cost_per_1m_tokens": { "input": 3.0, "output": 15.0 },
|
"cost_per_1m_tokens": { "input": 3.0, "output": 15.0 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 64000
|
"max_tokens": 64000
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"openai": [
|
"openai": [
|
||||||
{
|
{
|
||||||
"id": "gpt-4o",
|
"id": "gpt-4o",
|
||||||
"swe_score": 0.332,
|
"swe_score": 0.332,
|
||||||
"cost_per_1m_tokens": { "input": 2.5, "output": 10.0 },
|
"cost_per_1m_tokens": { "input": 2.5, "output": 10.0 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 16384
|
"max_tokens": 16384
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "o1",
|
"id": "o1",
|
||||||
"swe_score": 0.489,
|
"swe_score": 0.489,
|
||||||
"cost_per_1m_tokens": { "input": 15.0, "output": 60.0 },
|
"cost_per_1m_tokens": { "input": 15.0, "output": 60.0 },
|
||||||
"allowed_roles": ["main"]
|
"allowed_roles": ["main"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "o3",
|
"id": "o3",
|
||||||
"swe_score": 0.5,
|
"swe_score": 0.5,
|
||||||
"cost_per_1m_tokens": { "input": 10.0, "output": 40.0 },
|
"cost_per_1m_tokens": { "input": 10.0, "output": 40.0 },
|
||||||
"allowed_roles": ["main", "fallback"]
|
"allowed_roles": ["main", "fallback"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "o3-mini",
|
"id": "o3-mini",
|
||||||
"swe_score": 0.493,
|
"swe_score": 0.493,
|
||||||
"cost_per_1m_tokens": { "input": 1.1, "output": 4.4 },
|
"cost_per_1m_tokens": { "input": 1.1, "output": 4.4 },
|
||||||
"allowed_roles": ["main"],
|
"allowed_roles": ["main"],
|
||||||
"max_tokens": 100000
|
"max_tokens": 100000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "o4-mini",
|
"id": "o4-mini",
|
||||||
"swe_score": 0.45,
|
"swe_score": 0.45,
|
||||||
"cost_per_1m_tokens": { "input": 1.1, "output": 4.4 },
|
"cost_per_1m_tokens": { "input": 1.1, "output": 4.4 },
|
||||||
"allowed_roles": ["main", "fallback"]
|
"allowed_roles": ["main", "fallback"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "o1-mini",
|
"id": "o1-mini",
|
||||||
"swe_score": 0.4,
|
"swe_score": 0.4,
|
||||||
"cost_per_1m_tokens": { "input": 1.1, "output": 4.4 },
|
"cost_per_1m_tokens": { "input": 1.1, "output": 4.4 },
|
||||||
"allowed_roles": ["main"]
|
"allowed_roles": ["main"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "o1-pro",
|
"id": "o1-pro",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 150.0, "output": 600.0 },
|
"cost_per_1m_tokens": { "input": 150.0, "output": 600.0 },
|
||||||
"allowed_roles": ["main"]
|
"allowed_roles": ["main"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "gpt-4-5-preview",
|
"id": "gpt-4-5-preview",
|
||||||
"swe_score": 0.38,
|
"swe_score": 0.38,
|
||||||
"cost_per_1m_tokens": { "input": 75.0, "output": 150.0 },
|
"cost_per_1m_tokens": { "input": 75.0, "output": 150.0 },
|
||||||
"allowed_roles": ["main"]
|
"allowed_roles": ["main"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "gpt-4-1-mini",
|
"id": "gpt-4-1-mini",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0.4, "output": 1.6 },
|
"cost_per_1m_tokens": { "input": 0.4, "output": 1.6 },
|
||||||
"allowed_roles": ["main"]
|
"allowed_roles": ["main"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "gpt-4-1-nano",
|
"id": "gpt-4-1-nano",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0.1, "output": 0.4 },
|
"cost_per_1m_tokens": { "input": 0.1, "output": 0.4 },
|
||||||
"allowed_roles": ["main"]
|
"allowed_roles": ["main"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "gpt-4o-mini",
|
"id": "gpt-4o-mini",
|
||||||
"swe_score": 0.3,
|
"swe_score": 0.3,
|
||||||
"cost_per_1m_tokens": { "input": 0.15, "output": 0.6 },
|
"cost_per_1m_tokens": { "input": 0.15, "output": 0.6 },
|
||||||
"allowed_roles": ["main"]
|
"allowed_roles": ["main"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "gpt-4o-search-preview",
|
"id": "gpt-4o-search-preview",
|
||||||
"swe_score": 0.33,
|
"swe_score": 0.33,
|
||||||
"cost_per_1m_tokens": { "input": 2.5, "output": 10.0 },
|
"cost_per_1m_tokens": { "input": 2.5, "output": 10.0 },
|
||||||
"allowed_roles": ["research"]
|
"allowed_roles": ["research"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "gpt-4o-mini-search-preview",
|
"id": "gpt-4o-mini-search-preview",
|
||||||
"swe_score": 0.3,
|
"swe_score": 0.3,
|
||||||
"cost_per_1m_tokens": { "input": 0.15, "output": 0.6 },
|
"cost_per_1m_tokens": { "input": 0.15, "output": 0.6 },
|
||||||
"allowed_roles": ["research"]
|
"allowed_roles": ["research"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"google": [
|
"google": [
|
||||||
{
|
{
|
||||||
"id": "gemini-2.5-pro-preview-05-06",
|
"id": "gemini-2.5-pro-preview-05-06",
|
||||||
"swe_score": 0.638,
|
"swe_score": 0.638,
|
||||||
"cost_per_1m_tokens": null,
|
"cost_per_1m_tokens": null,
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 1048000
|
"max_tokens": 1048000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "gemini-2.5-pro-preview-03-25",
|
"id": "gemini-2.5-pro-preview-03-25",
|
||||||
"swe_score": 0.638,
|
"swe_score": 0.638,
|
||||||
"cost_per_1m_tokens": null,
|
"cost_per_1m_tokens": null,
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 1048000
|
"max_tokens": 1048000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "gemini-2.5-flash-preview-04-17",
|
"id": "gemini-2.5-flash-preview-04-17",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": null,
|
"cost_per_1m_tokens": null,
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 1048000
|
"max_tokens": 1048000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "gemini-2.0-flash",
|
"id": "gemini-2.0-flash",
|
||||||
"swe_score": 0.754,
|
"swe_score": 0.754,
|
||||||
"cost_per_1m_tokens": { "input": 0.15, "output": 0.6 },
|
"cost_per_1m_tokens": { "input": 0.15, "output": 0.6 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 1048000
|
"max_tokens": 1048000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "gemini-2.0-flash-lite",
|
"id": "gemini-2.0-flash-lite",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": null,
|
"cost_per_1m_tokens": null,
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 1048000
|
"max_tokens": 1048000
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"perplexity": [
|
"perplexity": [
|
||||||
{
|
{
|
||||||
"id": "sonar-pro",
|
"id": "sonar-pro",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 3, "output": 15 },
|
"cost_per_1m_tokens": { "input": 3, "output": 15 },
|
||||||
"allowed_roles": ["main", "research"],
|
"allowed_roles": ["main", "research"],
|
||||||
"max_tokens": 8700
|
"max_tokens": 8700
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "sonar",
|
"id": "sonar",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 1, "output": 1 },
|
"cost_per_1m_tokens": { "input": 1, "output": 1 },
|
||||||
"allowed_roles": ["research"],
|
"allowed_roles": ["research"],
|
||||||
"max_tokens": 8700
|
"max_tokens": 8700
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "deep-research",
|
"id": "deep-research",
|
||||||
"swe_score": 0.211,
|
"swe_score": 0.211,
|
||||||
"cost_per_1m_tokens": { "input": 2, "output": 8 },
|
"cost_per_1m_tokens": { "input": 2, "output": 8 },
|
||||||
"allowed_roles": ["research"],
|
"allowed_roles": ["research"],
|
||||||
"max_tokens": 8700
|
"max_tokens": 8700
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "sonar-reasoning-pro",
|
"id": "sonar-reasoning-pro",
|
||||||
"swe_score": 0.211,
|
"swe_score": 0.211,
|
||||||
"cost_per_1m_tokens": { "input": 2, "output": 8 },
|
"cost_per_1m_tokens": { "input": 2, "output": 8 },
|
||||||
"allowed_roles": ["main", "research", "fallback"],
|
"allowed_roles": ["main", "research", "fallback"],
|
||||||
"max_tokens": 8700
|
"max_tokens": 8700
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "sonar-reasoning",
|
"id": "sonar-reasoning",
|
||||||
"swe_score": 0.211,
|
"swe_score": 0.211,
|
||||||
"cost_per_1m_tokens": { "input": 1, "output": 5 },
|
"cost_per_1m_tokens": { "input": 1, "output": 5 },
|
||||||
"allowed_roles": ["main", "research", "fallback"],
|
"allowed_roles": ["main", "research", "fallback"],
|
||||||
"max_tokens": 8700
|
"max_tokens": 8700
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"xai": [
|
"xai": [
|
||||||
{
|
{
|
||||||
"id": "grok-3",
|
"id": "grok-3",
|
||||||
"name": "Grok 3",
|
"name": "Grok 3",
|
||||||
"swe_score": null,
|
"swe_score": null,
|
||||||
"cost_per_1m_tokens": { "input": 3, "output": 15 },
|
"cost_per_1m_tokens": { "input": 3, "output": 15 },
|
||||||
"allowed_roles": ["main", "fallback", "research"],
|
"allowed_roles": ["main", "fallback", "research"],
|
||||||
"max_tokens": 131072
|
"max_tokens": 131072
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "grok-3-fast",
|
"id": "grok-3-fast",
|
||||||
"name": "Grok 3 Fast",
|
"name": "Grok 3 Fast",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 5, "output": 25 },
|
"cost_per_1m_tokens": { "input": 5, "output": 25 },
|
||||||
"allowed_roles": ["main", "fallback", "research"],
|
"allowed_roles": ["main", "fallback", "research"],
|
||||||
"max_tokens": 131072
|
"max_tokens": 131072
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ollama": [
|
"ollama": [
|
||||||
{
|
{
|
||||||
"id": "devstral:latest",
|
"id": "devstral:latest",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
||||||
"allowed_roles": ["main", "fallback"]
|
"allowed_roles": ["main", "fallback"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "qwen3:latest",
|
"id": "qwen3:latest",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
||||||
"allowed_roles": ["main", "fallback"]
|
"allowed_roles": ["main", "fallback"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "qwen3:14b",
|
"id": "qwen3:14b",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
||||||
"allowed_roles": ["main", "fallback"]
|
"allowed_roles": ["main", "fallback"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "qwen3:32b",
|
"id": "qwen3:32b",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
||||||
"allowed_roles": ["main", "fallback"]
|
"allowed_roles": ["main", "fallback"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mistral-small3.1:latest",
|
"id": "mistral-small3.1:latest",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
||||||
"allowed_roles": ["main", "fallback"]
|
"allowed_roles": ["main", "fallback"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "llama3.3:latest",
|
"id": "llama3.3:latest",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
||||||
"allowed_roles": ["main", "fallback"]
|
"allowed_roles": ["main", "fallback"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "phi4:latest",
|
"id": "phi4:latest",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
||||||
"allowed_roles": ["main", "fallback"]
|
"allowed_roles": ["main", "fallback"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"openrouter": [
|
"openrouter": [
|
||||||
{
|
{
|
||||||
"id": "google/gemini-2.5-flash-preview-05-20",
|
"id": "google/gemini-2.5-flash-preview-05-20",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0.15, "output": 0.6 },
|
"cost_per_1m_tokens": { "input": 0.15, "output": 0.6 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 1048576
|
"max_tokens": 1048576
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "google/gemini-2.5-flash-preview-05-20:thinking",
|
"id": "google/gemini-2.5-flash-preview-05-20:thinking",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0.15, "output": 3.5 },
|
"cost_per_1m_tokens": { "input": 0.15, "output": 3.5 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 1048576
|
"max_tokens": 1048576
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "google/gemini-2.5-pro-exp-03-25",
|
"id": "google/gemini-2.5-pro-exp-03-25",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 1000000
|
"max_tokens": 1000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "deepseek/deepseek-chat-v3-0324:free",
|
"id": "deepseek/deepseek-chat-v3-0324:free",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 163840
|
"max_tokens": 163840
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "deepseek/deepseek-chat-v3-0324",
|
"id": "deepseek/deepseek-chat-v3-0324",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0.27, "output": 1.1 },
|
"cost_per_1m_tokens": { "input": 0.27, "output": 1.1 },
|
||||||
"allowed_roles": ["main"],
|
"allowed_roles": ["main"],
|
||||||
"max_tokens": 64000
|
"max_tokens": 64000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "openai/gpt-4.1",
|
"id": "openai/gpt-4.1",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 2, "output": 8 },
|
"cost_per_1m_tokens": { "input": 2, "output": 8 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 1000000
|
"max_tokens": 1000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "openai/gpt-4.1-mini",
|
"id": "openai/gpt-4.1-mini",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0.4, "output": 1.6 },
|
"cost_per_1m_tokens": { "input": 0.4, "output": 1.6 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 1000000
|
"max_tokens": 1000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "openai/gpt-4.1-nano",
|
"id": "openai/gpt-4.1-nano",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0.1, "output": 0.4 },
|
"cost_per_1m_tokens": { "input": 0.1, "output": 0.4 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 1000000
|
"max_tokens": 1000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "openai/o3",
|
"id": "openai/o3",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 10, "output": 40 },
|
"cost_per_1m_tokens": { "input": 10, "output": 40 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 200000
|
"max_tokens": 200000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "openai/codex-mini",
|
"id": "openai/codex-mini",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 1.5, "output": 6 },
|
"cost_per_1m_tokens": { "input": 1.5, "output": 6 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 100000
|
"max_tokens": 100000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "openai/gpt-4o-mini",
|
"id": "openai/gpt-4o-mini",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0.15, "output": 0.6 },
|
"cost_per_1m_tokens": { "input": 0.15, "output": 0.6 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 100000
|
"max_tokens": 100000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "openai/o4-mini",
|
"id": "openai/o4-mini",
|
||||||
"swe_score": 0.45,
|
"swe_score": 0.45,
|
||||||
"cost_per_1m_tokens": { "input": 1.1, "output": 4.4 },
|
"cost_per_1m_tokens": { "input": 1.1, "output": 4.4 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 100000
|
"max_tokens": 100000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "openai/o4-mini-high",
|
"id": "openai/o4-mini-high",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 1.1, "output": 4.4 },
|
"cost_per_1m_tokens": { "input": 1.1, "output": 4.4 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 100000
|
"max_tokens": 100000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "openai/o1-pro",
|
"id": "openai/o1-pro",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 150, "output": 600 },
|
"cost_per_1m_tokens": { "input": 150, "output": 600 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 100000
|
"max_tokens": 100000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "meta-llama/llama-3.3-70b-instruct",
|
"id": "meta-llama/llama-3.3-70b-instruct",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 120, "output": 600 },
|
"cost_per_1m_tokens": { "input": 120, "output": 600 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 1048576
|
"max_tokens": 1048576
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "meta-llama/llama-4-maverick",
|
"id": "meta-llama/llama-4-maverick",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0.18, "output": 0.6 },
|
"cost_per_1m_tokens": { "input": 0.18, "output": 0.6 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 1000000
|
"max_tokens": 1000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "meta-llama/llama-4-scout",
|
"id": "meta-llama/llama-4-scout",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0.08, "output": 0.3 },
|
"cost_per_1m_tokens": { "input": 0.08, "output": 0.3 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 1000000
|
"max_tokens": 1000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "qwen/qwen-max",
|
"id": "qwen/qwen-max",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 1.6, "output": 6.4 },
|
"cost_per_1m_tokens": { "input": 1.6, "output": 6.4 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 32768
|
"max_tokens": 32768
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "qwen/qwen-turbo",
|
"id": "qwen/qwen-turbo",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0.05, "output": 0.2 },
|
"cost_per_1m_tokens": { "input": 0.05, "output": 0.2 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 1000000
|
"max_tokens": 1000000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "qwen/qwen3-235b-a22b",
|
"id": "qwen/qwen3-235b-a22b",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0.14, "output": 2 },
|
"cost_per_1m_tokens": { "input": 0.14, "output": 2 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 24000
|
"max_tokens": 24000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mistralai/mistral-small-3.1-24b-instruct:free",
|
"id": "mistralai/mistral-small-3.1-24b-instruct:free",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 96000
|
"max_tokens": 96000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mistralai/mistral-small-3.1-24b-instruct",
|
"id": "mistralai/mistral-small-3.1-24b-instruct",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0.1, "output": 0.3 },
|
"cost_per_1m_tokens": { "input": 0.1, "output": 0.3 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 128000
|
"max_tokens": 128000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mistralai/devstral-small",
|
"id": "mistralai/devstral-small",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0.1, "output": 0.3 },
|
"cost_per_1m_tokens": { "input": 0.1, "output": 0.3 },
|
||||||
"allowed_roles": ["main"],
|
"allowed_roles": ["main"],
|
||||||
"max_tokens": 110000
|
"max_tokens": 110000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "mistralai/mistral-nemo",
|
"id": "mistralai/mistral-nemo",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0.03, "output": 0.07 },
|
"cost_per_1m_tokens": { "input": 0.03, "output": 0.07 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 100000
|
"max_tokens": 100000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "thudm/glm-4-32b:free",
|
"id": "thudm/glm-4-32b:free",
|
||||||
"swe_score": 0,
|
"swe_score": 0,
|
||||||
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
"cost_per_1m_tokens": { "input": 0, "output": 0 },
|
||||||
"allowed_roles": ["main", "fallback"],
|
"allowed_roles": ["main", "fallback"],
|
||||||
"max_tokens": 32768
|
"max_tokens": 32768
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,11 @@
|
|||||||
import path from "path";
|
import path from 'path';
|
||||||
import chalk from "chalk";
|
import chalk from 'chalk';
|
||||||
import boxen from "boxen";
|
import boxen from 'boxen';
|
||||||
import Table from "cli-table3";
|
import Table from 'cli-table3';
|
||||||
|
|
||||||
import { log, readJSON, writeJSON, truncate, isSilentMode } from "../utils.js";
|
import { log, readJSON, writeJSON, truncate, isSilentMode } from '../utils.js';
|
||||||
import { displayBanner } from "../ui.js";
|
import { displayBanner } from '../ui.js';
|
||||||
import generateTaskFiles from "./generate-task-files.js";
|
import generateTaskFiles from './generate-task-files.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear subtasks from specified tasks
|
* Clear subtasks from specified tasks
|
||||||
@@ -13,138 +13,138 @@ import generateTaskFiles from "./generate-task-files.js";
|
|||||||
* @param {string} taskIds - Task IDs to clear subtasks from
|
* @param {string} taskIds - Task IDs to clear subtasks from
|
||||||
*/
|
*/
|
||||||
function clearSubtasks(tasksPath, taskIds) {
|
function clearSubtasks(tasksPath, taskIds) {
|
||||||
log("info", `Reading tasks from ${tasksPath}...`);
|
log('info', `Reading tasks from ${tasksPath}...`);
|
||||||
const data = readJSON(tasksPath);
|
const data = readJSON(tasksPath);
|
||||||
if (!data || !data.tasks) {
|
if (!data || !data.tasks) {
|
||||||
log("error", "No valid tasks found.");
|
log('error', 'No valid tasks found.');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSilentMode()) {
|
if (!isSilentMode()) {
|
||||||
console.log(
|
console.log(
|
||||||
boxen(chalk.white.bold("Clearing Subtasks"), {
|
boxen(chalk.white.bold('Clearing Subtasks'), {
|
||||||
padding: 1,
|
padding: 1,
|
||||||
borderColor: "blue",
|
borderColor: 'blue',
|
||||||
borderStyle: "round",
|
borderStyle: 'round',
|
||||||
margin: { top: 1, bottom: 1 },
|
margin: { top: 1, bottom: 1 }
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle multiple task IDs (comma-separated)
|
// Handle multiple task IDs (comma-separated)
|
||||||
const taskIdArray = taskIds.split(",").map((id) => id.trim());
|
const taskIdArray = taskIds.split(',').map((id) => id.trim());
|
||||||
let clearedCount = 0;
|
let clearedCount = 0;
|
||||||
|
|
||||||
// Create a summary table for the cleared subtasks
|
// Create a summary table for the cleared subtasks
|
||||||
const summaryTable = new Table({
|
const summaryTable = new Table({
|
||||||
head: [
|
head: [
|
||||||
chalk.cyan.bold("Task ID"),
|
chalk.cyan.bold('Task ID'),
|
||||||
chalk.cyan.bold("Task Title"),
|
chalk.cyan.bold('Task Title'),
|
||||||
chalk.cyan.bold("Subtasks Cleared"),
|
chalk.cyan.bold('Subtasks Cleared')
|
||||||
],
|
],
|
||||||
colWidths: [10, 50, 20],
|
colWidths: [10, 50, 20],
|
||||||
style: { head: [], border: [] },
|
style: { head: [], border: [] }
|
||||||
});
|
});
|
||||||
|
|
||||||
taskIdArray.forEach((taskId) => {
|
taskIdArray.forEach((taskId) => {
|
||||||
const id = parseInt(taskId, 10);
|
const id = parseInt(taskId, 10);
|
||||||
if (isNaN(id)) {
|
if (isNaN(id)) {
|
||||||
log("error", `Invalid task ID: ${taskId}`);
|
log('error', `Invalid task ID: ${taskId}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const task = data.tasks.find((t) => t.id === id);
|
const task = data.tasks.find((t) => t.id === id);
|
||||||
if (!task) {
|
if (!task) {
|
||||||
log("error", `Task ${id} not found`);
|
log('error', `Task ${id} not found`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!task.subtasks || task.subtasks.length === 0) {
|
if (!task.subtasks || task.subtasks.length === 0) {
|
||||||
log("info", `Task ${id} has no subtasks to clear`);
|
log('info', `Task ${id} has no subtasks to clear`);
|
||||||
summaryTable.push([
|
summaryTable.push([
|
||||||
id.toString(),
|
id.toString(),
|
||||||
truncate(task.title, 47),
|
truncate(task.title, 47),
|
||||||
chalk.yellow("No subtasks"),
|
chalk.yellow('No subtasks')
|
||||||
]);
|
]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const subtaskCount = task.subtasks.length;
|
const subtaskCount = task.subtasks.length;
|
||||||
task.subtasks = [];
|
task.subtasks = [];
|
||||||
clearedCount++;
|
clearedCount++;
|
||||||
log("info", `Cleared ${subtaskCount} subtasks from task ${id}`);
|
log('info', `Cleared ${subtaskCount} subtasks from task ${id}`);
|
||||||
|
|
||||||
summaryTable.push([
|
summaryTable.push([
|
||||||
id.toString(),
|
id.toString(),
|
||||||
truncate(task.title, 47),
|
truncate(task.title, 47),
|
||||||
chalk.green(`${subtaskCount} subtasks cleared`),
|
chalk.green(`${subtaskCount} subtasks cleared`)
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (clearedCount > 0) {
|
if (clearedCount > 0) {
|
||||||
writeJSON(tasksPath, data);
|
writeJSON(tasksPath, data);
|
||||||
|
|
||||||
// Show summary table
|
// Show summary table
|
||||||
if (!isSilentMode()) {
|
if (!isSilentMode()) {
|
||||||
console.log(
|
console.log(
|
||||||
boxen(chalk.white.bold("Subtask Clearing Summary:"), {
|
boxen(chalk.white.bold('Subtask Clearing Summary:'), {
|
||||||
padding: { left: 2, right: 2, top: 0, bottom: 0 },
|
padding: { left: 2, right: 2, top: 0, bottom: 0 },
|
||||||
margin: { top: 1, bottom: 0 },
|
margin: { top: 1, bottom: 0 },
|
||||||
borderColor: "blue",
|
borderColor: 'blue',
|
||||||
borderStyle: "round",
|
borderStyle: 'round'
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
console.log(summaryTable.toString());
|
console.log(summaryTable.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regenerate task files to reflect changes
|
// Regenerate task files to reflect changes
|
||||||
log("info", "Regenerating task files...");
|
log('info', 'Regenerating task files...');
|
||||||
generateTaskFiles(tasksPath, path.dirname(tasksPath));
|
generateTaskFiles(tasksPath, path.dirname(tasksPath));
|
||||||
|
|
||||||
// Success message
|
// Success message
|
||||||
if (!isSilentMode()) {
|
if (!isSilentMode()) {
|
||||||
console.log(
|
console.log(
|
||||||
boxen(
|
boxen(
|
||||||
chalk.green(
|
chalk.green(
|
||||||
`Successfully cleared subtasks from ${chalk.bold(clearedCount)} task(s)`
|
`Successfully cleared subtasks from ${chalk.bold(clearedCount)} task(s)`
|
||||||
),
|
),
|
||||||
{
|
{
|
||||||
padding: 1,
|
padding: 1,
|
||||||
borderColor: "green",
|
borderColor: 'green',
|
||||||
borderStyle: "round",
|
borderStyle: 'round',
|
||||||
margin: { top: 1 },
|
margin: { top: 1 }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Next steps suggestion
|
// Next steps suggestion
|
||||||
console.log(
|
console.log(
|
||||||
boxen(
|
boxen(
|
||||||
chalk.white.bold("Next Steps:") +
|
chalk.white.bold('Next Steps:') +
|
||||||
"\n\n" +
|
'\n\n' +
|
||||||
`${chalk.cyan("1.")} Run ${chalk.yellow("task-master expand --id=<id>")} to generate new subtasks\n` +
|
`${chalk.cyan('1.')} Run ${chalk.yellow('task-master expand --id=<id>')} to generate new subtasks\n` +
|
||||||
`${chalk.cyan("2.")} Run ${chalk.yellow("task-master list --with-subtasks")} to verify changes`,
|
`${chalk.cyan('2.')} Run ${chalk.yellow('task-master list --with-subtasks')} to verify changes`,
|
||||||
{
|
{
|
||||||
padding: 1,
|
padding: 1,
|
||||||
borderColor: "cyan",
|
borderColor: 'cyan',
|
||||||
borderStyle: "round",
|
borderStyle: 'round',
|
||||||
margin: { top: 1 },
|
margin: { top: 1 }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!isSilentMode()) {
|
if (!isSilentMode()) {
|
||||||
console.log(
|
console.log(
|
||||||
boxen(chalk.yellow("No subtasks were cleared"), {
|
boxen(chalk.yellow('No subtasks were cleared'), {
|
||||||
padding: 1,
|
padding: 1,
|
||||||
borderColor: "yellow",
|
borderColor: 'yellow',
|
||||||
borderStyle: "round",
|
borderStyle: 'round',
|
||||||
margin: { top: 1 },
|
margin: { top: 1 }
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default clearSubtasks;
|
export default clearSubtasks;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,17 @@
|
|||||||
import path from "path";
|
import path from 'path';
|
||||||
import chalk from "chalk";
|
import chalk from 'chalk';
|
||||||
import boxen from "boxen";
|
import boxen from 'boxen';
|
||||||
|
|
||||||
import { log, readJSON, writeJSON, findTaskById } from "../utils.js";
|
import { log, readJSON, writeJSON, findTaskById } from '../utils.js';
|
||||||
import { displayBanner } from "../ui.js";
|
import { displayBanner } from '../ui.js';
|
||||||
import { validateTaskDependencies } from "../dependency-manager.js";
|
import { validateTaskDependencies } from '../dependency-manager.js';
|
||||||
import { getDebugFlag } from "../config-manager.js";
|
import { getDebugFlag } from '../config-manager.js';
|
||||||
import updateSingleTaskStatus from "./update-single-task-status.js";
|
import updateSingleTaskStatus from './update-single-task-status.js';
|
||||||
import generateTaskFiles from "./generate-task-files.js";
|
import generateTaskFiles from './generate-task-files.js';
|
||||||
import {
|
import {
|
||||||
isValidTaskStatus,
|
isValidTaskStatus,
|
||||||
TASK_STATUS_OPTIONS,
|
TASK_STATUS_OPTIONS
|
||||||
} from "../../../src/constants/task-status.js";
|
} from '../../../src/constants/task-status.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the status of a task
|
* Set the status of a task
|
||||||
@@ -22,100 +22,100 @@ import {
|
|||||||
* @returns {Object|undefined} Result object in MCP mode, undefined in CLI mode
|
* @returns {Object|undefined} Result object in MCP mode, undefined in CLI mode
|
||||||
*/
|
*/
|
||||||
async function setTaskStatus(tasksPath, taskIdInput, newStatus, options = {}) {
|
async function setTaskStatus(tasksPath, taskIdInput, newStatus, options = {}) {
|
||||||
try {
|
try {
|
||||||
if (!isValidTaskStatus(newStatus)) {
|
if (!isValidTaskStatus(newStatus)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Error: Invalid status value: ${newStatus}. Use one of: ${TASK_STATUS_OPTIONS.join(", ")}`
|
`Error: Invalid status value: ${newStatus}. Use one of: ${TASK_STATUS_OPTIONS.join(', ')}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Determine if we're in MCP mode by checking for mcpLog
|
// Determine if we're in MCP mode by checking for mcpLog
|
||||||
const isMcpMode = !!options?.mcpLog;
|
const isMcpMode = !!options?.mcpLog;
|
||||||
|
|
||||||
// Only display UI elements if not in MCP mode
|
// Only display UI elements if not in MCP mode
|
||||||
if (!isMcpMode) {
|
if (!isMcpMode) {
|
||||||
console.log(
|
console.log(
|
||||||
boxen(chalk.white.bold(`Updating Task Status to: ${newStatus}`), {
|
boxen(chalk.white.bold(`Updating Task Status to: ${newStatus}`), {
|
||||||
padding: 1,
|
padding: 1,
|
||||||
borderColor: "blue",
|
borderColor: 'blue',
|
||||||
borderStyle: "round",
|
borderStyle: 'round'
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
log("info", `Reading tasks from ${tasksPath}...`);
|
log('info', `Reading tasks from ${tasksPath}...`);
|
||||||
const data = readJSON(tasksPath);
|
const data = readJSON(tasksPath);
|
||||||
if (!data || !data.tasks) {
|
if (!data || !data.tasks) {
|
||||||
throw new Error(`No valid tasks found in ${tasksPath}`);
|
throw new Error(`No valid tasks found in ${tasksPath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle multiple task IDs (comma-separated)
|
// Handle multiple task IDs (comma-separated)
|
||||||
const taskIds = taskIdInput.split(",").map((id) => id.trim());
|
const taskIds = taskIdInput.split(',').map((id) => id.trim());
|
||||||
const updatedTasks = [];
|
const updatedTasks = [];
|
||||||
|
|
||||||
// Update each task
|
// Update each task
|
||||||
for (const id of taskIds) {
|
for (const id of taskIds) {
|
||||||
await updateSingleTaskStatus(tasksPath, id, newStatus, data, !isMcpMode);
|
await updateSingleTaskStatus(tasksPath, id, newStatus, data, !isMcpMode);
|
||||||
updatedTasks.push(id);
|
updatedTasks.push(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the updated tasks to the file
|
// Write the updated tasks to the file
|
||||||
writeJSON(tasksPath, data);
|
writeJSON(tasksPath, data);
|
||||||
|
|
||||||
// Validate dependencies after status update
|
// Validate dependencies after status update
|
||||||
log("info", "Validating dependencies after status update...");
|
log('info', 'Validating dependencies after status update...');
|
||||||
validateTaskDependencies(data.tasks);
|
validateTaskDependencies(data.tasks);
|
||||||
|
|
||||||
// Generate individual task files
|
// Generate individual task files
|
||||||
log("info", "Regenerating task files...");
|
log('info', 'Regenerating task files...');
|
||||||
await generateTaskFiles(tasksPath, path.dirname(tasksPath), {
|
await generateTaskFiles(tasksPath, path.dirname(tasksPath), {
|
||||||
mcpLog: options.mcpLog,
|
mcpLog: options.mcpLog
|
||||||
});
|
});
|
||||||
|
|
||||||
// Display success message - only in CLI mode
|
// Display success message - only in CLI mode
|
||||||
if (!isMcpMode) {
|
if (!isMcpMode) {
|
||||||
for (const id of updatedTasks) {
|
for (const id of updatedTasks) {
|
||||||
const task = findTaskById(data.tasks, id);
|
const task = findTaskById(data.tasks, id);
|
||||||
const taskName = task ? task.title : id;
|
const taskName = task ? task.title : id;
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
boxen(
|
boxen(
|
||||||
chalk.white.bold(`Successfully updated task ${id} status:`) +
|
chalk.white.bold(`Successfully updated task ${id} status:`) +
|
||||||
"\n" +
|
'\n' +
|
||||||
`From: ${chalk.yellow(task ? task.status : "unknown")}\n` +
|
`From: ${chalk.yellow(task ? task.status : 'unknown')}\n` +
|
||||||
`To: ${chalk.green(newStatus)}`,
|
`To: ${chalk.green(newStatus)}`,
|
||||||
{ padding: 1, borderColor: "green", borderStyle: "round" }
|
{ padding: 1, borderColor: 'green', borderStyle: 'round' }
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return success value for programmatic use
|
// Return success value for programmatic use
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
updatedTasks: updatedTasks.map((id) => ({
|
updatedTasks: updatedTasks.map((id) => ({
|
||||||
id,
|
id,
|
||||||
status: newStatus,
|
status: newStatus
|
||||||
})),
|
}))
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log("error", `Error setting task status: ${error.message}`);
|
log('error', `Error setting task status: ${error.message}`);
|
||||||
|
|
||||||
// Only show error UI in CLI mode
|
// Only show error UI in CLI mode
|
||||||
if (!options?.mcpLog) {
|
if (!options?.mcpLog) {
|
||||||
console.error(chalk.red(`Error: ${error.message}`));
|
console.error(chalk.red(`Error: ${error.message}`));
|
||||||
|
|
||||||
// Pass session to getDebugFlag
|
// Pass session to getDebugFlag
|
||||||
if (getDebugFlag(options?.session)) {
|
if (getDebugFlag(options?.session)) {
|
||||||
// Use getter
|
// Use getter
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
} else {
|
} else {
|
||||||
// In MCP mode, throw the error for the caller to handle
|
// In MCP mode, throw the error for the caller to handle
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default setTaskStatus;
|
export default setTaskStatus;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,214 +1,214 @@
|
|||||||
import { generateText, streamText, generateObject } from "ai";
|
import { generateText, streamText, generateObject } from 'ai';
|
||||||
import { log } from "../../scripts/modules/index.js";
|
import { log } from '../../scripts/modules/index.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for all AI providers
|
* Base class for all AI providers
|
||||||
*/
|
*/
|
||||||
export class BaseAIProvider {
|
export class BaseAIProvider {
|
||||||
constructor() {
|
constructor() {
|
||||||
if (this.constructor === BaseAIProvider) {
|
if (this.constructor === BaseAIProvider) {
|
||||||
throw new Error("BaseAIProvider cannot be instantiated directly");
|
throw new Error('BaseAIProvider cannot be instantiated directly');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each provider must set their name
|
// Each provider must set their name
|
||||||
this.name = this.constructor.name;
|
this.name = this.constructor.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates authentication parameters - can be overridden by providers
|
* Validates authentication parameters - can be overridden by providers
|
||||||
* @param {object} params - Parameters to validate
|
* @param {object} params - Parameters to validate
|
||||||
*/
|
*/
|
||||||
validateAuth(params) {
|
validateAuth(params) {
|
||||||
// Default: require API key (most providers need this)
|
// Default: require API key (most providers need this)
|
||||||
if (!params.apiKey) {
|
if (!params.apiKey) {
|
||||||
throw new Error(`${this.name} API key is required`);
|
throw new Error(`${this.name} API key is required`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates common parameters across all methods
|
* Validates common parameters across all methods
|
||||||
* @param {object} params - Parameters to validate
|
* @param {object} params - Parameters to validate
|
||||||
*/
|
*/
|
||||||
validateParams(params) {
|
validateParams(params) {
|
||||||
// Validate authentication (can be overridden by providers)
|
// Validate authentication (can be overridden by providers)
|
||||||
this.validateAuth(params);
|
this.validateAuth(params);
|
||||||
|
|
||||||
// Validate required model ID
|
// Validate required model ID
|
||||||
if (!params.modelId) {
|
if (!params.modelId) {
|
||||||
throw new Error(`${this.name} Model ID is required`);
|
throw new Error(`${this.name} Model ID is required`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate optional parameters
|
// Validate optional parameters
|
||||||
this.validateOptionalParams(params);
|
this.validateOptionalParams(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates optional parameters like temperature and maxTokens
|
* Validates optional parameters like temperature and maxTokens
|
||||||
* @param {object} params - Parameters to validate
|
* @param {object} params - Parameters to validate
|
||||||
*/
|
*/
|
||||||
validateOptionalParams(params) {
|
validateOptionalParams(params) {
|
||||||
if (
|
if (
|
||||||
params.temperature !== undefined &&
|
params.temperature !== undefined &&
|
||||||
(params.temperature < 0 || params.temperature > 1)
|
(params.temperature < 0 || params.temperature > 1)
|
||||||
) {
|
) {
|
||||||
throw new Error("Temperature must be between 0 and 1");
|
throw new Error('Temperature must be between 0 and 1');
|
||||||
}
|
}
|
||||||
if (params.maxTokens !== undefined && params.maxTokens <= 0) {
|
if (params.maxTokens !== undefined && params.maxTokens <= 0) {
|
||||||
throw new Error("maxTokens must be greater than 0");
|
throw new Error('maxTokens must be greater than 0');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates message array structure
|
* Validates message array structure
|
||||||
*/
|
*/
|
||||||
validateMessages(messages) {
|
validateMessages(messages) {
|
||||||
if (!messages || !Array.isArray(messages) || messages.length === 0) {
|
if (!messages || !Array.isArray(messages) || messages.length === 0) {
|
||||||
throw new Error("Invalid or empty messages array provided");
|
throw new Error('Invalid or empty messages array provided');
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const msg of messages) {
|
for (const msg of messages) {
|
||||||
if (!msg.role || !msg.content) {
|
if (!msg.role || !msg.content) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Invalid message format. Each message must have role and content"
|
'Invalid message format. Each message must have role and content'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common error handler
|
* Common error handler
|
||||||
*/
|
*/
|
||||||
handleError(operation, error) {
|
handleError(operation, error) {
|
||||||
const errorMessage = error.message || "Unknown error occurred";
|
const errorMessage = error.message || 'Unknown error occurred';
|
||||||
log("error", `${this.name} ${operation} failed: ${errorMessage}`, {
|
log('error', `${this.name} ${operation} failed: ${errorMessage}`, {
|
||||||
error,
|
error
|
||||||
});
|
});
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`${this.name} API error during ${operation}: ${errorMessage}`
|
`${this.name} API error during ${operation}: ${errorMessage}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and returns a client instance for the provider
|
* Creates and returns a client instance for the provider
|
||||||
* @abstract
|
* @abstract
|
||||||
*/
|
*/
|
||||||
getClient(params) {
|
getClient(params) {
|
||||||
throw new Error("getClient must be implemented by provider");
|
throw new Error('getClient must be implemented by provider');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates text using the provider's model
|
* Generates text using the provider's model
|
||||||
*/
|
*/
|
||||||
async generateText(params) {
|
async generateText(params) {
|
||||||
try {
|
try {
|
||||||
this.validateParams(params);
|
this.validateParams(params);
|
||||||
this.validateMessages(params.messages);
|
this.validateMessages(params.messages);
|
||||||
|
|
||||||
log(
|
log(
|
||||||
"debug",
|
'debug',
|
||||||
`Generating ${this.name} text with model: ${params.modelId}`
|
`Generating ${this.name} text with model: ${params.modelId}`
|
||||||
);
|
);
|
||||||
|
|
||||||
const client = this.getClient(params);
|
const client = this.getClient(params);
|
||||||
const result = await generateText({
|
const result = await generateText({
|
||||||
model: client(params.modelId),
|
model: client(params.modelId),
|
||||||
messages: params.messages,
|
messages: params.messages,
|
||||||
maxTokens: params.maxTokens,
|
maxTokens: params.maxTokens,
|
||||||
temperature: params.temperature,
|
temperature: params.temperature
|
||||||
});
|
});
|
||||||
|
|
||||||
log(
|
log(
|
||||||
"debug",
|
'debug',
|
||||||
`${this.name} generateText completed successfully for model: ${params.modelId}`
|
`${this.name} generateText completed successfully for model: ${params.modelId}`
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
text: result.text,
|
text: result.text,
|
||||||
usage: {
|
usage: {
|
||||||
inputTokens: result.usage?.promptTokens,
|
inputTokens: result.usage?.promptTokens,
|
||||||
outputTokens: result.usage?.completionTokens,
|
outputTokens: result.usage?.completionTokens,
|
||||||
totalTokens: result.usage?.totalTokens,
|
totalTokens: result.usage?.totalTokens
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.handleError("text generation", error);
|
this.handleError('text generation', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Streams text using the provider's model
|
* Streams text using the provider's model
|
||||||
*/
|
*/
|
||||||
async streamText(params) {
|
async streamText(params) {
|
||||||
try {
|
try {
|
||||||
this.validateParams(params);
|
this.validateParams(params);
|
||||||
this.validateMessages(params.messages);
|
this.validateMessages(params.messages);
|
||||||
|
|
||||||
log("debug", `Streaming ${this.name} text with model: ${params.modelId}`);
|
log('debug', `Streaming ${this.name} text with model: ${params.modelId}`);
|
||||||
|
|
||||||
const client = this.getClient(params);
|
const client = this.getClient(params);
|
||||||
const stream = await streamText({
|
const stream = await streamText({
|
||||||
model: client(params.modelId),
|
model: client(params.modelId),
|
||||||
messages: params.messages,
|
messages: params.messages,
|
||||||
maxTokens: params.maxTokens,
|
maxTokens: params.maxTokens,
|
||||||
temperature: params.temperature,
|
temperature: params.temperature
|
||||||
});
|
});
|
||||||
|
|
||||||
log(
|
log(
|
||||||
"debug",
|
'debug',
|
||||||
`${this.name} streamText initiated successfully for model: ${params.modelId}`
|
`${this.name} streamText initiated successfully for model: ${params.modelId}`
|
||||||
);
|
);
|
||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.handleError("text streaming", error);
|
this.handleError('text streaming', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a structured object using the provider's model
|
* Generates a structured object using the provider's model
|
||||||
*/
|
*/
|
||||||
async generateObject(params) {
|
async generateObject(params) {
|
||||||
try {
|
try {
|
||||||
this.validateParams(params);
|
this.validateParams(params);
|
||||||
this.validateMessages(params.messages);
|
this.validateMessages(params.messages);
|
||||||
|
|
||||||
if (!params.schema) {
|
if (!params.schema) {
|
||||||
throw new Error("Schema is required for object generation");
|
throw new Error('Schema is required for object generation');
|
||||||
}
|
}
|
||||||
if (!params.objectName) {
|
if (!params.objectName) {
|
||||||
throw new Error("Object name is required for object generation");
|
throw new Error('Object name is required for object generation');
|
||||||
}
|
}
|
||||||
|
|
||||||
log(
|
log(
|
||||||
"debug",
|
'debug',
|
||||||
`Generating ${this.name} object ('${params.objectName}') with model: ${params.modelId}`
|
`Generating ${this.name} object ('${params.objectName}') with model: ${params.modelId}`
|
||||||
);
|
);
|
||||||
|
|
||||||
const client = this.getClient(params);
|
const client = this.getClient(params);
|
||||||
const result = await generateObject({
|
const result = await generateObject({
|
||||||
model: client(params.modelId),
|
model: client(params.modelId),
|
||||||
messages: params.messages,
|
messages: params.messages,
|
||||||
schema: params.schema,
|
schema: params.schema,
|
||||||
mode: "auto",
|
mode: 'auto',
|
||||||
maxTokens: params.maxTokens,
|
maxTokens: params.maxTokens,
|
||||||
temperature: params.temperature,
|
temperature: params.temperature
|
||||||
});
|
});
|
||||||
|
|
||||||
log(
|
log(
|
||||||
"debug",
|
'debug',
|
||||||
`${this.name} generateObject completed successfully for model: ${params.modelId}`
|
`${this.name} generateObject completed successfully for model: ${params.modelId}`
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
object: result.object,
|
object: result.object,
|
||||||
usage: {
|
usage: {
|
||||||
inputTokens: result.usage?.promptTokens,
|
inputTokens: result.usage?.promptTokens,
|
||||||
outputTokens: result.usage?.completionTokens,
|
outputTokens: result.usage?.completionTokens,
|
||||||
totalTokens: result.usage?.totalTokens,
|
totalTokens: result.usage?.totalTokens
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.handleError("object generation", error);
|
this.handleError('object generation', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,400 +1,404 @@
|
|||||||
/**
|
/**
|
||||||
* Tests for the add-task.js module
|
* Tests for the add-task.js module
|
||||||
*/
|
*/
|
||||||
import { jest } from '@jest/globals';
|
import { jest } from "@jest/globals";
|
||||||
|
|
||||||
// Mock the dependencies before importing the module under test
|
// Mock the dependencies before importing the module under test
|
||||||
jest.unstable_mockModule('../../../../../scripts/modules/utils.js', () => ({
|
jest.unstable_mockModule("../../../../../scripts/modules/utils.js", () => ({
|
||||||
readJSON: jest.fn(),
|
readJSON: jest.fn(),
|
||||||
writeJSON: jest.fn(),
|
writeJSON: jest.fn(),
|
||||||
log: jest.fn(),
|
log: jest.fn(),
|
||||||
CONFIG: {
|
CONFIG: {
|
||||||
model: 'mock-claude-model',
|
model: "mock-claude-model",
|
||||||
maxTokens: 4000,
|
maxTokens: 4000,
|
||||||
temperature: 0.7,
|
temperature: 0.7,
|
||||||
debug: false
|
debug: false,
|
||||||
},
|
},
|
||||||
truncate: jest.fn((text) => text)
|
truncate: jest.fn((text) => text),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.unstable_mockModule('../../../../../scripts/modules/ui.js', () => ({
|
jest.unstable_mockModule("../../../../../scripts/modules/ui.js", () => ({
|
||||||
displayBanner: jest.fn(),
|
displayBanner: jest.fn(),
|
||||||
getStatusWithColor: jest.fn((status) => status),
|
getStatusWithColor: jest.fn((status) => status),
|
||||||
startLoadingIndicator: jest.fn(),
|
startLoadingIndicator: jest.fn(),
|
||||||
stopLoadingIndicator: jest.fn(),
|
stopLoadingIndicator: jest.fn(),
|
||||||
displayAiUsageSummary: jest.fn()
|
succeedLoadingIndicator: jest.fn(),
|
||||||
|
failLoadingIndicator: jest.fn(),
|
||||||
|
warnLoadingIndicator: jest.fn(),
|
||||||
|
infoLoadingIndicator: jest.fn(),
|
||||||
|
displayAiUsageSummary: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.unstable_mockModule(
|
jest.unstable_mockModule(
|
||||||
'../../../../../scripts/modules/ai-services-unified.js',
|
"../../../../../scripts/modules/ai-services-unified.js",
|
||||||
() => ({
|
() => ({
|
||||||
generateObjectService: jest.fn().mockResolvedValue({
|
generateObjectService: jest.fn().mockResolvedValue({
|
||||||
mainResult: {
|
mainResult: {
|
||||||
object: {
|
object: {
|
||||||
title: 'Task from prompt: Create a new authentication system',
|
title: "Task from prompt: Create a new authentication system",
|
||||||
description:
|
description:
|
||||||
'Task generated from: Create a new authentication system',
|
"Task generated from: Create a new authentication system",
|
||||||
details:
|
details:
|
||||||
'Implementation details for task generated from prompt: Create a new authentication system',
|
"Implementation details for task generated from prompt: Create a new authentication system",
|
||||||
testStrategy: 'Write unit tests to verify functionality',
|
testStrategy: "Write unit tests to verify functionality",
|
||||||
dependencies: []
|
dependencies: [],
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
telemetryData: {
|
telemetryData: {
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
userId: '1234567890',
|
userId: "1234567890",
|
||||||
commandName: 'add-task',
|
commandName: "add-task",
|
||||||
modelUsed: 'claude-3-5-sonnet',
|
modelUsed: "claude-3-5-sonnet",
|
||||||
providerName: 'anthropic',
|
providerName: "anthropic",
|
||||||
inputTokens: 1000,
|
inputTokens: 1000,
|
||||||
outputTokens: 500,
|
outputTokens: 500,
|
||||||
totalTokens: 1500,
|
totalTokens: 1500,
|
||||||
totalCost: 0.012414,
|
totalCost: 0.012414,
|
||||||
currency: 'USD'
|
currency: "USD",
|
||||||
}
|
},
|
||||||
})
|
}),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
jest.unstable_mockModule(
|
jest.unstable_mockModule(
|
||||||
'../../../../../scripts/modules/config-manager.js',
|
"../../../../../scripts/modules/config-manager.js",
|
||||||
() => ({
|
() => ({
|
||||||
getDefaultPriority: jest.fn(() => 'medium')
|
getDefaultPriority: jest.fn(() => "medium"),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
jest.unstable_mockModule(
|
jest.unstable_mockModule(
|
||||||
'../../../../../scripts/modules/task-manager/generate-task-files.js',
|
"../../../../../scripts/modules/task-manager/generate-task-files.js",
|
||||||
() => ({
|
() => ({
|
||||||
default: jest.fn().mockResolvedValue()
|
default: jest.fn().mockResolvedValue(),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// Mock external UI libraries
|
// Mock external UI libraries
|
||||||
jest.unstable_mockModule('chalk', () => ({
|
jest.unstable_mockModule("chalk", () => ({
|
||||||
default: {
|
default: {
|
||||||
white: { bold: jest.fn((text) => text) },
|
white: { bold: jest.fn((text) => text) },
|
||||||
cyan: Object.assign(
|
cyan: Object.assign(
|
||||||
jest.fn((text) => text),
|
jest.fn((text) => text),
|
||||||
{
|
{
|
||||||
bold: jest.fn((text) => text)
|
bold: jest.fn((text) => text),
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
green: jest.fn((text) => text),
|
green: jest.fn((text) => text),
|
||||||
yellow: jest.fn((text) => text),
|
yellow: jest.fn((text) => text),
|
||||||
bold: jest.fn((text) => text)
|
bold: jest.fn((text) => text),
|
||||||
}
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.unstable_mockModule('boxen', () => ({
|
jest.unstable_mockModule("boxen", () => ({
|
||||||
default: jest.fn((text) => text)
|
default: jest.fn((text) => text),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.unstable_mockModule('cli-table3', () => ({
|
jest.unstable_mockModule("cli-table3", () => ({
|
||||||
default: jest.fn().mockImplementation(() => ({
|
default: jest.fn().mockImplementation(() => ({
|
||||||
push: jest.fn(),
|
push: jest.fn(),
|
||||||
toString: jest.fn(() => 'mocked table')
|
toString: jest.fn(() => "mocked table"),
|
||||||
}))
|
})),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Import the mocked modules
|
// Import the mocked modules
|
||||||
const { readJSON, writeJSON, log } = await import(
|
const { readJSON, writeJSON, log } = await import(
|
||||||
'../../../../../scripts/modules/utils.js'
|
"../../../../../scripts/modules/utils.js"
|
||||||
);
|
);
|
||||||
|
|
||||||
const { generateObjectService } = await import(
|
const { generateObjectService } = await import(
|
||||||
'../../../../../scripts/modules/ai-services-unified.js'
|
"../../../../../scripts/modules/ai-services-unified.js"
|
||||||
);
|
);
|
||||||
|
|
||||||
const generateTaskFiles = await import(
|
const generateTaskFiles = await import(
|
||||||
'../../../../../scripts/modules/task-manager/generate-task-files.js'
|
"../../../../../scripts/modules/task-manager/generate-task-files.js"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Import the module under test
|
// Import the module under test
|
||||||
const { default: addTask } = await import(
|
const { default: addTask } = await import(
|
||||||
'../../../../../scripts/modules/task-manager/add-task.js'
|
"../../../../../scripts/modules/task-manager/add-task.js"
|
||||||
);
|
);
|
||||||
|
|
||||||
describe('addTask', () => {
|
describe("addTask", () => {
|
||||||
const sampleTasks = {
|
const sampleTasks = {
|
||||||
tasks: [
|
tasks: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
title: 'Task 1',
|
title: "Task 1",
|
||||||
description: 'First task',
|
description: "First task",
|
||||||
status: 'pending',
|
status: "pending",
|
||||||
dependencies: []
|
dependencies: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
title: 'Task 2',
|
title: "Task 2",
|
||||||
description: 'Second task',
|
description: "Second task",
|
||||||
status: 'pending',
|
status: "pending",
|
||||||
dependencies: []
|
dependencies: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
title: 'Task 3',
|
title: "Task 3",
|
||||||
description: 'Third task',
|
description: "Third task",
|
||||||
status: 'pending',
|
status: "pending",
|
||||||
dependencies: [1]
|
dependencies: [1],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create a helper function for consistent mcpLog mock
|
// Create a helper function for consistent mcpLog mock
|
||||||
const createMcpLogMock = () => ({
|
const createMcpLogMock = () => ({
|
||||||
info: jest.fn(),
|
info: jest.fn(),
|
||||||
warn: jest.fn(),
|
warn: jest.fn(),
|
||||||
error: jest.fn(),
|
error: jest.fn(),
|
||||||
debug: jest.fn(),
|
debug: jest.fn(),
|
||||||
success: jest.fn()
|
success: jest.fn(),
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
readJSON.mockReturnValue(JSON.parse(JSON.stringify(sampleTasks)));
|
readJSON.mockReturnValue(JSON.parse(JSON.stringify(sampleTasks)));
|
||||||
|
|
||||||
// Mock console.log to avoid output during tests
|
// Mock console.log to avoid output during tests
|
||||||
jest.spyOn(console, 'log').mockImplementation(() => {});
|
jest.spyOn(console, "log").mockImplementation(() => {});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
console.log.mockRestore();
|
console.log.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should add a new task using AI', async () => {
|
test("should add a new task using AI", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const prompt = 'Create a new authentication system';
|
const prompt = "Create a new authentication system";
|
||||||
const context = {
|
const context = {
|
||||||
mcpLog: createMcpLogMock()
|
mcpLog: createMcpLogMock(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const result = await addTask(
|
const result = await addTask(
|
||||||
'tasks/tasks.json',
|
"tasks/tasks.json",
|
||||||
prompt,
|
prompt,
|
||||||
[],
|
[],
|
||||||
'medium',
|
"medium",
|
||||||
context,
|
context,
|
||||||
'json'
|
"json"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(readJSON).toHaveBeenCalledWith('tasks/tasks.json');
|
expect(readJSON).toHaveBeenCalledWith("tasks/tasks.json");
|
||||||
expect(generateObjectService).toHaveBeenCalledWith(expect.any(Object));
|
expect(generateObjectService).toHaveBeenCalledWith(expect.any(Object));
|
||||||
expect(writeJSON).toHaveBeenCalledWith(
|
expect(writeJSON).toHaveBeenCalledWith(
|
||||||
'tasks/tasks.json',
|
"tasks/tasks.json",
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
tasks: expect.arrayContaining([
|
tasks: expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: 4, // Next ID after existing tasks
|
id: 4, // Next ID after existing tasks
|
||||||
title: expect.stringContaining(
|
title: expect.stringContaining(
|
||||||
'Create a new authentication system'
|
"Create a new authentication system"
|
||||||
),
|
),
|
||||||
status: 'pending'
|
status: "pending",
|
||||||
})
|
}),
|
||||||
])
|
]),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
expect(generateTaskFiles.default).toHaveBeenCalled();
|
expect(generateTaskFiles.default).toHaveBeenCalled();
|
||||||
expect(result).toEqual(
|
expect(result).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
newTaskId: 4,
|
newTaskId: 4,
|
||||||
telemetryData: expect.any(Object)
|
telemetryData: expect.any(Object),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should validate dependencies when adding a task', async () => {
|
test("should validate dependencies when adding a task", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const prompt = 'Create a new authentication system';
|
const prompt = "Create a new authentication system";
|
||||||
const validDependencies = [1, 2]; // These exist in sampleTasks
|
const validDependencies = [1, 2]; // These exist in sampleTasks
|
||||||
const context = {
|
const context = {
|
||||||
mcpLog: createMcpLogMock()
|
mcpLog: createMcpLogMock(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const result = await addTask(
|
const result = await addTask(
|
||||||
'tasks/tasks.json',
|
"tasks/tasks.json",
|
||||||
prompt,
|
prompt,
|
||||||
validDependencies,
|
validDependencies,
|
||||||
'medium',
|
"medium",
|
||||||
context,
|
context,
|
||||||
'json'
|
"json"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(writeJSON).toHaveBeenCalledWith(
|
expect(writeJSON).toHaveBeenCalledWith(
|
||||||
'tasks/tasks.json',
|
"tasks/tasks.json",
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
tasks: expect.arrayContaining([
|
tasks: expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: 4,
|
id: 4,
|
||||||
dependencies: validDependencies
|
dependencies: validDependencies,
|
||||||
})
|
}),
|
||||||
])
|
]),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should filter out invalid dependencies', async () => {
|
test("should filter out invalid dependencies", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const prompt = 'Create a new authentication system';
|
const prompt = "Create a new authentication system";
|
||||||
const invalidDependencies = [999]; // Non-existent task ID
|
const invalidDependencies = [999]; // Non-existent task ID
|
||||||
const context = { mcpLog: createMcpLogMock() };
|
const context = { mcpLog: createMcpLogMock() };
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const result = await addTask(
|
const result = await addTask(
|
||||||
'tasks/tasks.json',
|
"tasks/tasks.json",
|
||||||
prompt,
|
prompt,
|
||||||
invalidDependencies,
|
invalidDependencies,
|
||||||
'medium',
|
"medium",
|
||||||
context,
|
context,
|
||||||
'json'
|
"json"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(writeJSON).toHaveBeenCalledWith(
|
expect(writeJSON).toHaveBeenCalledWith(
|
||||||
'tasks/tasks.json',
|
"tasks/tasks.json",
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
tasks: expect.arrayContaining([
|
tasks: expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: 4,
|
id: 4,
|
||||||
dependencies: [] // Invalid dependencies should be filtered out
|
dependencies: [], // Invalid dependencies should be filtered out
|
||||||
})
|
}),
|
||||||
])
|
]),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
expect(context.mcpLog.warn).toHaveBeenCalledWith(
|
expect(context.mcpLog.warn).toHaveBeenCalledWith(
|
||||||
expect.stringContaining(
|
expect.stringContaining(
|
||||||
'The following dependencies do not exist or are invalid: 999'
|
"The following dependencies do not exist or are invalid: 999"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should use specified priority', async () => {
|
test("should use specified priority", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const prompt = 'Create a new authentication system';
|
const prompt = "Create a new authentication system";
|
||||||
const priority = 'high';
|
const priority = "high";
|
||||||
const context = {
|
const context = {
|
||||||
mcpLog: createMcpLogMock()
|
mcpLog: createMcpLogMock(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await addTask('tasks/tasks.json', prompt, [], priority, context, 'json');
|
await addTask("tasks/tasks.json", prompt, [], priority, context, "json");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(writeJSON).toHaveBeenCalledWith(
|
expect(writeJSON).toHaveBeenCalledWith(
|
||||||
'tasks/tasks.json',
|
"tasks/tasks.json",
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
tasks: expect.arrayContaining([
|
tasks: expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
priority: priority
|
priority: priority,
|
||||||
})
|
}),
|
||||||
])
|
]),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should handle empty tasks file', async () => {
|
test("should handle empty tasks file", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
readJSON.mockReturnValue({ tasks: [] });
|
readJSON.mockReturnValue({ tasks: [] });
|
||||||
const prompt = 'Create a new authentication system';
|
const prompt = "Create a new authentication system";
|
||||||
const context = {
|
const context = {
|
||||||
mcpLog: createMcpLogMock()
|
mcpLog: createMcpLogMock(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const result = await addTask(
|
const result = await addTask(
|
||||||
'tasks/tasks.json',
|
"tasks/tasks.json",
|
||||||
prompt,
|
prompt,
|
||||||
[],
|
[],
|
||||||
'medium',
|
"medium",
|
||||||
context,
|
context,
|
||||||
'json'
|
"json"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(result.newTaskId).toBe(1); // First task should have ID 1
|
expect(result.newTaskId).toBe(1); // First task should have ID 1
|
||||||
expect(writeJSON).toHaveBeenCalledWith(
|
expect(writeJSON).toHaveBeenCalledWith(
|
||||||
'tasks/tasks.json',
|
"tasks/tasks.json",
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
tasks: expect.arrayContaining([
|
tasks: expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: 1
|
id: 1,
|
||||||
})
|
}),
|
||||||
])
|
]),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should handle missing tasks file', async () => {
|
test("should handle missing tasks file", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
readJSON.mockReturnValue(null);
|
readJSON.mockReturnValue(null);
|
||||||
const prompt = 'Create a new authentication system';
|
const prompt = "Create a new authentication system";
|
||||||
const context = {
|
const context = {
|
||||||
mcpLog: createMcpLogMock()
|
mcpLog: createMcpLogMock(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const result = await addTask(
|
const result = await addTask(
|
||||||
'tasks/tasks.json',
|
"tasks/tasks.json",
|
||||||
prompt,
|
prompt,
|
||||||
[],
|
[],
|
||||||
'medium',
|
"medium",
|
||||||
context,
|
context,
|
||||||
'json'
|
"json"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(result.newTaskId).toBe(1); // First task should have ID 1
|
expect(result.newTaskId).toBe(1); // First task should have ID 1
|
||||||
expect(writeJSON).toHaveBeenCalledTimes(2); // Once to create file, once to add task
|
expect(writeJSON).toHaveBeenCalledTimes(2); // Once to create file, once to add task
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should handle AI service errors', async () => {
|
test("should handle AI service errors", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
generateObjectService.mockRejectedValueOnce(new Error('AI service failed'));
|
generateObjectService.mockRejectedValueOnce(new Error("AI service failed"));
|
||||||
const prompt = 'Create a new authentication system';
|
const prompt = "Create a new authentication system";
|
||||||
const context = {
|
const context = {
|
||||||
mcpLog: createMcpLogMock()
|
mcpLog: createMcpLogMock(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
await expect(
|
await expect(
|
||||||
addTask('tasks/tasks.json', prompt, [], 'medium', context, 'json')
|
addTask("tasks/tasks.json", prompt, [], "medium", context, "json")
|
||||||
).rejects.toThrow('AI service failed');
|
).rejects.toThrow("AI service failed");
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should handle file read errors', async () => {
|
test("should handle file read errors", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
readJSON.mockImplementation(() => {
|
readJSON.mockImplementation(() => {
|
||||||
throw new Error('File read failed');
|
throw new Error("File read failed");
|
||||||
});
|
});
|
||||||
const prompt = 'Create a new authentication system';
|
const prompt = "Create a new authentication system";
|
||||||
const context = {
|
const context = {
|
||||||
mcpLog: createMcpLogMock()
|
mcpLog: createMcpLogMock(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
await expect(
|
await expect(
|
||||||
addTask('tasks/tasks.json', prompt, [], 'medium', context, 'json')
|
addTask("tasks/tasks.json", prompt, [], "medium", context, "json")
|
||||||
).rejects.toThrow('File read failed');
|
).rejects.toThrow("File read failed");
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should handle file write errors', async () => {
|
test("should handle file write errors", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
writeJSON.mockImplementation(() => {
|
writeJSON.mockImplementation(() => {
|
||||||
throw new Error('File write failed');
|
throw new Error("File write failed");
|
||||||
});
|
});
|
||||||
const prompt = 'Create a new authentication system';
|
const prompt = "Create a new authentication system";
|
||||||
const context = {
|
const context = {
|
||||||
mcpLog: createMcpLogMock()
|
mcpLog: createMcpLogMock(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
await expect(
|
await expect(
|
||||||
addTask('tasks/tasks.json', prompt, [], 'medium', context, 'json')
|
addTask("tasks/tasks.json", prompt, [], "medium", context, "json")
|
||||||
).rejects.toThrow('File write failed');
|
).rejects.toThrow("File write failed");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -82,19 +82,19 @@ describe("UI Module", () => {
|
|||||||
test("should return done status with emoji for console output", () => {
|
test("should return done status with emoji for console output", () => {
|
||||||
const result = getStatusWithColor("done");
|
const result = getStatusWithColor("done");
|
||||||
expect(result).toMatch(/done/);
|
expect(result).toMatch(/done/);
|
||||||
expect(result).toContain("✅");
|
expect(result).toContain("✓");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should return pending status with emoji for console output", () => {
|
test("should return pending status with emoji for console output", () => {
|
||||||
const result = getStatusWithColor("pending");
|
const result = getStatusWithColor("pending");
|
||||||
expect(result).toMatch(/pending/);
|
expect(result).toMatch(/pending/);
|
||||||
expect(result).toContain("⏱️");
|
expect(result).toContain("○");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should return deferred status with emoji for console output", () => {
|
test("should return deferred status with emoji for console output", () => {
|
||||||
const result = getStatusWithColor("deferred");
|
const result = getStatusWithColor("deferred");
|
||||||
expect(result).toMatch(/deferred/);
|
expect(result).toMatch(/deferred/);
|
||||||
expect(result).toContain("⏱️");
|
expect(result).toContain("x");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should return in-progress status with emoji for console output", () => {
|
test("should return in-progress status with emoji for console output", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user