Compare commits

...

28 Commits

Author SHA1 Message Date
github-actions[bot]
51a351760c Version Packages (#1243)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Ralph Khreish <35776126+Crunchyman-ralph@users.noreply.github.com>
2025-09-24 19:21:21 +02:00
Ralph Khreish
732b2c61ad Merge pull request #1233 from eyaltoledano/ralph/chore/fix.ci.failure.main 2025-09-24 17:10:42 +02:00
Ralph Khreish
4c2801d5eb chore: run format and fix CI 2025-09-24 11:00:04 +02:00
Ralph Khreish
c911608f60 chore: last round of touchups and bug fixes 2025-09-24 10:57:17 +02:00
github-actions[bot]
8f1497407f chore: rc version bump 2025-09-23 20:43:32 +00:00
Ralph Khreish
10b64ec6f5 chore: re-enter rc mode for a last pre-release 2025-09-23 22:38:55 +02:00
Ralph Khreish
1a1879483b chore: do final test 2025-09-23 21:47:37 +02:00
Ralph Khreish
d691cbb7ae chore: CI fix format 2025-09-23 20:27:41 +02:00
Ralph Khreish
1b7c9637a5 chore: fix CI and tsdown config 2025-09-23 20:24:11 +02:00
Ralph Khreish
9ff5f158d5 chore: fix format 2025-09-23 19:27:57 +02:00
Ralph Khreish
b2ff06e8c5 fix: CI and unit tests 2025-09-23 19:26:02 +02:00
Ralph Khreish
6438f6c7c8 chore: exit pre-release mode and format 2025-09-23 11:46:20 +02:00
Ralph Khreish
6bbd777552 chore: fix --version weird error 2025-09-23 11:45:46 +02:00
github-actions[bot]
100482722f chore: rc version bump 2025-09-23 09:10:24 +00:00
Ralph Khreish
7ff882bf23 fix: improve commander instance in commands.js 2025-09-23 11:05:24 +02:00
Ralph Khreish
6ab768f6ec chore: fix CI failure 2025-09-22 22:41:21 +02:00
Ralph Khreish
f487736670 chore: fix CI failing to release (#1232) 2025-09-22 22:34:12 +02:00
github-actions[bot]
05f6242f7e Version Packages (#1228)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-09-22 19:23:22 +02:00
Ralph Khreish
a58719cf50 Merge pull request #1230 from eyaltoledano/next 2025-09-22 19:20:40 +02:00
Ralph Khreish
674d1f6de7 fix: update MCP config paths in various files (#1229) 2025-09-22 19:15:17 +02:00
Ralph Khreish
f106fb8e0b Merge pull request Release 0.27.0 #1224 from eyaltoledano/next 2025-09-22 18:40:55 +02:00
Ralph Khreish
fd9dd43ee0 fix: improve weekly metrics workflow with 14-day window and debug output (#1226) 2025-09-22 15:47:03 +02:00
Ralph Khreish
c395e93696 chore: remove pre-mode (get out of RC) 2025-09-20 01:11:50 +02:00
Ralph Khreish
a621ff05ea feat: update tm models defaults (#1225) 2025-09-20 01:07:33 +02:00
github-actions[bot]
47ddb60231 docs: Auto-update and format models.md 2025-09-19 22:08:36 +00:00
Eyal Toledano
fce841490a Tm start (#1200)
Co-authored-by: Max Tuzzolino <maxtuzz@Maxs-MacBook-Pro.local>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Max Tuzzolino <max.tuzsmith@gmail.com>
Co-authored-by: Ralph Khreish <35776126+Crunchyman-ralph@users.noreply.github.com>
2025-09-20 00:08:20 +02:00
Ralph Khreish
4e126430a0 chore: update docs to remove --package refs (#1220) 2025-09-18 23:39:50 +02:00
github-actions[bot]
a33abe6c21 chore: rc version bump 2025-09-18 21:17:55 +00:00
178 changed files with 4359 additions and 1018 deletions

View File

@@ -11,9 +11,6 @@
"access": "public",
"baseBranch": "main",
"ignore": [
"docs",
"@tm/cli",
"@tm/core",
"@tm/build-config"
"docs"
]
}

View File

@@ -1,5 +0,0 @@
---
"task-master-ai": minor
---
Testing one more pre-release iteration

View File

@@ -1,5 +0,0 @@
---
"task-master-ai": minor
---
Test out the RC

View File

@@ -1,5 +0,0 @@
---
"@tm/cli": minor
---
testing this stuff out to see how the release candidate works with monorepo

View File

@@ -1,18 +0,0 @@
{
"mode": "pre",
"tag": "rc",
"initialVersions": {
"task-master-ai": "0.26.0",
"@tm/cli": "0.26.0",
"docs": "0.0.2",
"extension": "0.24.2",
"@tm/build-config": "1.0.0",
"@tm/core": "0.26.0"
},
"changesets": [
"easy-deer-heal",
"moody-oranges-slide",
"odd-otters-tan",
"wild-ears-look"
]
}

View File

@@ -1,5 +0,0 @@
---
"task-master-ai": minor
---
@tm/cli: add auto-update functionality to every command

View File

@@ -1,5 +0,0 @@
---
"extension": minor
---
Added a Start Build button to the VSCODE Task Properties Right Panel

View File

@@ -2,7 +2,7 @@
"mcpServers": {
"task-master-ai": {
"command": "node",
"args": ["./mcp-server/server.js"],
"args": ["./dist/mcp-server.js"],
"env": {
"ANTHROPIC_API_KEY": "ANTHROPIC_API_KEY_HERE",
"PERPLEXITY_API_KEY": "PERPLEXITY_API_KEY_HERE",

157
.github/scripts/parse-metrics.mjs vendored Normal file
View File

@@ -0,0 +1,157 @@
#!/usr/bin/env node
import { readFileSync, existsSync, writeFileSync } from 'fs';
function parseMetricsTable(content, metricName) {
const lines = content.split('\n');
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
// Match a markdown table row like: | Metric Name | value | ...
const safeName = metricName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const re = new RegExp(`^\\|\\s*${safeName}\\s*\\|\\s*([^|]+)\\|?`);
const match = line.match(re);
if (match) {
return match[1].trim() || 'N/A';
}
}
return 'N/A';
}
function parseCountMetric(content, metricName) {
const result = parseMetricsTable(content, metricName);
// Extract number from string, handling commas and spaces
const numberMatch = result.toString().match(/[\d,]+/);
if (numberMatch) {
const number = parseInt(numberMatch[0].replace(/,/g, ''));
return isNaN(number) ? 0 : number;
}
return 0;
}
function main() {
const metrics = {
issues_created: 0,
issues_closed: 0,
prs_created: 0,
prs_merged: 0,
issue_avg_first_response: 'N/A',
issue_avg_time_to_close: 'N/A',
pr_avg_first_response: 'N/A',
pr_avg_merge_time: 'N/A'
};
// Parse issue metrics
if (existsSync('issue_metrics.md')) {
console.log('📄 Found issue_metrics.md, parsing...');
const issueContent = readFileSync('issue_metrics.md', 'utf8');
metrics.issues_created = parseCountMetric(
issueContent,
'Total number of items created'
);
metrics.issues_closed = parseCountMetric(
issueContent,
'Number of items closed'
);
metrics.issue_avg_first_response = parseMetricsTable(
issueContent,
'Time to first response'
);
metrics.issue_avg_time_to_close = parseMetricsTable(
issueContent,
'Time to close'
);
} else {
console.warn('[parse-metrics] issue_metrics.md not found; using defaults.');
}
// Parse PR created metrics
if (existsSync('pr_created_metrics.md')) {
console.log('📄 Found pr_created_metrics.md, parsing...');
const prCreatedContent = readFileSync('pr_created_metrics.md', 'utf8');
metrics.prs_created = parseCountMetric(
prCreatedContent,
'Total number of items created'
);
metrics.pr_avg_first_response = parseMetricsTable(
prCreatedContent,
'Time to first response'
);
} else {
console.warn(
'[parse-metrics] pr_created_metrics.md not found; using defaults.'
);
}
// Parse PR merged metrics (for more accurate merge data)
if (existsSync('pr_merged_metrics.md')) {
console.log('📄 Found pr_merged_metrics.md, parsing...');
const prMergedContent = readFileSync('pr_merged_metrics.md', 'utf8');
metrics.prs_merged = parseCountMetric(
prMergedContent,
'Total number of items created'
);
// For merged PRs, "Time to close" is actually time to merge
metrics.pr_avg_merge_time = parseMetricsTable(
prMergedContent,
'Time to close'
);
} else {
console.warn(
'[parse-metrics] pr_merged_metrics.md not found; falling back to pr_metrics.md.'
);
// Fallback: try old pr_metrics.md if it exists
if (existsSync('pr_metrics.md')) {
console.log('📄 Falling back to pr_metrics.md...');
const prContent = readFileSync('pr_metrics.md', 'utf8');
const mergedCount = parseCountMetric(prContent, 'Number of items merged');
metrics.prs_merged =
mergedCount || parseCountMetric(prContent, 'Number of items closed');
const maybeMergeTime = parseMetricsTable(
prContent,
'Average time to merge'
);
metrics.pr_avg_merge_time =
maybeMergeTime !== 'N/A'
? maybeMergeTime
: parseMetricsTable(prContent, 'Time to close');
} else {
console.warn('[parse-metrics] pr_metrics.md not found; using defaults.');
}
}
// Output for GitHub Actions
const output = Object.entries(metrics)
.map(([key, value]) => `${key}=${value}`)
.join('\n');
// Always output to stdout for debugging
console.log('\n=== FINAL METRICS ===');
Object.entries(metrics).forEach(([key, value]) => {
console.log(`${key}: ${value}`);
});
// Write to GITHUB_OUTPUT if in GitHub Actions
if (process.env.GITHUB_OUTPUT) {
try {
writeFileSync(process.env.GITHUB_OUTPUT, output + '\n', { flag: 'a' });
console.log(
`\nSuccessfully wrote metrics to ${process.env.GITHUB_OUTPUT}`
);
} catch (error) {
console.error(`Failed to write to GITHUB_OUTPUT: ${error.message}`);
process.exit(1);
}
} else {
console.log(
'\nNo GITHUB_OUTPUT environment variable found, skipping file write'
);
}
}
main();

View File

@@ -8,7 +8,7 @@ on:
permissions:
contents: read
issues: write
issues: read
pull-requests: read
jobs:
@@ -17,15 +17,25 @@ jobs:
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_METRICS_WEBHOOK }}
steps:
- name: Get dates for last week
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Get dates for last 14 days
run: |
# Last 7 days
first_day=$(date -d "7 days ago" +%Y-%m-%d)
set -Eeuo pipefail
# Last 14 days
first_day=$(date -d "14 days ago" +%Y-%m-%d)
last_day=$(date +%Y-%m-%d)
echo "first_day=$first_day" >> $GITHUB_ENV
echo "last_day=$last_day" >> $GITHUB_ENV
echo "week_of=$(date -d '7 days ago' +'Week of %B %d, %Y')" >> $GITHUB_ENV
echo "date_range=Past 14 days ($first_day to $last_day)" >> $GITHUB_ENV
- name: Generate issue metrics
uses: github/issue-metrics@v3
@@ -34,40 +44,39 @@ jobs:
SEARCH_QUERY: "repo:${{ github.repository }} is:issue created:${{ env.first_day }}..${{ env.last_day }}"
HIDE_TIME_TO_ANSWER: true
HIDE_LABEL_METRICS: false
OUTPUT_FILE: issue_metrics.md
- name: Generate PR metrics
- name: Generate PR created metrics
uses: github/issue-metrics@v3
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SEARCH_QUERY: "repo:${{ github.repository }} is:pr created:${{ env.first_day }}..${{ env.last_day }}"
OUTPUT_FILE: pr_metrics.md
OUTPUT_FILE: pr_created_metrics.md
- name: Generate PR merged metrics
uses: github/issue-metrics@v3
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SEARCH_QUERY: "repo:${{ github.repository }} is:pr is:merged merged:${{ env.first_day }}..${{ env.last_day }}"
OUTPUT_FILE: pr_merged_metrics.md
- name: Debug generated metrics
run: |
set -Eeuo pipefail
echo "Listing markdown files in workspace:"
ls -la *.md || true
for f in issue_metrics.md pr_created_metrics.md pr_merged_metrics.md; do
if [ -f "$f" ]; then
echo "== $f (first 10 lines) =="
head -n 10 "$f"
else
echo "Missing $f"
fi
done
- name: Parse metrics
id: metrics
run: |
# Parse the metrics from the generated markdown files
if [ -f "issue_metrics.md" ]; then
# Extract key metrics using grep/awk
AVG_TIME_TO_FIRST_RESPONSE=$(grep -A 1 "Average time to first response" issue_metrics.md | tail -1 | xargs || echo "N/A")
AVG_TIME_TO_CLOSE=$(grep -A 1 "Average time to close" issue_metrics.md | tail -1 | xargs || echo "N/A")
NUM_ISSUES_CREATED=$(grep -oP '\d+(?= issues created)' issue_metrics.md || echo "0")
NUM_ISSUES_CLOSED=$(grep -oP '\d+(?= issues closed)' issue_metrics.md || echo "0")
fi
if [ -f "pr_metrics.md" ]; then
PR_AVG_TIME_TO_MERGE=$(grep -A 1 "Average time to close" pr_metrics.md | tail -1 | xargs || echo "N/A")
NUM_PRS_CREATED=$(grep -oP '\d+(?= pull requests created)' pr_metrics.md || echo "0")
NUM_PRS_MERGED=$(grep -oP '\d+(?= pull requests closed)' pr_metrics.md || echo "0")
fi
# Set outputs for Discord action
echo "issues_created=${NUM_ISSUES_CREATED:-0}" >> $GITHUB_OUTPUT
echo "issues_closed=${NUM_ISSUES_CLOSED:-0}" >> $GITHUB_OUTPUT
echo "prs_created=${NUM_PRS_CREATED:-0}" >> $GITHUB_OUTPUT
echo "prs_merged=${NUM_PRS_MERGED:-0}" >> $GITHUB_OUTPUT
echo "avg_first_response=${AVG_TIME_TO_FIRST_RESPONSE:-N/A}" >> $GITHUB_OUTPUT
echo "avg_time_to_close=${AVG_TIME_TO_CLOSE:-N/A}" >> $GITHUB_OUTPUT
echo "pr_avg_merge_time=${PR_AVG_TIME_TO_MERGE:-N/A}" >> $GITHUB_OUTPUT
run: node .github/scripts/parse-metrics.mjs
- name: Send to Discord
uses: sarisia/actions-status-discord@v1
@@ -78,19 +87,22 @@ jobs:
title: "📊 Weekly Metrics Report"
description: |
**${{ env.week_of }}**
*${{ env.date_range }}*
**🎯 Issues**
• Created: ${{ steps.metrics.outputs.issues_created }}
• Closed: ${{ steps.metrics.outputs.issues_closed }}
• Avg Response Time: ${{ steps.metrics.outputs.issue_avg_first_response }}
• Avg Time to Close: ${{ steps.metrics.outputs.issue_avg_time_to_close }}
**🔀 Pull Requests**
• Created: ${{ steps.metrics.outputs.prs_created }}
• Merged: ${{ steps.metrics.outputs.prs_merged }}
• Avg Response Time: ${{ steps.metrics.outputs.pr_avg_first_response }}
• Avg Time to Merge: ${{ steps.metrics.outputs.pr_avg_merge_time }}
**⏱️ Response Times**
• First Response: ${{ steps.metrics.outputs.avg_first_response }}
• Time to Close: ${{ steps.metrics.outputs.avg_time_to_close }}
• PR Merge Time: ${{ steps.metrics.outputs.pr_avg_merge_time }}
**📈 Visual Analytics**
https://repobeats.axiom.co/api/embed/b439f28f0ab5bd7a2da19505355693cd2c55bfd4.svg
color: 0x58AFFF
username: Task Master Metrics Bot
avatar_url: https://raw.githubusercontent.com/eyaltoledano/claude-task-master/main/images/logo.png

View File

@@ -2,7 +2,7 @@
"mcpServers": {
"task-master-ai": {
"command": "npx",
"args": ["-y", "--package=task-master-ai", "task-master-ai"],
"args": ["-y", "task-master-ai"],
"env": {
"ANTHROPIC_API_KEY": "YOUR_ANTHROPIC_API_KEY_HERE",
"PERPLEXITY_API_KEY": "YOUR_PERPLEXITY_API_KEY_HERE",

6
.manypkg.json Normal file
View File

@@ -0,0 +1,6 @@
{
"$schema": "https://unpkg.com/@manypkg/get-packages@1.1.3/schema.json",
"defaultBranch": "main",
"ignoredRules": ["ROOT_HAS_DEPENDENCIES", "INTERNAL_MISMATCH"],
"ignoredPackages": ["@tm/core", "@tm/cli", "@tm/build-config"]
}

View File

@@ -85,7 +85,7 @@ Task Master provides an MCP server that Claude Code can connect to. Configure in
"mcpServers": {
"task-master-ai": {
"command": "npx",
"args": ["-y", "--package=task-master-ai", "task-master-ai"],
"args": ["-y", "task-master-ai"],
"env": {
"ANTHROPIC_API_KEY": "your_key_here",
"PERPLEXITY_API_KEY": "your_key_here",

View File

@@ -2,8 +2,8 @@
"models": {
"main": {
"provider": "anthropic",
"modelId": "claude-3-7-sonnet-20250219",
"maxTokens": 120000,
"modelId": "claude-sonnet-4-20250514",
"maxTokens": 64000,
"temperature": 0.2
},
"research": {
@@ -14,8 +14,8 @@
},
"fallback": {
"provider": "anthropic",
"modelId": "claude-3-5-sonnet-20241022",
"maxTokens": 8192,
"modelId": "claude-3-7-sonnet-20250219",
"maxTokens": 120000,
"temperature": 0.2
}
},
@@ -29,9 +29,15 @@
"ollamaBaseURL": "http://localhost:11434/api",
"bedrockBaseURL": "https://bedrock.us-east-1.amazonaws.com",
"responseLanguage": "English",
"enableCodebaseAnalysis": true,
"userId": "1234567890",
"azureBaseURL": "https://your-endpoint.azure.com/",
"defaultTag": "master"
},
"claudeCode": {}
"claudeCode": {},
"grokCli": {
"timeout": 120000,
"workingDirectory": null,
"defaultModel": "grok-4-latest"
}
}

View File

@@ -0,0 +1,91 @@
<context>
# Overview
Add a new CLI command: `task-master start <task_id>` (alias: `tm start <task_id>`). This command hard-codes `claude-code` as the executor, fetches task details, builds a standardized prompt, runs claude-code, shows the result, checks for git changes, and auto-marks the task as done if successful.
We follow the Commander class pattern, reuse task retrieval from `show` command flow. Extremely minimal for 1-hour hackathon timeline.
# Core Features
- `start` command (Commander class style)
- Hard-coded executor: `claude-code`
- Standardized prompt designed for minimal changes following existing patterns
- Shows claude-code output (no streaming)
- Git status check for success detection
- Auto-mark task done if successful
# User Experience
```
task-master start 12
```
1) Fetches Task #12 details
2) Builds standardized prompt with task context
3) Runs claude-code with the prompt
4) Shows output
5) Checks git status for changes
6) Auto-marks task done if changes detected
</context>
<PRD>
# Technical Architecture
- Command pattern:
- Create `apps/cli/src/commands/start.command.ts` modeled on [list.command.ts](mdc:apps/cli/src/commands/list.command.ts) and task lookup from [show.command.ts](mdc:apps/cli/src/commands/show.command.ts)
- Task retrieval:
- Use `@tm/core` via `createTaskMasterCore` to get task by ID
- Extract: id, title, description, details
- Executor (ultra-simple approach):
- Execute `claude "full prompt here"` command directly
- The prompt tells Claude to first run `tm show <task_id>` to get task details
- Then tells Claude to implement the code changes
- This opens Claude CLI interface naturally in the current terminal
- No subprocess management needed - just execute the command
- Execution flow:
1) Validate `<task_id>` exists; exit with error if not
2) Build standardized prompt that includes instructions to run `tm show <task_id>`
3) Execute `claude "prompt"` command directly in terminal
4) Claude CLI opens, runs `tm show`, then implements changes
5) After Claude session ends, run `git status --porcelain` to detect changes
6) If changes detected, auto-run `task-master set-status --id=<task_id> --status=done`
- Success criteria:
- Success = exit code 0 AND git shows modified/created files
- Print changed file paths; warn if no changes detected
# Development Roadmap
MVP (ship in ~1 hour):
1) Implement `start.command.ts` (Commander class), parse `<task_id>`
2) Validate task exists via tm-core
3) Build prompt that tells Claude to run `tm show <task_id>` then implement
4) Execute `claude "prompt"` command, then check git status and auto-mark done
# Risks and Mitigations
- Executor availability: Error clearly if `claude-code` provider fails
- False success: Git-change heuristic acceptable for hackathon MVP
# Appendix
**Standardized Prompt Template:**
```
You are an AI coding assistant with access to this repository's codebase.
First, run this command to get the task details:
tm show <task_id>
Then implement the task with these requirements:
- Make the SMALLEST number of code changes possible
- Follow ALL existing patterns in the codebase (you have access to analyze the code)
- Do NOT over-engineer the solution
- Use existing files/functions/patterns wherever possible
- When complete, print: COMPLETED: <brief summary of changes>
Begin by running tm show <task_id> to understand what needs to be implemented.
```
**Key References:**
- [list.command.ts](mdc:apps/cli/src/commands/list.command.ts) - Command structure
- [show.command.ts](mdc:apps/cli/src/commands/show.command.ts) - Task validation
- Node.js `child_process.exec()` - For executing `claude "prompt"` command
</PRD>

