chore: typescript fixes and quality of life improvements and formatting
This commit is contained in:
@@ -73,7 +73,6 @@ export class ListTasksCommand extends Command {
|
|||||||
* Execute the list command
|
* Execute the list command
|
||||||
*/
|
*/
|
||||||
private async executeCommand(options: ListCommandOptions): Promise<void> {
|
private async executeCommand(options: ListCommandOptions): Promise<void> {
|
||||||
console.log('executeCommand', options);
|
|
||||||
try {
|
try {
|
||||||
// Validate options
|
// Validate options
|
||||||
if (!this.validateOptions(options)) {
|
if (!this.validateOptions(options)) {
|
||||||
|
|||||||
@@ -9,33 +9,49 @@ import Table from 'cli-table3';
|
|||||||
import type { Task, TaskStatus, TaskPriority } from '@tm/core';
|
import type { Task, TaskStatus, TaskPriority } from '@tm/core';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get colored status display
|
* Get colored status display with ASCII icons (matches scripts/modules/ui.js style)
|
||||||
*/
|
*/
|
||||||
export function getStatusWithColor(status: TaskStatus): string {
|
export function getStatusWithColor(
|
||||||
const statusColors: Record<TaskStatus, (text: string) => string> = {
|
status: TaskStatus,
|
||||||
pending: chalk.yellow,
|
forTable: boolean = false
|
||||||
'in-progress': chalk.blue,
|
): string {
|
||||||
done: chalk.green,
|
const statusConfig = {
|
||||||
deferred: chalk.gray,
|
done: {
|
||||||
cancelled: chalk.red,
|
color: chalk.green,
|
||||||
blocked: chalk.magenta,
|
icon: String.fromCharCode(8730),
|
||||||
review: chalk.cyan
|
tableIcon: String.fromCharCode(8730)
|
||||||
|
}, // √
|
||||||
|
pending: { color: chalk.yellow, icon: 'o', tableIcon: 'o' },
|
||||||
|
'in-progress': {
|
||||||
|
color: chalk.hex('#FFA500'),
|
||||||
|
icon: String.fromCharCode(9654),
|
||||||
|
tableIcon: '>'
|
||||||
|
}, // ▶
|
||||||
|
deferred: { color: chalk.gray, icon: 'x', tableIcon: 'x' },
|
||||||
|
blocked: { color: chalk.red, icon: '!', tableIcon: '!' },
|
||||||
|
review: { color: chalk.magenta, icon: '?', tableIcon: '?' },
|
||||||
|
cancelled: { color: chalk.gray, icon: 'X', tableIcon: 'X' }
|
||||||
};
|
};
|
||||||
|
|
||||||
const statusEmojis: Record<TaskStatus, string> = {
|
const config = statusConfig[status] || {
|
||||||
pending: '⏳',
|
color: chalk.red,
|
||||||
'in-progress': '🚀',
|
icon: 'X',
|
||||||
done: '✅',
|
tableIcon: 'X'
|
||||||
deferred: '⏸️',
|
|
||||||
cancelled: '❌',
|
|
||||||
blocked: '🚫',
|
|
||||||
review: '👀'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const colorFn = statusColors[status] || chalk.white;
|
// Use simple ASCII characters for stable display
|
||||||
const emoji = statusEmojis[status] || '';
|
const simpleIcons = {
|
||||||
|
done: String.fromCharCode(8730), // √
|
||||||
|
pending: 'o',
|
||||||
|
'in-progress': '>',
|
||||||
|
deferred: 'x',
|
||||||
|
blocked: '!',
|
||||||
|
review: '?',
|
||||||
|
cancelled: 'X'
|
||||||
|
};
|
||||||
|
|
||||||
return `${emoji} ${colorFn(status)}`;
|
const icon = forTable ? simpleIcons[status] || 'X' : config.icon;
|
||||||
|
return config.color(`${icon} ${status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,23 +125,23 @@ export function createProgressBar(
|
|||||||
*/
|
*/
|
||||||
export function displayBanner(title: string = 'Task Master'): void {
|
export function displayBanner(title: string = 'Task Master'): void {
|
||||||
console.log(
|
console.log(
|
||||||
boxen(chalk.cyan.bold(title), {
|
boxen(chalk.white.bold(title), {
|
||||||
padding: 1,
|
padding: 1,
|
||||||
margin: { top: 1, bottom: 1 },
|
margin: { top: 1, bottom: 1 },
|
||||||
borderStyle: 'double',
|
borderStyle: 'round',
|
||||||
borderColor: 'cyan',
|
borderColor: 'blue',
|
||||||
textAlignment: 'center'
|
textAlignment: 'center'
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display an error message
|
* Display an error message (matches scripts/modules/ui.js style)
|
||||||
*/
|
*/
|
||||||
export function displayError(message: string, details?: string): void {
|
export function displayError(message: string, details?: string): void {
|
||||||
console.error(
|
console.error(
|
||||||
boxen(
|
boxen(
|
||||||
chalk.red.bold('Error: ') +
|
chalk.red.bold('X Error: ') +
|
||||||
chalk.white(message) +
|
chalk.white(message) +
|
||||||
(details ? '\n\n' + chalk.gray(details) : ''),
|
(details ? '\n\n' + chalk.gray(details) : ''),
|
||||||
{
|
{
|
||||||
@@ -142,11 +158,14 @@ export function displayError(message: string, details?: string): void {
|
|||||||
*/
|
*/
|
||||||
export function displaySuccess(message: string): void {
|
export function displaySuccess(message: string): void {
|
||||||
console.log(
|
console.log(
|
||||||
boxen(chalk.green.bold('✓ ') + chalk.white(message), {
|
boxen(
|
||||||
|
chalk.green.bold(String.fromCharCode(8730) + ' ') + chalk.white(message),
|
||||||
|
{
|
||||||
padding: 1,
|
padding: 1,
|
||||||
borderStyle: 'round',
|
borderStyle: 'round',
|
||||||
borderColor: 'green'
|
borderColor: 'green'
|
||||||
})
|
}
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +187,7 @@ export function displayWarning(message: string): void {
|
|||||||
*/
|
*/
|
||||||
export function displayInfo(message: string): void {
|
export function displayInfo(message: string): void {
|
||||||
console.log(
|
console.log(
|
||||||
boxen(chalk.blue.bold('ℹ ') + chalk.white(message), {
|
boxen(chalk.blue.bold('i ') + chalk.white(message), {
|
||||||
padding: 1,
|
padding: 1,
|
||||||
borderStyle: 'round',
|
borderStyle: 'round',
|
||||||
borderColor: 'blue'
|
borderColor: 'blue'
|
||||||
@@ -225,30 +244,42 @@ export function createTaskTable(
|
|||||||
showDependencies = true
|
showDependencies = true
|
||||||
} = options || {};
|
} = options || {};
|
||||||
|
|
||||||
const headers = ['ID', 'Title', 'Status', 'Priority'];
|
// Calculate dynamic column widths based on terminal width
|
||||||
const colWidths = [8, 40, 15, 10];
|
const terminalWidth = process.stdout.columns || 100;
|
||||||
|
const baseColWidths = showComplexity
|
||||||
|
? [8, Math.floor(terminalWidth * 0.35), 18, 12, 15, 12] // ID, Title, Status, Priority, Dependencies, Complexity
|
||||||
|
: [8, Math.floor(terminalWidth * 0.4), 18, 12, 20]; // ID, Title, Status, Priority, Dependencies
|
||||||
|
|
||||||
|
const headers = [
|
||||||
|
chalk.blue.bold('ID'),
|
||||||
|
chalk.blue.bold('Title'),
|
||||||
|
chalk.blue.bold('Status'),
|
||||||
|
chalk.blue.bold('Priority')
|
||||||
|
];
|
||||||
|
const colWidths = baseColWidths.slice(0, 4);
|
||||||
|
|
||||||
if (showDependencies) {
|
if (showDependencies) {
|
||||||
headers.push('Dependencies');
|
headers.push(chalk.blue.bold('Dependencies'));
|
||||||
colWidths.push(20);
|
colWidths.push(baseColWidths[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showComplexity) {
|
if (showComplexity) {
|
||||||
headers.push('Complexity');
|
headers.push(chalk.blue.bold('Complexity'));
|
||||||
colWidths.push(12);
|
colWidths.push(baseColWidths[5] || 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
head: headers,
|
head: headers,
|
||||||
style: { head: ['blue'] },
|
style: { head: [], border: [] },
|
||||||
colWidths
|
colWidths,
|
||||||
|
wordWrap: true
|
||||||
});
|
});
|
||||||
|
|
||||||
tasks.forEach((task) => {
|
tasks.forEach((task) => {
|
||||||
const row: string[] = [
|
const row: string[] = [
|
||||||
chalk.cyan(task.id.toString()),
|
chalk.cyan(task.id.toString()),
|
||||||
truncate(task.title, 38),
|
truncate(task.title, colWidths[1] - 3),
|
||||||
getStatusWithColor(task.status),
|
getStatusWithColor(task.status, true), // Use table version
|
||||||
getPriorityWithColor(task.priority)
|
getPriorityWithColor(task.priority)
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -267,8 +298,8 @@ export function createTaskTable(
|
|||||||
task.subtasks.forEach((subtask) => {
|
task.subtasks.forEach((subtask) => {
|
||||||
const subRow: string[] = [
|
const subRow: string[] = [
|
||||||
chalk.gray(` └─ ${subtask.id}`),
|
chalk.gray(` └─ ${subtask.id}`),
|
||||||
chalk.gray(truncate(subtask.title, 36)),
|
chalk.gray(truncate(subtask.title, colWidths[1] - 6)),
|
||||||
getStatusWithColor(subtask.status),
|
chalk.gray(getStatusWithColor(subtask.status, true)),
|
||||||
chalk.gray(subtask.priority || 'medium')
|
chalk.gray(subtask.priority || 'medium')
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -276,8 +307,8 @@ export function createTaskTable(
|
|||||||
subRow.push(
|
subRow.push(
|
||||||
chalk.gray(
|
chalk.gray(
|
||||||
subtask.dependencies && subtask.dependencies.length > 0
|
subtask.dependencies && subtask.dependencies.length > 0
|
||||||
? subtask.dependencies.join(', ')
|
? subtask.dependencies.map((dep) => String(dep)).join(', ')
|
||||||
: 'none'
|
: 'None'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
"workspaces": ["apps/*", "packages/*", "."],
|
"workspaces": ["apps/*", "packages/*", "."],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npm run build:packages && tsup",
|
"build": "npm run build:packages && tsup",
|
||||||
"dev": "npm run build:packages && (npm run dev:packages & tsup --watch --onSuccess 'echo Build complete')",
|
"dev": "npm run build:packages && npm link && (npm run dev:packages & tsup --watch --onSuccess 'echo Build complete && npm link')",
|
||||||
"dev:packages": "(cd packages/tm-core && npm run dev) & (cd apps/cli && npm run dev) & wait",
|
"dev:packages": "(cd packages/tm-core && npm run dev) & (cd apps/cli && npm run dev) & wait",
|
||||||
"dev:core": "cd packages/tm-core && npm run dev",
|
"dev:core": "cd packages/tm-core && npm run dev",
|
||||||
"dev:cli": "cd apps/cli && npm run dev",
|
"dev:cli": "cd apps/cli && npm run dev",
|
||||||
|
|||||||
@@ -3,15 +3,13 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Core library for Task Master - TypeScript task management system",
|
"description": "Core library for Task Master - TypeScript task management system",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.cjs",
|
|
||||||
"module": "./dist/index.js",
|
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
|
"main": "./dist/index.js",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"development": "./src/index.ts",
|
"types": "./src/index.ts",
|
||||||
"types": "./dist/index.d.ts",
|
|
||||||
"import": "./dist/index.js",
|
"import": "./dist/index.js",
|
||||||
"require": "./dist/index.cjs"
|
"require": "./dist/index.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -196,14 +196,14 @@ export class ConfigManager {
|
|||||||
* Get the currently active tag
|
* Get the currently active tag
|
||||||
*/
|
*/
|
||||||
getActiveTag(): string {
|
getActiveTag(): string {
|
||||||
return this.stateManager.getActiveTag();
|
return this.stateManager.getCurrentTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the active tag
|
* Set the active tag
|
||||||
*/
|
*/
|
||||||
async setActiveTag(tag: string): Promise<void> {
|
async setActiveTag(tag: string): Promise<void> {
|
||||||
await this.stateManager.setActiveTag(tag);
|
await this.stateManager.setCurrentTag(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== Configuration Updates ====================
|
// ==================== Configuration Updates ====================
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { DEFAULT_CONFIG_VALUES } from '../../interfaces/configuration.interface.
|
|||||||
*/
|
*/
|
||||||
export interface RuntimeState {
|
export interface RuntimeState {
|
||||||
/** Currently active tag */
|
/** Currently active tag */
|
||||||
activeTag: string;
|
currentTag: string;
|
||||||
/** Last updated timestamp */
|
/** Last updated timestamp */
|
||||||
lastUpdated?: string;
|
lastUpdated?: string;
|
||||||
/** Additional metadata */
|
/** Additional metadata */
|
||||||
@@ -34,7 +34,7 @@ export class RuntimeStateManager {
|
|||||||
constructor(projectRoot: string) {
|
constructor(projectRoot: string) {
|
||||||
this.stateFilePath = path.join(projectRoot, '.taskmaster', 'state.json');
|
this.stateFilePath = path.join(projectRoot, '.taskmaster', 'state.json');
|
||||||
this.currentState = {
|
this.currentState = {
|
||||||
activeTag: DEFAULT_CONFIG_VALUES.TAGS.DEFAULT_TAG
|
currentTag: DEFAULT_CONFIG_VALUES.TAGS.DEFAULT_TAG
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,11 +44,21 @@ export class RuntimeStateManager {
|
|||||||
async loadState(): Promise<RuntimeState> {
|
async loadState(): Promise<RuntimeState> {
|
||||||
try {
|
try {
|
||||||
const stateData = await fs.readFile(this.stateFilePath, 'utf-8');
|
const stateData = await fs.readFile(this.stateFilePath, 'utf-8');
|
||||||
const state = JSON.parse(stateData);
|
const rawState = JSON.parse(stateData);
|
||||||
|
|
||||||
// Apply environment variable override for active tag
|
// Map legacy field names to current interface
|
||||||
|
const state: RuntimeState = {
|
||||||
|
currentTag:
|
||||||
|
rawState.currentTag ||
|
||||||
|
rawState.activeTag ||
|
||||||
|
DEFAULT_CONFIG_VALUES.TAGS.DEFAULT_TAG,
|
||||||
|
lastUpdated: rawState.lastUpdated,
|
||||||
|
metadata: rawState.metadata
|
||||||
|
};
|
||||||
|
|
||||||
|
// Apply environment variable override for current tag
|
||||||
if (process.env.TASKMASTER_TAG) {
|
if (process.env.TASKMASTER_TAG) {
|
||||||
state.activeTag = process.env.TASKMASTER_TAG;
|
state.currentTag = process.env.TASKMASTER_TAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.currentState = state;
|
this.currentState = state;
|
||||||
@@ -60,7 +70,7 @@ export class RuntimeStateManager {
|
|||||||
|
|
||||||
// Check environment variable
|
// Check environment variable
|
||||||
if (process.env.TASKMASTER_TAG) {
|
if (process.env.TASKMASTER_TAG) {
|
||||||
this.currentState.activeTag = process.env.TASKMASTER_TAG;
|
this.currentState.currentTag = process.env.TASKMASTER_TAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.currentState;
|
return this.currentState;
|
||||||
@@ -103,15 +113,15 @@ export class RuntimeStateManager {
|
|||||||
/**
|
/**
|
||||||
* Get the currently active tag
|
* Get the currently active tag
|
||||||
*/
|
*/
|
||||||
getActiveTag(): string {
|
getCurrentTag(): string {
|
||||||
return this.currentState.activeTag;
|
return this.currentState.currentTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the active tag
|
* Set the current tag
|
||||||
*/
|
*/
|
||||||
async setActiveTag(tag: string): Promise<void> {
|
async setCurrentTag(tag: string): Promise<void> {
|
||||||
this.currentState.activeTag = tag;
|
this.currentState.currentTag = tag;
|
||||||
await this.saveState();
|
await this.saveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +155,7 @@ export class RuntimeStateManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.currentState = {
|
this.currentState = {
|
||||||
activeTag: DEFAULT_CONFIG_VALUES.TAGS.DEFAULT_TAG
|
currentTag: DEFAULT_CONFIG_VALUES.TAGS.DEFAULT_TAG
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,11 +128,12 @@ export class FileStorage implements IStorage {
|
|||||||
await this.ensureDirectoryExists();
|
await this.ensureDirectoryExists();
|
||||||
|
|
||||||
// Normalize task IDs to strings (force string IDs everywhere)
|
// Normalize task IDs to strings (force string IDs everywhere)
|
||||||
const normalizedTasks = tasks.map(task => ({
|
const normalizedTasks = tasks.map((task) => ({
|
||||||
...task,
|
...task,
|
||||||
id: String(task.id), // Force ID to string
|
id: String(task.id), // Force ID to string
|
||||||
dependencies: task.dependencies?.map(dep => String(dep)) || [],
|
dependencies: task.dependencies?.map((dep) => String(dep)) || [],
|
||||||
subtasks: task.subtasks?.map(subtask => ({
|
subtasks:
|
||||||
|
task.subtasks?.map((subtask) => ({
|
||||||
...subtask,
|
...subtask,
|
||||||
id: String(subtask.id),
|
id: String(subtask.id),
|
||||||
parentId: String(subtask.parentId)
|
parentId: String(subtask.parentId)
|
||||||
@@ -157,7 +158,8 @@ export class FileStorage implements IStorage {
|
|||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
lastModified: new Date().toISOString(),
|
lastModified: new Date().toISOString(),
|
||||||
taskCount: normalizedTasks.length,
|
taskCount: normalizedTasks.length,
|
||||||
completedCount: normalizedTasks.filter((t) => t.status === 'done').length,
|
completedCount: normalizedTasks.filter((t) => t.status === 'done')
|
||||||
|
.length,
|
||||||
tags: [resolvedTag]
|
tags: [resolvedTag]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,7 +172,8 @@ export class FileStorage implements IStorage {
|
|||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
lastModified: new Date().toISOString(),
|
lastModified: new Date().toISOString(),
|
||||||
taskCount: normalizedTasks.length,
|
taskCount: normalizedTasks.length,
|
||||||
completedCount: normalizedTasks.filter((t) => t.status === 'done').length,
|
completedCount: normalizedTasks.filter((t) => t.status === 'done')
|
||||||
|
.length,
|
||||||
tags: tag ? [tag] : []
|
tags: tag ? [tag] : []
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -183,7 +186,8 @@ export class FileStorage implements IStorage {
|
|||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
lastModified: new Date().toISOString(),
|
lastModified: new Date().toISOString(),
|
||||||
taskCount: normalizedTasks.length,
|
taskCount: normalizedTasks.length,
|
||||||
completedCount: normalizedTasks.filter((t) => t.status === 'done').length,
|
completedCount: normalizedTasks.filter((t) => t.status === 'done')
|
||||||
|
.length,
|
||||||
tags: tag ? [tag] : []
|
tags: tag ? [tag] : []
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user