Skip to content

Commit a4bde62

Browse files
Crunchyman-ralpheyaltoledanogithub-actions[bot]
authored
Release 0.40.0 (#1539)
Co-authored-by: Ralph Khreish <35776126+Crunchyman-ralph@users.noreply.github.com> Co-authored-by: Eyal Toledano <eyal@microangel.so> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2 parents f978cb8 + 74f9c2e commit a4bde62

38 files changed

Lines changed: 1537 additions & 173 deletions

.changeset/floppy-books-feel.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"task-master-ai": patch
3+
---
4+
5+
Improved model search in `task-master models --setup` to match both display names and model IDs

.changeset/frank-ears-remain.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"task-master-ai": minor
3+
---
4+
5+
Added Gemini 3 Flash Preview model support for Google and Gemini CLI providers

.changeset/gold-tigers-tap.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"task-master-ai": minor
3+
---
4+
5+
Add auto-detection for IDE profiles in rules command
6+
7+
- `tm rules add` now opens interactive setup with detected IDEs pre-selected
8+
- `tm rules add -y` auto-detects and installs rules without prompting
9+
- Detects 13 IDEs: Cursor, Claude Code, Windsurf, VS Code, Roo, Cline, Kiro, Zed, Kilo, Trae, Gemini, OpenCode, Codex

.changeset/list-watch-compact.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
"task-master-ai": minor
3+
---
4+
5+
Add watch mode and compact output to list command
6+
7+
- Add `-w/--watch` flag to continuously monitor task changes with real-time updates
8+
- Add `-c/--compact` flag for minimal task output format
9+
- Add `--no-header` flag to hide the command header
10+
- Support file-based watching via fs.watch for local tasks.json
11+
- Support API-based watching via Supabase Realtime for authenticated users
12+
- Display last sync timestamp and source in watch mode

.changeset/pre.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"mode": "exit",
3+
"tag": "rc",
4+
"initialVersions": {
5+
"task-master-ai": "0.39.0",
6+
"@tm/cli": "",
7+
"docs": "0.0.15",
8+
"extension": "0.26.0",
9+
"@tm/mcp": "",
10+
"@tm/ai-sdk-provider-grok-cli": "",
11+
"@tm/build-config": "",
12+
"@tm/claude-code-plugin": "0.0.9",
13+
"@tm/bridge": "",
14+
"@tm/core": "",
15+
"@tm/profiles": ""
16+
},
17+
"changesets": [
18+
"floppy-books-feel",
19+
"frank-ears-remain",
20+
"gold-tigers-tap",
21+
"list-watch-compact"
22+
]
23+
}

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,28 @@
11
# task-master-ai
22