View File

@@ -1,6 +1,6 @@
{
"currentTag": "master",
"lastSwitched": "2025-08-27T21:03:20.550Z",
"lastSwitched": "2025-09-12T22:25:27.535Z",
"branchTagMapping": {
"v017-adds": "v017-adds",
"next": "next"

View File

@@ -0,0 +1,34 @@
# Task ID: 1
# Title: Create start command class structure
# Status: pending
# Dependencies: None
# Priority: high
# Description: Create the basic structure for the start command following the Commander class pattern
# Details:
Create a new file `apps/cli/src/commands/start.command.ts` based on the existing list.command.ts pattern. Implement the command class with proper command registration, description, and argument handling for the task_id parameter. The class should extend the base Command class and implement the required methods.
Example structure:
```typescript
import { Command } from 'commander';
import { BaseCommand } from './base.command';
export class StartCommand extends BaseCommand {
public register(program: Command): void {
program
.command('start')
.alias('tm start')
.description('Start implementing a task using claude-code')
.argument('<task_id>', 'ID of the task to start')
.action(async (taskId: string) => {
await this.execute(taskId);
});
}
public async execute(taskId: string): Promise<void> {
// Implementation will be added in subsequent tasks
}
}
```
# Test Strategy:
Verify the command registers correctly by running the CLI with --help and checking that the start command appears with proper description and arguments. Test the basic structure by ensuring the command can be invoked without errors.

View File

@@ -0,0 +1,26 @@
# Task ID: 2
# Title: Register start command in CLI
# Status: pending
# Dependencies: 7
# Priority: high
# Description: Register the start command in the CLI application
# Details:
Update the CLI application to register the new start command. This involves importing the StartCommand class and adding it to the commands array in the CLI initialization.
In `apps/cli/src/index.ts` or the appropriate file where commands are registered:
```typescript
import { StartCommand } from './commands/start.command';
// Add StartCommand to the commands array
const commands = [
// ... existing commands
new StartCommand(),
];
// Register all commands
commands.forEach(command => command.register(program));
```
# Test Strategy:
Verify the command is correctly registered by running the CLI with --help and checking that the start command appears in the list of available commands.

View File

@@ -0,0 +1,32 @@
# Task ID: 3
# Title: Create standardized prompt builder
# Status: pending
# Dependencies: 1
# Priority: medium
# Description: Implement a function to build the standardized prompt for claude-code based on the task details
# Details:
Create a function in the StartCommand class that builds the standardized prompt according to the template provided in the PRD. The prompt should include instructions for Claude to first run `tm show <task_id>` to get task details, and then implement the required changes.
```typescript
private buildPrompt(taskId: string): string {
return `You are an AI coding assistant with access to this repository's codebase.
First, run this command to get the task details:
tm show ${taskId}
Then implement the task with these requirements:
- Make the SMALLEST number of code changes possible
- Follow ALL existing patterns in the codebase (you have access to analyze the code)
- Do NOT over-engineer the solution
- Use existing files/functions/patterns wherever possible
- When complete, print: COMPLETED: <brief summary of changes>
Begin by running tm show ${taskId} to understand what needs to be implemented.`;
}
```
<info added on 2025-09-12T02:40:01.812Z>
The prompt builder function will handle task context retrieval by instructing Claude to use the task-master show command. This approach ensures Claude has access to all necessary task details before implementation begins. The command syntax "tm show ${taskId}" embedded in the prompt will direct Claude to first gather the complete task context, including description, requirements, and any existing implementation details, before proceeding with code changes.
</info added on 2025-09-12T02:40:01.812Z>
# Test Strategy:
Verify the prompt is correctly formatted by calling the function with a sample task ID and checking that the output matches the expected template with the task ID properly inserted.

View File

@@ -0,0 +1,36 @@
# Task ID: 4
# Title: Implement claude-code executor
# Status: pending
# Dependencies: 3
# Priority: high
# Description: Add functionality to execute the claude-code command with the built prompt
# Details:
Implement the functionality to execute the claude command with the built prompt. This should use Node.js child_process.exec() to run the command directly in the terminal.
```typescript
import { exec } from 'child_process';
// Inside execute method, after task validation
private async executeClaude(prompt: string): Promise<void> {
console.log('Starting claude-code to implement the task...');
try {
// Execute claude with the prompt
const claudeCommand = `claude "${prompt.replace(/"/g, '\\"')}"`;
// Use execSync to wait for the command to complete
const { execSync } = require('child_process');
execSync(claudeCommand, { stdio: 'inherit' });
console.log('Claude session completed.');
} catch (error) {
console.error('Error executing claude-code:', error.message);
process.exit(1);
}
}
```
Then call this method from the execute method after building the prompt.
# Test Strategy:
Test by running the command with a valid task ID and verifying that the claude command is executed with the correct prompt. Check that the command handles errors appropriately if claude-code is not available.

View File

@@ -0,0 +1,49 @@
# Task ID: 7
# Title: Integrate execution flow in start command
# Status: pending
# Dependencies: 3, 4
# Priority: high
# Description: Connect all the components to implement the complete execution flow for the start command
# Details:
Update the execute method in the StartCommand class to integrate all the components and implement the complete execution flow as described in the PRD:
1. Validate task exists
2. Build standardized prompt
3. Execute claude-code
4. Check git status for changes
5. Auto-mark task as done if changes detected
```typescript
public async execute(taskId: string): Promise<void> {
// Validate task exists
const core = await createTaskMasterCore();
const task = await core.tasks.getById(parseInt(taskId, 10));
if (!task) {
console.error(`Task with ID ${taskId} not found`);
process.exit(1);
}
// Build prompt
const prompt = this.buildPrompt(taskId);
// Execute claude-code
await this.executeClaude(prompt);
// Check git status
const changedFiles = await this.checkGitChanges();
if (changedFiles.length > 0) {
console.log('\nChanges detected in the following files:');
changedFiles.forEach(file => console.log(`- ${file}`));
// Auto-mark task as done
await this.markTaskAsDone(taskId);
console.log(`\nTask ${taskId} completed successfully and marked as done.`);
} else {
console.warn('\nNo changes detected after claude-code execution. Task not marked as done.');
}
}
```
# Test Strategy:
Test the complete execution flow by running the start command with a valid task ID and verifying that all steps are executed correctly. Test with both scenarios: when changes are detected and when no changes are detected.

File diff suppressed because one or more lines are too long

View File

@@ -1,8 +1,84 @@
# task-master-ai
## 1.0.0-rc.2
## 0.27.1
### Major Changes
### Patch Changes
- [#1232](https://github.com/eyaltoledano/claude-task-master/pull/1232) [`f487736`](https://github.com/eyaltoledano/claude-task-master/commit/f487736670ef8c484059f676293777eabb249c9e) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix module not found for new 0.27.0 release
- [#1233](https://github.com/eyaltoledano/claude-task-master/pull/1233) [`c911608`](https://github.com/eyaltoledano/claude-task-master/commit/c911608f60454253f4e024b57ca84e5a5a53f65c) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix Zed MCP configuration by adding required "source" property
- Add "source": "custom" property to task-master-ai server in Zed settings.json
## 0.27.1-rc.1
### Patch Changes
- [#1233](https://github.com/eyaltoledano/claude-task-master/pull/1233) [`1a18794`](https://github.com/eyaltoledano/claude-task-master/commit/1a1879483b86c118a4e46c02cbf4acebfcf6bcf9) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - One last testing final final
## 0.27.1-rc.0
### Patch Changes
- [#1232](https://github.com/eyaltoledano/claude-task-master/pull/1232) [`f487736`](https://github.com/eyaltoledano/claude-task-master/commit/f487736670ef8c484059f676293777eabb249c9e) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix module not found for new 0.27.0 release
## 0.27.0
### Minor Changes
- [#1220](https://github.com/eyaltoledano/claude-task-master/pull/1220) [`4e12643`](https://github.com/eyaltoledano/claude-task-master/commit/4e126430a092fb54afb035514fb3d46115714f97) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - No longer need --package=task-master-ai in mcp server
- A lot of users were having issues with Taskmaster and usually a simple fix was to remove --package from your mcp.json
- we now bundle our whole package, so we no longer need the --package
- [#1200](https://github.com/eyaltoledano/claude-task-master/pull/1200) [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add new `task-master start` command for automated task execution with Claude Code
- You can now start working on tasks directly by running `task-master start <task-id>` which will automatically launch Claude Code with a comprehensive prompt containing all task details, implementation guidelines, and context.
- `task-master start` will automatically detect next-task when no ID is provided.
- [#1200](https://github.com/eyaltoledano/claude-task-master/pull/1200) [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Move from javascript to typescript, not a full refactor but we now have a typescript environment and are moving our javascript commands slowly into typescript
- [#1200](https://github.com/eyaltoledano/claude-task-master/pull/1200) [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add grok-cli as a provider with full codebase context support. You can now use Grok models (grok-2, grok-3, grok-4, etc.) with Task Master for AI operations that have access to your entire codebase context, enabling more informed task generation and PRD parsing.
## Setup Instructions
1. **Get your Grok API key** from [console.x.ai](https://console.x.ai)
2. **Set the environment variable**:
```bash
export GROK_CLI_API_KEY="your-api-key-here"
```
3. **Configure Task Master to use Grok**:
```bash
task-master models --set-main grok-beta
# or
task-master models --set-research grok-beta
# or
task-master models --set-fallback grok-beta
```
## Key Features
- **Full codebase context**: Grok models can analyze your entire project when generating tasks or parsing PRDs
- **xAI model access**: Support for latest Grok models (grok-2, grok-3, grok-4, etc.)
- **Code-aware task generation**: Create more accurate and contextual tasks based on your actual codebase
- **Intelligent PRD parsing**: Parse requirements with understanding of your existing code structure
## Available Models
- `grok-beta` - Latest Grok model with codebase context
- `grok-vision-beta` - Grok with vision capabilities and codebase context
The Grok CLI provider integrates with xAI's Grok models via grok-cli and can also use the local Grok CLI configuration file (`~/.grok/user-settings.json`) if available.
## Credits
Built using the [grok-cli](https://github.com/superagent-ai/grok-cli) by Superagent AI for seamless integration with xAI's Grok models.
- [#1225](https://github.com/eyaltoledano/claude-task-master/pull/1225) [`a621ff0`](https://github.com/eyaltoledano/claude-task-master/commit/a621ff05eafb51a147a9aabd7b37ddc0e45b0869) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve taskmaster ai provider defaults
- moving from main anthropic 3.7 to anthropic sonnet 4
- moving from fallback anthropic 3.5 to anthropic 3.7
- [#1217](https://github.com/eyaltoledano/claude-task-master/pull/1217) [`e6de285`](https://github.com/eyaltoledano/claude-task-master/commit/e6de285ceacb0a397e952a63435cd32a9c731515) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - @tm/cli: add auto-update functionality to every command
- [#1200](https://github.com/eyaltoledano/claude-task-master/pull/1200) [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Fix Grok model configuration validation and update deprecated Claude fallback model. Grok models now properly support their full 131K token capacity, and the fallback model has been upgraded to Claude Sonnet 4 for better performance and future compatibility.
## 0.27.0-rc.2
### Minor Changes
- [#1217](https://github.com/eyaltoledano/claude-task-master/pull/1217) [`e6de285`](https://github.com/eyaltoledano/claude-task-master/commit/e6de285ceacb0a397e952a63435cd32a9c731515) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - @tm/cli: add auto-update functionality to every command

View File

@@ -102,7 +102,7 @@ MCP (Model Control Protocol) lets you run Task Master directly from your editor.
"mcpServers": {
"task-master-ai": {
"command": "npx",
"args": ["-y", "--package=task-master-ai", "task-master-ai"],
"args": ["-y", "task-master-ai"],
"env": {
"ANTHROPIC_API_KEY": "YOUR_ANTHROPIC_API_KEY_HERE",
"PERPLEXITY_API_KEY": "YOUR_PERPLEXITY_API_KEY_HERE",
@@ -122,7 +122,7 @@ MCP (Model Control Protocol) lets you run Task Master directly from your editor.
> 🔑 Replace `YOUR_…_KEY_HERE` with your real API keys. You can remove keys you don't use.
> **Note**: If you see `0 tools enabled` in the MCP settings, try removing the `--package=task-master-ai` flag from `args`.
> **Note**: If you see `0 tools enabled` in the MCP settings, restart your editor and check that your API keys are correctly configured.
###### VSCode (`servers` + `type`)
@@ -131,7 +131,7 @@ MCP (Model Control Protocol) lets you run Task Master directly from your editor.
"servers": {
"task-master-ai": {
"command": "npx",
"args": ["-y", "--package=task-master-ai", "task-master-ai"],
"args": ["-y", "task-master-ai"],
"env": {
"ANTHROPIC_API_KEY": "YOUR_ANTHROPIC_API_KEY_HERE",
"PERPLEXITY_API_KEY": "YOUR_PERPLEXITY_API_KEY_HERE",

View File

@@ -1,5 +1,19 @@
# @tm/cli
## null
### Patch Changes
- Updated dependencies []:
- @tm/core@null
## 0.27.0
### Patch Changes
- Updated dependencies []:
- @tm/core@0.26.1
## 0.27.0-rc.0
### Minor Changes

View File

@@ -1,6 +1,5 @@
{
"name": "@tm/cli",
"version": "0.27.0-rc.0",
"description": "Task Master CLI - Command line interface for task management",
"type": "module",
"private": true,
@@ -24,12 +23,12 @@
},
"dependencies": {
"@tm/core": "*",
"boxen": "^7.1.1",
"boxen": "^8.0.1",
"chalk": "5.6.2",
"cli-table3": "^0.6.5",
"commander": "^12.1.0",
"inquirer": "^9.2.10",
"ora": "^8.1.0"
"inquirer": "^12.5.0",
"ora": "^8.2.0"
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",

View File

@@ -9,14 +9,7 @@ import boxen from 'boxen';
import { createTaskMasterCore, type Task, type TaskMasterCore } from '@tm/core';
import type { StorageType } from '@tm/core/types';
import * as ui from '../utils/ui.js';
import {
displayTaskHeader,
displayTaskProperties,
displayImplementationDetails,
displayTestStrategy,
displaySubtasks,
displaySuggestedActions
} from '../ui/components/task-detail.component.js';
import { displayTaskDetails } from '../ui/components/task-detail.component.js';
/**
* Options interface for the show command
@@ -264,44 +257,11 @@ export class ShowCommand extends Command {
return;
}
const task = result.task;
// Display header with tag
displayTaskHeader(task.id, task.title);
// Display task properties in table format
displayTaskProperties(task);
// Display implementation details if available
if (task.details) {
console.log(); // Empty line for spacing
displayImplementationDetails(task.details);
}
// Display test strategy if available
if ('testStrategy' in task && task.testStrategy) {
console.log(); // Empty line for spacing
displayTestStrategy(task.testStrategy as string);
}
// Display subtasks if available
if (task.subtasks && task.subtasks.length > 0) {
// Filter subtasks by status if provided
const filteredSubtasks = options.status
? task.subtasks.filter((sub) => sub.status === options.status)
: task.subtasks;
if (filteredSubtasks.length === 0 && options.status) {
console.log(
chalk.gray(` No subtasks with status '${options.status}'`)
);
} else {
displaySubtasks(filteredSubtasks, task.id);
}
}
// Display suggested actions
displaySuggestedActions(task.id);
// Use the global task details display function
displayTaskDetails(result.task, {
statusFilter: options.status,
showSuggestedActions: true
});
}
/**

View File

@@ -0,0 +1,512 @@
/**
* @fileoverview StartCommand using Commander's native class pattern
* Extends Commander.Command for better integration with the framework
* This is a thin presentation layer over @tm/core's TaskExecutionService
*/
import { Command } from 'commander';
import chalk from 'chalk';
import boxen from 'boxen';
import ora, { type Ora } from 'ora';
import { spawn } from 'child_process';
import {
createTaskMasterCore,
type TaskMasterCore,
type StartTaskResult as CoreStartTaskResult
} from '@tm/core';
import { displayTaskDetails } from '../ui/components/task-detail.component.js';
import * as ui from '../utils/ui.js';
/**
* CLI-specific options interface for the start command
*/
export interface StartCommandOptions {
id?: string;
format?: 'text' | 'json';
project?: string;
dryRun?: boolean;
force?: boolean;
noStatusUpdate?: boolean;
}
/**
* CLI-specific result type from start command
* Extends the core result with CLI-specific display information
*/
export interface StartCommandResult extends CoreStartTaskResult {
storageType?: string;
}
/**
* StartCommand extending Commander's Command class
* This is a thin presentation layer over @tm/core's TaskExecutionService
*/
export class StartCommand extends Command {
private tmCore?: TaskMasterCore;
private lastResult?: StartCommandResult;
constructor(name?: string) {
super(name || 'start');
// Configure the command
this.description(
'Start working on a task by launching claude-code with context'
)
.argument('[id]', 'Task ID to start working on')
.option('-i, --id <id>', 'Task ID to start working on')
.option('-f, --format <format>', 'Output format (text, json)', 'text')
.option('-p, --project <path>', 'Project root directory', process.cwd())
.option(
'--dry-run',
'Show what would be executed without launching claude-code'
)
.option(
'--force',
'Force start even if another task is already in-progress'
)
.option(
'--no-status-update',
'Do not automatically update task status to in-progress'
)
.action(
async (taskId: string | undefined, options: StartCommandOptions) => {
await this.executeCommand(taskId, options);
}
);
}
/**
* Execute the start command
*/
private async executeCommand(
taskId: string | undefined,
options: StartCommandOptions
): Promise<void> {
let spinner: Ora | null = null;
try {
// Validate options
if (!this.validateOptions(options)) {
process.exit(1);
}
// Initialize tm-core with spinner
spinner = ora('Initializing Task Master...').start();
await this.initializeCore(options.project || process.cwd());
spinner.succeed('Task Master initialized');
// Get the task ID from argument or option, or find next available task
const idArg = taskId || options.id || null;
let targetTaskId = idArg;
if (!targetTaskId) {
spinner = ora('Finding next available task...').start();
targetTaskId = await this.performGetNextTask();
if (targetTaskId) {
spinner.succeed(`Found next task: #${targetTaskId}`);
} else {
spinner.fail('No available tasks found');
}
}
if (!targetTaskId) {
ui.displayError('No task ID provided and no available tasks found');
process.exit(1);
}
// Show pre-launch message (no spinner needed, it's just display)
if (!options.dryRun) {
await this.showPreLaunchMessage(targetTaskId);
}
// Use tm-core's startTask method with spinner
spinner = ora('Preparing task execution...').start();
const coreResult = await this.performStartTask(targetTaskId, options);
if (coreResult.started) {
spinner.succeed(
options.dryRun
? 'Dry run completed'
: 'Task prepared - launching Claude...'
);
} else {
spinner.fail('Task execution failed');
}
// Execute command if we have one and it's not a dry run
if (!options.dryRun && coreResult.command) {
// Stop any remaining spinners before launching Claude
if (spinner && !spinner.isSpinning) {
// Clear the line to make room for Claude
console.log();
}
await this.executeChildProcess(coreResult.command);
}
// Convert core result to CLI result with storage type
const result: StartCommandResult = {
...coreResult,
storageType: this.tmCore?.getStorageType()
};
// Store result for programmatic access
this.setLastResult(result);
// Display results (only for dry run or if execution failed)
if (options.dryRun || !coreResult.started) {
this.displayResults(result, options);
}
} catch (error: any) {
if (spinner) {
spinner.fail('Operation failed');
}
this.handleError(error);
process.exit(1);
}
}
/**
* Validate command options
*/
private validateOptions(options: StartCommandOptions): boolean {
// Validate format
if (options.format && !['text', 'json'].includes(options.format)) {
console.error(chalk.red(`Invalid format: ${options.format}`));
console.error(chalk.gray(`Valid formats: text, json`));
return false;
}
return true;
}
/**
* Initialize TaskMasterCore
*/
private async initializeCore(projectRoot: string): Promise<void> {
if (!this.tmCore) {
this.tmCore = await createTaskMasterCore({ projectPath: projectRoot });
}
}
/**
* Get the next available task using tm-core
*/
private async performGetNextTask(): Promise<string | null> {
if (!this.tmCore) {
throw new Error('TaskMasterCore not initialized');
}
return this.tmCore.getNextAvailableTask();
}
/**
* Show pre-launch message using tm-core data
*/
private async showPreLaunchMessage(targetTaskId: string): Promise<void> {
if (!this.tmCore) return;
const { task, subtask, subtaskId } =
await this.tmCore.getTaskWithSubtask(targetTaskId);
if (task) {
const workItemText = subtask
? `Subtask #${task.id}.${subtaskId} - ${subtask.title}`
: `Task #${task.id} - ${task.title}`;
console.log(
chalk.green('🚀 Starting: ') + chalk.white.bold(workItemText)
);
console.log(chalk.gray('Launching Claude Code...'));
console.log(); // Empty line
}
}
/**
* Perform start task using tm-core business logic
*/
private async performStartTask(
targetTaskId: string,
options: StartCommandOptions
): Promise<CoreStartTaskResult> {
if (!this.tmCore) {
throw new Error('TaskMasterCore not initialized');
}
// Show spinner for status update if enabled
let statusSpinner: Ora | null = null;
if (!options.noStatusUpdate && !options.dryRun) {
statusSpinner = ora('Updating task status to in-progress...').start();
}
// Get execution command from tm-core (instead of executing directly)
const result = await this.tmCore.startTask(targetTaskId, {
dryRun: options.dryRun,
force: options.force,
updateStatus: !options.noStatusUpdate
});
if (statusSpinner) {
if (result.started) {
statusSpinner.succeed('Task status updated');
} else {
statusSpinner.warn('Task status update skipped');
}
}
if (!result) {
throw new Error('Failed to start task - core result is undefined');
}
// Don't execute here - let the main executeCommand method handle it
return result;
}
/**
* Execute the child process directly in the main thread for better process control
*/
private async executeChildProcess(command: {
executable: string;
args: string[];
cwd: string;
}): Promise<void> {
return new Promise((resolve, reject) => {
// Don't show the full command with args as it can be very long
console.log(chalk.green('🚀 Launching Claude Code...'));
console.log(); // Add space before Claude takes over
const childProcess = spawn(command.executable, command.args, {
cwd: command.cwd,
stdio: 'inherit', // Inherit stdio from parent process
shell: false
});
childProcess.on('close', (code) => {
if (code === 0) {
resolve();
} else {
reject(new Error(`Process exited with code ${code}`));
}
});
childProcess.on('error', (error) => {
reject(new Error(`Failed to spawn process: ${error.message}`));
});
// Handle process termination signals gracefully
const cleanup = () => {
if (childProcess && !childProcess.killed) {
childProcess.kill('SIGTERM');
}
};
process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);
process.on('exit', cleanup);
});
}
/**
* Display results based on format
*/
private displayResults(
result: StartCommandResult,
options: StartCommandOptions
): void {
const format = options.format || 'text';
switch (format) {
case 'json':
this.displayJson(result);
break;
case 'text':
default:
this.displayTextResult(result, options);
break;
}
}
/**
* Display in JSON format
*/
private displayJson(result: StartCommandResult): void {
console.log(JSON.stringify(result, null, 2));
}
/**
* Display result in text format
*/
private displayTextResult(
result: StartCommandResult,
options: StartCommandOptions
): void {
if (!result.found || !result.task) {
console.log(
boxen(chalk.yellow(`Task not found!`), {
padding: { top: 0, bottom: 0, left: 1, right: 1 },
borderColor: 'yellow',
borderStyle: 'round',
margin: { top: 1 }
})
);
return;
}
const task = result.task;
if (options.dryRun) {
// For dry run, show full details since Claude Code won't be launched
let headerText = `Dry Run: Starting Task #${task.id} - ${task.title}`;
// If working on a specific subtask, highlight it in the header
if (result.subtask && result.subtaskId) {
headerText = `Dry Run: Starting Subtask #${task.id}.${result.subtaskId} - ${result.subtask.title}`;
}
displayTaskDetails(task, {
customHeader: headerText,
headerColor: 'yellow'
});
// Show claude-code prompt
if (result.executionOutput) {
console.log(); // Empty line for spacing
console.log(
boxen(
chalk.white.bold('Claude-Code Prompt:') +
'\n\n' +
result.executionOutput,
{
padding: 1,
borderStyle: 'round',
borderColor: 'cyan',
width: process.stdout.columns * 0.95 || 100
}
)
);
}
console.log(); // Empty line for spacing
console.log(
boxen(
chalk.yellow(
'🔍 Dry run - claude-code would be launched with the above prompt'
),
{
padding: { top: 0, bottom: 0, left: 1, right: 1 },
borderColor: 'yellow',
borderStyle: 'round'
}
)
);
} else {
// For actual execution, show minimal info since Claude Code will clear the terminal
if (result.started) {
// Determine what was worked on - task or subtask
let workItemText = `Task: #${task.id} - ${task.title}`;
let statusTarget = task.id;
if (result.subtask && result.subtaskId) {
workItemText = `Subtask: #${task.id}.${result.subtaskId} - ${result.subtask.title}`;
statusTarget = `${task.id}.${result.subtaskId}`;
}
// Post-execution message (shown after Claude Code exits)
console.log(
boxen(
chalk.green.bold('🎉 Task Session Complete!') +
'\n\n' +
chalk.white(workItemText) +
'\n\n' +
chalk.cyan('Next steps:') +
'\n' +
`• Run ${chalk.yellow('tm show ' + task.id)} to review task details\n` +
`• Run ${chalk.yellow('tm set-status --id=' + statusTarget + ' --status=done')} when complete\n` +
`• Run ${chalk.yellow('tm next')} to find the next available task\n` +
`• Run ${chalk.yellow('tm start')} to begin the next task`,
{
padding: 1,
borderStyle: 'round',
borderColor: 'green',
width: process.stdout.columns * 0.95 || 100,
margin: { top: 1 }
}
)
);
} else {
// Error case
console.log(
boxen(
chalk.red(
'❌ Failed to launch claude-code' +
(result.error ? `\nError: ${result.error}` : '')
),
{
padding: { top: 0, bottom: 0, left: 1, right: 1 },
borderColor: 'red',
borderStyle: 'round'
}
)
);
}
}
console.log(`\n${chalk.gray('Storage: ' + result.storageType)}`);
}
/**
* Handle general errors
*/
private handleError(error: any): void {
const msg = error?.getSanitizedDetails?.() ?? {
message: error?.message ?? String(error)
};
console.error(chalk.red(`Error: ${msg.message || 'Unexpected error'}`));
// Show stack trace in development mode or when DEBUG is set
const isDevelopment = process.env.NODE_ENV !== 'production';
if ((isDevelopment || process.env.DEBUG) && error.stack) {
console.error(chalk.gray(error.stack));
}
}
/**
* Set the last result for programmatic access
*/
private setLastResult(result: StartCommandResult): void {
this.lastResult = result;
}
/**
* Get the last result (for programmatic usage)
*/
getLastResult(): StartCommandResult | undefined {
return this.lastResult;
}
/**
* Clean up resources
*/
async cleanup(): Promise<void> {
if (this.tmCore) {
await this.tmCore.close();
this.tmCore = undefined;
}
}
/**
* Static method to register this command on an existing program
*/
static registerOn(program: Command): Command {
const startCommand = new StartCommand();
program.addCommand(startCommand);
return startCommand;
}
/**
* Alternative registration that returns the command for chaining
*/
static register(program: Command, name?: string): StartCommand {
const startCommand = new StartCommand(name);
program.addCommand(startCommand);
return startCommand;
}
}

