mirror of
https://github.com/eyaltoledano/claude-task-master.git
synced 2026-01-30 06:12:05 +00:00
Merge pull request #1483 from eyaltoledano/next (0.37.1)
Release 0.37.1
This commit is contained in:
19
.changeset/pre.json
Normal file
19
.changeset/pre.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"mode": "exit",
|
||||
"tag": "rc",
|
||||
"initialVersions": {
|
||||
"task-master-ai": "0.37.0",
|
||||
"@tm/cli": "",
|
||||
"docs": "0.0.12",
|
||||
"extension": "0.26.0",
|
||||
"@tm/mcp": "",
|
||||
"@tm/ai-sdk-provider-grok-cli": "",
|
||||
"@tm/build-config": "",
|
||||
"@tm/claude-code-plugin": "0.0.6",
|
||||
"@tm/bridge": "",
|
||||
"@tm/core": ""
|
||||
},
|
||||
"changesets": [
|
||||
"small-files-go"
|
||||
]
|
||||
}
|
||||
5
.changeset/small-files-go.md
Normal file
5
.changeset/small-files-go.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"task-master-ai": patch
|
||||
---
|
||||
|
||||
Increase page size of brief selection (interactive cli setup)
|
||||
@@ -1,5 +1,11 @@
|
||||
# task-master-ai
|
||||
|
||||
## 0.37.1-rc.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1478](https://github.com/eyaltoledano/claude-task-master/pull/1478) [`6ff330f`](https://github.com/eyaltoledano/claude-task-master/commit/6ff330f8c2bc6e534e0a883c770e8394d7ad5fa8) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Increase page size of brief selection (interactive cli setup)
|
||||
|
||||
## 0.37.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -45,6 +45,7 @@ export async function selectBriefInteractive(
|
||||
// Prompt for selection with search
|
||||
const selectedBrief = await search<(typeof briefs)[0] | null>({
|
||||
message: 'Search for a brief:',
|
||||
pageSize: 15,
|
||||
source: async (input) => {
|
||||
const searchTerm = input?.toLowerCase() || '';
|
||||
|
||||
|
||||
@@ -275,7 +275,7 @@
|
||||
"tailwindcss": "4.1.11",
|
||||
"typescript": "^5.9.2",
|
||||
"@tm/core": "*",
|
||||
"task-master-ai": "*"
|
||||
"task-master-ai": "0.37.1-rc.0"
|
||||
},
|
||||
"overrides": {
|
||||
"glob@<8": "^10.4.5",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "task-master-ai",
|
||||
"version": "0.37.0",
|
||||
"version": "0.37.1-rc.0",
|
||||
"description": "A task management system for ambitious AI-driven development that doesn't overwhelm and confuse Cursor.",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
*/
|
||||
|
||||
import { join } from 'node:path';
|
||||
import { findProjectRoot } from '@tm/core';
|
||||
import { AuthManager, findProjectRoot } from '@tm/core';
|
||||
import { setSuppressConfigWarnings } from './modules/config-manager.js';
|
||||
|
||||
import dotenv from 'dotenv';
|
||||
import { initializeSentry } from '../src/telemetry/sentry.js';
|
||||
|
||||
@@ -35,6 +37,19 @@ if (process.env.DEBUG === '1') {
|
||||
console.error('DEBUG - dev.js received args:', process.argv.slice(2));
|
||||
}
|
||||
|
||||
// Suppress config warnings if user is authenticated (API mode)
|
||||
// When authenticated, we don't need local config - everything is remote
|
||||
try {
|
||||
const authManager = AuthManager.getInstance();
|
||||
const hasValidSession = await authManager.hasValidSession();
|
||||
if (hasValidSession) {
|
||||
setSuppressConfigWarnings(true);
|
||||
}
|
||||
} catch {
|
||||
setSuppressConfigWarnings(false);
|
||||
// Auth check failed, continue without suppressing
|
||||
}
|
||||
|
||||
// Use dynamic import to ensure dotenv.config() runs before module-level code executes
|
||||
const { runCLI } = await import('./modules/commands.js');
|
||||
|
||||
|
||||
@@ -72,7 +72,8 @@ import {
|
||||
getDebugFlag,
|
||||
getDefaultNumTasks,
|
||||
isApiKeySet,
|
||||
isConfigFilePresent
|
||||
isConfigFilePresent,
|
||||
setSuppressConfigWarnings
|
||||
} from './config-manager.js';
|
||||
|
||||
import {
|
||||
@@ -161,13 +162,17 @@ function isConnectedToHamster() {
|
||||
}
|
||||
|
||||
// Fallback: Check if storage type is 'api' (user selected Hamster during init)
|
||||
// Suppress warnings during this check since we're detecting API mode
|
||||
setSuppressConfigWarnings(true);
|
||||
try {
|
||||
const config = getConfig();
|
||||
const config = getConfig(null, false, { storageType: 'api' });
|
||||
if (config?.storage?.type === 'api') {
|
||||
return true;
|
||||
}
|
||||
} catch {
|
||||
// Config check failed, continue
|
||||
} finally {
|
||||
setSuppressConfigWarnings(false);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -72,6 +72,23 @@ const DEFAULTS = {
|
||||
let loadedConfig = null;
|
||||
let loadedConfigRoot = null; // Track which root loaded the config
|
||||
|
||||
/**
|
||||
* Suppress config file warnings (useful during API mode detection)
|
||||
* Uses global object so it can be shared across modules without circular deps
|
||||
* @param {boolean} suppress - Whether to suppress warnings
|
||||
*/
|
||||
export function setSuppressConfigWarnings(suppress) {
|
||||
global._tmSuppressConfigWarnings = suppress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if config warnings are currently suppressed
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isConfigWarningSuppressed() {
|
||||
return global._tmSuppressConfigWarnings === true;
|
||||
}
|
||||
|
||||
// Custom Error for configuration issues
|
||||
class ConfigurationError extends Error {
|
||||
constructor(message) {
|
||||
@@ -80,9 +97,10 @@ class ConfigurationError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
function _loadAndValidateConfig(explicitRoot = null) {
|
||||
function _loadAndValidateConfig(explicitRoot = null, options = {}) {
|
||||
const defaults = DEFAULTS; // Use the defined defaults
|
||||
let rootToUse = explicitRoot;
|
||||
const { storageType } = options;
|
||||
let configSource = explicitRoot
|
||||
? `explicit root (${explicitRoot})`
|
||||
: 'defaults (no root provided yet)';
|
||||
@@ -114,7 +132,7 @@ function _loadAndValidateConfig(explicitRoot = null) {
|
||||
if (hasProjectMarkers) {
|
||||
// Only try to find config if we have project markers
|
||||
// This prevents the repeated warnings during init
|
||||
configPath = findConfigPath(null, { projectRoot: rootToUse });
|
||||
configPath = findConfigPath(null, { projectRoot: rootToUse, storageType });
|
||||
}
|
||||
|
||||
if (configPath) {
|
||||
@@ -203,29 +221,36 @@ function _loadAndValidateConfig(explicitRoot = null) {
|
||||
}
|
||||
} else {
|
||||
// Config file doesn't exist at the determined rootToUse.
|
||||
if (explicitRoot) {
|
||||
// Only warn if an explicit root was *expected*.
|
||||
console.warn(
|
||||
chalk.yellow(
|
||||
`Warning: Configuration file not found at provided project root (${explicitRoot}). Using default configuration. Run 'task-master models --setup' to configure.`
|
||||
)
|
||||
);
|
||||
} else {
|
||||
// Don't warn about missing config during initialization
|
||||
// Only warn if this looks like an existing project (has .taskmaster dir or legacy config marker)
|
||||
const hasTaskmasterDir = fs.existsSync(
|
||||
path.join(rootToUse, TASKMASTER_DIR)
|
||||
);
|
||||
const hasLegacyMarker = fs.existsSync(
|
||||
path.join(rootToUse, LEGACY_CONFIG_FILE)
|
||||
);
|
||||
// Skip warnings if:
|
||||
// 1. Global suppress flag is set (during API mode detection)
|
||||
// 2. storageType is explicitly 'api' (remote storage mode - no local config expected)
|
||||
const shouldWarn = !isConfigWarningSuppressed() && storageType !== 'api';
|
||||
|
||||
if (hasTaskmasterDir || hasLegacyMarker) {
|
||||
if (shouldWarn) {
|
||||
if (explicitRoot) {
|
||||
// Warn about explicit root not having config
|
||||
console.warn(
|
||||
chalk.yellow(
|
||||
`Warning: Configuration file not found at derived root (${rootToUse}). Using defaults.`
|
||||
`Warning: Configuration file not found at provided project root (${explicitRoot}). Using default configuration. Run 'task-master models --setup' to configure.`
|
||||
)
|
||||
);
|
||||
} else {
|
||||
// Don't warn about missing config during initialization
|
||||
// Only warn if this looks like an existing project (has .taskmaster dir or legacy config marker)
|
||||
const hasTaskmasterDir = fs.existsSync(
|
||||
path.join(rootToUse, TASKMASTER_DIR)
|
||||
);
|
||||
const hasLegacyMarker = fs.existsSync(
|
||||
path.join(rootToUse, LEGACY_CONFIG_FILE)
|
||||
);
|
||||
|
||||
if (hasTaskmasterDir || hasLegacyMarker) {
|
||||
console.warn(
|
||||
chalk.yellow(
|
||||
`Warning: Configuration file not found at derived root (${rootToUse}). Using defaults.`
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Keep config as defaults
|
||||
@@ -241,9 +266,11 @@ function _loadAndValidateConfig(explicitRoot = null) {
|
||||
* Handles MCP initialization context gracefully.
|
||||
* @param {string|null} explicitRoot - Optional explicit path to the project root.
|
||||
* @param {boolean} forceReload - Force reloading the config file.
|
||||
* @param {object} options - Optional configuration options.
|
||||
* @param {'api'|'file'|'auto'} [options.storageType] - Storage type to suppress warnings for API mode.
|
||||
* @returns {object} The loaded configuration object.
|
||||
*/
|
||||
function getConfig(explicitRoot = null, forceReload = false) {
|
||||
function getConfig(explicitRoot = null, forceReload = false, options = {}) {
|
||||
// Determine if a reload is necessary
|
||||
const needsLoad =
|
||||
!loadedConfig ||
|
||||
@@ -251,7 +278,7 @@ function getConfig(explicitRoot = null, forceReload = false) {
|
||||
(explicitRoot && explicitRoot !== loadedConfigRoot);
|
||||
|
||||
if (needsLoad) {
|
||||
const newConfig = _loadAndValidateConfig(explicitRoot); // _load handles null explicitRoot
|
||||
const newConfig = _loadAndValidateConfig(explicitRoot, options); // _load handles null explicitRoot
|
||||
|
||||
// Only update the global cache if loading was forced or if an explicit root
|
||||
// was provided (meaning we attempted to load a specific project's config).
|
||||
|
||||
@@ -4,8 +4,10 @@ import { createHash } from 'crypto';
|
||||
* Provides error tracking and AI operation monitoring
|
||||
*/
|
||||
import * as Sentry from '@sentry/node';
|
||||
import { getAnonymousTelemetryEnabled } from '../../scripts/modules/config-manager.js';
|
||||
import { resolveEnvVariable } from '../../scripts/modules/utils.js';
|
||||
import {
|
||||
getAnonymousTelemetryEnabled,
|
||||
setSuppressConfigWarnings
|
||||
} from '../../scripts/modules/config-manager.js';
|
||||
|
||||
let isInitialized = false;
|
||||
|
||||
@@ -41,6 +43,8 @@ export function initializeSentry(options = {}) {
|
||||
// Check if user has opted out of anonymous telemetry
|
||||
// This applies to local storage users only
|
||||
// Hamster users don't use local config (API storage), so this check doesn't affect them
|
||||
// Suppress config warnings during this check to avoid noisy output at startup
|
||||
setSuppressConfigWarnings(true);
|
||||
try {
|
||||
const telemetryEnabled = getAnonymousTelemetryEnabled(options.projectRoot);
|
||||
|
||||
@@ -54,6 +58,8 @@ export function initializeSentry(options = {}) {
|
||||
} catch (error) {
|
||||
// If there's an error checking telemetry preferences (e.g., config not available yet),
|
||||
// default to enabled. This ensures telemetry works during initialization.
|
||||
} finally {
|
||||
setSuppressConfigWarnings(false);
|
||||
}
|
||||
|
||||
// Use internal Sentry DSN for Task Master telemetry
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
TASKMASTER_TASKS_FILE
|
||||
} from '../constants/paths.js';
|
||||
import { getLoggerOrDefault } from './logger-utils.js';
|
||||
import { isConfigWarningSuppressed } from '../../scripts/modules/config-manager.js';
|
||||
|
||||
/**
|
||||
* Normalize project root to ensure it doesn't end with .taskmaster
|
||||
@@ -453,15 +454,22 @@ export function findConfigPath(explicitPath = null, args = null, log = null) {
|
||||
}
|
||||
|
||||
// Only warn once per command execution to prevent spam during init
|
||||
const warningKey = `config_warning_${projectRoot}`;
|
||||
// Skip warning if:
|
||||
// Global suppress flag is set (during API mode detection)
|
||||
const shouldSkipWarning =
|
||||
isConfigWarningSuppressed() || args?.storageType === 'api';
|
||||
|
||||
if (!global._tmConfigWarningsThisRun) {
|
||||
global._tmConfigWarningsThisRun = new Set();
|
||||
}
|
||||
if (!shouldSkipWarning) {
|
||||
const warningKey = `config_warning_${projectRoot}`;
|
||||
|
||||
if (!global._tmConfigWarningsThisRun.has(warningKey)) {
|
||||
global._tmConfigWarningsThisRun.add(warningKey);
|
||||
logger.warn?.(`No configuration file found in project: ${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;
|
||||
|
||||
@@ -63,7 +63,9 @@ jest.unstable_mockModule('../../../scripts/modules/config-manager.js', () => ({
|
||||
getDebugFlag: jest.fn(() => false),
|
||||
getLogLevel: jest.fn(() => 'info'),
|
||||
isProxyEnabled: jest.fn(() => false),
|
||||
getAnonymousTelemetryEnabled: jest.fn(() => true)
|
||||
getAnonymousTelemetryEnabled: jest.fn(() => true),
|
||||
setSuppressConfigWarnings: jest.fn(),
|
||||
isConfigWarningSuppressed: jest.fn(() => false)
|
||||
}));
|
||||
|
||||
// Mock utils
|
||||
|
||||
@@ -38,7 +38,9 @@ jest.unstable_mockModule('../../../scripts/modules/utils.js', () => ({
|
||||
|
||||
jest.unstable_mockModule('../../../scripts/modules/config-manager.js', () => ({
|
||||
isProxyEnabled: jest.fn(() => false),
|
||||
getAnonymousTelemetryEnabled: jest.fn(() => true)
|
||||
getAnonymousTelemetryEnabled: jest.fn(() => true),
|
||||
setSuppressConfigWarnings: jest.fn(),
|
||||
isConfigWarningSuppressed: jest.fn(() => false)
|
||||
}));
|
||||
|
||||
// Import after mocking
|
||||
|
||||
@@ -17,7 +17,9 @@ jest.unstable_mockModule('../../../scripts/modules/utils.js', () => ({
|
||||
|
||||
jest.unstable_mockModule('../../../scripts/modules/config-manager.js', () => ({
|
||||
isProxyEnabled: jest.fn(() => false),
|
||||
getAnonymousTelemetryEnabled: jest.fn(() => true)
|
||||
getAnonymousTelemetryEnabled: jest.fn(() => true),
|
||||
setSuppressConfigWarnings: jest.fn(),
|
||||
isConfigWarningSuppressed: jest.fn(() => false)
|
||||
}));
|
||||
|
||||
// Import after mocking
|
||||
|
||||
@@ -189,7 +189,9 @@ jest.unstable_mockModule(
|
||||
getAllProviders: jest.fn(() => ['anthropic', 'openai', 'perplexity']),
|
||||
getVertexProjectId: jest.fn(() => undefined),
|
||||
getVertexLocation: jest.fn(() => undefined),
|
||||
hasCodebaseAnalysis: jest.fn(() => false)
|
||||
hasCodebaseAnalysis: jest.fn(() => false),
|
||||
setSuppressConfigWarnings: jest.fn(),
|
||||
isConfigWarningSuppressed: jest.fn(() => false)
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user