feat: enhance error display in new commands
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
|||||||
} from '@tm/core';
|
} from '@tm/core';
|
||||||
import type { StorageType } from '@tm/core/types';
|
import type { StorageType } from '@tm/core/types';
|
||||||
import * as ui from '../utils/ui.js';
|
import * as ui from '../utils/ui.js';
|
||||||
|
import { displayError } from '../utils/error-handler.js';
|
||||||
import {
|
import {
|
||||||
displayHeader,
|
displayHeader,
|
||||||
displayDashboards,
|
displayDashboards,
|
||||||
@@ -106,14 +107,7 @@ export class ListTasksCommand extends Command {
|
|||||||
this.displayResults(result, options);
|
this.displayResults(result, options);
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
const msg = error?.getSanitizedDetails?.() ?? {
|
displayError(error);
|
||||||
message: error?.message ?? String(error)
|
|
||||||
};
|
|
||||||
console.error(chalk.red(`Error: ${msg.message || 'Unexpected error'}`));
|
|
||||||
if (error.stack && process.env.DEBUG) {
|
|
||||||
console.error(chalk.gray(error.stack));
|
|
||||||
}
|
|
||||||
process.exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import chalk from 'chalk';
|
|||||||
import boxen from 'boxen';
|
import boxen from 'boxen';
|
||||||
import { createTaskMasterCore, type Task, type TaskMasterCore } from '@tm/core';
|
import { createTaskMasterCore, type Task, type TaskMasterCore } from '@tm/core';
|
||||||
import type { StorageType } from '@tm/core/types';
|
import type { StorageType } from '@tm/core/types';
|
||||||
|
import { displayError } from '../utils/error-handler.js';
|
||||||
import { displayTaskDetails } from '../ui/components/task-detail.component.js';
|
import { displayTaskDetails } from '../ui/components/task-detail.component.js';
|
||||||
import { displayHeader } from '../ui/index.js';
|
import { displayHeader } from '../ui/index.js';
|
||||||
|
|
||||||
@@ -76,12 +77,7 @@ export class NextCommand extends Command {
|
|||||||
this.displayResults(result, options);
|
this.displayResults(result, options);
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
const msg = error?.getSanitizedDetails?.() ?? {
|
displayError(error);
|
||||||
message: error?.message ?? String(error)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Allow error to propagate for library compatibility
|
|
||||||
throw new Error(msg.message || 'Unexpected error in next command');
|
|
||||||
} finally {
|
} finally {
|
||||||
// Always clean up resources, even on error
|
// Always clean up resources, even on error
|
||||||
await this.cleanup();
|
await this.cleanup();
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
type TaskStatus
|
type TaskStatus
|
||||||
} from '@tm/core';
|
} from '@tm/core';
|
||||||
import type { StorageType } from '@tm/core/types';
|
import type { StorageType } from '@tm/core/types';
|
||||||
|
import { displayError } from '../utils/error-handler.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Valid task status values for validation
|
* Valid task status values for validation
|
||||||
@@ -135,16 +136,14 @@ export class SetStatusCommand extends Command {
|
|||||||
oldStatus: result.oldStatus,
|
oldStatus: result.oldStatus,
|
||||||
newStatus: result.newStatus
|
newStatus: result.newStatus
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
const errorMessage =
|
|
||||||
error instanceof Error ? error.message : String(error);
|
|
||||||
|
|
||||||
if (!options.silent) {
|
|
||||||
console.error(
|
|
||||||
chalk.red(`Failed to update task ${taskId}: ${errorMessage}`)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (options.format === 'json') {
|
if (options.format === 'json') {
|
||||||
|
const errorMessage = error?.getSanitizedDetails
|
||||||
|
? error.getSanitizedDetails().message
|
||||||
|
: error instanceof Error
|
||||||
|
? error.message
|
||||||
|
: String(error);
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
success: false,
|
success: false,
|
||||||
@@ -153,8 +152,14 @@ export class SetStatusCommand extends Command {
|
|||||||
timestamp: new Date().toISOString()
|
timestamp: new Date().toISOString()
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
} else if (!options.silent) {
|
||||||
|
// Show which task failed with context
|
||||||
|
console.error(chalk.red(`\nFailed to update task ${taskId}:`));
|
||||||
|
displayError(error);
|
||||||
|
} else {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,19 +175,17 @@ export class SetStatusCommand extends Command {
|
|||||||
|
|
||||||
// Display results
|
// Display results
|
||||||
this.displayResults(this.lastResult, options);
|
this.displayResults(this.lastResult, options);
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
|
if (options.format === 'json') {
|
||||||
const errorMessage =
|
const errorMessage =
|
||||||
error instanceof Error ? error.message : 'Unknown error occurred';
|
error instanceof Error ? error.message : 'Unknown error occurred';
|
||||||
|
|
||||||
if (!options.silent) {
|
|
||||||
console.error(chalk.red(`Error: ${errorMessage}`));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.format === 'json') {
|
|
||||||
console.log(JSON.stringify({ success: false, error: errorMessage }));
|
console.log(JSON.stringify({ success: false, error: errorMessage }));
|
||||||
}
|
|
||||||
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
} else if (!options.silent) {
|
||||||
|
displayError(error);
|
||||||
|
} else {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// Clean up resources
|
// Clean up resources
|
||||||
if (this.tmCore) {
|
if (this.tmCore) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import boxen from 'boxen';
|
|||||||
import { createTaskMasterCore, type Task, type TaskMasterCore } from '@tm/core';
|
import { createTaskMasterCore, type Task, type TaskMasterCore } from '@tm/core';
|
||||||
import type { StorageType } from '@tm/core/types';
|
import type { StorageType } from '@tm/core/types';
|
||||||
import * as ui from '../utils/ui.js';
|
import * as ui from '../utils/ui.js';
|
||||||
|
import { displayError } from '../utils/error-handler.js';
|
||||||
import { displayTaskDetails } from '../ui/components/task-detail.component.js';
|
import { displayTaskDetails } from '../ui/components/task-detail.component.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -112,14 +113,7 @@ export class ShowCommand extends Command {
|
|||||||
this.displayResults(result, options);
|
this.displayResults(result, options);
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
const msg = error?.getSanitizedDetails?.() ?? {
|
displayError(error);
|
||||||
message: error?.message ?? String(error)
|
|
||||||
};
|
|
||||||
console.error(chalk.red(`Error: ${msg.message || 'Unexpected error'}`));
|
|
||||||
if (error.stack && process.env.DEBUG) {
|
|
||||||
console.error(chalk.gray(error.stack));
|
|
||||||
}
|
|
||||||
process.exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
} from '@tm/core';
|
} from '@tm/core';
|
||||||
import { displayTaskDetails } from '../ui/components/task-detail.component.js';
|
import { displayTaskDetails } from '../ui/components/task-detail.component.js';
|
||||||
import * as ui from '../utils/ui.js';
|
import * as ui from '../utils/ui.js';
|
||||||
|
import { displayError } from '../utils/error-handler.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CLI-specific options interface for the start command
|
* CLI-specific options interface for the start command
|
||||||
@@ -160,8 +161,7 @@ export class StartCommand extends Command {
|
|||||||
if (spinner) {
|
if (spinner) {
|
||||||
spinner.fail('Operation failed');
|
spinner.fail('Operation failed');
|
||||||
}
|
}
|
||||||
this.handleError(error);
|
displayError(error);
|
||||||
process.exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,22 +452,6 @@ export class StartCommand extends Command {
|
|||||||
console.log(`\n${chalk.gray('Storage: ' + result.storageType)}`);
|
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
|
* Set the last result for programmatic access
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ export {
|
|||||||
// UI utilities (for other commands to use)
|
// UI utilities (for other commands to use)
|
||||||
export * as ui from './utils/ui.js';
|
export * as ui from './utils/ui.js';
|
||||||
|
|
||||||
|
// Error handling utilities
|
||||||
|
export { displayError, isDebugMode } from './utils/error-handler.js';
|
||||||
|
|
||||||
// Auto-update utilities
|
// Auto-update utilities
|
||||||
export {
|
export {
|
||||||
checkForUpdate,
|
checkForUpdate,
|
||||||
|
|||||||
60
apps/cli/src/utils/error-handler.ts
Normal file
60
apps/cli/src/utils/error-handler.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Centralized error handling utilities for CLI
|
||||||
|
* Provides consistent error formatting and debug mode detection
|
||||||
|
*/
|
||||||
|
|
||||||
|
import chalk from 'chalk';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if debug mode is enabled via environment variable
|
||||||
|
* Only returns true when DEBUG is explicitly set to 'true' or '1'
|
||||||
|
*
|
||||||
|
* @returns True if debug mode is enabled
|
||||||
|
*/
|
||||||
|
export function isDebugMode(): boolean {
|
||||||
|
return process.env.DEBUG === 'true' || process.env.DEBUG === '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display an error to the user with optional stack trace in debug mode
|
||||||
|
* Handles both TaskMasterError instances and regular errors
|
||||||
|
*
|
||||||
|
* @param error - The error to display
|
||||||
|
* @param options - Display options
|
||||||
|
*/
|
||||||
|
export function displayError(
|
||||||
|
error: any,
|
||||||
|
options: {
|
||||||
|
/** Skip exit, useful when caller wants to handle exit */
|
||||||
|
skipExit?: boolean;
|
||||||
|
/** Force show stack trace regardless of debug mode */
|
||||||
|
forceStack?: boolean;
|
||||||
|
} = {}
|
||||||
|
): void {
|
||||||
|
// Check if it's a TaskMasterError with sanitized details
|
||||||
|
if (error?.getSanitizedDetails) {
|
||||||
|
const sanitized = error.getSanitizedDetails();
|
||||||
|
console.error(chalk.red(`\n${sanitized.message}`));
|
||||||
|
|
||||||
|
// Show stack trace in debug mode or if forced
|
||||||
|
if ((isDebugMode() || options.forceStack) && error.stack) {
|
||||||
|
console.error(chalk.gray('\nStack trace:'));
|
||||||
|
console.error(chalk.gray(error.stack));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For other errors, show the message
|
||||||
|
const message = error?.message ?? String(error);
|
||||||
|
console.error(chalk.red(`\nError: ${message}`));
|
||||||
|
|
||||||
|
// Show stack trace in debug mode or if forced
|
||||||
|
if ((isDebugMode() || options.forceStack) && error?.stack) {
|
||||||
|
console.error(chalk.gray('\nStack trace:'));
|
||||||
|
console.error(chalk.gray(error.stack));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit if not skipped
|
||||||
|
if (!options.skipExit) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,7 +52,10 @@ export const ERROR_CODES = {
|
|||||||
INVALID_INPUT: 'INVALID_INPUT',
|
INVALID_INPUT: 'INVALID_INPUT',
|
||||||
NOT_IMPLEMENTED: 'NOT_IMPLEMENTED',
|
NOT_IMPLEMENTED: 'NOT_IMPLEMENTED',
|
||||||
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
|
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
|
||||||
NOT_FOUND: 'NOT_FOUND'
|
NOT_FOUND: 'NOT_FOUND',
|
||||||
|
|
||||||
|
// Context errors
|
||||||
|
NO_BRIEF_SELECTED: 'NO_BRIEF_SELECTED'
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];
|
export type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];
|
||||||
|
|||||||
@@ -161,6 +161,13 @@ export class TaskService {
|
|||||||
storageType: this.getStorageType()
|
storageType: this.getStorageType()
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// If it's a user-facing error (like NO_BRIEF_SELECTED), don't log it as an internal error
|
||||||
|
if (error instanceof TaskMasterError && error.is(ERROR_CODES.NO_BRIEF_SELECTED)) {
|
||||||
|
// Just re-throw user-facing errors without wrapping
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log internal errors
|
||||||
this.logger.error('Failed to get task list', error);
|
this.logger.error('Failed to get task list', error);
|
||||||
throw new TaskMasterError(
|
throw new TaskMasterError(
|
||||||
'Failed to get task list',
|
'Failed to get task list',
|
||||||
@@ -186,6 +193,11 @@ export class TaskService {
|
|||||||
// Delegate to storage layer which handles the specific logic for tasks vs subtasks
|
// Delegate to storage layer which handles the specific logic for tasks vs subtasks
|
||||||
return await this.storage.loadTask(String(taskId), activeTag);
|
return await this.storage.loadTask(String(taskId), activeTag);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// If it's a user-facing error (like NO_BRIEF_SELECTED), don't wrap it
|
||||||
|
if (error instanceof TaskMasterError && error.is(ERROR_CODES.NO_BRIEF_SELECTED)) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
throw new TaskMasterError(
|
throw new TaskMasterError(
|
||||||
`Failed to get task ${taskId}`,
|
`Failed to get task ${taskId}`,
|
||||||
ERROR_CODES.STORAGE_ERROR,
|
ERROR_CODES.STORAGE_ERROR,
|
||||||
@@ -522,6 +534,11 @@ export class TaskService {
|
|||||||
activeTag
|
activeTag
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// If it's a user-facing error (like NO_BRIEF_SELECTED), don't wrap it
|
||||||
|
if (error instanceof TaskMasterError && error.is(ERROR_CODES.NO_BRIEF_SELECTED)) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
throw new TaskMasterError(
|
throw new TaskMasterError(
|
||||||
`Failed to update task status for ${taskIdStr}`,
|
`Failed to update task status for ${taskIdStr}`,
|
||||||
ERROR_CODES.STORAGE_ERROR,
|
ERROR_CODES.STORAGE_ERROR,
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ export class ApiStorage implements IStorage {
|
|||||||
private async loadTagsIntoCache(): Promise<void> {
|
private async loadTagsIntoCache(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const authManager = AuthManager.getInstance();
|
const authManager = AuthManager.getInstance();
|
||||||
const context = await authManager.getContext();
|
const context = authManager.getContext();
|
||||||
|
|
||||||
// If we have a selected brief, create a virtual "tag" for it
|
// If we have a selected brief, create a virtual "tag" for it
|
||||||
if (context?.briefId) {
|
if (context?.briefId) {
|
||||||
@@ -159,12 +159,18 @@ export class ApiStorage implements IStorage {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const authManager = AuthManager.getInstance();
|
const authManager = AuthManager.getInstance();
|
||||||
const context = await authManager.getContext();
|
const context = authManager.getContext();
|
||||||
|
|
||||||
// If no brief is selected in context, throw an error
|
// If no brief is selected in context, throw an error
|
||||||
if (!context?.briefId) {
|
if (!context?.briefId) {
|
||||||
throw new Error(
|
throw new TaskMasterError(
|
||||||
'No brief selected. Please select a brief first using: tm context brief <brief-id>'
|
'No brief selected',
|
||||||
|
ERROR_CODES.NO_BRIEF_SELECTED,
|
||||||
|
{
|
||||||
|
operation: 'loadTasks',
|
||||||
|
userMessage:
|
||||||
|
'No brief selected. Please select a brief first using: tm context brief <brief-id> or tm context brief <brief-url>'
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,6 +187,14 @@ export class ApiStorage implements IStorage {
|
|||||||
|
|
||||||
return tasks;
|
return tasks;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// If it's already a NO_BRIEF_SELECTED error, don't wrap it
|
||||||
|
if (
|
||||||
|
error instanceof TaskMasterError &&
|
||||||
|
error.is(ERROR_CODES.NO_BRIEF_SELECTED)
|
||||||
|
) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
throw new TaskMasterError(
|
throw new TaskMasterError(
|
||||||
'Failed to load tasks from API',
|
'Failed to load tasks from API',
|
||||||
ERROR_CODES.STORAGE_ERROR,
|
ERROR_CODES.STORAGE_ERROR,
|
||||||
@@ -237,10 +251,34 @@ export class ApiStorage implements IStorage {
|
|||||||
await this.ensureInitialized();
|
await this.ensureInitialized();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const authManager = AuthManager.getInstance();
|
||||||
|
const context = authManager.getContext();
|
||||||
|
|
||||||
|
// If no brief is selected in context, throw an error
|
||||||
|
if (!context?.briefId) {
|
||||||
|
throw new TaskMasterError(
|
||||||
|
'No brief selected',
|
||||||
|
ERROR_CODES.NO_BRIEF_SELECTED,
|
||||||
|
{
|
||||||
|
operation: 'loadTask',
|
||||||
|
userMessage:
|
||||||
|
'No brief selected. Please select a brief first using: tm context brief <brief-id> or tm context brief <brief-url>'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return await this.retryOperation(() =>
|
return await this.retryOperation(() =>
|
||||||
this.repository.getTask(this.projectId, taskId)
|
this.repository.getTask(this.projectId, taskId)
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// If it's already a NO_BRIEF_SELECTED error, don't wrap it
|
||||||
|
if (
|
||||||
|
error instanceof TaskMasterError &&
|
||||||
|
error.is(ERROR_CODES.NO_BRIEF_SELECTED)
|
||||||
|
) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
throw new TaskMasterError(
|
throw new TaskMasterError(
|
||||||
'Failed to load task from API',
|
'Failed to load task from API',
|
||||||
ERROR_CODES.STORAGE_ERROR,
|
ERROR_CODES.STORAGE_ERROR,
|
||||||
@@ -325,7 +363,7 @@ export class ApiStorage implements IStorage {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const authManager = AuthManager.getInstance();
|
const authManager = AuthManager.getInstance();
|
||||||
const context = await authManager.getContext();
|
const context = authManager.getContext();
|
||||||
|
|
||||||
// In our API-based system, we only have one "tag" at a time - the current brief
|
// In our API-based system, we only have one "tag" at a time - the current brief
|
||||||
if (context?.briefId) {
|
if (context?.briefId) {
|
||||||
@@ -510,6 +548,22 @@ export class ApiStorage implements IStorage {
|
|||||||
await this.ensureInitialized();
|
await this.ensureInitialized();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const authManager = AuthManager.getInstance();
|
||||||
|
const context = authManager.getContext();
|
||||||
|
|
||||||
|
// If no brief is selected in context, throw an error
|
||||||
|
if (!context?.briefId) {
|
||||||
|
throw new TaskMasterError(
|
||||||
|
'No brief selected',
|
||||||
|
ERROR_CODES.NO_BRIEF_SELECTED,
|
||||||
|
{
|
||||||
|
operation: 'updateTaskStatus',
|
||||||
|
userMessage:
|
||||||
|
'No brief selected. Please select a brief first using: tm context brief <brief-id> or tm context brief <brief-url>'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const existingTask = await this.retryOperation(() =>
|
const existingTask = await this.retryOperation(() =>
|
||||||
this.repository.getTask(this.projectId, taskId)
|
this.repository.getTask(this.projectId, taskId)
|
||||||
);
|
);
|
||||||
@@ -546,6 +600,14 @@ export class ApiStorage implements IStorage {
|
|||||||
taskId
|
taskId
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// If it's already a NO_BRIEF_SELECTED error, don't wrap it
|
||||||
|
if (
|
||||||
|
error instanceof TaskMasterError &&
|
||||||
|
error.is(ERROR_CODES.NO_BRIEF_SELECTED)
|
||||||
|
) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
throw new TaskMasterError(
|
throw new TaskMasterError(
|
||||||
'Failed to update task status via API',
|
'Failed to update task status via API',
|
||||||
ERROR_CODES.STORAGE_ERROR,
|
ERROR_CODES.STORAGE_ERROR,
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ import {
|
|||||||
registerAllCommands,
|
registerAllCommands,
|
||||||
checkForUpdate,
|
checkForUpdate,
|
||||||
performAutoUpdate,
|
performAutoUpdate,
|
||||||
displayUpgradeNotification
|
displayUpgradeNotification,
|
||||||
|
displayError
|
||||||
} from '@tm/cli';
|
} from '@tm/cli';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -5156,10 +5157,7 @@ async function runCLI(argv = process.argv) {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Generic error handling for other errors
|
// Generic error handling for other errors
|
||||||
console.error(chalk.red(`Error: ${error.message}`));
|
displayError(error);
|
||||||
if (getDebugFlag()) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|||||||
Reference in New Issue
Block a user