View File

@@ -8,6 +8,7 @@ export { ListTasksCommand } from './commands/list.command.js';
export { ShowCommand } from './commands/show.command.js';
export { AuthCommand } from './commands/auth.command.js';
export { ContextCommand } from './commands/context.command.js';
export { StartCommand } from './commands/start.command.js';
export { SetStatusCommand } from './commands/set-status.command.js';
// UI utilities (for other commands to use)
@@ -17,7 +18,8 @@ export * as ui from './utils/ui.js';
export {
checkForUpdate,
performAutoUpdate,
displayUpgradeNotification
displayUpgradeNotification,
compareVersions
} from './utils/auto-update.js';
// Re-export commonly used types from tm-core

View File

@@ -262,3 +262,74 @@ export function displaySuggestedActions(taskId: string | number): void {
)
);
}
/**
* Display complete task details - used by both show and start commands
*/
export function displayTaskDetails(
task: Task,
options?: {
statusFilter?: string;
showSuggestedActions?: boolean;
customHeader?: string;
headerColor?: string;
}
): void {
const {
statusFilter,
showSuggestedActions = false,
customHeader,
headerColor = 'blue'
} = options || {};
// Display header - either custom or default
if (customHeader) {
console.log(
boxen(chalk.white.bold(customHeader), {
padding: { top: 0, bottom: 0, left: 1, right: 1 },
borderColor: headerColor,
borderStyle: 'round',
margin: { top: 1 }
})
);
} else {
displayTaskHeader(task.id, task.title);
}
// Display task properties in table format
displayTaskProperties(task);
// Display implementation details if available
if (task.details) {
console.log(); // Empty line for spacing
displayImplementationDetails(task.details);
}
// Display test strategy if available
if ('testStrategy' in task && task.testStrategy) {
console.log(); // Empty line for spacing
displayTestStrategy(task.testStrategy as string);
}
// Display subtasks if available
if (task.subtasks && task.subtasks.length > 0) {
// Filter subtasks by status if provided
const filteredSubtasks = statusFilter
? task.subtasks.filter((sub) => sub.status === statusFilter)
: task.subtasks;
if (filteredSubtasks.length === 0 && statusFilter) {
console.log(); // Empty line for spacing
console.log(chalk.gray(` No subtasks with status '${statusFilter}'`));
} else if (filteredSubtasks.length > 0) {
console.log(); // Empty line for spacing
displaySubtasks(filteredSubtasks, task.id);
}
}
// Display suggested actions if requested
if (showSuggestedActions) {
console.log(); // Empty line for spacing
displaySuggestedActions(task.id);
}
}