3+
## 0.40.0-rc.0
4+
5+
### Minor Changes
6+
7+
- [#1538](https://github.com/eyaltoledano/claude-task-master/pull/1538) [`a2d5639`](https://github.com/eyaltoledano/claude-task-master/commit/a2d563991dd8ad6b8a9b76d0d43eac7a6156dd97) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Added Gemini 3 Flash Preview model support for Google and Gemini CLI providers
8+
9+
- [#1535](https://github.com/eyaltoledano/claude-task-master/pull/1535) [`4d1ed20`](https://github.com/eyaltoledano/claude-task-master/commit/4d1ed20345083ab2ec1c7fc268c69379281a68ea) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add auto-detection for IDE profiles in rules command
10+
- `tm rules add` now opens interactive setup with detected IDEs pre-selected
11+
- `tm rules add -y` auto-detects and installs rules without prompting
12+
- Detects 13 IDEs: Cursor, Claude Code, Windsurf, VS Code, Roo, Cline, Kiro, Zed, Kilo, Trae, Gemini, OpenCode, Codex
13+
14+
- [#1526](https://github.com/eyaltoledano/claude-task-master/pull/1526) [`38c2c08`](https://github.com/eyaltoledano/claude-task-master/commit/38c2c08af1f8de729d5d2dab586ec4622445f2db) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add watch mode and compact output to list command
15+
- Add `-w/--watch` flag to continuously monitor task changes with real-time updates
16+
- Add `-c/--compact` flag for minimal task output format
17+
- Add `--no-header` flag to hide the command header
18+
- Support file-based watching via fs.watch for local tasks.json
19+
- Support API-based watching via Supabase Realtime for authenticated users
20+
- Display last sync timestamp and source in watch mode
21+
22+
### Patch Changes
23+
24+
- [#1538](https://github.com/eyaltoledano/claude-task-master/pull/1538) [`a2d5639`](https://github.com/eyaltoledano/claude-task-master/commit/a2d563991dd8ad6b8a9b76d0d43eac7a6156dd97) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improved model search in `task-master models --setup` to match both display names and model IDs
25+
326
## 0.39.0
427

528
### Minor Changes

apps/cli/src/commands/list.command.ts

Lines changed: 118 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
type Task,
1212
type TaskStatus,
1313
type TmCore,
14+
type WatchSubscription,
1415
createTmCore
1516
} from '@tm/core';
1617
import type { StorageType } from '@tm/core';
@@ -24,6 +25,8 @@ import {
2425
displayDashboards,
2526
displayRecommendedNextTask,
2627
displaySuggestedNextSteps,
28+
displaySyncMessage,
29+
displayWatchFooter,
2730
getPriorityBreakdown,
2831
getTaskDescription
2932
} from '../ui/index.js';
@@ -42,8 +45,11 @@ export interface ListCommandOptions {
4245
withSubtasks?: boolean;
4346
format?: OutputFormat;
4447
json?: boolean;
48+
compact?: boolean;
49+
noHeader?: boolean;
4550
silent?: boolean;
4651
project?: string;
52+
watch?: boolean;
4753
}
4854

4955
/**
@@ -87,11 +93,17 @@ export class ListTasksCommand extends Command {
8793
'text'
8894
)
8995
.option('--json', 'Output in JSON format (shorthand for --format json)')
96+
.option(
97+
'-c, --compact',
98+
'Output in compact format (shorthand for --format compact)'
99+
)
100+
.option('--no-header', 'Hide the command header')
90101
.option('--silent', 'Suppress output (useful for programmatic usage)')
91102
.option(
92103
'-p, --project <path>',
93104
'Project root directory (auto-detected if not provided)'
94105
)
106+
.option('-w, --watch', 'Watch for changes and update list automatically')
95107
.action(async (statusArg?: string, options?: ListCommandOptions) => {
96108
// Handle special "all" keyword to show with subtasks
97109
let status = statusArg || options?.status;
@@ -127,20 +139,88 @@ export class ListTasksCommand extends Command {
127139
await this.initializeCore(getProjectRoot(options.project));
128140

129141
// Get tasks from core
130-
const result = await this.getTasks(options);
142+
if (options.watch) {
143+
await this.watchTasks(options);
144+
} else {
145+
const result = await this.getTasks(options);
131146

132-
// Store result for programmatic access
133-
this.setLastResult(result);
147+
// Store result for programmatic access
148+
this.setLastResult(result);
134149

135-
// Display results
136-
if (!options.silent) {
137-
this.displayResults(result, options);
150+
// Display results
151+
if (!options.silent) {
152+
this.displayResults(result, options);
153+
}
138154
}
139155
} catch (error: any) {
140156
displayError(error);
141157
}
142158
}
143159

160+
/**
161+
* Watch for changes and update list
162+
* Uses tm-core's unified watch API which handles both file and API storage
163+
*/
164+
private async watchTasks(options: ListCommandOptions): Promise<void> {
165+
if (!this.tmCore) {
166+
throw new Error('TmCore not initialized');
167+
}
168+
169+
// Initial render
170+
let result = await this.getTasks(options);
171+
let lastSync = new Date();
172+
173+
console.clear();
174+
this.displayResults(result, options);
175+
176+
const storageType = result.storageType;
177+
displayWatchFooter(storageType, lastSync);
178+
179+
let subscription: WatchSubscription | undefined;
180+
181+
try {
182+
// Subscribe to task changes via tm-core
183+
subscription = await this.tmCore.tasks.watch(
184+
async (event) => {
185+
if (event.type === 'change') {
186+
try {
187+
// Re-fetch tasks
188+
result = await this.getTasks(options);
189+
lastSync = new Date();
190+
191+
// Clear and display
192+
console.clear();
193+
this.displayResults(result, options);
194+
195+
// Show sync message with timestamp
196+
displaySyncMessage(storageType, lastSync);
197+
displayWatchFooter(storageType, lastSync);
198+
} catch {
199+
// Ignore errors during watch (e.g. partial writes)
200+
}
201+
} else if (event.type === 'error' && event.error) {
202+
console.error(chalk.red(`\n⚠ Watch error: ${event.error.message}`));
203+
}
204+
},
205+
{ tag: options.tag }
206+
);
207+
208+
// Cleanup on process termination
209+
const cleanup = () => {
210+
subscription?.unsubscribe();
211+
process.exit(0);
212+
};
213+
process.on('SIGINT', cleanup);
214+
process.on('SIGTERM', cleanup);
215+
216+
// Keep process alive
217+
await new Promise(() => {});
218+
} catch (error: any) {
219+
console.error(chalk.red(`Watch mode error: ${error.message}`));
220+
throw error;
221+
}
222+
}
223+
144224
/**
145225
* Validate command options
146226
*/
@@ -219,9 +299,13 @@ export class ListTasksCommand extends Command {
219299
result: ListTasksResult,
220300
options: ListCommandOptions
221301
): void {
222-
// If --json flag is set, override format to 'json'
302+
// Resolve format: --json and --compact flags override --format option
223303
const format = (
224-
options.json ? 'json' : options.format || 'text'
304+
options.json
305+
? 'json'
306+
: options.compact
307+
? 'compact'
308+
: options.format || 'text'
225309
) as OutputFormat;
226310

227311
switch (format) {
@@ -230,12 +314,12 @@ export class ListTasksCommand extends Command {
230314
break;
231315

232316
case 'compact':
233-
this.displayCompact(result.tasks, options.withSubtasks);
317+
this.displayCompact(result, options);
234318
break;
235319

236320
case 'text':
237321
default:
238-
this.displayText(result, options.withSubtasks, options.status);
322+
this.displayText(result, options);
239323
break;
240324
}
241325
}
@@ -264,12 +348,25 @@ export class ListTasksCommand extends Command {
264348
/**
265349
* Display in compact format
266350
*/
267-
private displayCompact(tasks: Task[], withSubtasks?: boolean): void {
351+
private displayCompact(
352+
data: ListTasksResult,
353+
options: ListCommandOptions
354+
): void {
355+
const { tasks, tag, storageType } = data;
356+
357+
// Display header unless --no-header is set
358+
if (options.noHeader !== true) {
359+
displayCommandHeader(this.tmCore, {
360+
tag: tag || 'master',
361+
storageType
362+
});
363+
}
364+
268365
tasks.forEach((task) => {
269366
const icon = STATUS_ICONS[task.status];
270367
console.log(`${chalk.cyan(task.id)} ${icon} ${task.title}`);
271368

272-
if (withSubtasks && task.subtasks?.length) {
369+
if (options.withSubtasks && task.subtasks?.length) {
273370
task.subtasks.forEach((subtask) => {
274371
const subIcon = STATUS_ICONS[subtask.status];
275372
console.log(
@@ -285,16 +382,17 @@ export class ListTasksCommand extends Command {
285382
*/
286383
private displayText(
287384
data: ListTasksResult,
288-
withSubtasks?: boolean,
289-
_statusFilter?: string
385+
options: ListCommandOptions
290386
): void {
291387
const { tasks, tag, storageType } = data;
292388

293-
// Display header using utility function
294-
displayCommandHeader(this.tmCore, {
295-
tag: tag || 'master',
296-
storageType
297-
});
389+
// Display header unless --no-header is set
390+
if (options.noHeader !== true) {
391+
displayCommandHeader(this.tmCore, {
392+
tag: tag || 'master',
393+
storageType
394+
});
395+
}
298396

299397
// No tasks message
300398
if (tasks.length === 0) {
@@ -328,7 +426,7 @@ export class ListTasksCommand extends Command {
328426
// Task table
329427
console.log(
330428
ui.createTaskTable(tasks, {
331-
showSubtasks: withSubtasks,
429+
showSubtasks: options.withSubtasks,
332430
showDependencies: true,
333431
showComplexity: true // Enable complexity column
334432
})

apps/cli/src/commands/models/prompts.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,15 @@ export function createSearchSource(
158158
const filteredChoices = choices.filter((choice) => {
159159
// Separators are always included
160160
if (choice instanceof Separator) return true;
161-
// Filter regular choices by search term
162-
const searchText = (choice as ModelChoice).name || '';
163-
return searchText.toLowerCase().includes(searchTerm.toLowerCase());
161+
// Filter regular choices by search term (name and model ID)
162+
const mc = choice as ModelChoice;
163+
const displayText = mc.name || '';
164+
const modelId =
165+
typeof mc.value === 'object' && mc.value !== null && 'id' in mc.value
166+
? mc.value.id
167+
: '';
168+
const searchText = `${displayText} ${modelId}`.toLowerCase();
169+
return searchText.includes(searchTerm.toLowerCase());
164170
});
165171
// Map ModelChoice to the format inquirer expects
166172
return Promise.resolve(

apps/cli/src/lib/model-management.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export interface ModelCost {
1818

1919
export interface ModelData {
2020
id: string;
21+
name?: string;
2122
provider?: string;
2223
swe_score?: number | null;
2324
cost_per_1m_tokens?: ModelCost | null;

apps/cli/src/ui/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ export * from './header.component.js';
99
export * from './next-task.component.js';
1010
export * from './suggested-steps.component.js';
1111
export * from './task-detail.component.js';
12+
export * from './watch-footer.component.js';

0 commit comments

Comments
 (0)