Compare commits
7 Commits
task-maste
...
task-maste
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7f32eac5a | ||
|
|
044a7bfc98 | ||
|
|
51a351760c | ||
|
|
732b2c61ad | ||
|
|
4c2801d5eb | ||
|
|
c911608f60 | ||
|
|
8f1497407f |
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"task-master-ai": patch
|
||||
---
|
||||
|
||||
Fix module not found for new 0.27.0 release
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"mode": "pre",
|
||||
"tag": "rc",
|
||||
"initialVersions": {
|
||||
"task-master-ai": "0.27.0",
|
||||
"docs": "0.0.3",
|
||||
"extension": "0.25.1"
|
||||
},
|
||||
"changesets": [
|
||||
"fluffy-clocks-cross"
|
||||
]
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"task-master-ai": patch
|
||||
---
|
||||
|
||||
One last testing final final
|
||||
23
CHANGELOG.md
23
CHANGELOG.md
@@ -1,5 +1,28 @@
|
||||
# task-master-ai
|
||||
|
||||
## 0.27.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1248](https://github.com/eyaltoledano/claude-task-master/pull/1248) [`044a7bf`](https://github.com/eyaltoledano/claude-task-master/commit/044a7bfc98049298177bc655cf341d7a8b6a0011) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix set-status for subtasks:
|
||||
- Parent tasks are now set as `done` when subtasks are all `done`
|
||||
- Parent tasks are now set as `in-progress` when at least one subtask is `in-progress` or `done`
|
||||
|
||||
## 0.27.1
|
||||
|
||||
### 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
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @tm/cli
|
||||
|
||||
## null
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @tm/core@null
|
||||
|
||||
## 0.27.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# docs
|
||||
|
||||
## 0.0.4
|
||||
|
||||
## 0.0.3
|
||||
|
||||
## 0.0.2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docs",
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.4",
|
||||
"private": true,
|
||||
"description": "Task Master documentation powered by Mintlify",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# Change Log
|
||||
|
||||
## 0.25.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`044a7bf`](https://github.com/eyaltoledano/claude-task-master/commit/044a7bfc98049298177bc655cf341d7a8b6a0011)]:
|
||||
- task-master-ai@0.27.2
|
||||
|
||||
## 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
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"private": true,
|
||||
"displayName": "TaskMaster",
|
||||
"description": "A visual Kanban board interface for TaskMaster projects in VS Code",
|
||||
"version": "0.25.2-rc.0",
|
||||
"version": "0.25.3",
|
||||
"publisher": "Hamster",
|
||||
"icon": "assets/icon.png",
|
||||
"engines": {
|
||||
@@ -240,7 +240,7 @@
|
||||
"check-types": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"task-master-ai": "0.27.1-rc.0"
|
||||
"task-master-ai": "0.27.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
|
||||
10
package-lock.json
generated
10
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "task-master-ai",
|
||||
"version": "0.27.1-rc.0",
|
||||
"version": "0.27.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "task-master-ai",
|
||||
"version": "0.27.1-rc.0",
|
||||
"version": "0.27.2",
|
||||
"license": "MIT WITH Commons-Clause",
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
@@ -351,15 +351,15 @@
|
||||
}
|
||||
},
|
||||
"apps/docs": {
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.4",
|
||||
"devDependencies": {
|
||||
"mintlify": "^4.2.111"
|
||||
}
|
||||
},
|
||||
"apps/extension": {
|
||||
"version": "0.25.2-rc.0",
|
||||
"version": "0.25.3",
|
||||
"dependencies": {
|
||||
"task-master-ai": "0.27.1-rc.0"
|
||||
"task-master-ai": "0.27.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "task-master-ai",
|
||||
"version": "0.27.1-rc.0",
|
||||
"version": "0.27.2",
|
||||
"description": "A task management system for ambitious AI-driven development that doesn't overwhelm and confuse Cursor.",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# @tm/build-config
|
||||
|
||||
## null
|
||||
|
||||
## 1.0.1
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Changelog
|
||||
|
||||
## null
|
||||
|
||||
## 0.26.1
|
||||
|
||||
All notable changes to the @task-master/tm-core package will be documented in this file.
|
||||
|
||||
@@ -3,7 +3,17 @@
|
||||
* This file defines the contract for all storage implementations
|
||||
*/
|
||||
|
||||
import type { Task, TaskMetadata } from '../types/index.js';
|
||||
import type { Task, TaskMetadata, TaskStatus } from '../types/index.js';
|
||||
|
||||
/**
|
||||
* Result type for updateTaskStatus operations
|
||||
*/
|
||||
export interface UpdateStatusResult {
|
||||
success: boolean;
|
||||
oldStatus: TaskStatus;
|
||||
newStatus: TaskStatus;
|
||||
taskId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for storage operations on tasks
|
||||
@@ -54,6 +64,19 @@ export interface IStorage {
|
||||
tag?: string
|
||||
): Promise<void>;
|
||||
|
||||
/**
|
||||
* Update task or subtask status by ID
|
||||
* @param taskId - ID of the task or subtask (e.g., "1" or "1.2")
|
||||
* @param newStatus - New status to set
|
||||
* @param tag - Optional tag context for the task
|
||||
* @returns Promise that resolves to update result with old and new status
|
||||
*/
|
||||
updateTaskStatus(
|
||||
taskId: string,
|
||||
newStatus: TaskStatus,
|
||||
tag?: string
|
||||
): Promise<UpdateStatusResult>;
|
||||
|
||||
/**
|
||||
* Delete a task by ID
|
||||
* @param taskId - ID of the task to delete
|
||||
@@ -191,6 +214,11 @@ export abstract class BaseStorage implements IStorage {
|
||||
updates: Partial<Task>,
|
||||
tag?: string
|
||||
): Promise<void>;
|
||||
abstract updateTaskStatus(
|
||||
taskId: string,
|
||||
newStatus: TaskStatus,
|
||||
tag?: string
|
||||
): Promise<UpdateStatusResult>;
|
||||
abstract deleteTask(taskId: string, tag?: string): Promise<void>;
|
||||
abstract exists(tag?: string): Promise<boolean>;
|
||||
abstract loadMetadata(tag?: string): Promise<TaskMetadata | null>;
|
||||
|
||||
@@ -446,7 +446,7 @@ export class TaskService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update task status
|
||||
* Update task status - delegates to storage layer which handles storage-specific logic
|
||||
*/
|
||||
async updateTaskStatus(
|
||||
taskId: string | number,
|
||||
@@ -468,49 +468,28 @@ export class TaskService {
|
||||
|
||||
// Use provided tag or get active tag
|
||||
const activeTag = tag || this.getActiveTag();
|
||||
|
||||
const taskIdStr = String(taskId);
|
||||
|
||||
// TODO: For now, assume it's a regular task and just try to update directly
|
||||
// In the future, we can add subtask support if needed
|
||||
if (taskIdStr.includes('.')) {
|
||||
throw new TaskMasterError(
|
||||
'Subtask status updates not yet supported in API storage',
|
||||
ERROR_CODES.NOT_IMPLEMENTED
|
||||
);
|
||||
}
|
||||
|
||||
// Get the current task to get old status (simple, direct approach)
|
||||
let currentTask: Task | null;
|
||||
try {
|
||||
// Try to get the task directly
|
||||
currentTask = await this.storage.loadTask(taskIdStr, activeTag);
|
||||
// Delegate to storage layer which handles the specific logic for tasks vs subtasks
|
||||
return await this.storage.updateTaskStatus(
|
||||
taskIdStr,
|
||||
newStatus,
|
||||
activeTag
|
||||
);
|
||||
} catch (error) {
|
||||
throw new TaskMasterError(
|
||||
`Failed to load task ${taskIdStr}`,
|
||||
ERROR_CODES.TASK_NOT_FOUND,
|
||||
{ taskId: taskIdStr },
|
||||
`Failed to update task status for ${taskIdStr}`,
|
||||
ERROR_CODES.STORAGE_ERROR,
|
||||
{
|
||||
operation: 'updateTaskStatus',
|
||||
resource: 'task',
|
||||
taskId: taskIdStr,
|
||||
newStatus,
|
||||
tag: activeTag
|
||||
},
|
||||
error as Error
|
||||
);
|
||||
}
|
||||
|
||||
if (!currentTask) {
|
||||
throw new TaskMasterError(
|
||||
`Task ${taskIdStr} not found`,
|
||||
ERROR_CODES.TASK_NOT_FOUND
|
||||
);
|
||||
}
|
||||
|
||||
const oldStatus = currentTask.status;
|
||||
|
||||
// Simple, direct update - just change the status
|
||||
await this.storage.updateTask(taskIdStr, { status: newStatus }, activeTag);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
oldStatus,
|
||||
newStatus,
|
||||
taskId: taskIdStr
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,15 @@
|
||||
|
||||
import type {
|
||||
IStorage,
|
||||
StorageStats
|
||||
StorageStats,
|
||||
UpdateStatusResult
|
||||
} from '../interfaces/storage.interface.js';
|
||||
import type { Task, TaskMetadata, TaskTag } from '../types/index.js';
|
||||
import type {
|
||||
Task,
|
||||
TaskMetadata,
|
||||
TaskTag,
|
||||
TaskStatus
|
||||
} from '../types/index.js';
|
||||
import { ERROR_CODES, TaskMasterError } from '../errors/task-master-error.js';
|
||||
import { TaskRepository } from '../repositories/task-repository.interface.js';
|
||||
import { SupabaseTaskRepository } from '../repositories/supabase-task-repository.js';
|
||||
@@ -485,6 +491,62 @@ export class ApiStorage implements IStorage {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update task or subtask status by ID - for API storage
|
||||
*/
|
||||
async updateTaskStatus(
|
||||
taskId: string,
|
||||
newStatus: TaskStatus,
|
||||
tag?: string
|
||||
): Promise<UpdateStatusResult> {
|
||||
await this.ensureInitialized();
|
||||
|
||||
try {
|
||||
const existingTask = await this.retryOperation(() =>
|
||||
this.repository.getTask(this.projectId, taskId)
|
||||
);
|
||||
|
||||
if (!existingTask) {
|
||||
throw new Error(`Task ${taskId} not found`);
|
||||
}
|
||||
|
||||
const oldStatus = existingTask.status;
|
||||
if (oldStatus === newStatus) {
|
||||
return {
|
||||
success: true,
|
||||
oldStatus,
|
||||
newStatus,
|
||||
taskId
|
||||
};
|
||||
}
|
||||
|
||||
// Update the task/subtask status
|
||||
await this.retryOperation(() =>
|
||||
this.repository.updateTask(this.projectId, taskId, {
|
||||
status: newStatus,
|
||||
updatedAt: new Date().toISOString()
|
||||
})
|
||||
);
|
||||
|
||||
// Note: Parent status auto-adjustment is handled by the backend API service
|
||||
// which has its own business logic for managing task relationships
|
||||
|
||||
return {
|
||||
success: true,
|
||||
oldStatus,
|
||||
newStatus,
|
||||
taskId
|
||||
};
|
||||
} catch (error) {
|
||||
throw new TaskMasterError(
|
||||
'Failed to update task status via API',
|
||||
ERROR_CODES.STORAGE_ERROR,
|
||||
{ operation: 'updateTaskStatus', taskId, newStatus, tag },
|
||||
error as Error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available tags
|
||||
*/
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
* @fileoverview Refactored file-based storage implementation for Task Master
|
||||
*/
|
||||
|
||||
import type { Task, TaskMetadata } from '../../types/index.js';
|
||||
import type { Task, TaskMetadata, TaskStatus } from '../../types/index.js';
|
||||
import type {
|
||||
IStorage,
|
||||
StorageStats
|
||||
StorageStats,
|
||||
UpdateStatusResult
|
||||
} from '../../interfaces/storage.interface.js';
|
||||
import { FormatHandler } from './format-handler.js';
|
||||
import { FileOperations } from './file-operations.js';
|
||||
@@ -281,6 +282,156 @@ export class FileStorage implements IStorage {
|
||||
await this.saveTasks(tasks, tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update task or subtask status by ID - handles file storage logic with parent/subtask relationships
|
||||
*/
|
||||
async updateTaskStatus(
|
||||
taskId: string,
|
||||
newStatus: TaskStatus,
|
||||
tag?: string
|
||||
): Promise<UpdateStatusResult> {
|
||||
const tasks = await this.loadTasks(tag);
|
||||
|
||||
// Check if this is a subtask (contains a dot)
|
||||
if (taskId.includes('.')) {
|
||||
return this.updateSubtaskStatusInFile(tasks, taskId, newStatus, tag);
|
||||
}
|
||||
|
||||
// Handle regular task update
|
||||
const taskIndex = tasks.findIndex((t) => String(t.id) === String(taskId));
|
||||
|
||||
if (taskIndex === -1) {
|
||||
throw new Error(`Task ${taskId} not found`);
|
||||
}
|
||||
|
||||
const oldStatus = tasks[taskIndex].status;
|
||||
if (oldStatus === newStatus) {
|
||||
return {
|
||||
success: true,
|
||||
oldStatus,
|
||||
newStatus,
|
||||
taskId: String(taskId)
|
||||
};
|
||||
}
|
||||
|
||||
tasks[taskIndex] = {
|
||||
...tasks[taskIndex],
|
||||
status: newStatus,
|
||||
updatedAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
await this.saveTasks(tasks, tag);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
oldStatus,
|
||||
newStatus,
|
||||
taskId: String(taskId)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update subtask status within file storage - handles parent status auto-adjustment
|
||||
*/
|
||||
private async updateSubtaskStatusInFile(
|
||||
tasks: Task[],
|
||||
subtaskId: string,
|
||||
newStatus: TaskStatus,
|
||||
tag?: string
|
||||
): Promise<UpdateStatusResult> {
|
||||
// Parse the subtask ID to get parent ID and subtask ID
|
||||
const parts = subtaskId.split('.');
|
||||
if (parts.length !== 2) {
|
||||
throw new Error(
|
||||
`Invalid subtask ID format: ${subtaskId}. Expected format: parentId.subtaskId`
|
||||
);
|
||||
}
|
||||
|
||||
const [parentId, subIdRaw] = parts;
|
||||
const subId = subIdRaw.trim();
|
||||
if (!/^\d+$/.test(subId)) {
|
||||
throw new Error(
|
||||
`Invalid subtask ID: ${subId}. Subtask ID must be a positive integer.`
|
||||
);
|
||||
}
|
||||
const subtaskNumericId = Number(subId);
|
||||
|
||||
// Find the parent task
|
||||
const parentTaskIndex = tasks.findIndex(
|
||||
(t) => String(t.id) === String(parentId)
|
||||
);
|
||||
|
||||
if (parentTaskIndex === -1) {
|
||||
throw new Error(`Parent task ${parentId} not found`);
|
||||
}
|
||||
|
||||
const parentTask = tasks[parentTaskIndex];
|
||||
|
||||
// Find the subtask within the parent task
|
||||
const subtaskIndex = parentTask.subtasks.findIndex(
|
||||
(st) => st.id === subtaskNumericId || String(st.id) === subId
|
||||
);
|
||||
|
||||
if (subtaskIndex === -1) {
|
||||
throw new Error(
|
||||
`Subtask ${subtaskId} not found in parent task ${parentId}`
|
||||
);
|
||||
}
|
||||
|
||||
const oldStatus = parentTask.subtasks[subtaskIndex].status || 'pending';
|
||||
if (oldStatus === newStatus) {
|
||||
return {
|
||||
success: true,
|
||||
oldStatus,
|
||||
newStatus,
|
||||
taskId: subtaskId
|
||||
};
|
||||
}
|
||||
|
||||
const now = new Date().toISOString();
|
||||
|
||||
// Update the subtask status
|
||||
parentTask.subtasks[subtaskIndex] = {
|
||||
...parentTask.subtasks[subtaskIndex],
|
||||
status: newStatus,
|
||||
updatedAt: now
|
||||
};
|
||||
|
||||
// Auto-adjust parent status based on subtask statuses
|
||||
const subs = parentTask.subtasks;
|
||||
let parentNewStatus = parentTask.status;
|
||||
if (subs.length > 0) {
|
||||
const norm = (s: any) => s.status || 'pending';
|
||||
const isDoneLike = (s: any) => {
|
||||
const st = norm(s);
|
||||
return st === 'done' || st === 'completed';
|
||||
};
|
||||
const allDone = subs.every(isDoneLike);
|
||||
const anyInProgress = subs.some((s) => norm(s) === 'in-progress');
|
||||
const anyDone = subs.some(isDoneLike);
|
||||
if (allDone) parentNewStatus = 'done';
|
||||
else if (anyInProgress || anyDone) parentNewStatus = 'in-progress';
|
||||
}
|
||||
|
||||
// Always bump updatedAt; update status only if changed
|
||||
tasks[parentTaskIndex] = {
|
||||
...parentTask,
|
||||
...(parentNewStatus !== parentTask.status
|
||||
? { status: parentNewStatus }
|
||||
: {}),
|
||||
updatedAt: now
|
||||
};
|
||||
|
||||
await this.saveTasks(tasks, tag);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
oldStatus,
|
||||
newStatus,
|
||||
taskId: subtaskId
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a task
|
||||
*/
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import readline from 'readline';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname } from 'path';
|
||||
import chalk from 'chalk';
|
||||
import figlet from 'figlet';
|
||||
import boxen from 'boxen';
|
||||
@@ -49,9 +47,6 @@ import {
|
||||
GITIGNORE_FILE
|
||||
} from '../src/constants/paths.js';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
// Define log levels
|
||||
const LOG_LEVELS = {
|
||||
debug: 0,
|
||||
@@ -619,13 +614,7 @@ function createProjectStructure(
|
||||
|
||||
// Copy .gitignore with GitTasks preference
|
||||
try {
|
||||
const gitignoreTemplatePath = path.join(
|
||||
__dirname,
|
||||
'..',
|
||||
'assets',
|
||||
'gitignore'
|
||||
);
|
||||
const templateContent = fs.readFileSync(gitignoreTemplatePath, 'utf8');
|
||||
const templateContent = readAsset('gitignore', 'utf8');
|
||||
manageGitignoreFile(
|
||||
path.join(targetDir, GITIGNORE_FILE),
|
||||
templateContent,
|
||||
|
||||
@@ -5077,7 +5077,7 @@ Examples:
|
||||
function setupCLI() {
|
||||
// Create a new program instance
|
||||
const programInstance = new Command()
|
||||
.name('dev')
|
||||
.name('task-master')
|
||||
.description('AI-driven development task management')
|
||||
.version(process.env.TM_PUBLIC_VERSION || 'unknown')
|
||||
.helpOption('-h, --help', 'Display help')
|
||||
@@ -5108,8 +5108,9 @@ function setupCLI() {
|
||||
*/
|
||||
async function runCLI(argv = process.argv) {
|
||||
try {
|
||||
// Display banner if not in a pipe
|
||||
if (process.stdout.isTTY) {
|
||||
// Display banner if not in a pipe (except for init command which has its own banner)
|
||||
const isInitCommand = argv.includes('init');
|
||||
if (process.stdout.isTTY && !isInitCommand) {
|
||||
displayBanner();
|
||||
}
|
||||
|
||||
|
||||
@@ -142,6 +142,14 @@ function onPostConvertRulesProfile(targetDir, assetsDir) {
|
||||
// Transform to Zed format
|
||||
const zedConfig = transformToZedFormat(mcpConfig);
|
||||
|
||||
// Add "source": "custom" to task-master-ai server for Zed
|
||||
if (
|
||||
zedConfig['context_servers'] &&
|
||||
zedConfig['context_servers']['task-master-ai']
|
||||
) {
|
||||
zedConfig['context_servers']['task-master-ai'].source = 'custom';
|
||||
}
|
||||
|
||||
// Write back the transformed config with proper formatting
|
||||
fs.writeFileSync(
|
||||
mcpConfigPath,
|
||||
|
||||
@@ -463,6 +463,17 @@ export function findConfigPath(explicitPath = null, args = null, log = null) {
|
||||
}
|
||||
}
|
||||
|
||||
logger.warn?.(`No configuration file found in project: ${projectRoot}`);
|
||||
// Only warn once per command execution to prevent spam during init
|
||||
const warningKey = `config_warning_${projectRoot}`;
|
||||
|
||||
if (!global._tmConfigWarningsThisRun) {
|
||||
global._tmConfigWarningsThisRun = new Set();
|
||||
}
|
||||
|
||||
if (!global._tmConfigWarningsThisRun.has(warningKey)) {
|
||||
global._tmConfigWarningsThisRun.add(warningKey);
|
||||
logger.warn?.(`No configuration file found in project: ${projectRoot}`);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ describe('Commands Module - CLI Setup and Integration', () => {
|
||||
test('should return Commander program instance', () => {
|
||||
const program = setupCLI();
|
||||
expect(program).toBeDefined();
|
||||
expect(program.name()).toBe('dev');
|
||||
expect(program.name()).toBe('task-master');
|
||||
});
|
||||
|
||||
test('should return version that matches package.json when TM_PUBLIC_VERSION is set', () => {
|
||||
|
||||
Reference in New Issue
Block a user