View File

@@ -7,7 +7,6 @@ import https from 'https';
import chalk from 'chalk';
import ora from 'ora';
import boxen from 'boxen';
import packageJson from '../../../../package.json' with { type: 'json' };
export interface UpdateInfo {
currentVersion: string;
@@ -16,15 +15,18 @@ export interface UpdateInfo {
}
/**
* Get current version from package.json
* Get current version from build-time injected environment variable
*/
function getCurrentVersion(): string {
try {
return packageJson.version;
} catch (error) {
console.warn('Could not read package.json for version info');
return '0.0.0';
// Version is injected at build time via TM_PUBLIC_VERSION
const version = process.env.TM_PUBLIC_VERSION;
if (version && version !== 'unknown') {
return version;
}
// Fallback for development or if injection failed
console.warn('Could not read version from TM_PUBLIC_VERSION, using fallback');
return '0.0.0';
}
/**
@@ -33,7 +35,7 @@ function getCurrentVersion(): string {
* @param v2 - Second version
* @returns -1 if v1 < v2, 0 if v1 = v2, 1 if v1 > v2
*/
function compareVersions(v1: string, v2: string): number {
export function compareVersions(v1: string, v2: string): number {
const toParts = (v: string) => {
const [core, pre = ''] = v.split('-', 2);
const nums = core.split('.').map((n) => Number.parseInt(n, 10) || 0);

View File

@@ -1,5 +1,9 @@
# docs
## 0.0.4
## 0.0.3
## 0.0.2
## 0.0.1

View File

@@ -19,7 +19,7 @@ description: "This guide walks you through setting up Task Master in your develo
"mcpServers": {
"taskmaster-ai": {
"command": "npx",
"args": ["-y", "--package", "task-master-ai", "task-master-mcp"],
"args": ["-y", "task-master-ai"],
"env": {
"ANTHROPIC_API_KEY": "YOUR_ANTHROPIC_API_KEY_HERE",
"PERPLEXITY_API_KEY": "YOUR_PERPLEXITY_API_KEY_HERE",

View File

@@ -48,7 +48,7 @@ description: "Learn how to set up and use Task Master with Cursor AI"
<Step title="Configure with the following details:">
- Name: "Task Master"
- Type: "Command"
- Command: "npx -y --package task-master-ai task-master-mcp"
- Command: "npx -y task-master-ai"
</Step>
<Step title="Save Settings">

View File

@@ -18,8 +18,8 @@ For MCP/Cursor usage: Configure keys in the env section of your .cursor/mcp.json
{
"mcpServers": {
"task-master-ai": {
"command": "node",
"args": ["./mcp-server/server.js"],
"command": "npx",
"args": ["-y", "task-master-ai"],
"env": {
"ANTHROPIC_API_KEY": "ANTHROPIC_API_KEY_HERE",
"PERPLEXITY_API_KEY": "PERPLEXITY_API_KEY_HERE",

View File

@@ -56,7 +56,7 @@ MCP (Model Control Protocol) lets you run Task Master directly from your editor.
"mcpServers": {
"taskmaster-ai": {
"command": "npx",
"args": ["-y", "--package=task-master-ai", "task-master-ai"],
"args": ["-y", "task-master-ai"],
"env": {
"ANTHROPIC_API_KEY": "YOUR_ANTHROPIC_API_KEY_HERE",
"PERPLEXITY_API_KEY": "YOUR_PERPLEXITY_API_KEY_HERE",
@@ -75,7 +75,7 @@ MCP (Model Control Protocol) lets you run Task Master directly from your editor.
> 🔑 Replace `YOUR_…_KEY_HERE` with your real API keys. You can remove keys you don't use.
> **Note**: If you see `0 tools enabled` in the MCP settings, try removing the `--package=task-master-ai` flag from `args`.
> **Note**: If you see `0 tools enabled` in the MCP settings, restart your editor and check that your API keys are correctly configured.
### VS Code (`servers` + `type`)
@@ -84,7 +84,7 @@ MCP (Model Control Protocol) lets you run Task Master directly from your editor.
"servers": {
"taskmaster-ai": {
"command": "npx",
"args": ["-y", "--package=task-master-ai", "task-master-ai"],
"args": ["-y", "task-master-ai"],
"env": {
"ANTHROPIC_API_KEY": "YOUR_ANTHROPIC_API_KEY_HERE",
"PERPLEXITY_API_KEY": "YOUR_PERPLEXITY_API_KEY_HERE",

View File

@@ -1,6 +1,6 @@
{
"name": "docs",
"version": "0.0.2",
"version": "0.0.4",
"private": true,
"description": "Task Master documentation powered by Mintlify",
"scripts": {

View File

@@ -1,5 +1,43 @@
# Change Log
## 0.25.2
### Patch Changes
- Updated dependencies [[`f487736`](https://github.com/eyaltoledano/claude-task-master/commit/f487736670ef8c484059f676293777eabb249c9e), [`c911608`](https://github.com/eyaltoledano/claude-task-master/commit/c911608f60454253f4e024b57ca84e5a5a53f65c), [`1a18794`](https://github.com/eyaltoledano/claude-task-master/commit/1a1879483b86c118a4e46c02cbf4acebfcf6bcf9)]:
- task-master-ai@0.27.1
## 0.25.2-rc.1
### Patch Changes
- Updated dependencies [[`1a18794`](https://github.com/eyaltoledano/claude-task-master/commit/1a1879483b86c118a4e46c02cbf4acebfcf6bcf9)]:
- task-master-ai@0.27.1-rc.1
## 0.25.2-rc.0
### Patch Changes
- Updated dependencies [[`f487736`](https://github.com/eyaltoledano/claude-task-master/commit/f487736670ef8c484059f676293777eabb249c9e)]:
- task-master-ai@0.27.1-rc.0
## 0.25.0
### Minor Changes
- [#1200](https://github.com/eyaltoledano/claude-task-master/pull/1200) [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add "Start Task" button to VS Code extension for seamless Claude Code integration
You can now click a "Start Task" button directly in the Task Master extension which will open a new terminal and automatically execute the task using Claude Code. This provides a seamless workflow from viewing tasks in the extension to implementing them without leaving VS Code.
- [#1201](https://github.com/eyaltoledano/claude-task-master/pull/1201) [`83af314`](https://github.com/eyaltoledano/claude-task-master/commit/83af314879fc0e563581161c60d2bd089899313e) Thanks [@losolosol](https://github.com/losolosol)! - Added a Start Build button to the VSCODE Task Properties Right Panel
### Patch Changes
- [#1229](https://github.com/eyaltoledano/claude-task-master/pull/1229) [`674d1f6`](https://github.com/eyaltoledano/claude-task-master/commit/674d1f6de7ea98116b61bdae6198bafe6c4e7c1a) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP not connecting to new Taskmaster version
- Updated dependencies [[`4e12643`](https://github.com/eyaltoledano/claude-task-master/commit/4e126430a092fb54afb035514fb3d46115714f97), [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142), [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142), [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142), [`a621ff0`](https://github.com/eyaltoledano/claude-task-master/commit/a621ff05eafb51a147a9aabd7b37ddc0e45b0869), [`e6de285`](https://github.com/eyaltoledano/claude-task-master/commit/e6de285ceacb0a397e952a63435cd32a9c731515), [`fce8414`](https://github.com/eyaltoledano/claude-task-master/commit/fce841490a9ebbf1801a42dd8a29397379cf1142)]:
- task-master-ai@0.27.0
## 0.25.0-rc.0
### Minor Changes

View File

@@ -109,7 +109,7 @@ Access settings via **File → Preferences → Settings** and search for "Taskma
### **MCP Connection Settings**
- **MCP Server Command** - Path to task-master-ai executable (default: `npx`)
- **MCP Server Args** - Arguments for the server command (default: `-y`, `--package=task-master-ai`, `task-master-ai`)
- **MCP Server Args** - Arguments for the server command (default: `-y`, `task-master-ai`)
- **Connection Timeout** - Server response timeout (default: 30s)
- **Auto Refresh** - Enable automatic task updates (default: enabled)

View File

@@ -3,7 +3,7 @@
"private": true,
"displayName": "TaskMaster",
"description": "A visual Kanban board interface for TaskMaster projects in VS Code",
"version": "0.25.0-rc.0",
"version": "0.25.2",
"publisher": "Hamster",
"icon": "assets/icon.png",
"engines": {
@@ -240,7 +240,7 @@
"check-types": "tsc --noEmit"
},
"dependencies": {
"task-master-ai": "*"
"task-master-ai": "0.27.1"
},
"devDependencies": {
"@dnd-kit/core": "^6.3.1",
@@ -254,8 +254,9 @@
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.2.3",
"@tailwindcss/postcss": "^4.1.11",
"@tanstack/react-query": "^5.83.0",
"@types/mocha": "^10.0.10",
"@types/node": "20.x",
"@types/node": "^22.10.5",
"@types/react": "19.1.8",
"@types/react-dom": "19.1.6",
"@types/vscode": "^1.101.0",
@@ -271,12 +272,11 @@
"lucide-react": "^0.525.0",
"npm-run-all": "^4.1.5",
"postcss": "8.5.6",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"tailwind-merge": "^3.3.1",
"tailwindcss": "4.1.11",
"typescript": "^5.8.3",
"@tanstack/react-query": "^5.83.0",
"react": "^19.0.0",
"react-dom": "^19.0.0"
"typescript": "^5.7.3"
},
"overrides": {
"glob@<8": "^10.4.5",

View File

@@ -95,7 +95,7 @@
"items": {
"type": "string"
},
"default": ["-y", "--package=task-master-ai", "task-master-ai"],
"default": ["-y", "task-master-ai"],
"description": "An array of arguments to pass to the MCP server command."
},
"taskmaster.mcp.cwd": {

View File

@@ -11,7 +11,6 @@ interface TaskMetadataSidebarProps {
tasks: TaskMasterTask[];
complexity: any;
isSubtask: boolean;
sendMessage: (message: any) => Promise<any>;
onStatusChange: (status: TaskMasterTask['status']) => void;
onDependencyClick: (depId: string) => void;
isRegenerating?: boolean;
@@ -23,13 +22,12 @@ export const TaskMetadataSidebar: React.FC<TaskMetadataSidebarProps> = ({
tasks,
complexity,
isSubtask,
sendMessage,
onStatusChange,
onDependencyClick,
isRegenerating = false,
isAppending = false
}) => {
const { vscode } = useVSCodeContext();
const { sendMessage } = useVSCodeContext();
const [isLoadingComplexity, setIsLoadingComplexity] = useState(false);
const [mcpComplexityScore, setMcpComplexityScore] = useState<
number | undefined
@@ -101,26 +99,37 @@ export const TaskMetadataSidebar: React.FC<TaskMetadataSidebarProps> = ({
};
// Handle starting a task
const handleStartTask = () => {
const handleStartTask = async () => {
if (!currentTask || isStartingTask) {
return;
}
setIsStartingTask(true);
// Send message to extension to open terminal
if (vscode) {
vscode.postMessage({
try {
// Send message to extension to open terminal
const result = await sendMessage({
type: 'openTerminal',
taskId: currentTask.id,
taskTitle: currentTask.title
data: {
taskId: currentTask.id,
taskTitle: currentTask.title
}
});
}
// Reset loading state after a short delay
setTimeout(() => {
// Handle the response
if (result && !result.success) {
console.error('Terminal execution failed:', result.error);
// The extension will show VS Code error notification and webview toast
} else if (result && result.success) {
console.log('Terminal started successfully:', result.terminalName);
}
} catch (error) {
console.error('Failed to start task:', error);
// This handles network/communication errors
} finally {
// Reset loading state
setIsStartingTask(false);
}, 500);
}
};
// Effect to handle complexity on task change

View File

@@ -208,7 +208,6 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
tasks={allTasks}
complexity={complexity}
isSubtask={isSubtask}
sendMessage={sendMessage}
onStatusChange={handleStatusChange}
onDependencyClick={handleDependencyClick}
/>

View File

@@ -8,6 +8,7 @@ import { ConfigService } from './services/config-service';
import { PollingService } from './services/polling-service';
import { createPollingStrategy } from './services/polling-strategies';
import { TaskRepository } from './services/task-repository';
import { TerminalManager } from './services/terminal-manager';
import { WebviewManager } from './services/webview-manager';
import { EventEmitter } from './utils/event-emitter';
import { ExtensionLogger } from './utils/logger';
@@ -22,6 +23,7 @@ let logger: ExtensionLogger;
let mcpClient: MCPClientManager;
let api: TaskMasterApi;
let repository: TaskRepository;
let terminalManager: TerminalManager;
let pollingService: PollingService;
let webviewManager: WebviewManager;
let events: EventEmitter;
@@ -46,6 +48,9 @@ export async function activate(context: vscode.ExtensionContext) {
// Repository with caching (actually useful for performance)
repository = new TaskRepository(api, logger);
// Terminal manager for task execution
terminalManager = new TerminalManager(context, logger);
// Config service for TaskMaster config.json
configService = new ConfigService(logger);
@@ -56,7 +61,13 @@ export async function activate(context: vscode.ExtensionContext) {
pollingService = new PollingService(repository, strategy, logger);
// Webview manager (cleaner than global panel array) - create before connection
webviewManager = new WebviewManager(context, repository, events, logger);
webviewManager = new WebviewManager(
context,
repository,
events,
logger,
terminalManager
);
webviewManager.setConfigService(configService);
// Sidebar webview manager
@@ -210,10 +221,11 @@ function registerCommands(context: vscode.ExtensionContext) {
);
}
export function deactivate() {
export async function deactivate() {
logger?.log('👋 TaskMaster Extension deactivating...');
pollingService?.stop();
webviewManager?.dispose();
await terminalManager?.dispose();
api?.destroy();
mcpClient?.disconnect();
}

View File

@@ -0,0 +1,156 @@
/**
* Terminal Manager - Handles task execution in VS Code terminals
* Uses @tm/core for consistent task management with the CLI
*/
import * as vscode from 'vscode';
import { createTaskMasterCore, type TaskMasterCore } from '@tm/core';
import type { ExtensionLogger } from '../utils/logger';
export interface TerminalExecutionOptions {
taskId: string;
taskTitle: string;
tag?: string;
}
export interface TerminalExecutionResult {
success: boolean;
error?: string;
terminalName?: string;
}
export class TerminalManager {
private terminals = new Map<string, vscode.Terminal>();
private tmCore?: TaskMasterCore;
constructor(
private context: vscode.ExtensionContext,
private logger: ExtensionLogger
) {}
/**
* Execute a task in a new VS Code terminal with Claude
* Uses @tm/core for consistent task management with the CLI
*/
async executeTask(
options: TerminalExecutionOptions
): Promise<TerminalExecutionResult> {
const { taskTitle, tag } = options;
// Ensure taskId is always a string
const taskId = String(options.taskId);
this.logger.log(
`Starting task execution for ${taskId}: ${taskTitle}${tag ? ` (tag: ${tag})` : ''}`
);
this.logger.log(`TaskId type: ${typeof taskId}, value: ${taskId}`);
try {
// Initialize tm-core if needed
await this.initializeCore();
// Use tm-core to start the task (same as CLI)
const startResult = await this.tmCore!.startTask(taskId, {
dryRun: false,
force: false,
updateStatus: true
});
if (!startResult.started || !startResult.executionOutput) {
throw new Error(
startResult.error || 'Failed to start task with tm-core'
);
}
// Create terminal with custom TaskMaster icon
const terminalName = `Task ${taskId}: ${taskTitle}`;
const terminal = this.createTerminal(terminalName);
// Store terminal reference for potential cleanup
this.terminals.set(taskId, terminal);
// Show terminal and run Claude command
terminal.show();
const command = `claude "${startResult.executionOutput}"`;
terminal.sendText(command);
this.logger.log(`Launched Claude for task ${taskId} using tm-core`);
return {
success: true,
terminalName
};
} catch (error) {
this.logger.error('Failed to execute task:', error);
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error'
};
}
}
/**
* Create a new terminal with TaskMaster branding
*/
private createTerminal(name: string): vscode.Terminal {
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
return vscode.window.createTerminal({
name,
cwd: workspaceRoot,
iconPath: new vscode.ThemeIcon('play') // Use a VS Code built-in icon for now
});
}
/**
* Initialize TaskMaster Core (same as CLI)
*/
private async initializeCore(): Promise<void> {
if (!this.tmCore) {
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
if (!workspaceRoot) {
throw new Error('No workspace folder found');
}
this.tmCore = await createTaskMasterCore({ projectPath: workspaceRoot });
}
}
/**
* Get terminal by task ID (if still active)
*/
getTerminalByTaskId(taskId: string): vscode.Terminal | undefined {
return this.terminals.get(taskId);
}
/**
* Clean up terminated terminals
*/
cleanupTerminal(taskId: string): void {
const terminal = this.terminals.get(taskId);
if (terminal) {
this.terminals.delete(taskId);
}
}
/**
* Dispose all managed terminals and clean up tm-core
*/
async dispose(): Promise<void> {
this.terminals.forEach((terminal) => {
try {
terminal.dispose();
} catch (error) {
this.logger.error('Failed to dispose terminal:', error);
}
});
this.terminals.clear();
if (this.tmCore) {
try {
await this.tmCore.close();
this.tmCore = undefined;
} catch (error) {
this.logger.error('Failed to close tm-core:', error);
}
}
}
}

View File

@@ -8,6 +8,7 @@ import type { EventEmitter } from '../utils/event-emitter';
import type { ExtensionLogger } from '../utils/logger';
import type { ConfigService } from './config-service';
import type { TaskRepository } from './task-repository';
import type { TerminalManager } from './terminal-manager';
export class WebviewManager {
private panels = new Set<vscode.WebviewPanel>();
@@ -19,7 +20,8 @@ export class WebviewManager {
private context: vscode.ExtensionContext,
private repository: TaskRepository,
private events: EventEmitter,
private logger: ExtensionLogger
private logger: ExtensionLogger,
private terminalManager: TerminalManager
) {}
setConfigService(configService: ConfigService): void {
@@ -362,27 +364,67 @@ export class WebviewManager {
return;
case 'openTerminal':
// Open VS Code terminal for task execution
// Delegate terminal execution to TerminalManager
const { taskId, taskTitle } = data.data || data; // Handle both nested and direct data
this.logger.log(
`Opening terminal for task ${data.taskId}: ${data.taskTitle}`
`Webview openTerminal - taskId: ${taskId} (type: ${typeof taskId}), taskTitle: ${taskTitle}`
);
try {
const terminal = vscode.window.createTerminal({
name: `Task ${data.taskId}: ${data.taskTitle}`,
cwd: vscode.workspace.workspaceFolders?.[0]?.uri.fsPath
});
terminal.show();
// Get current tag to ensure we're working in the right context
let currentTag = 'master'; // default fallback
if (this.mcpClient) {
try {
const tagsResult = await this.mcpClient.callTool('list_tags', {
projectRoot: vscode.workspace.workspaceFolders?.[0]?.uri.fsPath,
showMetadata: false
});
this.logger.log('Terminal created and shown successfully');
response = { success: true };
} catch (error) {
this.logger.error('Failed to create terminal:', error);
response = {
success: false,
error: error instanceof Error ? error.message : 'Unknown error'
};
let parsedData;
if (
tagsResult?.content &&
Array.isArray(tagsResult.content) &&
tagsResult.content[0]?.text
) {
try {
parsedData = JSON.parse(tagsResult.content[0].text);
if (parsedData?.data?.currentTag) {
currentTag = parsedData.data.currentTag;
}
} catch (e) {
this.logger.warn(
'Failed to parse tags response for terminal execution'
);
}
}
} catch (error) {
this.logger.warn(
'Failed to get current tag for terminal execution:',
error
);
}
}
const result = await this.terminalManager.executeTask({
taskId,
taskTitle,
tag: currentTag
});
response = result;
// Show user feedback AFTER sending the response (like the working "TaskMaster connected!" example)
setImmediate(() => {
if (result.success) {
// Success: Show info message
vscode.window.showInformationMessage(
`✅ Started Claude session for Task ${taskId}: ${taskTitle}`
);
} else {
// Error: Show VS Code native error notification only
const errorMsg = `Failed to start task: ${result.error}`;
vscode.window.showErrorMessage(errorMsg);
}
});
break;
default:

View File

@@ -408,7 +408,7 @@ export function createMCPConfigFromSettings(): MCPConfig {
const taskMasterPath = require.resolve('task-master-ai');
const mcpServerPath = path.resolve(
path.dirname(taskMasterPath),
'mcp-server/server.js'
'./dist/mcp-server.js'
);
// Verify the server file exists

View File

@@ -20,7 +20,8 @@
"paths": {
"@/*": ["./src/*"],
"@/components/*": ["./src/components/*"],
"@/lib/*": ["./src/lib/*"]
"@/lib/*": ["./src/lib/*"],
"@tm/core": ["../core/src"]
}
},
"exclude": ["node_modules", ".vscode-test", "out", "dist"]

View File

@@ -85,7 +85,7 @@ Task Master provides an MCP server that Claude Code can connect to. Configure in
"mcpServers": {
"task-master-ai": {
"command": "npx",
"args": ["-y", "--package=task-master-ai", "task-master-ai"],
"args": ["-y", "task-master-ai"],
"env": {
"ANTHROPIC_API_KEY": "your_key_here",
"PERPLEXITY_API_KEY": "your_key_here",

Some files were not shown because too many files have changed in this diff Show More