-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Release 0.28.0 #1275
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Release 0.28.0 #1275
Conversation
Co-authored-by: Ralph Khreish <[email protected]>
Co-authored-by: Ralph Khreish <[email protected]>
fix CI failing to release (#1232)
Co-authored-by: Claude <[email protected]> Co-authored-by: Ralph Khreish <[email protected]>
β¦cation (#1264) Co-authored-by: Ralph Khreish <[email protected]> Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
β¦es (#1262) Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Ben Vargas <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 25
Caution
Some comments are outside the diff and canβt be posted inline due to platform limitations.
β οΈ Outside diff range comments (11)
tests/unit/ai-providers/openai.test.js (1)
10-18: Add mock for @ai-sdk/openai to ensure test isolation.The test file is missing a mock for the
@ai-sdk/openaipackage, which violates unit test isolation principles. Without this mock, the tests may be exercising the real OpenAI SDK code rather than testing the provider wrapper in isolation.Based on learnings and coding guidelines, add the following mock before importing the provider:
// Mock the utils module to prevent logging during tests jest.mock('../../../scripts/modules/utils.js', () => ({ log: jest.fn() })); +// Mock the @ai-sdk/openai module +jest.mock('@ai-sdk/openai', () => ({ + openai: jest.fn((config) => { + return jest.fn((modelId) => ({ + modelId, + provider: 'openai', + ...config + })); + }) +})); + // Import the provider import { OpenAIProvider } from '../../../src/ai-providers/openai.js';src/ai-providers/ollama.js (1)
43-53: Clarify API key requirement logic.The
isRequiredApiKey()method returnsfalse(indicating no API key is required), butgetRequiredApiKeyName()returns'OLLAMA_API_KEY'. This inconsistency is confusing.If Ollama truly does not require an API key (as indicated by line 43-45 and the
validateAuthimplementation), consider one of the following:Option 1: Remove
getRequiredApiKeyName()if it's not needed:- /** - * Returns the required API key environment variable name for Ollama. - * @returns {string} The environment variable name - */ - getRequiredApiKeyName() { - return 'OLLAMA_API_KEY'; - }Option 2: If the method is required by the base class interface, return
nullor throw an error:getRequiredApiKeyName() { - return 'OLLAMA_API_KEY'; + return null; // Ollama does not require an API key }Option 3: If Ollama optionally supports API keys, update the comment and
isRequiredApiKey()to clarify:/** - * Returns the required API key environment variable name for Ollama. + * Returns the optional API key environment variable name for Ollama. * @returns {string} The environment variable name */src/utils/create-mcp-config.js (1)
6-25: Add JSDoc documentation for the newly exported function.Since
formatJSONWithTabsis now part of the public API (exported at line 267), it should have JSDoc documentation explaining its purpose, parameters, return value, and the single-line array conversion behavior. This is consistent with the documentation pattern used forremoveTaskMasterMCPConfiguration(lines 140-146).Apply this diff to add documentation:
+/** + * Format an object as JSON string with tab indentation, converting simple arrays to single-line format + * @param {Object} obj - The object to format as JSON + * @returns {string} Formatted JSON string with tabs for indentation and simple arrays on single lines + */ function formatJSONWithTabs(obj) { let json = JSON.stringify(obj, null, '\t');tests/integration/cli/complex-cross-tag-scenarios.test.js (1)
362-371: LGTM! Non-overlapping IDs prevent conflicts.The loop correctly creates tasks with IDs 26-50 in the in-progress tag, avoiding conflicts with the master tasks (IDs 1-25). Consider adding a brief comment explaining this ID separation for clarity.
tsdown.config.ts (1)
11-18: Fixrequireusage in ESM moduleThis file is authored as an ES module (native
importstatements and"type": "module"packaging), sorequire(...)is undefined at runtime. The new version-reading block will throw before the build starts. ImportreadFileSyncfromnode:fs(or usecreateRequire) instead of callingrequiredirectly.Apply this diff:
-import { defineConfig } from 'tsdown'; -import { baseConfig, mergeConfig } from '@tm/build-config'; -import 'dotenv/config'; +import { defineConfig } from 'tsdown'; +import { baseConfig, mergeConfig } from '@tm/build-config'; +import { readFileSync } from 'node:fs'; +import 'dotenv/config'; @@ - const packageJson = JSON.parse( - require('fs').readFileSync('package.json', 'utf8') - ); + const packageJson = JSON.parse(readFileSync('package.json', 'utf8'));scripts/modules/task-manager/update-task-by-id.js (1)
401-407: Guard against missingmainResultbefore dereferencing.If the AI service returns an unexpected payload (or
mainResultis missing),aiServiceResponse.mainResultbecomesundefined, so the new line blows up with aTypeErrorbefore we reach the validation block. We should fail fast with a clear error instead of surfacingCannot read properties of undefined (reading 'task').Please add an explicit guard:
- const updatedTask = aiServiceResponse.mainResult.task; + const mainResult = aiServiceResponse?.mainResult; + if (!mainResult || typeof mainResult !== 'object' || !mainResult.task) { + throw new Error('AI service returned an invalid task payload.'); + } + const updatedTask = mainResult.task;tests/unit/ai-providers/gemini-cli.test.js (1)
521-614: Complete themaxOutputTokensrename in test inputs.We now assert that the provider calls the AI SDK with
maxOutputTokens, but the test fixtures still passmaxTokens. As soon as the implementation stops aliasingmaxTokens, these tests will fail (and they currently donβt cover the new option surface). The fallback assertion later in the file still expectsmaxTokenstoo.Please update the fixtures and expectations to match the renamed parameter:
const mockParams = { ..., - maxTokens: 100, + maxOutputTokens: 100, temperature: 0.7 }; β¦ - maxTokens: undefined, + maxOutputTokens: undefined,Make the same change wherever else the tests create params or expectations for this option so we genuinely validate the new API surface.
src/ai-providers/gemini-cli.js (1)
430-435: NormalizemaxTokensbefore passing to the SDK.All three call sites now feed
maxOutputTokens: params.maxTokensstraight into the Vercel SDK, bypassingprepareTokenParam(). When this value is provided as a string (the CLI still surfaces strings from config/env), the provider call receives a non-numeric token limit and the request fails. Please reusethis.prepareTokenParam(...)(like the base implementation) so the limit is coerced to a safe integer before we callgenerateText/streamText/generateObject.Also applies to: 531-536, 588-595
apps/cli/src/commands/list.command.ts (1)
283-323: Subtask recommendations regressed.
findNextTaskstill returns IDs like"12.3"for subtasks, buttasks.find((t) => t.id === '12.3')can never succeedβonly parents live intasks. As a result, whenever a subtask is the best candidate,nextTaskisundefined, the dashboard shows βNo tasks available,β and we lose the recommendation entirely. Please restore subtask handling (e.g., detect dotted IDs, look up the parent plus the specific subtask, and pass that through) before shipping.packages/tm-core/src/storage/file-storage/file-storage.ts (1)
454-491: Parent status flips fromin-progressβpendingafter any subtask reset
With the newallPendingbranch, a parent that was previouslyin-progressreverts topendingas soon as all subtasks happen to be back in the pending stateβe.g., if one subtask is reopened the parent loses the fact that work started. Prior behavior left the parent in-progress until the final completion. Please keep the previous ordering (only transition topendingwhen appropriate contexts demand it) or gate the pending reset behind an explicit state.scripts/modules/task-manager/analyze-task-complexity.js (1)
485-498: Avoid dropping existing analyses when running targeted IDs
WhenspecificIds(or a narrow range) is used,tasksData.tasksonly holds that subset. BecausecurrentTagTaskIdsis derived from this filtered list, every pre-existing analysis for other tasks in the same tag fails thecurrentTagTaskIds.has(...)check and gets purged fromfinalComplexityAnalysis. Running a targeted refresh therefore erases the rest of the reportβmajor data loss.Remove the extra set check (or build it from the full tag task list) so previously generated entries survive subset runs.
- const currentTagTaskIds = new Set(tasksData.tasks.map((t) => t.id)); const existingEntriesNotAnalyzed = existingReport.complexityAnalysis.filter( - (item) => - !analyzedTaskIds.has(item.taskId) && - currentTagTaskIds.has(item.taskId) // Only keep entries for tasks in current tag + (item) => !analyzedTaskIds.has(item.taskId) );
β»οΈ Duplicate comments (1)
apps/extension/package.json (1)
279-279: Verify TypeScript version consistency.The TypeScript version
^5.9.2appears in multiple packages and may be a downgrade from previous versions. This should be verified for consistency across the monorepo and to ensure it's not an unintentional change.See comment on packages/tm-core/package.json for verification script.
| --- | ||
| "task-master-ai": patch | ||
| --- | ||
|
|
||
| Improve `analyze-complexity` cli docs and `--research` flag documentation No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Nitpick | π΅ Trivial
Optional: Address markdown formatting issues.
The changeset content is appropriate, but markdown linting flags two formatting issues:
- Missing top-level heading (MD041)
- Missing trailing newline (MD047)
Apply this diff to fix the formatting:
---
"task-master-ai": patch
---
-Improve `analyze-complexity` cli docs and `--research` flag documentation
+# Improve analyze-complexity CLI documentation
+
+Improve `analyze-complexity` cli docs and `--research` flag documentation
+Committable suggestion skipped: line range outside the PR's diff.
π§° Tools
πͺ markdownlint-cli2 (0.18.1)
5-5: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
5-5: Files should end with a single newline character
(MD047, single-trailing-newline)
π€ Prompt for AI Agents
In .changeset/chore-fix-docs.md around lines 1-5, the changeset lacks a
top-level heading and a trailing newline; add a single top-level Markdown
heading as the very first line (e.g. "# task-master-ai: patch" or another
suitable project/semver title), keep the existing YAML block after that heading,
and save the file with a final newline so it ends with a trailing newline
character.
| --- | ||
| "task-master-ai": minor | ||
| --- | ||
|
|
||
| Add Cursor IDE custom slash command support | ||
|
|
||
| Expose Task Master commands as Cursor slash commands by copying assets/claude/commands to .cursor/commands on profile add and cleaning up on remove. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Nitpick | π΅ Trivial
Optional: Address markdown formatting issues.
The changeset content is appropriate, but markdown linting flags two formatting issues:
- Missing top-level heading (MD041)
- Missing trailing newline (MD047)
Apply this diff to fix the formatting:
---
"task-master-ai": minor
---
+# Add Cursor IDE custom slash command support
+
Add Cursor IDE custom slash command support
Expose Task Master commands as Cursor slash commands by copying assets/claude/commands to .cursor/commands on profile add and cleaning up on remove.
+π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| --- | |
| "task-master-ai": minor | |
| --- | |
| Add Cursor IDE custom slash command support | |
| Expose Task Master commands as Cursor slash commands by copying assets/claude/commands to .cursor/commands on profile add and cleaning up on remove. | |
| --- | |
| "task-master-ai": minor | |
| --- | |
| # Add Cursor IDE custom slash command support | |
| Add Cursor IDE custom slash command support | |
| Expose Task Master commands as Cursor slash commands by copying assets/claude/commands to .cursor/commands on profile add and cleaning up on remove. | |
π§° Tools
πͺ markdownlint-cli2 (0.18.1)
5-5: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
5-5: Files should end with a single newline character
(MD047, single-trailing-newline)
π€ Prompt for AI Agents
In .changeset/cursor-slash-commands.md around lines 1 to 7, the changeset is
missing a top-level heading and a trailing newline; add a single H1 heading
(e.g., "# Cursor Slash Commands" or similar descriptive title) as the first
non-metadata line and ensure the file ends with a newline character so the
markdown linter no longer reports MD041 and MD047.
| --- | ||
| "task-master-ai": patch | ||
| --- | ||
|
|
||
| Change parent task back to "pending" when all subtasks are in "pending" state |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Nitpick | π΅ Trivial
Optional: Address markdown formatting issues.
The changeset content is appropriate, but markdown linting flags two formatting issues:
- Missing top-level heading (MD041)
- Missing trailing newline (MD047)
Apply this diff to fix the formatting:
---
"task-master-ai": patch
---
-Change parent task back to "pending" when all subtasks are in "pending" state
+# Change parent task state to pending when all subtasks are pending
+
+Change parent task back to "pending" when all subtasks are in "pending" state
+Committable suggestion skipped: line range outside the PR's diff.
π§° Tools
πͺ markdownlint-cli2 (0.18.1)
5-5: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
5-5: Files should end with a single newline character
(MD047, single-trailing-newline)
π€ Prompt for AI Agents
In .changeset/curvy-weeks-flow.md around lines 1 to 5, the changeset is missing
a top-level heading and a trailing newline; add a top-level heading (e.g., "#
Patch: task-master-ai") as the first line, ensure the existing YAML block and
description remain, and add a single trailing newline at the end of the file so
the file ends with a newline character.
| "task-master-ai": patch | ||
| --- | ||
|
|
||
| Do a quick fix on build |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clarify the changeset summary
Changeset entries should be user-facing, concise, and written in imperative mood. βDo a quick fix on buildβ reads like an internal note and doesnβt tell consumers what improved. Please rephrase with a clear action, e.g., βFix the build configuration for task-master-ai.β
π§° Tools
πͺ markdownlint-cli2 (0.18.1)
5-5: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
π€ Prompt for AI Agents
.changeset/easy-spiders-wave.md around line 5: the changeset summary "Do a quick
fix on build" is vague and not user-facing; replace it with a concise,
imperative, consumer-focused sentence that describes the actual change (for
example, "Fix build configuration for task-master-ai" or "Fix CI build step for
task-master-ai"), preserving tone and brevity so the entry communicates what
changed to package consumers.
| "task-master-ai": minor | ||
| --- | ||
|
|
||
| Added api keys page on docs website: docs.task-master.dev/getting-started/api-keys |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion | π Major
Use imperative voice in the changeset summary
Per the repoβs changeset guidelines, summaries should be user-facing and written in the imperative mood. Please rewrite this line accordingly (e.g., βAdd API keys page to docs at docs.task-master.dev/getting-started/api-keysβ).
-Added api keys page on docs website: docs.task-master.dev/getting-started/api-keys
+Add API keys page to docs website: docs.task-master.dev/getting-started/api-keysπ Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Added api keys page on docs website: docs.task-master.dev/getting-started/api-keys | |
| Add API keys page to docs website: docs.task-master.dev/getting-started/api-keys |
π§° Tools
πͺ markdownlint-cli2 (0.18.1)
5-5: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
π€ Prompt for AI Agents
In .changeset/flat-cities-say.md at line 5, the changeset summary is not written
in the imperative voice; rewrite the sentence to be user-facing and imperative
(for example: "Add API keys page to docs at
docs.task-master.dev/getting-started/api-keys") so it follows the repository's
changeset guidelines.
| const PRDSingleTaskSchema = z.object({ | ||
| id: z.number().int().positive(), | ||
| title: z.string().min(1), | ||
| description: z.string().min(1), | ||
| details: z.string().nullable(), | ||
| testStrategy: z.string().nullable(), | ||
| priority: z.enum(['high', 'medium', 'low']).nullable(), | ||
| dependencies: z.array(z.number().int().positive()).nullable(), | ||
| status: z.string().nullable() | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Nitpick | π΅ Trivial
Consider adding default values for nullable fields.
The schema defines priority, dependencies, and status as nullable without defaults, which could lead to inconsistent task data. For consistency with BaseTaskSchema (in src/schemas/base-schemas.js), consider:
dependencies(line 11): Should default to[]for consistency with task conventionsstatus(line 12): Should default to'pending'to ensure all tasks have a statuspriority(line 10): Nullable is acceptable, but consider defaulting tonullexplicitly
Apply this diff to add defaults:
const PRDSingleTaskSchema = z.object({
id: z.number().int().positive(),
title: z.string().min(1),
description: z.string().min(1),
details: z.string().nullable(),
testStrategy: z.string().nullable(),
- priority: z.enum(['high', 'medium', 'low']).nullable(),
- dependencies: z.array(z.number().int().positive()).nullable(),
- status: z.string().nullable()
+ priority: z.enum(['high', 'medium', 'low']).nullable().default(null),
+ dependencies: z.array(z.number().int().positive()).default([]),
+ status: z.string().default('pending')
});π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const PRDSingleTaskSchema = z.object({ | |
| id: z.number().int().positive(), | |
| title: z.string().min(1), | |
| description: z.string().min(1), | |
| details: z.string().nullable(), | |
| testStrategy: z.string().nullable(), | |
| priority: z.enum(['high', 'medium', 'low']).nullable(), | |
| dependencies: z.array(z.number().int().positive()).nullable(), | |
| status: z.string().nullable() | |
| }); | |
| const PRDSingleTaskSchema = z.object({ | |
| id: z.number().int().positive(), | |
| title: z.string().min(1), | |
| description: z.string().min(1), | |
| details: z.string().nullable(), | |
| testStrategy: z.string().nullable(), | |
| priority: z.enum(['high', 'medium', 'low']).nullable().default(null), | |
| dependencies: z.array(z.number().int().positive()).default([]), | |
| status: z.string().default('pending') | |
| }); |
π€ Prompt for AI Agents
In src/schemas/parse-prd.js around lines 4 to 13, the PRDSingleTaskSchema marks
priority, dependencies, and status as nullable but does not provide defaults;
update the schema so dependencies defaults to an empty array, status defaults to
'pending', and priority explicitly defaults to null (keep it nullable) by
chaining .default(...) on each respective field to ensure consistent task
objects across the app.
|
|
||
| // Export the formatting function for use by other modules | ||
| export { formatJSONWithTabs }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion | π Major
π§© Analysis chain
Verify test coverage and usage of the exported function.
As per coding guidelines, utility functions must meet 90% test coverage. Since formatJSONWithTabs is now exported and part of the public API, ensure that comprehensive tests exist covering:
- Basic formatting with tabs
- Single-line array conversion for simple arrays
- Preservation of nested structures in arrays
- Edge cases (empty objects, nested objects, etc.)
Additionally, verify that there is actual usage or planned usage of this export in other modules, as no importing files are shown in the provided context.
Run the following script to check for test coverage and usage:
π Script executed:
#!/bin/bash
# Description: Verify test coverage for formatJSONWithTabs and check for external usage
# Search for test files covering this function
echo "=== Searching for tests of formatJSONWithTabs ==="
rg -n "formatJSONWithTabs" --type=js -g "*test*" -g "*spec*"
# Search for imports of this function from other modules
echo -e "\n=== Searching for imports of formatJSONWithTabs from other modules ==="
rg -n "import.*formatJSONWithTabs.*from.*create-mcp-config" --type=js
# Alternative: search for any usage of the function outside this file
echo -e "\n=== Searching for any external usage ==="
rg -n "formatJSONWithTabs" --type=js -g "!src/utils/create-mcp-config.js"Length of output: 402
Add tests for formatJSONWithTabs and confirm its import usage
- No test currently imports or invokes
formatJSONWithTabs; add tests covering basic tab formatting, single-line arrays, nested structures, and edge cases (empty objects, nested objects, etc.). - Verify correct import and usage in
src/profiles/roo.js:9.
π€ Prompt for AI Agents
In src/utils/create-mcp-config.js around lines 265-267, add unit tests that
import the named export formatJSONWithTabs and cover basic tab formatting,
single-line arrays, nested structures, empty objects, and deeply nested objects
and arrays (edge cases), asserting exact string output for each; create a test
file (e.g., tests/utils/formatJSONWithTabs.test.js) that imports the function
with the same named import as exported and includes cases for tabs count
variations and null/undefined handling; also open src/profiles/roo.js line 9 and
verify the import path and syntax match the named export (export {
formatJSONWithTabs }) β if it currently uses a default import or wrong path,
change it to a named import from the correct relative path and update any call
sites to pass expected arguments so tests and runtime use are consistent.
| describe('Large Task Set Performance', () => { | ||
| it('should handle large task sets efficiently', () => { | ||
| // Create a large task set (100 tasks) | ||
| // Create a large task set (50 tasks) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Nitpick | π΅ Trivial
LGTM! Consider adding more context.
The comment accurately reflects the reduced task set size. Consider expanding it to mention the distribution (e.g., "50 tasks total: 25 in master with dependencies, 25 in in-progress") for better test documentation.
π€ Prompt for AI Agents
In tests/integration/cli/complex-cross-tag-scenarios.test.js around line 333,
the inline comment "// Create a large task set (50 tasks)" should be expanded to
document the task distribution; update it to something like "Create a large task
set (50 tasks total: 25 in master with dependencies, 25 in in-progress)" or
similar wording that specifies how the 50 tasks are split and any important
dependency relationships so the test intent is clearer.
| // Execute move; correctness is validated below (no timing assertion) | ||
| execSync( | ||
| `node ${binPath} move --from=50 --from-tag=master --to-tag=in-progress --with-dependencies`, | ||
| `node ${binPath} move --from=25 --from-tag=master --to-tag=in-progress --with-dependencies`, | ||
| { stdio: 'pipe' } | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion | π Major
Update test description to match its purpose.
The test execution is correct, but the test description "should handle large task sets efficiently" implies performance testing. Since timing assertions were removed (as noted in line 374), consider renaming to something like "should handle large task sets correctly" or "should move large dependency chains".
Apply this diff to update the test description:
- it('should handle large task sets efficiently', () => {
+ it('should handle large task sets correctly', () => {π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Execute move; correctness is validated below (no timing assertion) | |
| execSync( | |
| `node ${binPath} move --from=50 --from-tag=master --to-tag=in-progress --with-dependencies`, | |
| `node ${binPath} move --from=25 --from-tag=master --to-tag=in-progress --with-dependencies`, | |
| { stdio: 'pipe' } | |
| ); | |
| it('should handle large task sets correctly', () => { | |
| // Execute move; correctness is validated below (no timing assertion) | |
| execSync( | |
| `node ${binPath} move --from=25 --from-tag=master --to-tag=in-progress --with-dependencies`, | |
| { stdio: 'pipe' } | |
| ); |
π€ Prompt for AI Agents
In tests/integration/cli/complex-cross-tag-scenarios.test.js around lines 374 to
378, the test title still reads "should handle large task sets efficiently"
which implies performance assertions that were removed; update the test
description to reflect correctness rather than performance (e.g., "should handle
large task sets correctly" or "should move large dependency chains") by changing
the test/title string accordingly so it matches the actual behavior being
validated by the execSync move call.
|
|
||
| // Verify all tasks in the dependency chain were moved | ||
| for (let i = 1; i <= 25; i++) { | ||
| expect(tasksAfter.master.tasks.find((t) => t.id === i)).toBeUndefined(); | ||
| expect( | ||
| tasksAfter['in-progress'].tasks.find((t) => t.id === i) | ||
| ).toBeDefined(); | ||
| } | ||
|
|
||
| // Verify in-progress still has its original tasks (26-50) | ||
| for (let i = 26; i <= 50; i++) { | ||
| expect( | ||
| tasksAfter['in-progress'].tasks.find((t) => t.id === i) | ||
| ).toBeDefined(); | ||
| } | ||
|
|
||
| // Final count check | ||
| expect(tasksAfter['in-progress'].tasks).toHaveLength(50); // 25 moved + 25 original |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Nitpick | π΅ Trivial
LGTM! Comprehensive verification logic.
The verification correctly checks:
- Tasks 1-25 are removed from master and present in in-progress
- Tasks 26-50 remain in in-progress
- Final count is 50 (25 moved + 25 original)
Minor style suggestion: Line 382 contains an unnecessary blank line that could be removed for cleaner code.
π€ Prompt for AI Agents
In tests/integration/cli/complex-cross-tag-scenarios.test.js around lines 382 to
399 there is an unnecessary blank line at line 382; remove that blank line so
the verification block is contiguous and the surrounding comments/code flow
cleanly, then run the test suite to ensure formatting-only change passes.
Co-authored-by: Ralph Khreish <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and canβt be posted inline due to platform limitations.
β οΈ Outside diff range comments (5)
packages/tm-core/src/repositories/supabase-task-repository.ts (2)
20-29: Minor: Validation schema includes non-persisted fields.The
TaskUpdateSchemavalidatesdetailsandtestStrategyfields (lines 26-27), but these are explicitly skipped when persisting to the database (line 182). This creates a disconnect where validation suggests these fields are supported, but they are silently discarded.Consider one of these approaches:
Option 1: Remove non-persisted fields from validation schema (preferred if these fields aren't used):
const TaskUpdateSchema = z .object({ title: z.string().min(1).optional(), description: z.string().optional(), status: TaskStatusSchema.optional(), priority: z.enum(['low', 'medium', 'high', 'critical']).optional(), - details: z.string().optional(), - testStrategy: z.string().optional() }) .partial();Option 2: Add a comment explaining why these fields are validated but not persisted:
const TaskUpdateSchema = z .object({ title: z.string().min(1).optional(), description: z.string().optional(), status: TaskStatusSchema.optional(), priority: z.enum(['low', 'medium', 'high', 'critical']).optional(), + // Note: details and testStrategy are validated for Task interface compatibility + // but not persisted to the database (stored elsewhere or computed) details: z.string().optional(), testStrategy: z.string().optional() }) .partial();Also applies to: 182-182
9-17: Critical: TaskStatusSchema allows unsupported statuses
- Schema permits seven values, but the database enum (
database.types.ts:405) only supports'todo','in_progress', and'done'.mapStatusToDatabasehandles only'pending','in-progress', and'done', throwing for others.- Remove unsupported statuses (
review,deferred,cancelled,blocked) fromTaskStatusSchemaor, if needed, extend both the DB enum andmapStatusToDatabaseto cover all seven.scripts/modules/commands.js (1)
3621-3680: Restore Azure/Vertex provider hint handlingThe provider-flag check and
setModelhint mapping now omit--azureand--vertex. As a result, specifying those flags no longer prevents conflicts, and more importantly, the CLI stops sending the provider hint, so setting Azure or Vertex models fails. This regresses existing functionality. Please restore the Azure/Vertex branches alongside the new Codex CLI path.- const providerFlags = [ - options.openrouter, - options.ollama, - options.bedrock, - options.claudeCode, - options.geminiCli, - options.codexCli - ].filter(Boolean).length; + const providerFlags = [ + options.openrouter, + options.ollama, + options.bedrock, + options.claudeCode, + options.azure, + options.vertex, + options.geminiCli, + options.codexCli + ].filter(Boolean).length; @@ - providerHint: options.openrouter - ? 'openrouter' - : options.ollama - ? 'ollama' - : options.bedrock - ? 'bedrock' - : options.claudeCode - ? 'claude-code' - : options.geminiCli - ? 'gemini-cli' - : options.codexCli - ? 'codex-cli' - : undefined + providerHint: options.openrouter + ? CUSTOM_PROVIDERS.OPENROUTER + : options.ollama + ? CUSTOM_PROVIDERS.OLLAMA + : options.bedrock + ? CUSTOM_PROVIDERS.BEDROCK + : options.claudeCode + ? CUSTOM_PROVIDERS.CLAUDE_CODE + : options.azure + ? CUSTOM_PROVIDERS.AZURE + : options.vertex + ? CUSTOM_PROVIDERS.VERTEX + : options.geminiCli + ? CUSTOM_PROVIDERS.GEMINI_CLI + : options.codexCli + ? CUSTOM_PROVIDERS.CODEX_CLI + : undefinedBe sure to apply the same mapping fix to the
--set-researchand--set-fallbackbranches.Also applies to: 3665-3738
src/ai-providers/gemini-cli.js (1)
479-485: Normalize usage tokens consistently.Here (and in the manual
generateObjectretry) you only readpromptTokens/completionTokens. When the SDK returns the newer{ inputTokens, outputTokens }shape, both values becomeundefined, so telemetry and cost accounting break. Mirror the base-class normalisation so both formats are supported.- return { - text: finalText, - usage: { - inputTokens: result.usage?.promptTokens, - outputTokens: result.usage?.completionTokens, - totalTokens: result.usage?.totalTokens - } - }; + const inputTokens = + result.usage?.inputTokens ?? result.usage?.promptTokens ?? 0; + const outputTokens = + result.usage?.outputTokens ?? result.usage?.completionTokens ?? 0; + const totalTokens = + result.usage?.totalTokens ?? inputTokens + outputTokens; + + return { + text: finalText, + usage: { inputTokens, outputTokens, totalTokens } + };Make the corresponding change around Line 620 for the object-generation fallback to keep both paths in sync.
src/ai-providers/base-provider.js (1)
149-201: RestoremaxTokenswhen piping limits to AI SDK text calls
prepareTokenParamnow emits onlymaxOutputTokens. The text/stream helpers in this repo (and upstream SDK) still rely onmaxTokens, so limits silently vanishβrequests can run uncapped and spike cost. Please send both fields to preserve existing behaviour.prepareTokenParam(modelId, maxTokens) { if (maxTokens === undefined) { return {}; } // Ensure maxTokens is an integer const tokenValue = Math.floor(Number(maxTokens)); - return { maxOutputTokens: tokenValue }; + return { maxTokens: tokenValue, maxOutputTokens: tokenValue }; }
β»οΈ Duplicate comments (2)
README.md (1)
109-109: Add Windows path for Q CLI entry.The Q CLI row in the MCP table only shows the Unix/macOS path (
~/.aws/amazonq/mcp.json). The manual configuration header update on line 113 indicates Q Developer CLI support, but Windows users lack equivalent path guidance.As noted in the previous review, consider adding the Windows equivalent path (e.g.,
%USERPROFILE%\.aws\amazonq\mcp.json) to complete the cross-platform documentation, consistent with other rows in the table.Also applies to: 113-113
src/ai-providers/claude-code.js (1)
89-109: Reinstate Anthropic env isolation before creating the Claude Code client
We already learned the hard way thatai-sdk-provider-claude-codewill happily consume any ambientANTHROPIC_API_KEY, charging the wrong account. The newgetClientdropped the temporary override/restore flow we previously agreed on, so a globally configured Anthropic key will leak into Claudeβ―Code again. Please wrapcreateClaudeCodein the same sandbox as before: stash the originalANTHROPIC_API_KEY, temporarily set/delete it based onCLAUDE_CODE_API_KEY(or the passedapiKey), and restore it in afinally.getClient(params = {}) { try { const settings = getClaudeCodeSettingsForCommand(params.commandName) || {}; - - return createClaudeCode({ - defaultSettings: settings - }); + const originalAnthropic = process.env.ANTHROPIC_API_KEY; + const claudeCodeKey = + params.apiKey || process.env.CLAUDE_CODE_API_KEY || null; + + const restoreAnthropicEnv = () => { + if (originalAnthropic !== undefined) { + process.env.ANTHROPIC_API_KEY = originalAnthropic; + } else { + delete process.env.ANTHROPIC_API_KEY; + } + }; + + try { + if (claudeCodeKey) { + process.env.ANTHROPIC_API_KEY = claudeCodeKey; + } else if (originalAnthropic !== undefined) { + delete process.env.ANTHROPIC_API_KEY; + } + + return createClaudeCode({ + defaultSettings: settings + }); + } finally { + restoreAnthropicEnv(); + } } catch (error) { // Provide more helpful error message
π Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
β Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
π Files selected for processing (27)
.changeset/brave-lions-sing.md(1 hunks)CLAUDE.md(1 hunks)README.md(3 hunks)docs/command-reference.md(1 hunks)docs/configuration.md(2 hunks)docs/examples/codex-cli-usage.md(1 hunks)docs/models.md(5 hunks)docs/providers/codex-cli.md(1 hunks)package.json(7 hunks)packages/tm-core/src/repositories/supabase-task-repository.ts(1 hunks)scripts/modules/ai-services-unified.js(5 hunks)scripts/modules/commands.js(7 hunks)scripts/modules/config-manager.js(13 hunks)scripts/modules/supported-models.json(2 hunks)scripts/modules/task-manager/models.js(2 hunks)src/ai-providers/base-provider.js(6 hunks)src/ai-providers/claude-code.js(1 hunks)src/ai-providers/codex-cli.js(1 hunks)src/ai-providers/gemini-cli.js(4 hunks)src/ai-providers/grok-cli.js(1 hunks)src/ai-providers/index.js(1 hunks)src/constants/providers.js(1 hunks)tests/integration/providers/temperature-support.test.js(1 hunks)tests/unit/ai-providers/base-provider.test.js(1 hunks)tests/unit/ai-providers/codex-cli.test.js(1 hunks)tests/unit/ai-services-unified.test.js(4 hunks)tests/unit/config-manager.test.js(4 hunks)
π§° Additional context used
π Path-based instructions (28)
docs/**/*
π CodeRabbit inference engine (.cursor/rules/new_features.mdc)
Add feature documentation to '/docs' folder, include tagged system usage examples, update command reference documentation, and provide migration notes if relevant.
Files:
docs/providers/codex-cli.mddocs/models.mddocs/examples/codex-cli-usage.mddocs/configuration.mddocs/command-reference.md
tests/{unit,integration,e2e,fixtures}/**/*.js
π CodeRabbit inference engine (.cursor/rules/architecture.mdc)
Test files must be organized as follows: unit tests in tests/unit/, integration tests in tests/integration/, end-to-end tests in tests/e2e/, and test fixtures in tests/fixtures/.
Files:
tests/unit/config-manager.test.jstests/unit/ai-providers/base-provider.test.jstests/unit/ai-services-unified.test.jstests/integration/providers/temperature-support.test.jstests/unit/ai-providers/codex-cli.test.js
tests/unit/*.js
π CodeRabbit inference engine (.cursor/rules/architecture.mdc)
Each module should have a corresponding unit test file in tests/unit/ that reflects the module structure (one test file per module).
Files:
tests/unit/config-manager.test.jstests/unit/ai-services-unified.test.js
**/*.{test,spec}.{js,ts,jsx,tsx}
π CodeRabbit inference engine (.cursor/rules/git_workflow.mdc)
**/*.{test,spec}.{js,ts,jsx,tsx}: Create a test file and ensure all tests pass when all subtasks are complete; commit tests if added or modified
When all subtasks are complete, run final testing using the appropriate test runner (e.g., npm test, jest, or manual testing)
Files:
tests/unit/config-manager.test.jstests/unit/ai-providers/base-provider.test.jstests/unit/ai-services-unified.test.jstests/integration/providers/temperature-support.test.jstests/unit/ai-providers/codex-cli.test.js
**/*.test.js
π CodeRabbit inference engine (.cursor/rules/tests.mdc)
**/*.test.js: Never use asynchronous operations in tests. Make all mocks return synchronous values when possible.
Always mock tests properly based on the way the tested functions are defined and used.
Follow the test file organization: mocks must be set up before importing modules under test, and spies on mocked modules should be set up after imports.
Use fixtures from tests/fixtures/ for consistent sample data across tests.
Always declare mocks before importing the modules being tested in Jest test files.
Use jest.spyOn() after imports to create spies on mock functions and reference these spies in test assertions.
When testing functions with callbacks, get the callback from your mock's call arguments, execute it directly with test inputs, and verify the results.
For ES modules, use jest.mock() before static imports and jest.unstable_mockModule() before dynamic imports to mock dependencies.
Reset mock functions (mockFn.mockReset()) before dynamic imports if they might have been called previously.
When verifying console assertions, assert against the actual arguments passed (single formatted string), not multiple arguments.
Use mock-fs to mock file system operations in tests, and restore the file system after each test.
Mock API calls (e.g., Anthropic/Claude) by mocking the entire module and providing predictable responses.
Set mock environment variables in test setup and restore them after each test.
Maintain test fixtures separate from test logic.
Follow the mock-first-then-import pattern for all Jest mocks.
Do not define mock variables before jest.mock() calls (they won't be accessible due to hoisting).
Use test-specific file paths (e.g., 'test-tasks.json') for all file operations in tests.
Mock readJSON and writeJSON to avoid real file system interactions in tests.
Verify file operations use the correct paths in expect statements.
Use different file paths for each test to avoid test interdependence.
Verify modifications on the in-memory task objects passed to w...
Files:
tests/unit/config-manager.test.jstests/unit/ai-providers/base-provider.test.jstests/unit/ai-services-unified.test.jstests/integration/providers/temperature-support.test.jstests/unit/ai-providers/codex-cli.test.js
tests/unit/**/*.test.js
π CodeRabbit inference engine (.cursor/rules/tests.mdc)
tests/unit/**/*.test.js: Unit tests must be located in tests/unit/, test individual functions and utilities in isolation, mock all external dependencies, and keep tests small, focused, and fast.
Do not include actual command execution in unit tests.
Files:
tests/unit/config-manager.test.jstests/unit/ai-providers/base-provider.test.jstests/unit/ai-services-unified.test.jstests/unit/ai-providers/codex-cli.test.js
tests/{unit,integration,e2e}/**/*.test.js
π CodeRabbit inference engine (.cursor/rules/tests.mdc)
tests/{unit,integration,e2e}/**/*.test.js: When testing CLI commands built with Commander.js, test the command action handlers directly rather than trying to mock the entire Commander.js chain.
When mocking the Commander.js chain, mock ALL chainable methods (option, argument, action, on, etc.) and return this (or the mock object) from all chainable method mocks.
Explicitly handle all options, including defaults and shorthand flags (e.g., -p for --prompt), and include null/undefined checks in test implementations for parameters that might be optional.
Do not try to use the real action implementation without proper mocking, and do not mock Commander partiallyβeither mock it completely or test the action directly.
Mock the action handlers for CLI commands and verify they're called with correct arguments.
Use sample task fixtures for consistent test data, mock file system operations, and test both success and error paths for task operations.
Mock console output and verify correct formatting in UI function tests. Use flexible assertions like toContain() or toMatch() for formatted output.
Mock chalk functions to return the input text to make testing easier while still verifying correct function calls.
Files:
tests/unit/config-manager.test.jstests/unit/ai-providers/base-provider.test.jstests/unit/ai-services-unified.test.jstests/integration/providers/temperature-support.test.jstests/unit/ai-providers/codex-cli.test.js
**/*.js
π CodeRabbit inference engine (.cursor/rules/tests.mdc)
**/*.js: Declare and initialize global variables at the top of modules to avoid hoisting issues.
Use proper function declarations to avoid hoisting issues and initialize variables before they are referenced.
Do not reference variables before their declaration in module scope.
Use dynamic imports (import()) to avoid initialization order issues in modules.
Files:
tests/unit/config-manager.test.jssrc/ai-providers/grok-cli.jstests/unit/ai-providers/base-provider.test.jsscripts/modules/task-manager/models.jssrc/constants/providers.jsscripts/modules/ai-services-unified.jssrc/ai-providers/codex-cli.jsscripts/modules/config-manager.jssrc/ai-providers/base-provider.jstests/unit/ai-services-unified.test.jssrc/ai-providers/index.jstests/integration/providers/temperature-support.test.jssrc/ai-providers/gemini-cli.jsscripts/modules/commands.jssrc/ai-providers/claude-code.jstests/unit/ai-providers/codex-cli.test.js
**/*.{test,spec}.*
π CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)
Test files should follow naming conventions: .test., .spec., or _test. depending on the language
Files:
tests/unit/config-manager.test.jstests/unit/ai-providers/base-provider.test.jstests/unit/ai-services-unified.test.jstests/integration/providers/temperature-support.test.jstests/unit/ai-providers/codex-cli.test.js
tests/{unit,integration,e2e}/**
π CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)
Organize test directories by test type (unit, integration, e2e) and mirror source structure where possible
Files:
tests/unit/config-manager.test.jstests/unit/ai-providers/base-provider.test.jstests/unit/ai-services-unified.test.jstests/integration/providers/temperature-support.test.jstests/unit/ai-providers/codex-cli.test.js
src/ai-providers/*.js
π CodeRabbit inference engine (.cursor/rules/ai_providers.mdc)
src/ai-providers/*.js: Create a new provider module file in src/ai-providers/ named .js when adding a new AI provider.
Provider modules must export three functions: generateText, streamText, and generateObject.
Provider modules must import the provider's create function from @ai-sdk/, and import generateText, streamText, generateObject from the core ai package, as well as the log utility from ../../scripts/modules/utils.js.
Implement generateText, streamText, and generateObject functions in provider modules with basic validation and try/catch error handling.Provider-specific wrappers for Vercel AI SDK functions must be implemented in src/ai-providers/*.js, each file corresponding to a provider.
Files:
src/ai-providers/grok-cli.jssrc/ai-providers/codex-cli.jssrc/ai-providers/base-provider.jssrc/ai-providers/index.jssrc/ai-providers/gemini-cli.jssrc/ai-providers/claude-code.js
tests/unit/ai-providers/*.test.js
π CodeRabbit inference engine (.cursor/rules/ai_providers.mdc)
Create unit tests for the new provider in tests/unit/ai-providers/.test.js, mocking @ai-sdk/ and core ai module functions, and testing all exported functions for correct behavior and error handling.
Files:
tests/unit/ai-providers/base-provider.test.jstests/unit/ai-providers/codex-cli.test.js
.changeset/*.md
π CodeRabbit inference engine (.cursor/rules/changeset.mdc)
.changeset/*.md: When runningnpm run changesetornpx changeset add, provide a concise summary of the changes for theCHANGELOG.mdin imperative mood, typically a single line, and not a detailed Git commit message.
The changeset summary should be user-facing, describing what changed in the released version that is relevant to users or consumers of the package.
Do not use your detailed Git commit message body as the changeset summary.
Files:
.changeset/brave-lions-sing.md
.changeset/*
π CodeRabbit inference engine (.cursor/rules/new_features.mdc)
Create appropriate changesets for new features, use semantic versioning, include tagged system information in release notes, and document breaking changes if any.
Files:
.changeset/brave-lions-sing.md
scripts/modules/task-manager/*.js
π CodeRabbit inference engine (.cursor/rules/ai_services.mdc)
scripts/modules/task-manager/*.js: Centralize all LLM calls throughgenerateTextServiceorgenerateObjectService.
Do not import or call anything from the oldai-services.js,ai-client-factory.js, orai-client-utils.jsfiles.
Do not initialize AI clients (Anthropic, Perplexity, etc.) directly within core logic (task-manager/) or MCP direct functions.
Do not fetch AI-specific parameters (model ID, max tokens, temp) usingconfig-manager.jsgetters for the AI call. Pass theroleinstead.
Do not implement fallback or retry logic outsideai-services-unified.js.
Do not handle API key resolution outside the service layer (it usesutils.jsinternally).
Determine the appropriaterole(main,research,fallback) in your core logic and pass it to the service.
Pass thesessionobject (received in thecontextparameter, especially from direct function wrappers) to the service call when in MCP context.
UsegenerateTextServiceand implement robust manual JSON parsing (with Zod validation after parsing) when structured output is needed, asgenerateObjectServicehas shown unreliability with some providers/schemas.
Be aware of potential reliability issues withgenerateObjectServiceacross different providers and complex schemas. PrefergenerateTextService+ manual parsing as a more robust alternative for structured data needs.Files in scripts/modules/task-manager/ should each handle a specific action related to task management (e.g., add-task.js, expand-task.js), supporting the tagged task lists system and backward compatibility.
Files:
scripts/modules/task-manager/models.js
scripts/modules/**
π CodeRabbit inference engine (.cursor/rules/dev_workflow.mdc)
When using the MCP server, restart it if core logic in
scripts/modulesor MCP tool/direct function definitions change.
Files:
scripts/modules/task-manager/models.jsscripts/modules/ai-services-unified.jsscripts/modules/supported-models.jsonscripts/modules/config-manager.jsscripts/modules/commands.js
scripts/modules/task-manager/*
π CodeRabbit inference engine (.cursor/rules/tags.mdc)
scripts/modules/task-manager/*: All core functions in scripts/modules/task-manager/ must accept a context parameter and use it to extract projectRoot and tag
All core functions in scripts/modules/task-manager/ must use readJSON(tasksPath, projectRoot, tag) and writeJSON(tasksPath, data, projectRoot, tag)
Files:
scripts/modules/task-manager/models.js
scripts/modules/task-manager/**/*.js
π CodeRabbit inference engine (.cursor/rules/telemetry.mdc)
scripts/modules/task-manager/**/*.js: Functions in scripts/modules/task-manager/ that invoke AI services must call the appropriate AI service function (e.g., generateObjectService), passing commandName and outputType in the params object.
Core logic functions in scripts/modules/task-manager/ must return an object that includes aiServiceResponse.telemetryData.
If the core logic function handles CLI output (outputFormat === 'text' or 'cli'), and aiServiceResponse.telemetryData is available, it must call displayAiUsageSummary(aiServiceResponse.telemetryData, 'cli') from scripts/modules/ui.js.Do not call AI-specific getters (like
getMainModelId,getMainMaxTokens) from core logic functions inscripts/modules/task-manager/*; instead, pass theroleto the unified AI service.
Files:
scripts/modules/task-manager/models.js
scripts/modules/ai-services-unified.js
π CodeRabbit inference engine (.cursor/rules/ai_providers.mdc)
Integrate the new provider module with scripts/modules/ai-services-unified.js by importing it and adding an entry to the PROVIDER_FUNCTIONS map.
scripts/modules/ai-services-unified.js: Centralize all LLM calls throughgenerateTextServiceorgenerateObjectService.
Do not import or call anything from the oldai-services.js,ai-client-factory.js, orai-client-utils.jsfiles.
Do not fetch AI-specific parameters (model ID, max tokens, temp) usingconfig-manager.jsgetters for the AI call. Pass theroleinstead.
Do not implement fallback or retry logic outsideai-services-unified.js.
Do not handle API key resolution outside the service layer (it usesutils.jsinternally).The telemetryData object returned by ai-services-unified.js must include the fields: timestamp, userId, commandName, modelUsed, providerName, inputTokens, outputTokens, totalTokens, totalCost, and currency.
Files:
scripts/modules/ai-services-unified.js
scripts/modules/*.js
π CodeRabbit inference engine (.cursor/rules/architecture.mdc)
Each module in scripts/modules/ should be focused on a single responsibility, following the modular architecture (e.g., commands.js for CLI command handling, task-manager.js for task data and core logic, dependency-manager.js for dependency management, ui.js for CLI output formatting, ai-services-unified.js for AI service integration, config-manager.js for configuration management, utils.js for utility functions).
scripts/modules/*.js: Export all core functions, helper functions, and utility methods needed by your new function or command from their respective modules. Explicitly review the module's export block to ensure every required dependency is included.
Pass all required parameters to functions you call within your implementation and verify that direct function parameters match their core function counterparts.
Use consistent file naming conventions: 'task_${id.toString().padStart(3, '0')}.txt', use path.join for composing file paths, and use appropriate file extensions (.txt for tasks, .json for data).
Use structured error objects with code and message properties, include clear error messages, and handle both function-specific and file system errors.
Import all silent mode utilities together from 'scripts/modules/utils.js' and always use isSilentMode() to check global silent mode status. Wrap core function calls within direct functions using enableSilentMode() and disableSilentMode() in a try/finally block if the core function might produce console output.
Core functions should check outputFormat === 'text' before displaying UI elements and use internal logging that respects silent mode.
Design functions to accept dependencies as parameters (dependency injection) and avoid hard-coded dependencies that are difficult to mock.
Keep pure logic separate from I/O operations or UI rendering to allow testing the logic without mocking complex dependencies.
When implementing core logic for new features, do so in 'scripts/modules/' before CLI or MCP interfaces, and d...
Files:
scripts/modules/ai-services-unified.jsscripts/modules/config-manager.jsscripts/modules/commands.js
scripts/modules/ai-services*.js
π CodeRabbit inference engine (.cursor/rules/new_features.mdc)
Ensure AI calls correctly handle and propagate telemetryData as described in 'telemetry.mdc'.
Files:
scripts/modules/ai-services-unified.js
scripts/modules/*
π CodeRabbit inference engine (.cursor/rules/tags.mdc)
scripts/modules/*: Every command that reads or writes tasks.json must be tag-aware
All command files must import getCurrentTag from utils.js
Every CLI command that operates on tasks must include the --tag CLI option
All commands must resolve the tag using the pattern: options.tag || getCurrentTag(projectRoot) || 'master'
All commands must find projectRoot with error handling before proceeding
All commands must pass { projectRoot, tag } as context to core functions
MCP direct functions must accept and use a context object containing projectRoot and tag, and pass them to core functions
Do not hard-code tag resolution (e.g., const tag = options.tag || 'master';); always use getCurrentTag
Do not omit the --tag CLI option in commands that operate on tasks
Do not omit the context parameter when calling core functions from commands
Do not call readJSON or writeJSON without passing projectRoot and tag
Files:
scripts/modules/ai-services-unified.jsscripts/modules/supported-models.jsonscripts/modules/config-manager.jsscripts/modules/commands.js
package.json
π CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)
Add and update test scripts in package.json to include test, test:watch, test:coverage, test:unit, test:integration, test:e2e, and test:ci
Files:
package.json
scripts/modules/supported-models.json
π CodeRabbit inference engine (.cursor/rules/ai_providers.mdc)
Add a new key for the provider and an array of model objects under it in scripts/modules/supported-models.json, including id, name, allowed_roles, and optionally swe_score, cost_per_1m_tokens, and max_tokens.
Files:
scripts/modules/supported-models.json
scripts/modules/config-manager.js
π CodeRabbit inference engine (.cursor/rules/ai_providers.mdc)
scripts/modules/config-manager.js: Update scripts/modules/config-manager.js to add the new provider to MODEL_MAP, ensure it is included in VALID_PROVIDERS, and update API key handling logic.
If adding Ollama or another provider not requiring an API key, add a specific check at the beginning of isApiKeySet and getMcpApiKeyStatus in scripts/modules/config-manager.js to return true immediately for that provider.
scripts/modules/config-manager.js: Import and use specific getters fromscripts/modules/config-manager.jsto access configuration values needed for application logic; pass theexplicitRootparameter to getters if calling from MCP direct functions.
UseisApiKeySet(providerName, session)fromconfig-manager.jsto check if a provider's key is available before attempting an AI call.
Handle potentialConfigurationErrorif the.taskmasterconfigfile is missing or invalid when accessed viagetConfig.
Files:
scripts/modules/config-manager.js
tests/integration/**/*.test.js
π CodeRabbit inference engine (.cursor/rules/tests.mdc)
Integration tests must be located in tests/integration/, test interactions between modules, and focus on component interfaces rather than implementation details.
Files:
tests/integration/providers/temperature-support.test.js
tests/{integration,e2e}/**/*.test.js
π CodeRabbit inference engine (.cursor/rules/tests.mdc)
Properly mock session objects when required by functions, and reset environment variables between tests if modified.
Files:
tests/integration/providers/temperature-support.test.js
scripts/modules/commands.js
π CodeRabbit inference engine (.cursor/rules/ai_services.mdc)
scripts/modules/commands.js: Centralize all LLM calls throughgenerateTextServiceorgenerateObjectService.
Do not import or call anything from the oldai-services.js,ai-client-factory.js, orai-client-utils.jsfiles.
Do not fetch AI-specific parameters (model ID, max tokens, temp) usingconfig-manager.jsgetters for the AI call. Pass theroleinstead.
Do not implement fallback or retry logic outsideai-services-unified.js.
Do not handle API key resolution outside the service layer (it usesutils.jsinternally).
Determine the appropriaterole(main,research,fallback) in your core logic and pass it to the service.
Pass thesessionobject (received in thecontextparameter, especially from direct function wrappers) to the service call when in MCP context.
UsegenerateTextServiceand implement robust manual JSON parsing (with Zod validation after parsing) when structured output is needed, asgenerateObjectServicehas shown unreliability with some providers/schemas.
Be aware of potential reliability issues withgenerateObjectServiceacross different providers and complex schemas. PrefergenerateTextService+ manual parsing as a more robust alternative for structured data needs.
scripts/modules/commands.js: All new user-facing commands should be added to 'scripts/modules/commands.js'.
Use consistent patterns for option naming and help text in CLI commands.
Follow the Commander.js model for subcommand structure in CLI commands.
When using callbacks (like in Commander.js commands), define them separately to allow testing the callback logic independently.
Add help text to the command definition and update 'dev_workflow.mdc' with command reference when adding a new feature.
Follow the established pattern in 'commands.js' for CLI command implementation, using Commander.js for argument parsing, including comprehensive help text and examples, and supporting tagged task context awareness.
Provide clear error messages for common failu...
Files:
scripts/modules/commands.js
π§ Learnings (34)
π Common learnings
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1262
File: scripts/modules/task-manager/update-tasks.js:216-233
Timestamp: 2025-10-01T19:53:34.261Z
Learning: For scripts/modules/task-manager/*.js: Use generateObjectService with Zod schemas for structured AI responses rather than generateTextService + manual JSON parsing, as modern AI providers increasingly support the tool use and generateObject paradigm with improved reliability.
π Learning: 2025-07-18T17:07:39.336Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/architecture.mdc:0-0
Timestamp: 2025-07-18T17:07:39.336Z
Learning: Applies to src/ai-providers/*.js : Provider-specific wrappers for Vercel AI SDK functions must be implemented in src/ai-providers/*.js, each file corresponding to a provider.
Applied to files:
src/ai-providers/grok-cli.js
π Learning: 2025-07-18T17:06:04.909Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_providers.mdc:0-0
Timestamp: 2025-07-18T17:06:04.909Z
Learning: Applies to src/ai-providers/*.js : Provider modules must import the provider's create<ProviderName> function from ai-sdk/<provider-name>, and import generateText, streamText, generateObject from the core ai package, as well as the log utility from ../../scripts/modules/utils.js.
Applied to files:
src/ai-providers/grok-cli.jspackage.jsonsrc/ai-providers/codex-cli.jstests/unit/ai-services-unified.test.jssrc/ai-providers/index.jssrc/ai-providers/gemini-cli.jstests/unit/ai-providers/codex-cli.test.js
π Learning: 2025-07-18T17:06:04.909Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_providers.mdc:0-0
Timestamp: 2025-07-18T17:06:04.909Z
Learning: Applies to tests/unit/ai-providers/*.test.js : Create unit tests for the new provider in tests/unit/ai-providers/<provider-name>.test.js, mocking ai-sdk/<provider-name> and core ai module functions, and testing all exported functions for correct behavior and error handling.
Applied to files:
tests/unit/ai-providers/base-provider.test.jstests/unit/ai-services-unified.test.jstests/integration/providers/temperature-support.test.jstests/unit/ai-providers/codex-cli.test.js
π Learning: 2025-07-18T17:06:04.909Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_providers.mdc:0-0
Timestamp: 2025-07-18T17:06:04.909Z
Learning: Applies to src/ai-providers/*.js : Implement generate<ProviderName>Text, stream<ProviderName>Text, and generate<ProviderName>Object functions in provider modules with basic validation and try/catch error handling.
Applied to files:
tests/unit/ai-providers/base-provider.test.jssrc/ai-providers/base-provider.jstests/unit/ai-services-unified.test.js
π Learning: 2025-07-18T17:16:13.793Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-07-18T17:16:13.793Z
Learning: Applies to **/*.test.js : Do not import real AI service clients in tests; create fully mocked versions that return predictable responses.
Applied to files:
tests/unit/ai-providers/base-provider.test.jstests/unit/ai-services-unified.test.jstests/unit/ai-providers/codex-cli.test.js
π Learning: 2025-09-24T15:12:58.855Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: assets/AGENTS.md:0-0
Timestamp: 2025-09-24T15:12:58.855Z
Learning: Applies to assets/**/.mcp.json : Configure the Task Master MCP server in .mcp.json under mcpServers.task-master-ai using npx task-master-ai and provide required API key env vars
Applied to files:
docs/configuration.mdREADME.md
π Learning: 2025-07-18T17:10:12.881Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dev_workflow.mdc:0-0
Timestamp: 2025-07-18T17:10:12.881Z
Learning: For CLI usage, install Taskmaster globally with `npm install -g task-master-ai` or use locally via `npx task-master-ai ...`.
Applied to files:
README.mdscripts/modules/commands.js
π Learning: 2025-07-31T22:08:16.039Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/taskmaster.mdc:0-0
Timestamp: 2025-07-31T22:08:16.039Z
Learning: Applies to {.env,.cursor/mcp.json} : Set API keys for AI providers (e.g., ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.) in your .env file in the project root (for CLI use) or within the env section of your .cursor/mcp.json file (for MCP/Cursor integration).
Applied to files:
README.md
π Learning: 2025-07-18T17:06:04.909Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_providers.mdc:0-0
Timestamp: 2025-07-18T17:06:04.909Z
Learning: Applies to .cursor/mcp.json.example : Add the new PROVIDER_API_KEY with its placeholder to the env section for taskmaster-ai in .cursor/mcp.json.example.
Applied to files:
README.md
π Learning: 2025-09-29T13:33:46.952Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1246
File: src/ai-providers/claude-code.js:40-42
Timestamp: 2025-09-29T13:33:46.952Z
Learning: Claude Code provider should use CLAUDE_CODE_API_KEY environment variable instead of automatically picking up ANTHROPIC_API_KEY to avoid conflicts, since the ai-sdk-provider-claude-code package follows standard Anthropic patterns and prioritizes API keys over OAuth authentication, which can cause unexpected API charges.
Applied to files:
README.mdsrc/ai-providers/claude-code.js
π Learning: 2025-07-31T22:08:16.039Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/taskmaster.mdc:0-0
Timestamp: 2025-07-31T22:08:16.039Z
Learning: Applies to .cursor/mcp.json : When using MCP/Cursor integration, ensure that the required API keys are present in the env section of .cursor/mcp.json.
Applied to files:
README.md
π Learning: 2025-07-18T17:18:17.759Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-07-18T17:18:17.759Z
Learning: Applies to {.env,.cursor/mcp.json} : Store API keys only in `.env` (for CLI, loaded by `dotenv` in `scripts/dev.js`) or `.cursor/mcp.json` (for MCP, accessed via `session.env`).
Applied to files:
README.md
π Learning: 2025-07-18T17:10:12.881Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dev_workflow.mdc:0-0
Timestamp: 2025-07-18T17:10:12.881Z
Learning: Applies to {.env,.cursor/mcp.json} : Store sensitive API keys and specific endpoint URLs in the `.env` file in the project root for CLI usage, or in the `env` section of `.cursor/mcp.json` for MCP/Cursor integration. Do not store non-API key settings in these files.
Applied to files:
README.md
π Learning: 2025-07-18T17:10:02.683Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dev_workflow.mdc:0-0
Timestamp: 2025-07-18T17:10:02.683Z
Learning: Applies to {.env,.cursor/mcp.json} : Store sensitive API keys and endpoint URLs for Taskmaster in a `.env` file (for CLI usage) or in the `env` section of `.cursor/mcp.json` (for MCP/Cursor integration). Do not store non-API key settings in these files.
Applied to files:
README.md
π Learning: 2025-08-03T12:13:33.875Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-08-03T12:13:33.875Z
Learning: Applies to package.json : Add and update test scripts in package.json to include test, test:watch, test:coverage, test:unit, test:integration, test:e2e, and test:ci
Applied to files:
package.json
π Learning: 2025-09-26T19:03:33.225Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1252
File: package.json:130-132
Timestamp: 2025-09-26T19:03:33.225Z
Learning: In the eyaltoledano/claude-task-master repository, packages are bundled using tsdown during the build process, which means dependencies imported by the source code (including tm internal packages like tm/ai-sdk-provider-grok-cli) are included in the final bundle and don't need to be available as separate runtime dependencies, so they should remain as devDependencies rather than being moved to dependencies.
Applied to files:
package.json
π Learning: 2025-07-18T17:06:04.909Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_providers.mdc:0-0
Timestamp: 2025-07-18T17:06:04.909Z
Learning: Applies to scripts/modules/supported-models.json : Add a new key for the provider and an array of model objects under it in scripts/modules/supported-models.json, including id, name, allowed_roles, and optionally swe_score, cost_per_1m_tokens, and max_tokens.
Applied to files:
scripts/modules/supported-models.json
π Learning: 2025-07-18T17:06:04.909Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_providers.mdc:0-0
Timestamp: 2025-07-18T17:06:04.909Z
Learning: Applies to scripts/modules/config-manager.js : Update scripts/modules/config-manager.js to add the new provider to MODEL_MAP, ensure it is included in VALID_PROVIDERS, and update API key handling logic.
Applied to files:
scripts/modules/config-manager.js
π Learning: 2025-07-18T17:16:13.793Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-07-18T17:16:13.793Z
Learning: Applies to **/*.test.js : Never use asynchronous operations in tests. Make all mocks return synchronous values when possible.
Applied to files:
CLAUDE.md
π Learning: 2025-07-18T17:10:53.657Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/glossary.mdc:0-0
Timestamp: 2025-07-18T17:10:53.657Z
Learning: Guidelines for implementing and maintaining tests for Task Master CLI (tests.mdc).
Applied to files:
CLAUDE.md
π Learning: 2025-08-11T12:30:23.843Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-11T12:30:23.843Z
Learning: Import Task Master's development workflow commands and guidelines; treat the contents of ./.taskmaster/CLAUDE.md as if included in the main CLAUDE.md
Applied to files:
CLAUDE.md
π Learning: 2025-07-18T17:16:13.793Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-07-18T17:16:13.793Z
Learning: Applies to tests/{unit,integration,e2e}/**/*.test.js : Use sample task fixtures for consistent test data, mock file system operations, and test both success and error paths for task operations.
Applied to files:
CLAUDE.md
π Learning: 2025-07-18T17:16:13.793Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-07-18T17:16:13.793Z
Learning: Applies to **/*.test.js : Follow the test file organization: mocks must be set up before importing modules under test, and spies on mocked modules should be set up after imports.
Applied to files:
CLAUDE.md
π Learning: 2025-07-18T17:07:39.336Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/architecture.mdc:0-0
Timestamp: 2025-07-18T17:07:39.336Z
Learning: Applies to tests/{unit,integration,e2e,fixtures}/**/*.js : Test files must be organized as follows: unit tests in tests/unit/, integration tests in tests/integration/, end-to-end tests in tests/e2e/, and test fixtures in tests/fixtures/.
Applied to files:
CLAUDE.md
π Learning: 2025-07-18T17:12:57.903Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-07-18T17:12:57.903Z
Learning: Applies to scripts/modules/**/*.test.js : Test core logic independently with both data formats, mock file system operations, test tag resolution behavior, and verify migration compatibility in unit tests.
Applied to files:
CLAUDE.md
π Learning: 2025-07-18T17:12:57.903Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-07-18T17:12:57.903Z
Learning: Applies to scripts/modules/**/*.test.js : Test CLI and MCP interfaces with real task data, verify end-to-end workflows across tag contexts, and test error scenarios and recovery in integration tests.
Applied to files:
CLAUDE.md
π Learning: 2025-07-18T17:16:13.793Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-07-18T17:16:13.793Z
Learning: Applies to **/*.test.js : Mock API calls (e.g., Anthropic/Claude) by mocking the entire module and providing predictable responses.
Applied to files:
tests/unit/ai-services-unified.test.jstests/unit/ai-providers/codex-cli.test.js
π Learning: 2025-07-18T17:06:04.909Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_providers.mdc:0-0
Timestamp: 2025-07-18T17:06:04.909Z
Learning: Applies to src/ai-providers/*.js : Create a new provider module file in src/ai-providers/ named <provider-name>.js when adding a new AI provider.
Applied to files:
src/ai-providers/index.js
π Learning: 2025-07-18T17:06:57.833Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_services.mdc:0-0
Timestamp: 2025-07-18T17:06:57.833Z
Learning: Ensure `.taskmasterconfig` exists and has valid provider/model IDs for the roles you intend to use (manage via `task-master models --setup`).
Applied to files:
docs/command-reference.md
π Learning: 2025-07-31T22:08:16.039Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/taskmaster.mdc:0-0
Timestamp: 2025-07-31T22:08:16.039Z
Learning: Applies to .taskmaster/config.json : All other Taskmaster settings (model choice, max tokens, temperature, log level, custom endpoints) are managed in .taskmaster/config.json via the task-master models command or models MCP tool.
Applied to files:
docs/command-reference.mdscripts/modules/commands.js
π Learning: 2025-07-18T17:12:57.903Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-07-18T17:12:57.903Z
Learning: Applies to scripts/modules/commands.js : Use consistent patterns for option naming and help text in CLI commands.
Applied to files:
scripts/modules/commands.js
π Learning: 2025-09-29T13:33:46.952Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1246
File: src/ai-providers/claude-code.js:40-42
Timestamp: 2025-09-29T13:33:46.952Z
Learning: Claude Code provider should use environment variable isolation to control API key access, temporarily managing ANTHROPIC_API_KEY during client creation to prevent the ai-sdk-provider-claude-code package from automatically picking up API keys intended for other providers, while allowing explicit CLAUDE_CODE_API_KEY usage as a fallback to OAuth authentication.
Applied to files:
src/ai-providers/claude-code.js
π Learning: 2025-09-29T13:33:46.952Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1246
File: src/ai-providers/claude-code.js:40-42
Timestamp: 2025-09-29T13:33:46.952Z
Learning: Claude Code provider should use environment variable isolation to temporarily manage ANTHROPIC_API_KEY during client creation: if CLAUDE_CODE_API_KEY is set, temporarily set ANTHROPIC_API_KEY to that value; if CLAUDE_CODE_API_KEY is not set but ANTHROPIC_API_KEY exists, temporarily unset ANTHROPIC_API_KEY to force OAuth mode. This prevents the ai-sdk-provider-claude-code package from accidentally using API keys intended for the regular Anthropic provider while still allowing explicit API key usage as a fallback.
Applied to files:
src/ai-providers/claude-code.js
𧬠Code graph analysis (14)
tests/unit/config-manager.test.js (1)
tests/unit/config-manager.test.mjs (1)
DEFAULT_CONFIG(61-90)
src/ai-providers/grok-cli.js (2)
packages/ai-sdk-provider-grok-cli/src/grok-cli-provider.ts (1)
GrokCliProvider(13-35)src/ai-providers/base-provider.js (1)
BaseAIProvider(16-377)
tests/unit/ai-providers/base-provider.test.js (1)
src/ai-providers/base-provider.js (1)
BaseAIProvider(16-377)
scripts/modules/task-manager/models.js (2)
mcp-server/src/core/direct-functions/models.js (1)
providerHint(41-41)src/constants/providers.js (2)
CUSTOM_PROVIDERS(18-29)CUSTOM_PROVIDERS(18-29)
scripts/modules/ai-services-unified.js (5)
src/ai-providers/codex-cli.js (1)
CodexCliProvider(15-106)scripts/modules/config-manager.js (2)
providerName(704-704)modelId(703-703)scripts/modules/update-config-tokens.js (2)
modelId(25-25)modelData(29-31)scripts/modules/task-manager/parse-prd/parse-prd-streaming.js (1)
modelId(236-236)scripts/modules/task-manager/models.js (1)
modelData(426-426)
src/ai-providers/codex-cli.js (2)
src/ai-providers/base-provider.js (1)
BaseAIProvider(16-377)scripts/modules/config-manager.js (3)
settings(445-445)settings(455-455)settings(471-471)
scripts/modules/config-manager.js (2)
src/constants/commands.js (2)
AI_COMMAND_NAMES(7-17)AI_COMMAND_NAMES(7-17)src/constants/providers.js (2)
CUSTOM_PROVIDERS(18-29)CUSTOM_PROVIDERS(18-29)
src/ai-providers/base-provider.js (4)
scripts/modules/task-manager/parse-prd/parse-prd-streaming.js (3)
inputTokens(592-593)result(559-568)outputTokens(589-591)scripts/modules/ai-services-unified.js (2)
result(430-430)totalTokens(894-894)scripts/modules/task-manager/parse-prd/parse-prd-helpers.js (1)
outputTokens(278-280)scripts/modules/task-manager/parse-prd/parse-prd.js (1)
outputTokens(154-154)
tests/unit/ai-services-unified.test.js (2)
tests/unit/config-manager.test.mjs (1)
mockResolveEnvVariable(44-44)scripts/modules/ai-services-unified.js (1)
result(430-430)
tests/integration/providers/temperature-support.test.js (4)
src/ai-providers/claude-code.js (1)
ClaudeCodeProvider(30-129)src/ai-providers/codex-cli.js (1)
CodexCliProvider(15-106)src/ai-providers/gemini-cli.js (1)
GeminiCliProvider(14-651)src/ai-providers/grok-cli.js (1)
GrokCliProvider(10-83)
src/ai-providers/gemini-cli.js (1)
src/ai-providers/base-provider.js (1)
BaseAIProvider(16-377)
scripts/modules/commands.js (1)
scripts/modules/task-manager/models.js (4)
options(149-149)options(277-277)options(368-368)options(656-656)
src/ai-providers/claude-code.js (2)
src/ai-providers/base-provider.js (1)
BaseAIProvider(16-377)scripts/modules/config-manager.js (4)
settings(445-445)settings(455-455)settings(471-471)modelId(703-703)
tests/unit/ai-providers/codex-cli.test.js (1)
src/ai-providers/codex-cli.js (1)
CodexCliProvider(15-106)
πͺ markdownlint-cli2 (0.18.1)
docs/providers/codex-cli.md
92-92: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
350-350: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
355-355: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
360-360: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
374-374: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
379-379: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
385-385: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
400-400: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
405-405: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
410-410: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
412-412: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
444-444: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
454-454: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
469-469: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
478-478: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
487-487: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
.changeset/brave-lions-sing.md
5-5: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
docs/configuration.md
443-443: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
448-448: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
450-450: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
455-455: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
458-458: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
462-462: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
518-518: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
540-540: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
CLAUDE.md
9-9: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
14-14: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
| ## Test Guidelines | ||
|
|
||
| ### Synchronous Tests | ||
| - **NEVER use async/await in test functions** unless testing actual asynchronous operations | ||
| - Use synchronous top-level imports instead of dynamic `await import()` | ||
| - Test bodies should be synchronous whenever possible | ||
| - Example: | ||
| ```javascript | ||
| // β CORRECT - Synchronous imports | ||
| import { MyClass } from '../src/my-class.js'; | ||
|
|
||
| it('should verify behavior', () => { | ||
| expect(new MyClass().property).toBe(value); | ||
| }); | ||
|
|
||
| // β INCORRECT - Async imports | ||
| it('should verify behavior', async () => { | ||
| const { MyClass } = await import('../src/my-class.js'); | ||
| expect(new MyClass().property).toBe(value); | ||
| }); | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix markdownlint violations in new section.
markdownlint is failing this block (MD022, MD031). Add a blank line before the ## Test Guidelines heading and surround the fenced code block with blank lines so the list item renders correctly.
-**Import Task Master's development workflow commands and guidelines, treat as if import is in the main CLAUDE.md file.**
-@./.taskmaster/CLAUDE.md
-
-## Test Guidelines
+**Import Task Master's development workflow commands and guidelines, treat as if import is in the main CLAUDE.md file.**
+@./.taskmaster/CLAUDE.md
+
+
+## Test Guidelines
@@
-- Example:
- ```javascript
+- Example:
+
+ ```javascript
@@
- ```
+ ```
+π§° Tools
πͺ markdownlint-cli2 (0.18.1)
9-9: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
14-14: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
π€ Prompt for AI Agents
In CLAUDE.md around lines 7 to 27, the new "## Test Guidelines" section is
causing markdownlint errors (MD022, MD031) because there is no blank line before
the heading and the fenced code block inside the list item isnβt surrounded by
blank lines; add a single blank line immediately before the "## Test Guidelines"
heading, and insert a blank line after the "Example:" list item line and another
blank line after the closing ``` fence (preserving list indentation) so the
fenced code block is separated from the list and renders correctly.
| ### Codex CLI Provider | ||
|
|
||
| The Codex CLI provider integrates Task Master with OpenAI's Codex CLI, allowing you to use ChatGPT subscription models via OAuth authentication. | ||
|
|
||
| 1. **Prerequisites**: | ||
| - Node.js >= 18 | ||
| - Codex CLI >= 0.42.0 (>= 0.44.0 recommended) | ||
| - ChatGPT subscription: Plus, Pro, Business, Edu, or Enterprise (for OAuth access to GPT-5 models) | ||
|
|
||
| 2. **Installation**: | ||
| ```bash | ||
| npm install -g @openai/codex | ||
| ``` | ||
|
|
||
| 3. **Authentication** (OAuth - Primary Method): | ||
| ```bash | ||
| codex login | ||
| ``` | ||
| This will open a browser window for OAuth authentication with your ChatGPT account. Once authenticated, Task Master will automatically use these credentials. | ||
|
|
||
| 4. **Optional API Key Method**: | ||
| While OAuth is the primary and recommended authentication method, you can optionally set an OpenAI API key: | ||
| ```bash | ||
| # In .env file | ||
| OPENAI_API_KEY=sk-your-openai-api-key-here | ||
| ``` | ||
| **Note**: The API key will only be injected if explicitly provided. OAuth is always preferred. | ||
|
|
||
| 5. **Configuration**: | ||
| ```json | ||
| // In .taskmaster/config.json | ||
| { | ||
| "models": { | ||
| "main": { | ||
| "provider": "codex-cli", | ||
| "modelId": "gpt-5-codex", | ||
| "maxTokens": 128000, | ||
| "temperature": 0.2 | ||
| }, | ||
| "fallback": { | ||
| "provider": "codex-cli", | ||
| "modelId": "gpt-5", | ||
| "maxTokens": 128000, | ||
| "temperature": 0.2 | ||
| } | ||
| }, | ||
| "codexCli": { | ||
| "allowNpx": true, | ||
| "skipGitRepoCheck": true, | ||
| "approvalMode": "on-failure", | ||
| "sandboxMode": "workspace-write" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| 6. **Available Models**: | ||
| - `gpt-5` - Latest GPT-5 model (272K max input, 128K max output) | ||
| - `gpt-5-codex` - GPT-5 optimized for agentic software engineering (272K max input, 128K max output) | ||
|
|
||
| 7. **Codex CLI Settings (`codexCli` section)**: | ||
|
|
||
| The `codexCli` section in your configuration file supports the following options: | ||
|
|
||
| - **`allowNpx`** (boolean, default: `false`): Allow fallback to `npx @openai/codex` if CLI not found on PATH | ||
| - **`skipGitRepoCheck`** (boolean, default: `false`): Skip git repository safety check (recommended for CI/non-repo usage) | ||
| - **`approvalMode`** (string): Control command execution approval | ||
| - `"untrusted"`: Require approval for all commands | ||
| - `"on-failure"`: Only require approval after a command fails (default) | ||
| - `"on-request"`: Approve only when explicitly requested | ||
| - `"never"`: Never require approval (not recommended) | ||
| - **`sandboxMode`** (string): Control filesystem access | ||
| - `"read-only"`: Read-only access | ||
| - `"workspace-write"`: Allow writes to workspace (default) | ||
| - `"danger-full-access"`: Full filesystem access (use with caution) | ||
| - **`codexPath`** (string, optional): Custom path to codex CLI executable | ||
| - **`cwd`** (string, optional): Working directory for Codex CLI execution | ||
| - **`fullAuto`** (boolean, optional): Fully automatic mode (equivalent to `--full-auto` flag) | ||
| - **`dangerouslyBypassApprovalsAndSandbox`** (boolean, optional): Bypass all safety checks (dangerous!) | ||
| - **`color`** (string, optional): Color handling - `"always"`, `"never"`, or `"auto"` | ||
| - **`outputLastMessageFile`** (string, optional): Write last agent message to specified file | ||
| - **`verbose`** (boolean, optional): Enable verbose logging | ||
| - **`env`** (object, optional): Additional environment variables for Codex CLI | ||
|
|
||
| 8. **Command-Specific Settings** (optional): | ||
| You can override settings for specific Task Master commands: | ||
| ```json | ||
| { | ||
| "codexCli": { | ||
| "allowNpx": true, | ||
| "approvalMode": "on-failure", | ||
| "commandSpecific": { | ||
| "parse-prd": { | ||
| "approvalMode": "never", | ||
| "verbose": true | ||
| }, | ||
| "expand": { | ||
| "sandboxMode": "read-only" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| 9. **Codebase Features**: | ||
| The Codex CLI provider is codebase-capable, meaning it can analyze and interact with your project files. Codebase analysis features are automatically enabled when using `codex-cli` as your provider and `enableCodebaseAnalysis` is set to `true` in your global configuration (default). | ||
|
|
||
| 10. **Setup Commands**: | ||
| ```bash | ||
| # Set Codex CLI for main role | ||
| task-master models --set-main gpt-5-codex --codex-cli | ||
|
|
||
| # Set Codex CLI for fallback role | ||
| task-master models --set-fallback gpt-5 --codex-cli | ||
|
|
||
| # Verify configuration | ||
| task-master models | ||
| ``` | ||
|
|
||
| 11. **Troubleshooting**: | ||
|
|
||
| **"codex: command not found" error:** | ||
| - Install Codex CLI globally: `npm install -g @openai/codex` | ||
| - Verify installation: `codex --version` | ||
| - Alternatively, enable `allowNpx: true` in your codexCli configuration | ||
|
|
||
| **"Not logged in" errors:** | ||
| - Run `codex login` to authenticate with your ChatGPT account | ||
| - Verify authentication status: `codex` (opens interactive CLI) | ||
|
|
||
| **"Old version" warnings:** | ||
| - Check version: `codex --version` | ||
| - Upgrade: `npm install -g @openai/codex@latest` | ||
| - Minimum version: 0.42.0, recommended: >= 0.44.0 | ||
|
|
||
| **"Model not available" errors:** | ||
| - Only `gpt-5` and `gpt-5-codex` are available via OAuth subscription | ||
| - Verify your ChatGPT subscription is active | ||
| - For other OpenAI models, use the standard `openai` provider with an API key | ||
|
|
||
| **API key not being used:** | ||
| - API key is only injected when explicitly provided | ||
| - OAuth authentication is always preferred | ||
| - If you want to use an API key, ensure `OPENAI_API_KEY` is set in your `.env` file | ||
|
|
||
| 12. **Important Notes**: | ||
| - OAuth subscription required for model access (no API key needed for basic operation) | ||
| - Limited to OAuth-available models only (`gpt-5` and `gpt-5-codex`) | ||
| - Pricing information is not available for OAuth models (shows as "Unknown" in cost calculations) | ||
| - See [Codex CLI Provider Documentation](./providers/codex-cli.md) for more details |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Nitpick | π΅ Trivial
LGTM! Comprehensive Codex CLI provider documentation.
The Codex CLI Provider section is thorough, covering prerequisites, authentication, configuration, models, features, and troubleshooting. Well-organized for user reference.
Optional: Fix markdown formatting issues.
Static analysis detected missing blank lines around several fenced code blocks (lines 443, 448, 450, 455, 458, 462, 518, 540). While minor, adding blank lines would improve markdown consistency:
2. **Installation**:
+
```bash
npm install -g @openai/codex
```
+
3. **Authentication** (OAuth - Primary Method):Apply similar fixes to other flagged locations for consistency with markdown best practices.
π§° Tools
πͺ markdownlint-cli2 (0.18.1)
443-443: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
448-448: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
450-450: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
455-455: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
458-458: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
462-462: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
518-518: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
540-540: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
π€ Prompt for AI Agents
docs/configuration.md lines 433-581: Several fenced code blocks lack surrounding
blank lines (reported at ~443, 448, 450, 455, 458, 462, 518, 540); update the
markdown by ensuring there is a blank line before each opening ``` and a blank
line after each closing ``` for those blocks (and any other fenced blocks in
this range) so the fenced code blocks are properly separated from surrounding
text and render consistently.
| # Codex CLI Provider | ||
|
|
||
| The `codex-cli` provider integrates Task Master with OpenAI's Codex CLI via the community AI SDK provider [`ai-sdk-provider-codex-cli`](https://github.com/ben-vargas/ai-sdk-provider-codex-cli). It uses your ChatGPT subscription (OAuth) via `codex login`, with optional `OPENAI_CODEX_API_KEY` support. | ||
|
|
||
| ## Why Use Codex CLI? | ||
|
|
||
| The primary benefits of using the `codex-cli` provider include: | ||
|
|
||
| - **Use Latest OpenAI Models**: Access to cutting-edge models like GPT-5 and GPT-5-Codex via ChatGPT subscription | ||
| - **OAuth Authentication**: No API key management needed - authenticate once with `codex login` | ||
| - **Built-in Tool Execution**: Native support for command execution, file changes, MCP tools, and web search | ||
| - **Native JSON Schema Support**: Structured output generation without post-processing | ||
| - **Approval/Sandbox Modes**: Fine-grained control over command execution and filesystem access for safety | ||
|
|
||
| ## Quickstart | ||
|
|
||
| Get up and running with Codex CLI in 3 steps: | ||
|
|
||
| ```bash | ||
| # 1. Install Codex CLI globally | ||
| npm install -g @openai/codex | ||
|
|
||
| # 2. Authenticate with your ChatGPT account | ||
| codex login | ||
|
|
||
| # 3. Configure Task Master to use Codex CLI | ||
| task-master models --set-main gpt-5-codex --codex-cli | ||
| ``` | ||
|
|
||
| ## Requirements | ||
|
|
||
| - **Node.js**: >= 18.0.0 | ||
| - **Codex CLI**: >= 0.42.0 (>= 0.44.0 recommended) | ||
| - **ChatGPT Subscription**: Required for OAuth access (Plus, Pro, Business, Edu, or Enterprise) | ||
| - **Task Master**: >= 0.27.3 (version with Codex CLI support) | ||
|
|
||
| ### Checking Your Versions | ||
|
|
||
| ```bash | ||
| # Check Node.js version | ||
| node --version | ||
|
|
||
| # Check Codex CLI version | ||
| codex --version | ||
|
|
||
| # Check Task Master version | ||
| task-master --version | ||
| ``` | ||
|
|
||
| ## Installation | ||
|
|
||
| ### Install Codex CLI | ||
|
|
||
| ```bash | ||
| # Install globally via npm | ||
| npm install -g @openai/codex | ||
|
|
||
| # Verify installation | ||
| codex --version | ||
| ``` | ||
|
|
||
| Expected output: `v0.44.0` or higher | ||
|
|
||
| ### Install Task Master (if not already installed) | ||
|
|
||
| ```bash | ||
| # Install globally | ||
| npm install -g task-master-ai | ||
|
|
||
| # Or install in your project | ||
| npm install --save-dev task-master-ai | ||
| ``` | ||
|
|
||
| ## Authentication | ||
|
|
||
| ### OAuth Authentication (Primary Method - Recommended) | ||
|
|
||
| The Codex CLI provider is designed to use OAuth authentication with your ChatGPT subscription: | ||
|
|
||
| ```bash | ||
| # Launch Codex CLI and authenticate | ||
| codex login | ||
| ``` | ||
|
|
||
| This will: | ||
| 1. Open a browser window for OAuth authentication | ||
| 2. Prompt you to log in with your ChatGPT account | ||
| 3. Store authentication credentials locally | ||
| 4. Allow Task Master to automatically use these credentials | ||
|
|
||
| To verify your authentication: | ||
| ```bash | ||
| # Open interactive Codex CLI | ||
| codex | ||
|
|
||
| # Use /about command to see auth status | ||
| /about | ||
| ``` | ||
|
|
||
| ### Optional: API Key Method | ||
|
|
||
| While OAuth is the primary and recommended method, you can optionally use an OpenAI API key: | ||
|
|
||
| ```bash | ||
| # In your .env file | ||
| OPENAI_CODEX_API_KEY=sk-your-openai-api-key-here | ||
| ``` | ||
|
|
||
| **Important Notes**: | ||
| - The API key will **only** be injected when explicitly provided | ||
| - OAuth authentication is always preferred when available | ||
| - Using an API key doesn't provide access to subscription-only models like GPT-5-Codex | ||
| - For full OpenAI API access with non-subscription models, consider using the standard `openai` provider instead | ||
| - `OPENAI_CODEX_API_KEY` is specific to the codex-cli provider to avoid conflicts with the `openai` provider's `OPENAI_API_KEY` | ||
|
|
||
| ## Available Models | ||
|
|
||
| The Codex CLI provider supports only models available through ChatGPT subscription: | ||
|
|
||
| | Model ID | Description | Max Input Tokens | Max Output Tokens | | ||
| |----------|-------------|------------------|-------------------| | ||
| | `gpt-5` | Latest GPT-5 model | 272K | 128K | | ||
| | `gpt-5-codex` | GPT-5 optimized for agentic software engineering | 272K | 128K | | ||
|
|
||
| **Note**: These models are only available via OAuth subscription through Codex CLI (ChatGPT Plus, Pro, Business, Edu, or Enterprise plans). For other OpenAI models, use the standard `openai` provider with an API key. | ||
|
|
||
| **Research Capabilities**: Both GPT-5 models support web search tools, making them suitable for the `research` role in addition to `main` and `fallback` roles. | ||
|
|
||
| ## Configuration | ||
|
|
||
| ### Basic Configuration | ||
|
|
||
| Add Codex CLI to your `.taskmaster/config.json`: | ||
|
|
||
| ```json | ||
| { | ||
| "models": { | ||
| "main": { | ||
| "provider": "codex-cli", | ||
| "modelId": "gpt-5-codex", | ||
| "maxTokens": 128000, | ||
| "temperature": 0.2 | ||
| }, | ||
| "fallback": { | ||
| "provider": "codex-cli", | ||
| "modelId": "gpt-5", | ||
| "maxTokens": 128000, | ||
| "temperature": 0.2 | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Advanced Configuration with Codex CLI Settings | ||
|
|
||
| The `codexCli` section allows you to customize Codex CLI behavior: | ||
|
|
||
| ```json | ||
| { | ||
| "models": { | ||
| "main": { | ||
| "provider": "codex-cli", | ||
| "modelId": "gpt-5-codex", | ||
| "maxTokens": 128000, | ||
| "temperature": 0.2 | ||
| } | ||
| }, | ||
| "codexCli": { | ||
| "allowNpx": true, | ||
| "skipGitRepoCheck": true, | ||
| "approvalMode": "on-failure", | ||
| "sandboxMode": "workspace-write", | ||
| "verbose": false | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Codex CLI Settings Reference | ||
|
|
||
| #### Core Settings | ||
|
|
||
| - **`allowNpx`** (boolean, default: `false`) | ||
| - Allow fallback to `npx @openai/codex` if the CLI is not found on PATH | ||
| - Useful for CI environments or systems without global npm installations | ||
| - Example: `"allowNpx": true` | ||
|
|
||
| - **`skipGitRepoCheck`** (boolean, default: `false`) | ||
| - Skip git repository safety check before execution | ||
| - Recommended for CI environments or non-repository usage | ||
| - Example: `"skipGitRepoCheck": true` | ||
|
|
||
| #### Execution Control | ||
|
|
||
| - **`approvalMode`** (string) | ||
| - Controls when to require user approval for command execution | ||
| - Options: | ||
| - `"untrusted"`: Require approval for all commands | ||
| - `"on-failure"`: Only require approval after a command fails (default) | ||
| - `"on-request"`: Approve only when explicitly requested | ||
| - `"never"`: Never require approval (use with caution) | ||
| - Example: `"approvalMode": "on-failure"` | ||
|
|
||
| - **`sandboxMode`** (string) | ||
| - Controls filesystem access permissions | ||
| - Options: | ||
| - `"read-only"`: Read-only access to filesystem | ||
| - `"workspace-write"`: Allow writes to workspace directory (default) | ||
| - `"danger-full-access"`: Full filesystem access (use with extreme caution) | ||
| - Example: `"sandboxMode": "workspace-write"` | ||
|
|
||
| #### Path and Environment | ||
|
|
||
| - **`codexPath`** (string, optional) | ||
| - Custom path to Codex CLI executable | ||
| - Useful when Codex is installed in a non-standard location | ||
| - Example: `"codexPath": "/usr/local/bin/codex"` | ||
|
|
||
| - **`cwd`** (string, optional) | ||
| - Working directory for Codex CLI execution | ||
| - Defaults to current working directory | ||
| - Example: `"cwd": "/path/to/project"` | ||
|
|
||
| - **`env`** (object, optional) | ||
| - Additional environment variables for Codex CLI | ||
| - Example: `"env": { "DEBUG": "true" }` | ||
|
|
||
| #### Advanced Settings | ||
|
|
||
| - **`fullAuto`** (boolean, optional) | ||
| - Fully automatic mode (equivalent to `--full-auto` flag) | ||
| - Bypasses most approvals for fully automated workflows | ||
| - Example: `"fullAuto": true` | ||
|
|
||
| - **`dangerouslyBypassApprovalsAndSandbox`** (boolean, optional) | ||
| - Bypass all safety checks including approvals and sandbox | ||
| - **WARNING**: Use with extreme caution - can execute arbitrary code | ||
| - Example: `"dangerouslyBypassApprovalsAndSandbox": false` | ||
|
|
||
| - **`color`** (string, optional) | ||
| - Force color handling in Codex CLI output | ||
| - Options: `"always"`, `"never"`, `"auto"` | ||
| - Example: `"color": "auto"` | ||
|
|
||
| - **`outputLastMessageFile`** (string, optional) | ||
| - Write last agent message to specified file | ||
| - Useful for debugging or logging | ||
| - Example: `"outputLastMessageFile": "./last-message.txt"` | ||
|
|
||
| - **`verbose`** (boolean, optional) | ||
| - Enable verbose provider logging | ||
| - Helpful for debugging issues | ||
| - Example: `"verbose": true` | ||
|
|
||
| ### Command-Specific Settings | ||
|
|
||
| Override settings for specific Task Master commands: | ||
|
|
||
| ```json | ||
| { | ||
| "codexCli": { | ||
| "allowNpx": true, | ||
| "approvalMode": "on-failure", | ||
| "commandSpecific": { | ||
| "parse-prd": { | ||
| "approvalMode": "never", | ||
| "verbose": true | ||
| }, | ||
| "expand": { | ||
| "sandboxMode": "read-only" | ||
| }, | ||
| "add-task": { | ||
| "approvalMode": "untrusted" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Usage | ||
|
|
||
| ### Setting Codex CLI Models | ||
|
|
||
| ```bash | ||
| # Set Codex CLI for main role | ||
| task-master models --set-main gpt-5-codex --codex-cli | ||
|
|
||
| # Set Codex CLI for fallback role | ||
| task-master models --set-fallback gpt-5 --codex-cli | ||
|
|
||
| # Set Codex CLI for research role | ||
| task-master models --set-research gpt-5 --codex-cli | ||
|
|
||
| # Verify configuration | ||
| task-master models | ||
| ``` | ||
|
|
||
| ### Using Codex CLI with Task Master Commands | ||
|
|
||
| Once configured, use Task Master commands as normal: | ||
|
|
||
| ```bash | ||
| # Parse a PRD with Codex CLI | ||
| task-master parse-prd my-requirements.txt | ||
|
|
||
| # Analyze project complexity | ||
| task-master analyze-complexity --research | ||
|
|
||
| # Expand a task into subtasks | ||
| task-master expand --id=1.2 | ||
|
|
||
| # Add a new task with AI assistance | ||
| task-master add-task --prompt="Implement user authentication" --research | ||
| ``` | ||
|
|
||
| The provider will automatically use your OAuth credentials when Codex CLI is configured. | ||
|
|
||
| ## Codebase Features | ||
|
|
||
| The Codex CLI provider is **codebase-capable**, meaning it can analyze and interact with your project files. This enables advanced features like: | ||
|
|
||
| - **Code Analysis**: Understanding your project structure and dependencies | ||
| - **Intelligent Suggestions**: Context-aware task recommendations | ||
| - **File Operations**: Reading and analyzing project files for better task generation | ||
| - **Pattern Recognition**: Identifying common patterns and best practices in your codebase | ||
|
|
||
| ### Enabling Codebase Analysis | ||
|
|
||
| Codebase analysis is automatically enabled when: | ||
| 1. Your provider is set to `codex-cli` | ||
| 2. `enableCodebaseAnalysis` is `true` in your global configuration (default) | ||
|
|
||
| To verify or configure: | ||
|
|
||
| ```json | ||
| { | ||
| "global": { | ||
| "enableCodebaseAnalysis": true | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### "codex: command not found" Error | ||
|
|
||
| **Symptoms**: Task Master reports that the Codex CLI is not found. | ||
|
|
||
| **Solutions**: | ||
| 1. **Install Codex CLI globally**: | ||
| ```bash | ||
| npm install -g @openai/codex | ||
| ``` | ||
|
|
||
| 2. **Verify installation**: | ||
| ```bash | ||
| codex --version | ||
| ``` | ||
|
|
||
| 3. **Alternative: Enable npx fallback**: | ||
| ```json | ||
| { | ||
| "codexCli": { | ||
| "allowNpx": true | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### "Not logged in" Errors | ||
|
|
||
| **Symptoms**: Authentication errors when trying to use Codex CLI. | ||
|
|
||
| **Solutions**: | ||
| 1. **Authenticate with OAuth**: | ||
| ```bash | ||
| codex login | ||
| ``` | ||
|
|
||
| 2. **Verify authentication status**: | ||
| ```bash | ||
| codex | ||
| # Then use /about command | ||
| ``` | ||
|
|
||
| 3. **Re-authenticate if needed**: | ||
| ```bash | ||
| # Logout first | ||
| codex | ||
| # Use /auth command to change auth method | ||
|
|
||
| # Then login again | ||
| codex login | ||
| ``` | ||
|
|
||
| ### "Old version" Warnings | ||
|
|
||
| **Symptoms**: Warnings about Codex CLI version being outdated. | ||
|
|
||
| **Solutions**: | ||
| 1. **Check current version**: | ||
| ```bash | ||
| codex --version | ||
| ``` | ||
|
|
||
| 2. **Upgrade to latest version**: | ||
| ```bash | ||
| npm install -g @openai/codex@latest | ||
| ``` | ||
|
|
||
| 3. **Verify upgrade**: | ||
| ```bash | ||
| codex --version | ||
| ``` | ||
| Should show >= 0.44.0 | ||
|
|
||
| ### "Model not available" Errors | ||
|
|
||
| **Symptoms**: Error indicating the requested model is not available. | ||
|
|
||
| **Causes and Solutions**: | ||
|
|
||
| 1. **Using unsupported model**: | ||
| - Only `gpt-5` and `gpt-5-codex` are available via Codex CLI | ||
| - For other OpenAI models, use the standard `openai` provider | ||
|
|
||
| 2. **Subscription not active**: | ||
| - Verify your ChatGPT subscription is active | ||
| - Check subscription status at <https://platform.openai.com> | ||
|
|
||
| 3. **Wrong provider selected**: | ||
| - Verify you're using `--codex-cli` flag when setting models | ||
| - Check `.taskmaster/config.json` shows `"provider": "codex-cli"` | ||
|
|
||
| ### API Key Not Being Used | ||
|
|
||
| **Symptoms**: You've set `OPENAI_CODEX_API_KEY` but it's not being used. | ||
|
|
||
| **Expected Behavior**: | ||
| - OAuth authentication is always preferred | ||
| - API key is only injected when explicitly provided | ||
| - API key doesn't grant access to subscription-only models | ||
|
|
||
| **Solutions**: | ||
| 1. **Verify OAuth is working**: | ||
| ```bash | ||
| codex | ||
| # Check /about for auth status | ||
| ``` | ||
|
|
||
| 2. **If you want to force API key usage**: | ||
| - This is not recommended with Codex CLI | ||
| - Consider using the standard `openai` provider instead | ||
|
|
||
| 3. **Verify .env file is being loaded**: | ||
| ```bash | ||
| # Check if .env exists in project root | ||
| ls -la .env | ||
|
|
||
| # Verify OPENAI_CODEX_API_KEY is set | ||
| grep OPENAI_CODEX_API_KEY .env | ||
| ``` | ||
|
|
||
| ### Approval/Sandbox Issues | ||
|
|
||
| **Symptoms**: Commands are blocked or filesystem access is denied. | ||
|
|
||
| **Solutions**: | ||
|
|
||
| 1. **Adjust approval mode**: | ||
| ```json | ||
| { | ||
| "codexCli": { | ||
| "approvalMode": "on-request" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| 2. **Adjust sandbox mode**: | ||
| ```json | ||
| { | ||
| "codexCli": { | ||
| "sandboxMode": "workspace-write" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| 3. **For fully automated workflows** (use cautiously): | ||
| ```json | ||
| { | ||
| "codexCli": { | ||
| "fullAuto": true | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Important Notes | ||
|
|
||
| - **OAuth subscription required**: No API key needed for basic operation, but requires active ChatGPT subscription | ||
| - **Limited model selection**: Only `gpt-5` and `gpt-5-codex` available via OAuth | ||
| - **Pricing information**: Not available for OAuth models (shows as "Unknown" in cost calculations) | ||
| - **No automatic dependency**: The `@openai/codex` package is not added to Task Master's dependencies - install it globally or enable `allowNpx` | ||
| - **Codebase analysis**: Automatically enabled when using `codex-cli` provider | ||
| - **Safety first**: Default settings prioritize safety with `approvalMode: "on-failure"` and `sandboxMode: "workspace-write"` | ||
|
|
||
| ## See Also | ||
|
|
||
| - [Configuration Guide](../configuration.md#codex-cli-provider) - Complete Codex CLI configuration reference | ||
| - [Command Reference](../command-reference.md) - Using `--codex-cli` flag with commands | ||
| - [Gemini CLI Provider](./gemini-cli.md) - Similar CLI-based provider for Google Gemini | ||
| - [Claude Code Integration](../claude-code-integration.md) - Another CLI-based provider | ||
| - [ai-sdk-provider-codex-cli](https://github.com/ben-vargas/ai-sdk-provider-codex-cli) - Source code for the provider package |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Nitpick | π΅ Trivial
LGTM! Excellent comprehensive Codex CLI provider documentation.
This documentation is thorough and well-structured, covering all essential aspects from quickstart to troubleshooting. The organization makes it easy for users to find information at different skill levels.
Optional: Fix markdown formatting for consistency.
Static analysis detected multiple instances of missing blank lines around fenced code blocks (MD031 violations at lines 92, 350, 355, 360, 374, 379, 385, 400, 405, 410, 412, 444, 454, 469, 478, 487). While these don't affect functionality, adding blank lines would improve markdown consistency:
To verify your authentication:
+
```bash
# Open interactive Codex CLI
codexOptional: API Key Method
Apply similar spacing around all code blocks for better consistency with markdown best practices.
<details>
<summary>π§° Tools</summary>
<details>
<summary>πͺ markdownlint-cli2 (0.18.1)</summary>
92-92: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
---
350-350: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
---
355-355: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
---
360-360: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
---
374-374: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
---
379-379: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
---
385-385: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
---
400-400: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
---
405-405: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
---
410-410: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
---
412-412: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
---
444-444: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
---
454-454: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
---
469-469: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
---
478-478: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
---
487-487: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
</details>
</details>
<details>
<summary>π€ Prompt for AI Agents</summary>
In docs/providers/codex-cli.md lines 1-510, static analysis flagged MD031
(missing blank lines around fenced code blocks) at several locations (e.g., ~92,
350, 355, 360, 374, 379, 385, 400, 405, 410, 412, 444, 454, 469, 478, 487); fix
by adding a blank line immediately before and after each fenced code block
(bash or json blocks) so every fenced block is separated from surrounding
text with one empty line, matching the example shown in the review and ensuring
consistent markdown formatting throughout the document.
</details>
<!-- This is an auto-generated comment by CodeRabbit -->
| model: client(params.modelId), | ||
| system: systemPrompt, | ||
| messages: messages, | ||
| maxTokens: params.maxTokens, | ||
| maxOutputTokens: params.maxTokens, | ||
| temperature: params.temperature | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stop forwarding temperature when the provider says it cannot.
GeminiCliProvider sets supportsTemperature = false, yet this override always passes params.temperature through to the SDK (same issue in streamText and the generateObject retry path). Gemini CLI rejects a temperature argument, so any call that supplies one will fail even though the provider advertises that it doesnβt support it. Reuse the base-class guard (this.supportsTemperature && β¦) and stick with prepareTokenParam so you donβt leak unsupported knobs.
- const result = await generateText({
- model: client(params.modelId),
- system: systemPrompt,
- messages: messages,
- maxOutputTokens: params.maxTokens,
- temperature: params.temperature
- });
+ const tokenParams = this.prepareTokenParam(
+ params.modelId,
+ params.maxTokens
+ );
+ const request = {
+ model: client(params.modelId),
+ system: systemPrompt,
+ messages,
+ ...tokenParams,
+ ...(this.supportsTemperature && params.temperature !== undefined
+ ? { temperature: params.temperature }
+ : {})
+ };
+ const result = await generateText(request);Apply the same guard/prepareTokenParam pattern to streamText (Line 533) and the manual generateObject retry (Line 590).
π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| model: client(params.modelId), | |
| system: systemPrompt, | |
| messages: messages, | |
| maxTokens: params.maxTokens, | |
| maxOutputTokens: params.maxTokens, | |
| temperature: params.temperature | |
| }); | |
| // replace the original generateText call with temperature guard + token params | |
| const tokenParams = this.prepareTokenParam( | |
| params.modelId, | |
| params.maxTokens | |
| ); | |
| const request = { | |
| model: client(params.modelId), | |
| system: systemPrompt, | |
| messages, | |
| ...tokenParams, | |
| ...(this.supportsTemperature && params.temperature !== undefined | |
| ? { temperature: params.temperature } | |
| : {}) | |
| }; | |
| const result = await generateText(request); |
π€ Prompt for AI Agents
In src/ai-providers/gemini-cli.js around lines 429-434, 533, and 590, stop
always forwarding params.temperature to the Gemini SDK; since GeminiCliProvider
sets supportsTemperature = false, wrap temperature in the base-class guard and
use the prepareTokenParam helper (e.g. set temperature only if
this.supportsTemperature && prepareTokenParam(params.temperature)), applying
that same pattern in the streamText call (line ~533) and the manual
generateObject retry path (line ~590) so unsupported temperature values are
never passed to the SDK.
β¦r not provided (#1276) Co-authored-by: Ralph Khreish <[email protected]> Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Fixes #1272
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
π Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
π Files selected for processing (2)
.changeset/fix-mcp-default-tasks-path.md(1 hunks)mcp-server/src/core/utils/path-utils.js(1 hunks)
π§° Additional context used
π Path-based instructions (6)
.changeset/*.md
π CodeRabbit inference engine (.cursor/rules/changeset.mdc)
.changeset/*.md: When runningnpm run changesetornpx changeset add, provide a concise summary of the changes for theCHANGELOG.mdin imperative mood, typically a single line, and not a detailed Git commit message.
The changeset summary should be user-facing, describing what changed in the released version that is relevant to users or consumers of the package.
Do not use your detailed Git commit message body as the changeset summary.
Files:
.changeset/fix-mcp-default-tasks-path.md
.changeset/*
π CodeRabbit inference engine (.cursor/rules/new_features.mdc)
Create appropriate changesets for new features, use semantic versioning, include tagged system information in release notes, and document breaking changes if any.
Files:
.changeset/fix-mcp-default-tasks-path.md
**/*.js
π CodeRabbit inference engine (.cursor/rules/tests.mdc)
**/*.js: Declare and initialize global variables at the top of modules to avoid hoisting issues.
Use proper function declarations to avoid hoisting issues and initialize variables before they are referenced.
Do not reference variables before their declaration in module scope.
Use dynamic imports (import()) to avoid initialization order issues in modules.
Files:
mcp-server/src/core/utils/path-utils.js
mcp-server/src/{core/utils,tools}/**/*.js
π CodeRabbit inference engine (.cursor/rules/utilities.mdc)
Place utilities specifically designed to support the MCP server implementation into the appropriate subdirectories within
mcp-server/src/(e.g., path/core logic helpers inmcp-server/src/core/utils/, tool execution/response helpers inmcp-server/src/tools/utils.js).
Files:
mcp-server/src/core/utils/path-utils.js
mcp-server/src/core/utils/path-utils.js
π CodeRabbit inference engine (.cursor/rules/utilities.mdc)
Call
findTasksJsonPath(args, log)from within direct function wrappers inmcp-server/src/core/direct-functions/to get the absolute path to the relevanttasks.json.
Files:
mcp-server/src/core/utils/path-utils.js
{scripts/modules/utils.js,mcp-server/src/core/utils/path-utils.js,mcp-server/src/tools/utils.js}
π CodeRabbit inference engine (.cursor/rules/utilities.mdc)
{scripts/modules/utils.js,mcp-server/src/core/utils/path-utils.js,mcp-server/src/tools/utils.js}: Keep utilities relevant to their location, export all utility functions in a single statement per file, group related exports together, export configuration constants, do not use default exports, and do not create circular dependencies.
Export all utility functions explicitly, group related functions logically, and include new tagged system utilities.
Files:
mcp-server/src/core/utils/path-utils.js
π§ Learnings (9)
π Common learnings
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1262
File: scripts/modules/task-manager/update-tasks.js:216-233
Timestamp: 2025-10-01T19:53:34.261Z
Learning: For scripts/modules/task-manager/*.js: Use generateObjectService with Zod schemas for structured AI responses rather than generateTextService + manual JSON parsing, as modern AI providers increasingly support the tool use and generateObject paradigm with improved reliability.
π Learning: 2025-09-24T15:12:58.855Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: assets/AGENTS.md:0-0
Timestamp: 2025-09-24T15:12:58.855Z
Learning: Applies to assets/**/.mcp.json : Configure the Task Master MCP server in .mcp.json under mcpServers.task-master-ai using npx task-master-ai and provide required API key env vars
Applied to files:
.changeset/fix-mcp-default-tasks-path.md
π Learning: 2025-07-17T21:33:57.585Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1002
File: .changeset/puny-friends-give.md:2-3
Timestamp: 2025-07-17T21:33:57.585Z
Learning: In the eyaltoledano/claude-task-master repository, the MCP server code in mcp-server/src/ is part of the main "task-master-ai" package, not a separate "mcp-server" package. When creating changesets for MCP server changes, use "task-master-ai" as the package name.
Applied to files:
.changeset/fix-mcp-default-tasks-path.md
π Learning: 2025-07-18T17:18:17.759Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-07-18T17:18:17.759Z
Learning: Applies to mcp-server/src/core/utils/path-utils.js : Call `findTasksJsonPath(args, log)` from within direct function wrappers in `mcp-server/src/core/direct-functions/` to get the absolute path to the relevant `tasks.json`.
Applied to files:
mcp-server/src/core/utils/path-utils.js
π Learning: 2025-07-18T17:11:36.732Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-07-18T17:11:36.732Z
Learning: Applies to mcp-server/src/core/direct-functions/*.js : The *Direct function is responsible for finding the exact tasks.json path using findTasksJsonPath, relying on the projectRoot passed in args.
Applied to files:
mcp-server/src/core/utils/path-utils.js
π Learning: 2025-07-18T17:18:17.759Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-07-18T17:18:17.759Z
Learning: Applies to mcp-server/src/tools/utils.js : Use `normalizeProjectRoot(rawPath, log)`, `getRawProjectRootFromSession(session, log)`, and `withNormalizedProjectRoot(executeFn)` in `mcp-server/src/tools/utils.js` to ensure project root paths are normalized for MCP tools.
Applied to files:
mcp-server/src/core/utils/path-utils.js
π Learning: 2025-07-18T05:38:17.352Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#943
File: scripts/modules/task-manager/move-task.js:24-24
Timestamp: 2025-07-18T05:38:17.352Z
Learning: In the Claude Task Master system, core task-manager functions are designed with fallback mechanisms for missing projectRoot parameters using the pattern `const projectRoot = providedProjectRoot || findProjectRoot();`. The readJSON and writeJSON functions have default parameters (projectRoot = null, tag = null) and handle missing parameters gracefully. Adding strict validation to these core functions would break the established flexible architecture pattern.
Applied to files:
mcp-server/src/core/utils/path-utils.js
π Learning: 2025-07-18T17:12:57.903Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-07-18T17:12:57.903Z
Learning: Applies to mcp-server/src/core/direct-functions/*.js : Create direct function wrappers in 'mcp-server/src/core/direct-functions/' for MCP tool implementation, following silent mode patterns and using findTasksJsonPath for consistent path resolution.
Applied to files:
mcp-server/src/core/utils/path-utils.js
π Learning: 2025-07-18T17:11:36.732Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-07-18T17:11:36.732Z
Learning: Applies to mcp-server/src/core/direct-functions/*.js : Use path.join() instead of string concatenation for file paths, and follow established file naming conventions (e.g., 'task_001.txt') in direct functions.
Applied to files:
mcp-server/src/core/utils/path-utils.js
𧬠Code graph analysis (1)
mcp-server/src/core/utils/path-utils.js (1)
src/utils/path-utils.js (8)
defaultPath(343-343)defaultPath(395-395)projectRoot(108-108)projectRoot(197-197)projectRoot(269-269)projectRoot(340-340)projectRoot(386-386)projectRoot(445-445)
πͺ markdownlint-cli2 (0.18.1)
.changeset/fix-mcp-default-tasks-path.md
5-5: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
5-5: Files should end with a single newline character
(MD047, single-trailing-newline)
β° Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: build
- GitHub Check: typecheck
- GitHub Check: Test
- GitHub Check: Test
- GitHub Check: update-docs
π Additional comments (1)
mcp-server/src/core/utils/path-utils.js (1)
91-94: LGTM!The refactoring to introduce the
foundPathvariable improves readability, and the explanatory comment clearly documents why no default path fallback is available in this branch.
| "task-master-ai": patch | ||
| --- | ||
|
|
||
| Fix MCP server error when file parameter not provided - now properly constructs default tasks.json path instead of failing with 'tasksJsonPath is required' error. No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add trailing newline.
The file should end with a single newline character to comply with standard formatting conventions.
Apply this diff to add the trailing newline:
-Fix MCP server error when file parameter not provided - now properly constructs default tasks.json path instead of failing with 'tasksJsonPath is required' error.
+Fix MCP server error when file parameter not provided - now properly constructs default tasks.json path instead of failing with 'tasksJsonPath is required' error.
+π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Fix MCP server error when file parameter not provided - now properly constructs default tasks.json path instead of failing with 'tasksJsonPath is required' error. | |
| Fix MCP server error when file parameter not provided - now properly constructs default tasks.json path instead of failing with 'tasksJsonPath is required' error. | |
π§° Tools
πͺ markdownlint-cli2 (0.18.1)
5-5: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
5-5: Files should end with a single newline character
(MD047, single-trailing-newline)
π€ Prompt for AI Agents
In .changeset/fix-mcp-default-tasks-path.md around line 5, the file is missing a
trailing newline; add a single newline character at the end of the file so it
ends with exactly one trailing newline to comply with standard file formatting.
| const foundPath = coreFindTasksPath(explicitPath, { projectRoot }, log); | ||
| // If core function returns null and no explicit path was provided, | ||
| // construct the expected default path as documented | ||
| if (foundPath === null && !explicitPath) { | ||
| const defaultPath = path.join( | ||
| projectRoot, | ||
| '.taskmaster', | ||
| 'tasks', | ||
| 'tasks.json' | ||
| ); | ||
| log?.info?.( | ||
| `Core findTasksPath returned null, using default path: ${defaultPath}` | ||
| ); | ||
| return defaultPath; | ||
| } | ||
| return foundPath; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Nitpick | π΅ Trivial
Consider using a shared constant for the default path.
The hardcoded path construction '.taskmaster', 'tasks', 'tasks.json' duplicates logic that likely exists in a constant (e.g., TASKMASTER_TASKS_FILE as seen in src/utils/path-utils.js:342). Using a shared constant would improve maintainability and prevent drift between the MCP server and core utilities.
If a constant like TASKMASTER_TASKS_FILE exists, import and use it:
+import { TASKMASTER_TASKS_FILE } from '../../../../src/constants/paths.js';
...
- const defaultPath = path.join(
- projectRoot,
- '.taskmaster',
- 'tasks',
- 'tasks.json'
- );
+ const defaultPath = path.join(projectRoot, TASKMASTER_TASKS_FILE);π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const foundPath = coreFindTasksPath(explicitPath, { projectRoot }, log); | |
| // If core function returns null and no explicit path was provided, | |
| // construct the expected default path as documented | |
| if (foundPath === null && !explicitPath) { | |
| const defaultPath = path.join( | |
| projectRoot, | |
| '.taskmaster', | |
| 'tasks', | |
| 'tasks.json' | |
| ); | |
| log?.info?.( | |
| `Core findTasksPath returned null, using default path: ${defaultPath}` | |
| ); | |
| return defaultPath; | |
| } | |
| return foundPath; | |
| // βββ At the top of mcp-server/src/core/utils/path-utils.js ββββββββββββββββββββββββ | |
| import { TASKMASTER_TASKS_FILE } from '../../../../src/constants/paths.js'; | |
| β¦ | |
| const foundPath = coreFindTasksPath(explicitPath, { projectRoot }, log); | |
| // If core function returns null and no explicit path was provided, | |
| // construct the expected default path as documented | |
| if (foundPath === null && !explicitPath) { | |
| const defaultPath = path.join(projectRoot, TASKMASTER_TASKS_FILE); | |
| log?.info?.( | |
| `Core findTasksPath returned null, using default path: ${defaultPath}` | |
| ); | |
| return defaultPath; | |
| } | |
| return foundPath; |
π€ Prompt for AI Agents
In mcp-server/src/core/utils/path-utils.js around lines 72 to 87, replace the
hardcoded default path construction ('.taskmaster', 'tasks', 'tasks.json') with
the shared TASKMASTER_TASKS_FILE constant to avoid duplication; import
TASKMASTER_TASKS_FILE from its module (e.g., '../../utils/path-utils' or the
correct relative path where it is defined) at the top of this file and use
path.join(projectRoot, TASKMASTER_TASKS_FILE) (or simply
path.resolve(projectRoot, TASKMASTER_TASKS_FILE) if appropriate), and update the
log message to reference the constant-based path instead of the hardcoded
segments.
Co-authored-by: Ralph Khreish <[email protected]> Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Resolves issue #1271 - MCP Connection Closed Error After Upgrading to v0.27.3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and canβt be posted inline due to platform limitations.
β οΈ Outside diff range comments (3)
scripts/modules/task-manager/add-subtask.js (1)
21-21: Remove the unusedgenerateFilesparameter.The
generateFilesparameter is no longer used since task file generation has been removed. Consider removing this parameter to clean up the function signature and avoid confusion for callers.Apply this diff to remove the unused parameter:
async function addSubtask( tasksPath, parentId, existingTaskId = null, newSubtaskData = null, - generateFiles = false, context = {} )Note: If this is a public API and you need to maintain backward compatibility, you could deprecate the parameter in documentation instead of removing it immediately.
scripts/modules/task-manager/remove-subtask.js (1)
18-18: Remove the unusedgenerateFilesparameter.The
generateFilesparameter is no longer used since task file generation has been removed. Consider removing this parameter to clean up the function signature.Apply this diff to remove the unused parameter:
async function removeSubtask( tasksPath, subtaskId, convertToTask = false, - generateFiles = false, context = {} )Note: If backward compatibility is a concern, deprecate in documentation first.
scripts/modules/task-manager/move-task.js (1)
115-115: Remove the unusedgenerateFilesparameter.The
generateFilesparameter is no longer used since task file generation has been removed. Even though the recursive call at line 138 explicitly passesfalsefor this parameter, it serves no purpose and should be removed for clarity.Apply this diff to remove the unused parameter:
async function moveTask( tasksPath, sourceId, destinationId, - generateFiles = false, options = {} )And update the recursive call at line 138:
const result = await moveTask( tasksPath, sourceIds[i], destinationIds[i], - false, // Don't generate files for each individual move options );Note: If this is a public API requiring backward compatibility, consider deprecating first.
π Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
π Files selected for processing (6)
.changeset/fix-mcp-connection-errors.md(1 hunks)scripts/modules/task-manager/add-subtask.js(1 hunks)scripts/modules/task-manager/move-task.js(2 hunks)scripts/modules/task-manager/remove-subtask.js(1 hunks)tests/unit/scripts/modules/task-manager/add-subtask.test.js(0 hunks)tests/unit/scripts/modules/task-manager/move-task.test.js(0 hunks)
π€ Files with no reviewable changes (2)
- tests/unit/scripts/modules/task-manager/move-task.test.js
- tests/unit/scripts/modules/task-manager/add-subtask.test.js
π§° Additional context used
π Path-based instructions (7)
scripts/modules/task-manager/*.js
π CodeRabbit inference engine (.cursor/rules/ai_services.mdc)
scripts/modules/task-manager/*.js: Centralize all LLM calls throughgenerateTextServiceorgenerateObjectService.
Do not import or call anything from the oldai-services.js,ai-client-factory.js, orai-client-utils.jsfiles.
Do not initialize AI clients (Anthropic, Perplexity, etc.) directly within core logic (task-manager/) or MCP direct functions.
Do not fetch AI-specific parameters (model ID, max tokens, temp) usingconfig-manager.jsgetters for the AI call. Pass theroleinstead.
Do not implement fallback or retry logic outsideai-services-unified.js.
Do not handle API key resolution outside the service layer (it usesutils.jsinternally).
Determine the appropriaterole(main,research,fallback) in your core logic and pass it to the service.
Pass thesessionobject (received in thecontextparameter, especially from direct function wrappers) to the service call when in MCP context.
UsegenerateTextServiceand implement robust manual JSON parsing (with Zod validation after parsing) when structured output is needed, asgenerateObjectServicehas shown unreliability with some providers/schemas.
Be aware of potential reliability issues withgenerateObjectServiceacross different providers and complex schemas. PrefergenerateTextService+ manual parsing as a more robust alternative for structured data needs.Files in scripts/modules/task-manager/ should each handle a specific action related to task management (e.g., add-task.js, expand-task.js), supporting the tagged task lists system and backward compatibility.
Files:
scripts/modules/task-manager/add-subtask.jsscripts/modules/task-manager/remove-subtask.jsscripts/modules/task-manager/move-task.js
scripts/modules/**
π CodeRabbit inference engine (.cursor/rules/dev_workflow.mdc)
When using the MCP server, restart it if core logic in
scripts/modulesor MCP tool/direct function definitions change.
Files:
scripts/modules/task-manager/add-subtask.jsscripts/modules/task-manager/remove-subtask.jsscripts/modules/task-manager/move-task.js
scripts/modules/task-manager/*
π CodeRabbit inference engine (.cursor/rules/tags.mdc)
scripts/modules/task-manager/*: All core functions in scripts/modules/task-manager/ must accept a context parameter and use it to extract projectRoot and tag
All core functions in scripts/modules/task-manager/ must use readJSON(tasksPath, projectRoot, tag) and writeJSON(tasksPath, data, projectRoot, tag)
Files:
scripts/modules/task-manager/add-subtask.jsscripts/modules/task-manager/remove-subtask.jsscripts/modules/task-manager/move-task.js
scripts/modules/task-manager/**/*.js
π CodeRabbit inference engine (.cursor/rules/telemetry.mdc)
scripts/modules/task-manager/**/*.js: Functions in scripts/modules/task-manager/ that invoke AI services must call the appropriate AI service function (e.g., generateObjectService), passing commandName and outputType in the params object.
Core logic functions in scripts/modules/task-manager/ must return an object that includes aiServiceResponse.telemetryData.
If the core logic function handles CLI output (outputFormat === 'text' or 'cli'), and aiServiceResponse.telemetryData is available, it must call displayAiUsageSummary(aiServiceResponse.telemetryData, 'cli') from scripts/modules/ui.js.Do not call AI-specific getters (like
getMainModelId,getMainMaxTokens) from core logic functions inscripts/modules/task-manager/*; instead, pass theroleto the unified AI service.
Files:
scripts/modules/task-manager/add-subtask.jsscripts/modules/task-manager/remove-subtask.jsscripts/modules/task-manager/move-task.js
**/*.js
π CodeRabbit inference engine (.cursor/rules/tests.mdc)
**/*.js: Declare and initialize global variables at the top of modules to avoid hoisting issues.
Use proper function declarations to avoid hoisting issues and initialize variables before they are referenced.
Do not reference variables before their declaration in module scope.
Use dynamic imports (import()) to avoid initialization order issues in modules.
Files:
scripts/modules/task-manager/add-subtask.jsscripts/modules/task-manager/remove-subtask.jsscripts/modules/task-manager/move-task.js
.changeset/*.md
π CodeRabbit inference engine (.cursor/rules/changeset.mdc)
.changeset/*.md: When runningnpm run changesetornpx changeset add, provide a concise summary of the changes for theCHANGELOG.mdin imperative mood, typically a single line, and not a detailed Git commit message.
The changeset summary should be user-facing, describing what changed in the released version that is relevant to users or consumers of the package.
Do not use your detailed Git commit message body as the changeset summary.
Files:
.changeset/fix-mcp-connection-errors.md
.changeset/*
π CodeRabbit inference engine (.cursor/rules/new_features.mdc)
Create appropriate changesets for new features, use semantic versioning, include tagged system information in release notes, and document breaking changes if any.
Files:
.changeset/fix-mcp-connection-errors.md
π§ Learnings (24)
π Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Use AI to generate detailed subtasks within the current tag context, considering complexity analysis for subtask counts and ensuring proper IDs for newly created subtasks.
Applied to files:
scripts/modules/task-manager/add-subtask.jsscripts/modules/task-manager/move-task.js
π Learning: 2025-07-31T22:07:49.716Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/commands.mdc:0-0
Timestamp: 2025-07-31T22:07:49.716Z
Learning: Applies to scripts/modules/commands.js : Follow the provided structure for removing subtasks, including options for conversion, file path, and regeneration, with detailed error handling.
Applied to files:
scripts/modules/task-manager/add-subtask.jsscripts/modules/task-manager/remove-subtask.js
π Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Use consistent formatting for task files, include all task properties in text files, and format dependencies with status indicators.
Applied to files:
scripts/modules/task-manager/add-subtask.jsscripts/modules/task-manager/remove-subtask.jsscripts/modules/task-manager/move-task.js
π Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Do not create circular dependencies between subtasks
Applied to files:
scripts/modules/task-manager/add-subtask.js
π Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Generate task files from the current tag context, include tag information in generated files, and do not mix tasks from different tags in file generation.
Applied to files:
scripts/modules/task-manager/add-subtask.jsscripts/modules/task-manager/remove-subtask.jsscripts/modules/task-manager/move-task.js
π Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Provide functions for updating task status within the current tag context, handling both individual tasks and subtasks, and considering subtask status when updating parent tasks.
Applied to files:
scripts/modules/task-manager/add-subtask.js
π Learning: 2025-07-18T17:07:39.336Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/architecture.mdc:0-0
Timestamp: 2025-07-18T17:07:39.336Z
Learning: Applies to scripts/modules/task-manager/*.js : Files in scripts/modules/task-manager/ should each handle a specific action related to task management (e.g., add-task.js, expand-task.js), supporting the tagged task lists system and backward compatibility.
Applied to files:
scripts/modules/task-manager/add-subtask.jsscripts/modules/task-manager/remove-subtask.jsscripts/modules/task-manager/move-task.js
π Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Allow numeric subtask IDs to reference other subtasks within the same parent
Applied to files:
scripts/modules/task-manager/add-subtask.js
π Learning: 2025-07-18T17:08:48.695Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/commands.mdc:0-0
Timestamp: 2025-07-18T17:08:48.695Z
Learning: Applies to scripts/modules/commands.js : Follow the provided structure for adding subtasks, including required options and detailed error handling.
Applied to files:
scripts/modules/task-manager/add-subtask.js
π Learning: 2025-09-24T15:12:12.658Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: assets/.windsurfrules:0-0
Timestamp: 2025-09-24T15:12:12.658Z
Learning: Use task-master generate to create or update task files from tasks.json and keep dependencies valid with fix-dependencies
Applied to files:
scripts/modules/task-manager/add-subtask.jsscripts/modules/task-manager/move-task.js
π Learning: 2025-07-31T22:07:49.716Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/commands.mdc:0-0
Timestamp: 2025-07-31T22:07:49.716Z
Learning: Applies to scripts/modules/commands.js : Follow the provided structure for adding subtasks, including required and optional options, parameter validation, and detailed error handling.
Applied to files:
scripts/modules/task-manager/add-subtask.js
π Learning: 2025-07-18T17:06:57.833Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_services.mdc:0-0
Timestamp: 2025-07-18T17:06:57.833Z
Learning: Applies to scripts/modules/task-manager/*.js : Do not import or call anything from the old `ai-services.js`, `ai-client-factory.js`, or `ai-client-utils.js` files.
Applied to files:
scripts/modules/task-manager/remove-subtask.jsscripts/modules/task-manager/move-task.js
π Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Check for and remove references to non-existent tasks during cleanup
Applied to files:
scripts/modules/task-manager/remove-subtask.js
π Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Remove references to non-existent tasks during validation
Applied to files:
scripts/modules/task-manager/remove-subtask.js
π Learning: 2025-07-18T17:08:48.695Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/commands.mdc:0-0
Timestamp: 2025-07-18T17:08:48.695Z
Learning: Applies to scripts/modules/commands.js : Follow the provided structure for removing subtasks, including required options, conversion option, and detailed error handling.
Applied to files:
scripts/modules/task-manager/remove-subtask.js
π Learning: 2025-07-18T17:13:30.188Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tags.mdc:0-0
Timestamp: 2025-07-18T17:13:30.188Z
Learning: Applies to scripts/modules/task-manager/* : All core functions in scripts/modules/task-manager/ must use readJSON(tasksPath, projectRoot, tag) and writeJSON(tasksPath, data, projectRoot, tag)
Applied to files:
scripts/modules/task-manager/remove-subtask.jsscripts/modules/task-manager/move-task.js
π Learning: 2025-09-24T15:12:58.855Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: assets/AGENTS.md:0-0
Timestamp: 2025-09-24T15:12:58.855Z
Learning: Applies to assets/**/.mcp.json : Configure the Task Master MCP server in .mcp.json under mcpServers.task-master-ai using npx task-master-ai and provide required API key env vars
Applied to files:
.changeset/fix-mcp-connection-errors.md
π Learning: 2025-07-17T21:33:57.585Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1002
File: .changeset/puny-friends-give.md:2-3
Timestamp: 2025-07-17T21:33:57.585Z
Learning: In the eyaltoledano/claude-task-master repository, the MCP server code in mcp-server/src/ is part of the main "task-master-ai" package, not a separate "mcp-server" package. When creating changesets for MCP server changes, use "task-master-ai" as the package name.
Applied to files:
.changeset/fix-mcp-connection-errors.md
π Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Implement silent migration from legacy to tagged format in the readJSON() function, detect legacy format, convert automatically, and preserve all existing task data during migration.
Applied to files:
scripts/modules/task-manager/move-task.js
π Learning: 2025-07-18T17:12:57.903Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-07-18T17:12:57.903Z
Learning: Applies to scripts/modules/task-manager.js : Features that create, read, update, or delete tasks belong in 'scripts/modules/task-manager.js'.
Applied to files:
scripts/modules/task-manager/move-task.js
π Learning: 2025-07-18T17:18:17.759Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-07-18T17:18:17.759Z
Learning: Applies to scripts/modules/utils.js : Use tagged task system aware functions for task finding and manipulation, handle both task and subtask operations, and validate task IDs before operations.
Applied to files:
scripts/modules/task-manager/move-task.js
π Learning: 2025-07-18T17:18:17.759Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-07-18T17:18:17.759Z
Learning: Applies to scripts/modules/utils.js : Use tag resolution functions for all task data access, provide backward compatibility with legacy format, and default to 'master' tag when no tag is specified.
Applied to files:
scripts/modules/task-manager/move-task.js
π Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Represent task dependencies as arrays of task IDs
Applied to files:
scripts/modules/task-manager/move-task.js
π Learning: 2025-07-18T17:10:12.881Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dev_workflow.mdc:0-0
Timestamp: 2025-07-18T17:10:12.881Z
Learning: Applies to tasks.json : Use the `tasks.json` file (generated by Taskmaster) to store the project's task list, including tags and task structures.
Applied to files:
scripts/modules/task-manager/move-task.js
πͺ markdownlint-cli2 (0.18.1)
.changeset/fix-mcp-connection-errors.md
5-5: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
5-5: Files should end with a single newline character
(MD047, single-trailing-newline)
β° Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: typecheck
- GitHub Check: build
- GitHub Check: Test
- GitHub Check: Test
- GitHub Check: update-docs
π Additional comments (3)
scripts/modules/task-manager/add-subtask.js (1)
142-142: LGTM! Clear documentation of the removed feature.The inline note effectively documents the removal of task file generation functionality.
scripts/modules/task-manager/remove-subtask.js (1)
109-109: LGTM! Clear documentation of the removed feature.The inline note effectively documents the removal of task file generation functionality.
scripts/modules/task-manager/move-task.js (1)
144-144: LGTM! Clear documentation of the removed feature.The inline notes at both the batch move path (line 144) and single move path (line 205) effectively document the removal of task file generation functionality.
Also applies to: 205-205
| "task-master-ai": patch | ||
| --- | ||
|
|
||
| Fix MCP connection errors caused by deprecated generateTaskFiles calls. Resolves "Cannot read properties of null (reading 'toString')" errors when using MCP tools for task management operations. No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add the trailing newline.
The file is missing the terminal newline, which triggers markdownlint MD047. Please append a newline at EOF so the changeset passes lint.
π§° Tools
πͺ markdownlint-cli2 (0.18.1)
5-5: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
5-5: Files should end with a single newline character
(MD047, single-trailing-newline)
π€ Prompt for AI Agents
In .changeset/fix-mcp-connection-errors.md around line 5, the file is missing a
terminal newline which triggers markdownlint MD047; open the file and append a
single trailing newline (ensure the file ends with '\n') so the changeset passes
lint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
Caution
Some comments are outside the diff and canβt be posted inline due to platform limitations.
β οΈ Outside diff range comments (5)
packages/tm-core/src/types/index.ts (1)
172-185: isTaskStatus omits 'completed' from TaskStatus union.Tasks with status 'completed' will fail the guard.
Apply this diff:
export function isTaskStatus(value: unknown): value is TaskStatus { return ( typeof value === 'string' && - [ + [ 'pending', 'in-progress', 'done', 'deferred', 'cancelled', 'blocked', - 'review' + 'review', + 'completed' ].includes(value) ); }packages/tm-core/src/entities/task.entity.ts (1)
122-132: Status validator omits 'completed'.This rejects valid tasks if 'completed' is used.
Apply this diff:
private isValidStatus(status: any): status is TaskStatus { return [ 'pending', 'in-progress', 'done', 'deferred', 'cancelled', 'blocked', - 'review' + 'review', + 'completed' ].includes(status); }packages/tm-core/src/mappers/TaskMapper.ts (1)
142-144: Null-safe subtask sorting.If subtask_position is null/undefined, subtraction yields NaN.
Apply this diff:
- subtasks.sort((a, b) => a.subtask_position - b.subtask_position); + subtasks.sort((a, b) => { + const aPos = a.subtask_position ?? Number.MAX_SAFE_INTEGER; + const bPos = b.subtask_position ?? Number.MAX_SAFE_INTEGER; + return aPos - bPos; + });packages/tm-core/src/repositories/supabase/supabase-task-repository.ts (2)
13-22: Fix status schema vs DB mapping mismatch (runtime error risk).Zod allows statuses (review, deferred, cancelled, blocked) that mapStatusToDatabase cannot handle; parse succeeds then mapping throws. Align schema with supported statuses.
Apply this diff to restrict allowed statuses:
-// Zod schema for task status validation -const TaskStatusSchema = z.enum([ - 'pending', - 'in-progress', - 'done', - 'review', - 'deferred', - 'cancelled', - 'blocked' -]); +// Zod schema for task status validation (must match mapStatusToDatabase) +const TaskStatusSchema = z.enum(['pending', 'in-progress', 'done']);Alternative (if you need the extra states): extend mapStatusToDatabase to coerce them to 'todo' | 'in_progress' appropriately; otherwise reject them at validation time as above.
Also applies to: 218-233
24-35: Remove redundant .partial().Fields are already optional; .partial() is unnecessary and may confuse readers.
Apply this diff:
-const TaskUpdateSchema = z - .object({ +const TaskUpdateSchema = z.object({ title: z.string().min(1).optional(), description: z.string().optional(), status: TaskStatusSchema.optional(), priority: z.enum(['low', 'medium', 'high', 'critical']).optional(), details: z.string().optional(), testStrategy: z.string().optional() - }) - .partial(); +});
π Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
β Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
π Files selected for processing (13)
apps/cli/src/commands/list.command.ts(4 hunks)apps/cli/src/commands/set-status.command.ts(0 hunks)apps/cli/src/ui/components/task-detail.component.ts(5 hunks)apps/cli/src/utils/ui.ts(5 hunks)packages/tm-core/src/entities/task.entity.ts(4 hunks)packages/tm-core/src/mappers/TaskMapper.test.ts(1 hunks)packages/tm-core/src/mappers/TaskMapper.ts(5 hunks)packages/tm-core/src/repositories/supabase/dependency-fetcher.ts(1 hunks)packages/tm-core/src/repositories/supabase/index.ts(1 hunks)packages/tm-core/src/repositories/supabase/supabase-task-repository.ts(7 hunks)packages/tm-core/src/storage/api-storage.ts(1 hunks)packages/tm-core/src/types/index.ts(1 hunks)packages/tm-core/src/types/repository-types.ts(1 hunks)
π€ Files with no reviewable changes (1)
- apps/cli/src/commands/set-status.command.ts
π§° Additional context used
π Path-based instructions (4)
**/*.{test,spec}.{js,ts,jsx,tsx}
π CodeRabbit inference engine (.cursor/rules/git_workflow.mdc)
**/*.{test,spec}.{js,ts,jsx,tsx}: Create a test file and ensure all tests pass when all subtasks are complete; commit tests if added or modified
When all subtasks are complete, run final testing using the appropriate test runner (e.g., npm test, jest, or manual testing)
Files:
packages/tm-core/src/mappers/TaskMapper.test.ts
**/*.{test,spec}.*
π CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)
Test files should follow naming conventions: .test., .spec., or _test. depending on the language
Files:
packages/tm-core/src/mappers/TaskMapper.test.ts
**/?(*.)+(spec|test).ts
π CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)
In JavaScript/TypeScript projects using Jest, test files should match *.test.ts and *.spec.ts patterns
Files:
packages/tm-core/src/mappers/TaskMapper.test.ts
**/*.test.ts
π CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)
**/*.test.ts: Use established mocking patterns for dependencies such as bcrypt and Prisma in test files
Test all code paths, including edge cases and error scenarios, in test files
Use descriptive names for test functions, such as should_return_error_for_invalid_input
Files:
packages/tm-core/src/mappers/TaskMapper.test.ts
π§ Learnings (11)
π Common learnings
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1262
File: scripts/modules/task-manager/update-tasks.js:216-233
Timestamp: 2025-10-01T19:53:34.261Z
Learning: For scripts/modules/task-manager/*.js: Use generateObjectService with Zod schemas for structured AI responses rather than generateTextService + manual JSON parsing, as modern AI providers increasingly support the tool use and generateObject paradigm with improved reliability.
π Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Represent task dependencies as arrays of task IDs
Applied to files:
packages/tm-core/src/mappers/TaskMapper.tsapps/cli/src/ui/components/task-detail.component.tspackages/tm-core/src/repositories/supabase/dependency-fetcher.ts
π Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Format task and dependency IDs consistently when adding dependencies
Applied to files:
packages/tm-core/src/mappers/TaskMapper.tsapps/cli/src/ui/components/task-detail.component.ts
π Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Support both task and subtask dependencies in cycle detection
Applied to files:
packages/tm-core/src/mappers/TaskMapper.tsapps/cli/src/ui/components/task-detail.component.ts
π Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Allow numeric subtask IDs to reference other subtasks within the same parent
Applied to files:
packages/tm-core/src/entities/task.entity.tsapps/cli/src/ui/components/task-detail.component.ts
π Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Subtasks must use consistent properties, maintain simple numeric IDs unique within the parent task, and must not duplicate parent task properties.
Applied to files:
packages/tm-core/src/entities/task.entity.ts
π Learning: 2025-09-26T19:05:47.555Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1252
File: packages/ai-sdk-provider-grok-cli/package.json:11-13
Timestamp: 2025-09-26T19:05:47.555Z
Learning: In the eyaltoledano/claude-task-master repository, internal tm/ packages use a specific export pattern where the "exports" field points to TypeScript source files (./src/index.ts) while "main" points to compiled output (./dist/index.js) and "types" points to source files (./src/index.ts). This pattern is used consistently across internal packages like tm/core and tm/ai-sdk-provider-grok-cli because they are consumed directly during build-time bundling with tsdown rather than being published as separate packages.
Applied to files:
packages/tm-core/src/repositories/supabase/index.ts
π Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Use consistent formatting for task files, include all task properties in text files, and format dependencies with status indicators.
Applied to files:
apps/cli/src/ui/components/task-detail.component.ts
π Learning: 2025-07-18T17:09:40.548Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:40.548Z
Learning: Applies to scripts/modules/dependency-manager.js : Use string IDs with dot notation (e.g., "1.2") for subtask references
Applied to files:
apps/cli/src/ui/components/task-detail.component.ts
π Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Allow filtering tasks by status within the current tag context, handle subtask display in lists, and use consistent table formats.
Applied to files:
apps/cli/src/ui/components/task-detail.component.ts
π Learning: 2025-07-18T17:16:13.793Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-07-18T17:16:13.793Z
Learning: Applies to tests/{unit,integration,e2e}/**/*.test.js : Use sample task fixtures for consistent test data, mock file system operations, and test both success and error paths for task operations.
Applied to files:
packages/tm-core/src/mappers/TaskMapper.test.ts
𧬠Code graph analysis (7)
packages/tm-core/src/types/repository-types.ts (2)
packages/tm-core/src/types/database.types.ts (2)
Tables(413-436)Database(9-411)packages/tm-core/src/types/index.ts (1)
TaskMetadata(97-105)
apps/cli/src/commands/list.command.ts (1)
apps/cli/src/ui/components/next-task.component.ts (2)
getTaskDescription(125-141)displayRecommendedNextTask(27-120)
packages/tm-core/src/mappers/TaskMapper.ts (2)
packages/tm-core/src/types/database.types.ts (1)
Tables(413-436)packages/tm-core/src/types/index.ts (1)
Task(57-82)
apps/cli/src/ui/components/task-detail.component.ts (1)
apps/cli/src/utils/ui.ts (1)
getComplexityWithColor(105-115)
packages/tm-core/src/mappers/TaskMapper.test.ts (2)
packages/tm-core/src/types/database.types.ts (1)
Tables(413-436)packages/tm-core/src/mappers/TaskMapper.ts (1)
TaskMapper(12-216)
packages/tm-core/src/repositories/supabase/dependency-fetcher.ts (1)
packages/tm-core/src/types/repository-types.ts (1)
DependencyWithDisplayId(21-26)
packages/tm-core/src/repositories/supabase/supabase-task-repository.ts (4)
packages/tm-core/src/repositories/supabase/dependency-fetcher.ts (1)
DependencyFetcher(8-68)packages/tm-core/src/types/database.types.ts (2)
Database(9-411)Json(1-7)packages/tm-core/src/types/repository-types.ts (2)
TaskWithRelations(9-16)TaskDatabaseUpdate(40-41)packages/tm-core/src/mappers/TaskMapper.ts (1)
TaskMapper(12-216)
β° Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Test
- GitHub Check: build
- GitHub Check: typecheck
- GitHub Check: Test
- GitHub Check: update-docs
π Additional comments (24)
packages/tm-core/src/types/repository-types.ts (9)
1-4: LGTM!File header and imports are correctly structured. The
.jsextension in the import path is appropriate for ESM compatibility.
9-16: LGTM!The
TaskWithRelationsinterface appropriately extends the base tasks table row with an optional joined document relation. The structure aligns with typical SQL join patterns and provides type safety for related document data.
21-26: LGTM!The
DependencyWithDisplayIdinterface correctly models the dependency relationship with a nesteddisplay_idfield, matching the expected join structure for task dependencies.
40-41: LGTM!The
TaskDatabaseUpdatetype alias provides a convenient shorthand for the database update payload, improving code readability and maintainability.
45-50: LGTM!The
TaskQueryConfiginterface provides clear configuration options for task queries with appropriate optional flags for including related data.
55-59: LGTM!The
TaskFetchResultinterface appropriately aggregates task fetch results including the main task, subtasks, and a map of dependencies. The use ofMap<string, string[]>for dependencies is a good choice for efficient lookups.
64-73: LGTM!The
TaskValidationErrorcustom error class is well-structured with appropriate readonly properties forfieldandvalue, enabling detailed error context. Thenameproperty is correctly set for proper error identification.
78-83: LGTM!The
ContextValidationErrorcustom error class is appropriately simple and follows error handling best practices by setting thenameproperty correctly.
31-35: No TS conflict: separate TaskMetadata definitions
These interfaces live in different modules (types/index.tsvs.types/repository-types.ts) and are only imported via their distinct paths, so TypeScript wonβt merge or collide them.Likely an incorrect or invalid review comment.
apps/cli/src/utils/ui.ts (3)
87-100: LGTM!The complexity level mapping logic is clear and well-structured. The thresholds (β₯7 for High, β₯4 for Medium, <4 for Low) are reasonable for a 0-10 scale, and the color choices (red, orange, green) provide intuitive visual feedback.
105-115: LGTM!The updated implementation correctly handles both numeric and string inputs, provides appropriate fallback for invalid values, and uses the new
getComplexityLevelhelper for consistent color coding.
120-127: LGTM!The new exported function provides a clear, formatted complexity display with score and label. The type guard correctly handles undefined input, and the output format (
${complexity}/10 (${label})) is informative and user-friendly.apps/cli/src/ui/components/task-detail.component.ts (3)
12-16: LGTM!The import statement correctly adds
getComplexityWithColorfrom the UI utilities module, which is needed for the complexity rendering changes below.
115-117: LGTM!The complexity rendering correctly uses type guards and the new
getComplexityWithColorhelper, with an appropriate N/A fallback for missing or invalid complexity values.
331-331: LGTM!The
displaySubtaskscall correctly aligns with the updated function signature, removing the parentId argument as expected.apps/cli/src/commands/list.command.ts (3)
249-249: LGTM!The subtask ID formatting change aligns with the simplification in task-detail.component.ts (line 230). This suggests that
subtask.idnow contains the full identifier rather than just the numeric part.
284-289: LGTM!The separation of next task identification (
nextTaskInfo) from full task lookup (nextTask) is a sound design that allows accessing enriched task data (including complexity) from storage while maintaining the existing recommendation logic.
311-321: LGTM!The change from spreading
nextTaskto explicitly passing individual fields improves maintainability and type safety by:
- Making the interface contract explicit
- Preventing unintended property propagation
- Allowing proper type handling for
complexityasnumber | undefinedpackages/tm-core/src/types/index.ts (1)
76-81: LGTM on new complexity fields.Shape and docs look good.
packages/tm-core/src/entities/task.entity.ts (2)
36-39: New complexity-related fields wired through entity/JSON: LGTM.Also applies to: 68-71, 255-258
166-183: Confirm canonical final status: 'done' vs 'completed'.markAsComplete sets 'done' while TaskStatus also includes 'completed'. Align on one to avoid ambiguity.
Would you like me to refactor to use 'completed' consistently across types/guards and mappers?
packages/tm-core/src/repositories/supabase/dependency-fetcher.ts (1)
16-38: Dependency fetch with joined display_ids: LGTM.Input validation, error handling, and mapping are clean.
Please confirm the FK alias matches your generated types ('task_dependencies_depends_on_task_id_fkey') in the target DB.
packages/tm-core/src/repositories/supabase/index.ts (1)
1-5: Barrel exports LGTM.Consolidating Supabase exports here improves DX and import consistency. Based on learnings.
packages/tm-core/src/storage/api-storage.ts (1)
19-19: Approve barrel import: no direct imports remainNo direct imports of supabase-task-repository.js found; all usage via barrel index.js.
|
|
||
| subtasks.forEach((subtask) => { | ||
| const subtaskId = `${parentId}.${subtask.id}`; | ||
| const subtaskId = String(subtask.id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§© Analysis chain
Verify subtask ID format consistency across the codebase.
The subtask ID construction was simplified from parentId.subtask.id to String(subtask.id). Ensure that:
- All subtask creation/storage logic populates
subtask.idwith the full ID (e.g., "1.2") rather than just the numeric part - This change aligns with the subtask ID formatting in list.command.ts (line 249)
Run the following script to verify subtask ID handling:
π Script executed:
#!/bin/bash
# Description: Verify subtask ID format usage across the codebase
# Search for subtask ID assignments and formatting
echo "=== Subtask ID assignments ==="
rg -nP -A3 -B3 'subtask\.id\s*=' --type=ts
echo -e "\n=== Subtask ID string concatenations (old pattern) ==="
rg -nP 'parentId.*subtask\.id|task\.id.*subtask\.id' --type=ts
echo -e "\n=== displaySubtasks calls ==="
rg -nP 'displaySubtasks\(' --type=ts -A2Length of output: 2257
In apps/cli/src/ui/components/task-detail.component.ts:230, reinstate full dotted subtask IDs: String(subtask.id) only yields the numeric portion; prepend the parent task ID (e.g., ${task.id}.${subtask.id}) or ensure subtask.id carries the complete β1.2β format.
π€ Prompt for AI Agents
In apps/cli/src/ui/components/task-detail.component.ts around line 230,
converting subtask.id with String(subtask.id) strips the parent task prefix and
yields only the numeric part; restore full dotted IDs by using the composite
form (e.g., `${task.id}.${subtask.id}`) or ensure you read a preformatted dotted
id from the subtask object and use that instead; update the assignment to
produce the dotted id so downstream code displays and references the full "1.2"
style identifier.
| const complexityDisplay = | ||
| typeof subtask.complexity === 'number' | ||
| ? getComplexityWithColor(subtask.complexity) | ||
| : '--'; | ||
| subRow.push(chalk.gray(complexityDisplay)); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Nitpick | π΅ Trivial
Consider consistent fallback values.
Tasks use chalk.gray('N/A') for missing complexity (line 353), while subtasks use '--' (line 383). For consistency, consider using the same fallback value across both contexts.
Apply this diff to align the fallback values:
if (showComplexity) {
const complexityDisplay =
typeof subtask.complexity === 'number'
? getComplexityWithColor(subtask.complexity)
- : '--';
+ : 'N/A';
subRow.push(chalk.gray(complexityDisplay));
}π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const complexityDisplay = | |
| typeof subtask.complexity === 'number' | |
| ? getComplexityWithColor(subtask.complexity) | |
| : '--'; | |
| subRow.push(chalk.gray(complexityDisplay)); | |
| } | |
| if (showComplexity) { | |
| const complexityDisplay = | |
| typeof subtask.complexity === 'number' | |
| ? getComplexityWithColor(subtask.complexity) | |
| : 'N/A'; | |
| subRow.push(chalk.gray(complexityDisplay)); | |
| } |
π€ Prompt for AI Agents
In apps/cli/src/utils/ui.ts around lines 380 to 385, the subtask complexity
fallback uses '--' while tasks use 'N/A'; change the subtask fallback string
from '--' to 'N/A' so both branches use the same fallback value (the existing
chalk.gray wrapping remains unchanged).
| this.subtasks = (data.subtasks || []).map((subtask) => ({ | ||
| ...subtask, | ||
| id: Number(subtask.id), // Keep subtask IDs as numbers per interface | ||
| id: String(subtask.id), | ||
| parentId: String(subtask.parentId) | ||
| })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent subtask ID types within TaskEntity (constructor normalizes to string; addSubtask uses number).
Mixed types can break equality/join logic and downstream assumptions.
Unify on string IDs to match constructor:
addSubtask(subtask: Omit<Subtask, 'id' | 'parentId'>): void {
- const nextId = this.subtasks.length + 1;
- this.subtasks.push({
+ const nextId = String(this.subtasks.length + 1);
+ this.subtasks.push({
...subtask,
id: nextId,
parentId: this.id
});
this.updatedAt = new Date().toISOString();
}Also applies to: 202-209
π€ Prompt for AI Agents
In packages/tm-core/src/entities/task.entity.ts around lines 54-58 (and also
update the addSubtask area at lines ~202-209), the constructor normalizes
subtask.id and subtask.parentId to strings but addSubtask currently creates
subtasks with numeric IDs; change addSubtask to convert id and parentId to
String(...) before storing (and ensure any new subtask objects follow the same
{...subtask, id: String(subtask.id), parentId: String(subtask.parentId)}
pattern) so all subtask IDs are consistently strings across the entity.
| describe('TaskMapper', () => { | ||
| describe('extractMetadataField', () => { | ||
| it('should extract string field from metadata', () => { | ||
| const taskRow: TaskRow = { | ||
| id: '123', | ||
| display_id: '1', | ||
| title: 'Test Task', | ||
| description: 'Test description', | ||
| status: 'todo', | ||
| priority: 'medium', | ||
| parent_task_id: null, | ||
| subtask_position: 0, | ||
| created_at: new Date().toISOString(), | ||
| updated_at: new Date().toISOString(), | ||
| metadata: { | ||
| details: 'Some details', | ||
| testStrategy: 'Test with unit tests' | ||
| }, | ||
| complexity: null, | ||
| assignee_id: null, | ||
| estimated_hours: null, | ||
| actual_hours: null, | ||
| due_date: null, | ||
| completed_at: null | ||
| }; | ||
|
|
||
| const task = TaskMapper.mapDatabaseTaskToTask(taskRow, [], new Map()); | ||
|
|
||
| expect(task.details).toBe('Some details'); | ||
| expect(task.testStrategy).toBe('Test with unit tests'); | ||
| }); | ||
|
|
||
| it('should use default value when metadata field is missing', () => { | ||
| const taskRow: TaskRow = { | ||
| id: '123', | ||
| display_id: '1', | ||
| title: 'Test Task', | ||
| description: 'Test description', | ||
| status: 'todo', | ||
| priority: 'medium', | ||
| parent_task_id: null, | ||
| subtask_position: 0, | ||
| created_at: new Date().toISOString(), | ||
| updated_at: new Date().toISOString(), | ||
| metadata: {}, | ||
| complexity: null, | ||
| assignee_id: null, | ||
| estimated_hours: null, | ||
| actual_hours: null, | ||
| due_date: null, | ||
| completed_at: null | ||
| }; | ||
|
|
||
| const task = TaskMapper.mapDatabaseTaskToTask(taskRow, [], new Map()); | ||
|
|
||
| expect(task.details).toBe(''); | ||
| expect(task.testStrategy).toBe(''); | ||
| }); | ||
|
|
||
| it('should use default value when metadata is null', () => { | ||
| const taskRow: TaskRow = { | ||
| id: '123', | ||
| display_id: '1', | ||
| title: 'Test Task', | ||
| description: 'Test description', | ||
| status: 'todo', | ||
| priority: 'medium', | ||
| parent_task_id: null, | ||
| subtask_position: 0, | ||
| created_at: new Date().toISOString(), | ||
| updated_at: new Date().toISOString(), | ||
| metadata: null, | ||
| complexity: null, | ||
| assignee_id: null, | ||
| estimated_hours: null, | ||
| actual_hours: null, | ||
| due_date: null, | ||
| completed_at: null | ||
| }; | ||
|
|
||
| const task = TaskMapper.mapDatabaseTaskToTask(taskRow, [], new Map()); | ||
|
|
||
| expect(task.details).toBe(''); | ||
| expect(task.testStrategy).toBe(''); | ||
| }); | ||
|
|
||
| it('should use default value and warn when metadata field has wrong type', () => { | ||
| const consoleWarnSpy = vi | ||
| .spyOn(console, 'warn') | ||
| .mockImplementation(() => {}); | ||
|
|
||
| const taskRow: TaskRow = { | ||
| id: '123', | ||
| display_id: '1', | ||
| title: 'Test Task', | ||
| description: 'Test description', | ||
| status: 'todo', | ||
| priority: 'medium', | ||
| parent_task_id: null, | ||
| subtask_position: 0, | ||
| created_at: new Date().toISOString(), | ||
| updated_at: new Date().toISOString(), | ||
| metadata: { | ||
| details: 12345, // Wrong type: number instead of string | ||
| testStrategy: ['test1', 'test2'] // Wrong type: array instead of string | ||
| }, | ||
| complexity: null, | ||
| assignee_id: null, | ||
| estimated_hours: null, | ||
| actual_hours: null, | ||
| due_date: null, | ||
| completed_at: null | ||
| }; | ||
|
|
||
| const task = TaskMapper.mapDatabaseTaskToTask(taskRow, [], new Map()); | ||
|
|
||
| // Should use empty string defaults when type doesn't match | ||
| expect(task.details).toBe(''); | ||
| expect(task.testStrategy).toBe(''); | ||
|
|
||
| // Should have logged warnings | ||
| expect(consoleWarnSpy).toHaveBeenCalledWith( | ||
| expect.stringContaining('Type mismatch in metadata field "details"') | ||
| ); | ||
| expect(consoleWarnSpy).toHaveBeenCalledWith( | ||
| expect.stringContaining( | ||
| 'Type mismatch in metadata field "testStrategy"' | ||
| ) | ||
| ); | ||
|
|
||
| consoleWarnSpy.mockRestore(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('mapStatus', () => { | ||
| it('should map database status to internal status', () => { | ||
| expect(TaskMapper.mapStatus('todo')).toBe('pending'); | ||
| expect(TaskMapper.mapStatus('in_progress')).toBe('in-progress'); | ||
| expect(TaskMapper.mapStatus('done')).toBe('done'); | ||
| }); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Nitpick | π΅ Trivial
Unit tests look solid for metadata and status mapping.
Consider adding a parentId mapping assertion to prevent regressions.
Example additional test:
@@
describe('TaskMapper', () => {
+ it('should set subtask.parentId to the exposed parent id (display_id when present)', () => {
+ const parent: TaskRow = {
+ id: 'uuid-123',
+ display_id: 'T-1',
+ title: 'Parent',
+ description: '',
+ status: 'todo',
+ priority: 'medium',
+ parent_task_id: null,
+ subtask_position: 0,
+ created_at: new Date().toISOString(),
+ updated_at: new Date().toISOString(),
+ metadata: {},
+ complexity: null,
+ assignee_id: null,
+ estimated_hours: null,
+ actual_hours: null,
+ due_date: null,
+ completed_at: null
+ };
+ const sub: TaskRow = {
+ ...parent,
+ id: 'uuid-sub-1',
+ display_id: 'T-1.1',
+ title: 'Sub',
+ parent_task_id: 'uuid-123',
+ subtask_position: 1
+ };
+ const task = TaskMapper.mapDatabaseTaskToTask(parent, [sub], new Map());
+ expect(task.id).toBe('T-1');
+ expect(task.subtasks[0].parentId).toBe('T-1');
+ });Please run the test suite after applying the mapper fixes:
- npx vitest run
| const subtasks: Subtask[] = dbSubtasks.map((subtask, index) => ({ | ||
| id: index + 1, // Use numeric ID for subtasks | ||
| id: subtask.display_id || String(index + 1), // Use display_id if available (API storage), fallback to numeric (file storage) | ||
| parentId: dbTask.id, | ||
| title: subtask.title, | ||
| description: subtask.description || '', | ||
| status: this.mapStatus(subtask.status), | ||
| priority: this.mapPriority(subtask.priority), | ||
| dependencies: dependenciesByTaskId.get(subtask.id) || [], | ||
| details: (subtask.metadata as any)?.details || '', | ||
| testStrategy: (subtask.metadata as any)?.testStrategy || '', | ||
| details: this.extractMetadataField(subtask.metadata, 'details', ''), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Subtask.parentId should match exposed parent Task.id (display_id when present).
Currently uses dbTask.id, which desynchronizes references when display_id exists.
Apply this diff:
const subtasks: Subtask[] = dbSubtasks.map((subtask, index) => ({
id: subtask.display_id || String(index + 1),
- parentId: dbTask.id,
+ parentId: dbTask.display_id || dbTask.id,
title: subtask.title,
description: subtask.description || '',
status: this.mapStatus(subtask.status),
priority: this.mapPriority(subtask.priority),
dependencies: dependenciesByTaskId.get(subtask.id) || [],π€ Prompt for AI Agents
In packages/tm-core/src/mappers/TaskMapper.ts around lines 55 to 63, the
Subtask.parentId is set to dbTask.id which breaks references when the parent
Task exposes display_id; change parentId to use the exposed parent identifier
(dbTask.display_id if present, otherwise dbTask.id) so subtask.parentId matches
the Task.id consumers see, and ensure the value is coerced to a string if
needed.
| // Handle both old format (UUID string) and new format (object with display_id) | ||
| const dependencyId = | ||
| typeof dep.depends_on_task === 'object' | ||
| ? dep.depends_on_task?.display_id | ||
| : dep.depends_on_task_id; | ||
| if (dependencyId) { | ||
| deps.push(dependencyId); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Legacy dependency grouping can drop IDs when display_id is null due to null being typeof 'object'.
Fallback to depends_on_task_id when display_id is missing.
Apply this diff:
- // Handle both old format (UUID string) and new format (object with display_id)
- const dependencyId =
- typeof dep.depends_on_task === 'object'
- ? dep.depends_on_task?.display_id
- : dep.depends_on_task_id;
+ // Handle both formats; prefer display_id when present, else fallback to UUID
+ const dependencyId =
+ dep.depends_on_task?.display_id ?? dep.depends_on_task_id;
if (dependencyId) {
deps.push(dependencyId);
}π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Handle both old format (UUID string) and new format (object with display_id) | |
| const dependencyId = | |
| typeof dep.depends_on_task === 'object' | |
| ? dep.depends_on_task?.display_id | |
| : dep.depends_on_task_id; | |
| if (dependencyId) { | |
| deps.push(dependencyId); | |
| } | |
| // Handle both formats; prefer display_id when present, else fallback to UUID | |
| const dependencyId = | |
| dep.depends_on_task?.display_id ?? dep.depends_on_task_id; | |
| if (dependencyId) { | |
| deps.push(dependencyId); | |
| } |
π€ Prompt for AI Agents
In packages/tm-core/src/mappers/TaskMapper.ts around lines 110 to 117, the
current ternary picks dep.depends_on_task.display_id when depends_on_task is an
object even if display_id is null, causing IDs to be dropped; change the
conditional to prefer display_id only when it is non-null/defined (e.g. typeof
depends_on_task === 'object' && dep.depends_on_task?.display_id != null),
otherwise fall back to dep.depends_on_task_id, and keep the existing push only
when the resolved dependencyId is truthy.
| // Handle metadata fields (details, testStrategy, etc.) | ||
| // Load existing metadata to preserve fields not being updated | ||
| const { data: existingMetadataRow, error: existingMetadataError } = | ||
| await this.supabase | ||
| .from('tasks') | ||
| .select('metadata') | ||
| .eq('brief_id', briefId) | ||
| .eq('display_id', taskId.toUpperCase()) | ||
| .single(); | ||
|
|
||
| if (existingMetadataError) { | ||
| throw new Error( | ||
| `Failed to load existing task metadata: ${existingMetadataError.message}` | ||
| ); | ||
| } | ||
|
|
||
| const metadata: Record<string, unknown> = { | ||
| ...((existingMetadataRow?.metadata as Record<string, unknown>) ?? {}) | ||
| }; | ||
|
|
||
| if (updates.details !== undefined) metadata.details = updates.details; | ||
| if (updates.testStrategy !== undefined) | ||
| metadata.testStrategy = updates.testStrategy; | ||
|
|
||
| if (Object.keys(metadata).length > 0) { | ||
| dbUpdates.metadata = metadata as Json; | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Nitpick | π΅ Trivial
Avoid unnecessary DB roundtrip for metadata.
You always SELECT metadata even when neither details nor testStrategy is being updated. Gate the fetch to those cases.
Apply this diff:
- // Handle metadata fields (details, testStrategy, etc.)
- // Load existing metadata to preserve fields not being updated
- const { data: existingMetadataRow, error: existingMetadataError } =
- await this.supabase
- .from('tasks')
- .select('metadata')
- .eq('brief_id', briefId)
- .eq('display_id', taskId.toUpperCase())
- .single();
-
- if (existingMetadataError) {
- throw new Error(
- `Failed to load existing task metadata: ${existingMetadataError.message}`
- );
- }
-
- const metadata: Record<string, unknown> = {
- ...((existingMetadataRow?.metadata as Record<string, unknown>) ?? {})
- };
-
- if (updates.details !== undefined) metadata.details = updates.details;
- if (updates.testStrategy !== undefined)
- metadata.testStrategy = updates.testStrategy;
-
- if (Object.keys(metadata).length > 0) {
- dbUpdates.metadata = metadata as Json;
- }
+ // Handle metadata fields (details, testStrategy, etc.)
+ if (updates.details !== undefined || updates.testStrategy !== undefined) {
+ // Load existing metadata to preserve fields not being updated
+ const { data: existingMetadataRow, error: existingMetadataError } =
+ await this.supabase
+ .from('tasks')
+ .select('metadata')
+ .eq('brief_id', briefId)
+ .eq('display_id', taskId.toUpperCase())
+ .single();
+
+ if (existingMetadataError) {
+ throw new Error(
+ `Failed to load existing task metadata: ${existingMetadataError.message}`
+ );
+ }
+
+ const metadata: Record<string, unknown> = {
+ ...((existingMetadataRow?.metadata as Record<string, unknown>) ?? {})
+ };
+
+ if (updates.details !== undefined) metadata.details = updates.details;
+ if (updates.testStrategy !== undefined)
+ metadata.testStrategy = updates.testStrategy;
+
+ if (Object.keys(metadata).length > 0) {
+ dbUpdates.metadata = metadata as Json;
+ }
+ }π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Handle metadata fields (details, testStrategy, etc.) | |
| // Load existing metadata to preserve fields not being updated | |
| const { data: existingMetadataRow, error: existingMetadataError } = | |
| await this.supabase | |
| .from('tasks') | |
| .select('metadata') | |
| .eq('brief_id', briefId) | |
| .eq('display_id', taskId.toUpperCase()) | |
| .single(); | |
| if (existingMetadataError) { | |
| throw new Error( | |
| `Failed to load existing task metadata: ${existingMetadataError.message}` | |
| ); | |
| } | |
| const metadata: Record<string, unknown> = { | |
| ...((existingMetadataRow?.metadata as Record<string, unknown>) ?? {}) | |
| }; | |
| if (updates.details !== undefined) metadata.details = updates.details; | |
| if (updates.testStrategy !== undefined) | |
| metadata.testStrategy = updates.testStrategy; | |
| if (Object.keys(metadata).length > 0) { | |
| dbUpdates.metadata = metadata as Json; | |
| } | |
| // Handle metadata fields (details, testStrategy, etc.) | |
| if (updates.details !== undefined || updates.testStrategy !== undefined) { | |
| // Load existing metadata to preserve fields not being updated | |
| const { data: existingMetadataRow, error: existingMetadataError } = | |
| await this.supabase | |
| .from('tasks') | |
| .select('metadata') | |
| .eq('brief_id', briefId) | |
| .eq('display_id', taskId.toUpperCase()) | |
| .single(); | |
| if (existingMetadataError) { | |
| throw new Error( | |
| `Failed to load existing task metadata: ${existingMetadataError.message}` | |
| ); | |
| } | |
| const metadata: Record<string, unknown> = { | |
| ...((existingMetadataRow?.metadata as Record<string, unknown>) ?? {}) | |
| }; | |
| if (updates.details !== undefined) metadata.details = updates.details; | |
| if (updates.testStrategy !== undefined) | |
| metadata.testStrategy = updates.testStrategy; | |
| if (Object.keys(metadata).length > 0) { | |
| dbUpdates.metadata = metadata as Json; | |
| } | |
| } |
π€ Prompt for AI Agents
In packages/tm-core/src/repositories/supabase/supabase-task-repository.ts around
lines 167 to 194, the code always performs a SELECT to load existing metadata
even when neither updates.details nor updates.testStrategy are provided; modify
the logic to first check if at least one of those metadata fields is being
updated and only then perform the DB fetch and merge so we avoid an unnecessary
roundtrip. Specifically: gate the supabase.from('tasks').select('metadata') call
behind a condition that checks updates.details !== undefined ||
updates.testStrategy !== undefined, then keep the existing error handling, merge
existing metadata with the provided metadata fields, and assign
dbUpdates.metadata only when there are metadata changes.
| private mapPriorityToDatabase( | ||
| priority: string | ||
| ): Database['public']['Enums']['task_priority'] { | ||
| switch (priority) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Nitpick | π΅ Trivial
Narrow the priority param type.
Use the domain type for clarity and better type-safety.
Apply this diff:
- private mapPriorityToDatabase(
- priority: string
- ): Database['public']['Enums']['task_priority'] {
+ private mapPriorityToDatabase(
+ priority: Task['priority']
+ ): Database['public']['Enums']['task_priority'] {π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| private mapPriorityToDatabase( | |
| priority: string | |
| ): Database['public']['Enums']['task_priority'] { | |
| switch (priority) { | |
| private mapPriorityToDatabase( | |
| priority: Task['priority'] | |
| ): Database['public']['Enums']['task_priority'] { | |
| switch (priority) { |
π€ Prompt for AI Agents
In packages/tm-core/src/repositories/supabase/supabase-task-repository.ts around
lines 240 to 243, the mapPriorityToDatabase function accepts a plain string;
change its parameter to the domain priority type (use the existing domain type
for task priority, e.g. TaskPriority or whatever the project defines) to improve
type-safety, import that type at the top of the file, update the function
signature to use it instead of string, and ensure the switch cases and any
callers still compile (adjust callers if they pass raw strings by
converting/validating to the domain type before calling).
| * Subtask interface extending Task | ||
| * ID can be number (file storage) or string (API storage with display_id) | ||
| */ | ||
| export interface Subtask extends Omit<Task, 'id' | 'subtasks'> { | ||
| id: number; | ||
| id: number | string; | ||
| parentId: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type guard mismatch: Subtask.id widened to string | number, but isSubtask still enforces number.
This will reject valid subtasks with string IDs (e.g., display_id from API storage).
Apply this diff:
export function isSubtask(obj: unknown): obj is Subtask {
if (!obj || typeof obj !== 'object') return false;
const subtask = obj as Record<string, unknown>;
return (
- typeof subtask.id === 'number' &&
+ (typeof subtask.id === 'number' || typeof subtask.id === 'string') &&
typeof subtask.parentId === 'string' &&
typeof subtask.title === 'string' &&
typeof subtask.description === 'string' &&
isTaskStatus(subtask.status) &&
isTaskPriority(subtask.priority) &&
!('subtasks' in subtask)
);
}Also applies to: 234-243
π€ Prompt for AI Agents
In packages/tm-core/src/types/index.ts around lines 85-90 (and similarly lines
234-243), the Subtask interface was changed so id is number | string but the
isSubtask type guard still only accepts number IDs; update the isSubtask
implementation(s) to allow both string and number IDs (e.g., check typeof id ===
'number' || typeof id === 'string' and ensure parentId is present), and adjust
the guard's narrowing/return type accordingly so string-based subtasks
(display_id) are not rejected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 11
Caution
Some comments are outside the diff and canβt be posted inline due to platform limitations.
β οΈ Outside diff range comments (5)
apps/cli/src/commands/list.command.ts (1)
284-299: Bug: nextTask subtask IDs arenβt resolved to objects (breaks dashboard/recommendation).When findNextTask returns an id like "5.2", tasks.find(...) against top-level ids fails, so nextTask becomes undefined. Resolve parent/subtask explicitly and pass correct data to dashboards and recommendation.
Apply this fix:
- const nextTask = nextTaskInfo - ? tasks.find((t) => String(t.id) === String(nextTaskInfo.id)) - : undefined; + const nextTaskResolved = nextTaskInfo + ? (() => { + const idStr = String(nextTaskInfo.id); + if (idStr.includes('.')) { + const [parentId, subId] = idStr.split('.'); + const parent = tasks.find((t) => String(t.id) === parentId); + const sub = parent?.subtasks?.find((st) => String(st.id) === subId); + return parent && sub ? { kind: 'subtask' as const, parent, sub } : undefined; + } + const task = tasks.find((t) => String(t.id) === idStr); + return task ? { kind: 'task' as const, task } : undefined; + })() + : undefined; @@ - displayDashboards( + displayDashboards( taskStats, subtaskStats, priorityBreakdown, depStats, - nextTask + nextTaskResolved + ? nextTaskResolved.kind === 'task' + ? nextTaskResolved.task + : nextTaskResolved.parent + : undefined ); @@ - if (nextTask) { - const description = getTaskDescription(nextTask); - displayRecommendedNextTask({ - id: nextTask.id, - title: nextTask.title, - priority: nextTask.priority, - status: nextTask.status, - dependencies: nextTask.dependencies, - description, - complexity: nextTask.complexity as number | undefined - }); + if (nextTaskResolved && nextTaskInfo) { + const displayId = String(nextTaskInfo.id); + const payload = + nextTaskResolved.kind === 'task' + ? { + id: displayId, + title: nextTaskResolved.task.title, + priority: nextTaskResolved.task.priority, + status: nextTaskResolved.task.status, + dependencies: nextTaskResolved.task.dependencies?.map(String), + description: getTaskDescription(nextTaskResolved.task), + complexity: (nextTaskResolved.task as any).complexity as number | undefined + } + : { + id: displayId, + title: nextTaskResolved.sub.title || `Subtask ${displayId}`, + priority: + nextTaskResolved.sub.priority || nextTaskResolved.parent.priority, + status: nextTaskResolved.sub.status, + dependencies: (nextTaskResolved.sub.dependencies || []).map(String), + description: + (nextTaskResolved.sub as any).description ?? + ((nextTaskResolved.sub as any).details + ? String((nextTaskResolved.sub as any).details) + .split('\n')[0] + .split('.')[0] + : undefined), + complexity: (nextTaskResolved.sub as any).complexity as number | undefined + }; + displayRecommendedNextTask(payload); } else { displayRecommendedNextTask(undefined); }Also applies to: 309-321
apps/cli/src/commands/context.command.ts (2)
353-358: Fix return message to use defined brief labelselectedBrief.name is not set in choices, resulting in βundefinedβ. Use briefName (already computed) or a fallback.
- return { - success: true, - action: 'select-brief', - context: this.authManager.getContext() || undefined, - message: `Selected brief: ${selectedBrief.name}` - }; + return { + success: true, + action: 'select-brief', + context: this.authManager.getContext() || undefined, + message: `Selected brief: ${briefName}` + };
470-473: Provide a safe default for TM_PUBLIC_BASE_DOMAIN in help textIf the env is unset, message shows βhttps://undefined/...β. Add a fallback.
- ui.displayError( - `Provide a valid brief ID or a Hamster brief URL, e.g. https://${process.env.TM_PUBLIC_BASE_DOMAIN}/home/hamster/briefs/<id>` - ); + const base = process.env.TM_PUBLIC_BASE_DOMAIN || 'app.tryhamster.com'; + ui.displayError( + `Provide a valid brief ID or a Hamster brief URL, e.g. https://${base}/home/hamster/briefs/<id>` + );apps/cli/src/commands/start.command.ts (1)
293-303: Remove process signal listeners after child exitsAvoid accumulating listeners in tests/long-lived processes.
- process.on('SIGINT', cleanup); - process.on('SIGTERM', cleanup); - process.on('exit', cleanup); + const onSigInt = cleanup; + const onSigTerm = cleanup; + const onExit = cleanup; + process.on('SIGINT', onSigInt); + process.on('SIGTERM', onSigTerm); + process.on('exit', onExit); + const removeListeners = () => { + process.off('SIGINT', onSigInt); + process.off('SIGTERM', onSigTerm); + process.off('exit', onExit); + }; + childProcess.on('close', () => removeListeners()); + childProcess.on('error', () => removeListeners());apps/cli/src/commands/auth.command.ts (1)
221-223: Unify CLI binary name in help textElsewhere you use βtmβ; this says βtask-masterβ. Align for consistency.
- console.log( - chalk.gray('\n Run "task-master auth login" to authenticate') - ); + console.log(chalk.gray('\n Run "tm auth login" to authenticate'));
β»οΈ Duplicate comments (2)
packages/tm-core/src/storage/file-storage/file-storage.ts (2)
24-31: Stale complexity cache after mutating opsAfter introducing
complexityManager, none of the write paths (saveTasks,deleteTag,renameTag, etc.) clear the per-tag cache. Any task mutation now leavesComplexityReportManagerserving stale entries, so subsequentloadTasksreturns outdated complexity data until the process restarts. Please callthis.complexityManager.clearCache(resolvedTag)(and clear affected tags in rename/delete flows) once writes succeed.await this.fileOps.writeJson(filePath, existingData); + this.complexityManager.clearCache(resolvedTag);Propagate similar invalidations to other write paths that bypass
saveTasks.
96-121: Make complexity enrichment opt-in
loadTasksnow always callsenrichTasksWithComplexity. For tags without a report this issues anfs.access+ENOENThandling every read becauseComplexityReportManagerdoesnβt cache negative lookups. High-volume reads (CLI listing, metadata updates) now incur wasted disk I/O and JSON parsing with no benefit, matching the previously raised latency concern. Please gate enrichment behind an option (e.g.,options?.includeComplexity) or otherwise short-circuit when callers donβt need it, caching βno reportβ results if enrichment is requested.
π Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
π Files selected for processing (25)
.changeset/pre.json(1 hunks)CHANGELOG.md(1 hunks)apps/cli/src/command-registry.ts(1 hunks)apps/cli/src/commands/auth.command.ts(1 hunks)apps/cli/src/commands/context.command.ts(1 hunks)apps/cli/src/commands/export.command.ts(1 hunks)apps/cli/src/commands/list.command.ts(5 hunks)apps/cli/src/commands/set-status.command.ts(1 hunks)apps/cli/src/commands/show.command.ts(1 hunks)apps/cli/src/commands/start.command.ts(1 hunks)apps/cli/src/index.ts(1 hunks)package.json(7 hunks)packages/tm-core/src/errors/task-master-error.ts(1 hunks)packages/tm-core/src/index.ts(2 hunks)packages/tm-core/src/interfaces/storage.interface.ts(3 hunks)packages/tm-core/src/repositories/supabase/supabase-task-repository.ts(1 hunks)packages/tm-core/src/repositories/task-repository.interface.ts(1 hunks)packages/tm-core/src/services/export.service.ts(1 hunks)packages/tm-core/src/services/index.ts(1 hunks)packages/tm-core/src/services/task-service.ts(3 hunks)packages/tm-core/src/storage/api-storage.ts(4 hunks)packages/tm-core/src/storage/file-storage/file-storage.ts(5 hunks)packages/tm-core/src/task-master-core.ts(6 hunks)scripts/modules/commands.js(11 hunks)tsdown.config.ts(2 hunks)
π§° Additional context used
π Path-based instructions (7)
.changeset/*
π CodeRabbit inference engine (.cursor/rules/new_features.mdc)
Create appropriate changesets for new features, use semantic versioning, include tagged system information in release notes, and document breaking changes if any.
Files:
.changeset/pre.json
package.json
π CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)
Add and update test scripts in package.json to include test, test:watch, test:coverage, test:unit, test:integration, test:e2e, and test:ci
Files:
package.json
scripts/modules/commands.js
π CodeRabbit inference engine (.cursor/rules/ai_services.mdc)
scripts/modules/commands.js: Centralize all LLM calls throughgenerateTextServiceorgenerateObjectService.
Do not import or call anything from the oldai-services.js,ai-client-factory.js, orai-client-utils.jsfiles.
Do not fetch AI-specific parameters (model ID, max tokens, temp) usingconfig-manager.jsgetters for the AI call. Pass theroleinstead.
Do not implement fallback or retry logic outsideai-services-unified.js.
Do not handle API key resolution outside the service layer (it usesutils.jsinternally).
Determine the appropriaterole(main,research,fallback) in your core logic and pass it to the service.
Pass thesessionobject (received in thecontextparameter, especially from direct function wrappers) to the service call when in MCP context.
UsegenerateTextServiceand implement robust manual JSON parsing (with Zod validation after parsing) when structured output is needed, asgenerateObjectServicehas shown unreliability with some providers/schemas.
Be aware of potential reliability issues withgenerateObjectServiceacross different providers and complex schemas. PrefergenerateTextService+ manual parsing as a more robust alternative for structured data needs.
scripts/modules/commands.js: All new user-facing commands should be added to 'scripts/modules/commands.js'.
Use consistent patterns for option naming and help text in CLI commands.
Follow the Commander.js model for subcommand structure in CLI commands.
When using callbacks (like in Commander.js commands), define them separately to allow testing the callback logic independently.
Add help text to the command definition and update 'dev_workflow.mdc' with command reference when adding a new feature.
Follow the established pattern in 'commands.js' for CLI command implementation, using Commander.js for argument parsing, including comprehensive help text and examples, and supporting tagged task context awareness.
Provide clear error messages for common failu...
Files:
scripts/modules/commands.js
scripts/modules/*.js
π CodeRabbit inference engine (.cursor/rules/architecture.mdc)
Each module in scripts/modules/ should be focused on a single responsibility, following the modular architecture (e.g., commands.js for CLI command handling, task-manager.js for task data and core logic, dependency-manager.js for dependency management, ui.js for CLI output formatting, ai-services-unified.js for AI service integration, config-manager.js for configuration management, utils.js for utility functions).
scripts/modules/*.js: Export all core functions, helper functions, and utility methods needed by your new function or command from their respective modules. Explicitly review the module's export block to ensure every required dependency is included.
Pass all required parameters to functions you call within your implementation and verify that direct function parameters match their core function counterparts.
Use consistent file naming conventions: 'task_${id.toString().padStart(3, '0')}.txt', use path.join for composing file paths, and use appropriate file extensions (.txt for tasks, .json for data).
Use structured error objects with code and message properties, include clear error messages, and handle both function-specific and file system errors.
Import all silent mode utilities together from 'scripts/modules/utils.js' and always use isSilentMode() to check global silent mode status. Wrap core function calls within direct functions using enableSilentMode() and disableSilentMode() in a try/finally block if the core function might produce console output.
Core functions should check outputFormat === 'text' before displaying UI elements and use internal logging that respects silent mode.
Design functions to accept dependencies as parameters (dependency injection) and avoid hard-coded dependencies that are difficult to mock.
Keep pure logic separate from I/O operations or UI rendering to allow testing the logic without mocking complex dependencies.
When implementing core logic for new features, do so in 'scripts/modules/' before CLI or MCP interfaces, and d...
Files:
scripts/modules/commands.js
scripts/modules/**
π CodeRabbit inference engine (.cursor/rules/dev_workflow.mdc)
When using the MCP server, restart it if core logic in
scripts/modulesor MCP tool/direct function definitions change.
Files:
scripts/modules/commands.js
scripts/modules/*
π CodeRabbit inference engine (.cursor/rules/tags.mdc)
scripts/modules/*: Every command that reads or writes tasks.json must be tag-aware
All command files must import getCurrentTag from utils.js
Every CLI command that operates on tasks must include the --tag CLI option
All commands must resolve the tag using the pattern: options.tag || getCurrentTag(projectRoot) || 'master'
All commands must find projectRoot with error handling before proceeding
All commands must pass { projectRoot, tag } as context to core functions
MCP direct functions must accept and use a context object containing projectRoot and tag, and pass them to core functions
Do not hard-code tag resolution (e.g., const tag = options.tag || 'master';); always use getCurrentTag
Do not omit the --tag CLI option in commands that operate on tasks
Do not omit the context parameter when calling core functions from commands
Do not call readJSON or writeJSON without passing projectRoot and tag
Files:
scripts/modules/commands.js
**/*.js
π CodeRabbit inference engine (.cursor/rules/tests.mdc)
**/*.js: Declare and initialize global variables at the top of modules to avoid hoisting issues.
Use proper function declarations to avoid hoisting issues and initialize variables before they are referenced.
Do not reference variables before their declaration in module scope.
Use dynamic imports (import()) to avoid initialization order issues in modules.
Files:
scripts/modules/commands.js
π§ Learnings (23)
π Learning: 2025-09-26T19:05:47.555Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1252
File: packages/ai-sdk-provider-grok-cli/package.json:11-13
Timestamp: 2025-09-26T19:05:47.555Z
Learning: In the eyaltoledano/claude-task-master repository, internal tm/ packages use a specific export pattern where the "exports" field points to TypeScript source files (./src/index.ts) while "main" points to compiled output (./dist/index.js) and "types" points to source files (./src/index.ts). This pattern is used consistently across internal packages like tm/core and tm/ai-sdk-provider-grok-cli because they are consumed directly during build-time bundling with tsdown rather than being published as separate packages.
Applied to files:
packages/tm-core/src/index.tspackages/tm-core/src/services/index.tspackages/tm-core/src/task-master-core.ts
π Learning: 2025-07-31T22:07:49.716Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/commands.mdc:0-0
Timestamp: 2025-07-31T22:07:49.716Z
Learning: Applies to scripts/modules/commands.js : Export the registerCommands function and keep the CLI setup code clean and maintainable.
Applied to files:
apps/cli/src/index.tsapps/cli/src/command-registry.tsscripts/modules/commands.js
π Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Use AI to generate detailed subtasks within the current tag context, considering complexity analysis for subtask counts and ensuring proper IDs for newly created subtasks.
Applied to files:
packages/tm-core/src/storage/file-storage/file-storage.ts
π Learning: 2025-07-18T17:12:57.903Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-07-18T17:12:57.903Z
Learning: Applies to .changeset/* : Create appropriate changesets for new features, use semantic versioning, include tagged system information in release notes, and document breaking changes if any.
Applied to files:
.changeset/pre.json
π Learning: 2025-08-03T12:13:33.875Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-08-03T12:13:33.875Z
Learning: Applies to package.json : Add and update test scripts in package.json to include test, test:watch, test:coverage, test:unit, test:integration, test:e2e, and test:ci
Applied to files:
package.json
π Learning: 2025-09-26T19:03:33.225Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1252
File: package.json:130-132
Timestamp: 2025-09-26T19:03:33.225Z
Learning: In the eyaltoledano/claude-task-master repository, packages are bundled using tsdown during the build process, which means dependencies imported by the source code (including tm internal packages like tm/ai-sdk-provider-grok-cli) are included in the final bundle and don't need to be available as separate runtime dependencies, so they should remain as devDependencies rather than being moved to dependencies.
Applied to files:
package.json
π Learning: 2025-07-18T17:06:04.909Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/ai_providers.mdc:0-0
Timestamp: 2025-07-18T17:06:04.909Z
Learning: Applies to src/ai-providers/*.js : Provider modules must import the provider's create<ProviderName> function from ai-sdk/<provider-name>, and import generateText, streamText, generateObject from the core ai package, as well as the log utility from ../../scripts/modules/utils.js.
Applied to files:
package.json
π Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Extract tasks from PRD documents using AI, create them in the current tag context (defaulting to 'master'), provide clear prompts to guide AI task generation, and validate/clean up AI-generated tasks.
Applied to files:
scripts/modules/commands.js
π Learning: 2025-07-18T17:18:17.759Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-07-18T17:18:17.759Z
Learning: Applies to scripts/modules/utils.js : Use tagged task system aware functions for task finding and manipulation, handle both task and subtask operations, and validate task IDs before operations.
Applied to files:
scripts/modules/commands.js
π Learning: 2025-07-18T17:07:39.336Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/architecture.mdc:0-0
Timestamp: 2025-07-18T17:07:39.336Z
Learning: Applies to scripts/modules/task-manager/*.js : Files in scripts/modules/task-manager/ should each handle a specific action related to task management (e.g., add-task.js, expand-task.js), supporting the tagged task lists system and backward compatibility.
Applied to files:
scripts/modules/commands.js
π Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Provide functions for updating task status within the current tag context, handling both individual tasks and subtasks, and considering subtask status when updating parent tasks.
Applied to files:
scripts/modules/commands.js
π Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Tasks must be accessed and updated through the tag resolution layer using getTasksForTag(data, tagName) and setTasksForTag(data, tagName, tasks); direct manipulation of the tagged structure in core functions is not allowed.
Applied to files:
scripts/modules/commands.js
π Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Tasks must be organized into separate contexts (tags) within tasks.json, using the tagged format: {"master": {"tasks": [...]}, "feature-branch": {"tasks": [...]}}. Legacy format {"tasks": [...]} must be silently migrated to the tagged format on first use.
Applied to files:
scripts/modules/commands.js
π Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Use tag resolution functions to maintain backward compatibility, returning legacy format to core functions and not exposing the tagged structure to existing core logic.
Applied to files:
scripts/modules/commands.js
π Learning: 2025-07-18T17:14:29.399Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-07-18T17:14:29.399Z
Learning: Applies to scripts/modules/task-manager.js : Generate task files from the current tag context, include tag information in generated files, and do not mix tasks from different tags in file generation.
Applied to files:
scripts/modules/commands.js
π Learning: 2025-07-18T17:12:57.903Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-07-18T17:12:57.903Z
Learning: Applies to scripts/modules/task-manager.js : Features that create, read, update, or delete tasks belong in 'scripts/modules/task-manager.js'.
Applied to files:
scripts/modules/commands.js
π Learning: 2025-07-18T17:09:40.548Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:40.548Z
Learning: Applies to scripts/modules/dependency-manager.js : Provide clear error messages for non-existent dependencies
Applied to files:
scripts/modules/commands.js
π Learning: 2025-09-24T15:12:12.658Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: assets/.windsurfrules:0-0
Timestamp: 2025-09-24T15:12:12.658Z
Learning: Manage dependencies with task-master add-dependency and remove-dependency; validate and fix using validate-dependencies and fix-dependencies
Applied to files:
scripts/modules/commands.js
π Learning: 2025-07-18T17:12:57.903Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-07-18T17:12:57.903Z
Learning: Applies to scripts/modules/dependency-manager.js : Features that handle task relationships belong in 'scripts/modules/dependency-manager.js'.
Applied to files:
scripts/modules/commands.js
π Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Check for existing dependencies to prevent duplicates
Applied to files:
scripts/modules/commands.js
π Learning: 2025-07-18T17:09:45.690Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dependencies.mdc:0-0
Timestamp: 2025-07-18T17:09:45.690Z
Learning: Applies to scripts/modules/dependency-manager.js : Format dependency lists consistently for visualization
Applied to files:
scripts/modules/commands.js
π Learning: 2025-07-31T22:08:16.039Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/taskmaster.mdc:0-0
Timestamp: 2025-07-31T22:08:16.039Z
Learning: Applies to .taskmaster/config.json : All other Taskmaster settings (model choice, max tokens, temperature, log level, custom endpoints) are managed in .taskmaster/config.json via the task-master models command or models MCP tool.
Applied to files:
scripts/modules/commands.js
π Learning: 2025-07-18T17:10:12.881Z
Learnt from: CR
PR: eyaltoledano/claude-task-master#0
File: .cursor/rules/dev_workflow.mdc:0-0
Timestamp: 2025-07-18T17:10:12.881Z
Learning: For CLI usage, install Taskmaster globally with `npm install -g task-master-ai` or use locally via `npx task-master-ai ...`.
Applied to files:
scripts/modules/commands.js
𧬠Code graph analysis (12)
packages/tm-core/src/repositories/task-repository.interface.ts (1)
packages/tm-core/src/interfaces/storage.interface.ts (1)
LoadTasksOptions(11-16)
packages/tm-core/src/storage/api-storage.ts (1)
packages/tm-core/src/interfaces/storage.interface.ts (1)
LoadTasksOptions(11-16)
packages/tm-core/src/services/task-service.ts (3)
packages/tm-core/src/logger/factory.ts (1)
getLogger(23-44)packages/tm-core/src/entities/task.entity.ts (1)
TaskEntity(17-275)packages/tm-core/src/logger/logger.ts (1)
error(163-166)
packages/tm-core/src/storage/file-storage/file-storage.ts (3)
packages/tm-core/src/reports/complexity-report-manager.ts (1)
ComplexityReportManager(21-185)packages/tm-core/src/interfaces/storage.interface.ts (1)
LoadTasksOptions(11-16)packages/tm-core/src/types/index.ts (1)
Task(57-82)
packages/tm-core/src/repositories/supabase/supabase-task-repository.ts (6)
packages/tm-core/src/repositories/supabase/dependency-fetcher.ts (1)
DependencyFetcher(8-68)packages/tm-core/src/types/database.types.ts (2)
Database(9-411)Json(1-7)packages/tm-core/src/interfaces/storage.interface.ts (1)
LoadTasksOptions(11-16)packages/tm-core/src/types/index.ts (1)
Task(57-82)packages/tm-core/src/types/repository-types.ts (2)
TaskWithRelations(9-16)TaskDatabaseUpdate(40-41)packages/tm-core/src/mappers/TaskMapper.ts (1)
TaskMapper(12-216)
packages/tm-core/src/interfaces/storage.interface.ts (1)
packages/tm-core/src/types/index.ts (2)
TaskStatus(20-28)Task(57-82)
apps/cli/src/commands/list.command.ts (1)
apps/cli/src/ui/components/next-task.component.ts (2)
getTaskDescription(125-141)displayRecommendedNextTask(27-120)
packages/tm-core/src/services/export.service.ts (2)
packages/tm-core/src/errors/task-master-error.ts (2)
TaskMasterError(130-329)ERROR_CODES(9-56)packages/tm-core/src/storage/file-storage/file-storage.ts (1)
FileStorage(20-662)
apps/cli/src/command-registry.ts (8)
apps/cli/src/index.ts (11)
CommandMetadata(20-20)CommandRegistry(17-17)ListTasksCommand(7-7)ShowCommand(8-8)StartCommand(11-11)SetStatusCommand(12-12)ExportCommand(13-13)AuthCommand(9-9)ContextCommand(10-10)registerAllCommands(18-18)registerCommandsByCategory(19-19)apps/cli/src/commands/list.command.ts (1)
ListTasksCommand(60-484)apps/cli/src/commands/show.command.ts (1)
ShowCommand(47-332)apps/cli/src/commands/start.command.ts (1)
StartCommand(44-503)apps/cli/src/commands/set-status.command.ts (1)
SetStatusCommand(57-297)apps/cli/src/commands/export.command.ts (1)
ExportCommand(32-379)apps/cli/src/commands/auth.command.ts (1)
AuthCommand(32-503)apps/cli/src/commands/context.command.ts (1)
ContextCommand(31-704)
packages/tm-core/src/task-master-core.ts (3)
packages/tm-core/src/services/export.service.ts (3)
ExportService(86-496)ExportTasksOptions(39-50)ExportResult(55-71)packages/tm-core/src/auth/auth-manager.ts (1)
AuthManager(26-280)packages/tm-core/src/auth/types.ts (1)
UserContext(16-22)
scripts/modules/commands.js (3)
apps/cli/src/command-registry.ts (1)
registerAllCommands(238-240)apps/cli/src/index.ts (1)
registerAllCommands(18-18)scripts/modules/task-manager/models.js (4)
options(149-149)options(277-277)options(368-368)options(656-656)
apps/cli/src/commands/export.command.ts (2)
packages/tm-core/src/services/export.service.ts (1)
ExportResult(55-71)packages/tm-core/src/task-master-core.ts (2)
ExportResult(59-59)TaskMasterCore(66-350)
πͺ markdownlint-cli2 (0.18.1)
CHANGELOG.md
46-46: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
53-53: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
59-59: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
π Additional comments (26)
packages/tm-core/src/services/index.ts (1)
8-13: Exports look correctRe-exporting
ExportServiceand its option/result types keeps the barrel in sync with the new service API. Good addition.packages/tm-core/src/index.ts (2)
14-16: Exported Types Verified:ConflictCheckResult,ExportTasksOptions, andExportResultare correctly declared and exported fromtask-master-core.tsand re-exported inindex.ts.
67-74: Exports verified ComplexityReportManager and all report types are correctly re-exported in packages/tm-core/src/reports/index.ts.packages/tm-core/src/errors/task-master-error.ts (1)
54-56: NOT_FOUND error code addition looks goodThe new entry keeps the enum-style map consistent and broadens downstream matching as expected.
packages/tm-core/src/repositories/task-repository.interface.ts (1)
2-6: Repository signature update is alignedImporting
LoadTasksOptionsand extendinggetTaskswith the optional options argument keeps the repo contract in sync with storage. Looks good to me.packages/tm-core/src/interfaces/storage.interface.ts (1)
8-40: LoadTasksOptions integration checks outDefining
LoadTasksOptionsand threading it throughIStorage/BaseStoragegives a clean extension point for pushing filters down to storage. Nicely structured.packages/tm-core/src/storage/api-storage.ts (1)
7-167: API storage now forwarding filter options correctlyImport updates and passing
optionsthrough torepository.getTasksmake the API backend participate in the new filter flow. Implementation stays consistent with existing tagging context.packages/tm-core/src/services/task-service.ts (1)
96-103: Guard optional filter before dereferencingWhen
options.filteris omitted (the default call path),options.filter.priorityon Line 98 throwsTypeError: Cannot read properties of undefined. Please cacheoptions.filterand use optional chaining (or similar) for all subsequent accesses so we safely handle the no-filter case.- const canPushStatusFilter = - options.filter?.status && - !options.filter.priority && - !options.filter.tags && - !options.filter.assignee && - !options.filter.search && - options.filter.hasSubtasks === undefined; + const filter = options.filter; + const canPushStatusFilter = + !!filter?.status && + !filter?.priority && + !filter?.tags && + !filter?.assignee && + !filter?.search && + filter?.hasSubtasks === undefined;Likely an incorrect or invalid review comment.
.changeset/pre.json (1)
1-26: LGTM! Pre-release configuration is correctly structured.The pre-release configuration properly sets up the RC flow with:
- RC tag for pre-release versions
- Initial versions matching the baseline (0.27.3)
- Comprehensive list of changesets to be included in the release
tsdown.config.ts (1)
3-7: LGTM! Clean migration to standard dotenv.The migration from
dotenv-monoto standarddotenvwith explicit absolute path resolution is a solid improvement. Usingresolve(process.cwd(), '.env')ensures the correct .env file is loaded regardless of the working directory.package.json (4)
3-3: Version bump aligns with pre-release configuration.The version bump to
0.28.0-rc.2correctly reflects the RC pre-release flow configured in.changeset/pre.json.
20-20: Good practice: Explicit NODE_ENV for tests.Setting
NODE_ENV=testexplicitly ensures consistent test behavior across environments.
131-131: Internal Grok CLI provider package verified.
- Implements
ProviderV2and exportscreateGrokCli/grokCli.- Imported in
src/ai-providers/grok-cli.js.- Covered by unit tests (
packages/ai-sdk-provider-grok-cli/src/grok-cli-provider.test.ts) and integration tests (tests/integration/providers/temperature-support.test.js).
55-103: Verify major dependency upgrades and integration code
- No deprecated AI SDK v4 patterns remain; v5 imports (
generateObject,generateText,streamText) are used insrc/ai-providers/gemini-cli.jsβreplace the commented legacy import inscripts/modules/ai-services-unified.js.- Review all Zod schemas for v4 breaking changes (unified error API, default unknownβkey behavior; opt into
.passthrough()or.strict()).- Confirm OpenRouter provider calls (
createOpenRouter) align with v1 factory API and updatedproviderOptions.apps/cli/src/index.ts (2)
13-13: Good addition of ExportCommand export.Public surface updated cleanly; no issues.
15-21: Command registry re-exports look correct.Consistent named and type re-exports for registry APIs. Matches consumers expecting centralized registration.
apps/cli/src/commands/show.command.ts (1)
325-331: Standardized register API looks good.Returning the command instance improves composability and aligns with registry usage.
apps/cli/src/commands/list.command.ts (1)
479-483: Register API alignment looks good.Returning the ListTasksCommand instance aligns with registry usage.
scripts/modules/commands.js (4)
17-23: Importing registry utilities from @tm/cli looks correct.Keeps this module lean; reuses centralized command definitions.
1813-1814: Wording update LGTM.βUse configured research modelβ is clearer and provider-agnostic.
1670-1675: Centralized command registration: no name collisions detected. Verified that none of the commands (list, show, start, set-status, export, auth, context) are defined locally in scripts/modules/commands.js.
3552-3555: Codex CLI provider flag support verified end-to-end. setModel(), config-manager, model registry, docs/models, and examples includecodex-cli.apps/cli/src/commands/context.command.ts (1)
697-703: Registration API change looks goodStatic register(program, name?) returning the command instance aligns with the new registry model.
apps/cli/src/commands/start.command.ts (1)
496-502: Registration method LGTMConsistent with the centralized registry pattern.
apps/cli/src/commands/auth.command.ts (1)
496-502: Registration method LGTMConstructor name param + static register(program, name?) pattern matches other commands.
apps/cli/src/commands/export.command.ts (1)
95-101: Avoid direct process.exit in export.command.ts; use this.error and program.exitOverride
- In export.command.ts (lines 99, 122, 131, 138, 151 & 201), replace each
ui.displayError(...)+process.exit(1),spinner.fail(...)+process.exit(1), and theprocess.exit(0)on cancellation with Commanderβsthis.error('β¦')(non-zero) or return/this.exit(0)(zero).- In your CLI bootstrap (e.g., apps/cli/src/index.ts), invoke
program.exitOverride()before.parse()sothis.error()flows through without killing the process.β Skipped due to learnings
Learnt from: joedanz PR: eyaltoledano/claude-task-master#748 File: scripts/modules/task-manager/parse-prd.js:726-733 Timestamp: 2025-07-21T17:51:07.239Z Learning: In CLI contexts within task-manager modules like scripts/modules/task-manager/parse-prd.js, using process.exit(1) for validation failures and error conditions is correct and preferred over throwing errors, as it provides immediate termination with appropriate exit codes for scripting. The code should distinguish between MCP contexts (throw errors) and CLI contexts (use process.exit).
| export interface CommandMetadata { | ||
| name: string; | ||
| description: string; | ||
| commandClass: typeof Command; | ||
| category?: 'task' | 'auth' | 'utility' | 'development'; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Nitpick | π΅ Trivial
Tighten typing for command constructors; avoid any casts.
Define a constructor type that optionally includes static register/registerOn, and use it in metadata/registration. This preserves compile-time safety.
export interface CommandMetadata {
name: string;
description: string;
- commandClass: typeof Command;
+ commandClass: RegistrableCommandCtor;
category?: 'task' | 'auth' | 'utility' | 'development';
}
+
+type RegistrableCommandCtor = {
+ new (name?: string): Command;
+ register?: (program: Command, name?: string) => unknown;
+ registerOn?: (program: Command) => unknown;
+};
@@
- private static registerCommand(
- program: Command,
- metadata: CommandMetadata
- ): void {
- const CommandClass = metadata.commandClass as any;
+ private static registerCommand(
+ program: Command,
+ metadata: CommandMetadata
+ ): void {
+ const CommandClass = metadata.commandClass;
@@
- if (CommandClass.registerOn) {
+ if (CommandClass.registerOn) {
CommandClass.registerOn(program);
- } else if (CommandClass.register) {
+ } else if (CommandClass.register) {
CommandClass.register(program);
} else {
// Fallback to creating instance and adding
- const instance = new CommandClass();
+ const instance = new CommandClass();
program.addCommand(instance);
}
}Also applies to: 129-145
| // Use the static registration method that all commands have | ||
| if (CommandClass.registerOn) { | ||
| CommandClass.registerOn(program); | ||
| } else if (CommandClass.register) { | ||
| CommandClass.register(program); | ||
| } else { | ||
| // Fallback to creating instance and adding |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Nitpick | π΅ Trivial
Legacy registerOn fallback retained.
Ok for transition; consider removing once all commands adopt static register(program, name?).
π€ Prompt for AI Agents
In apps/cli/src/command-registry.ts around lines 135-141 the code still keeps
the legacy registerOn and instance-creation fallback; remove the else branch
that falls back to creating a Command instance and the registerOn path so the
registry always calls the modern static register(program, name?) method on
CommandClass; update the Command type/interface to require static
register(program, name?) and adjust the callsite to pass the name if needed,
then run tests and update any command modules that still implement registerOn or
instance registration to the new static signature.
| try { | ||
| // Initialize TaskMasterCore | ||
| this.taskMasterCore = await TaskMasterCore.create({ | ||
| projectPath: process.cwd() | ||
| }); | ||
| } catch (error) { | ||
| throw new Error( | ||
| `Failed to initialize services: ${(error as Error).message}` | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Nitpick | π΅ Trivial
Preserve error cause when wrapping initialization errors
Keep original stack/cause for debugging.
- throw new Error(
- `Failed to initialize services: ${(error as Error).message}`
- );
+ throw new Error('Failed to initialize services', { cause: error as Error });π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| try { | |
| // Initialize TaskMasterCore | |
| this.taskMasterCore = await TaskMasterCore.create({ | |
| projectPath: process.cwd() | |
| }); | |
| } catch (error) { | |
| throw new Error( | |
| `Failed to initialize services: ${(error as Error).message}` | |
| ); | |
| } | |
| try { | |
| // Initialize TaskMasterCore | |
| this.taskMasterCore = await TaskMasterCore.create({ | |
| projectPath: process.cwd() | |
| }); | |
| } catch (error) { | |
| throw new Error('Failed to initialize services', { cause: error as Error }); | |
| } |
π€ Prompt for AI Agents
In apps/cli/src/commands/export.command.ts around lines 74 to 83, the catch
block currently rethrows a new Error and loses the original error's stack/cause;
update the throw to preserve the original error by passing it as the cause (for
example: throw new Error('Failed to initialize services', { cause: error })) or
rethrow the original error after annotating, ensuring the original stack and
error object are retained for debugging.
| } catch (error: any) { | ||
| if (spinner?.isSpinning) spinner.fail('Export failed'); | ||
| this.handleError(error); | ||
| process.exit(1); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion | π Major
Set lastResult on failure before exiting
So programmatic callers/tests can inspect failure details.
} catch (error: any) {
if (spinner?.isSpinning) spinner.fail('Export failed');
this.handleError(error);
+ this.lastResult = { success: false, action: 'export', message: error?.message || 'Export failed' };
process.exit(1);
}π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| } catch (error: any) { | |
| if (spinner?.isSpinning) spinner.fail('Export failed'); | |
| this.handleError(error); | |
| process.exit(1); | |
| } | |
| } | |
| } catch (error: any) { | |
| if (spinner?.isSpinning) spinner.fail('Export failed'); | |
| this.handleError(error); | |
| this.lastResult = { success: false, action: 'export', message: error?.message || 'Export failed' }; | |
| process.exit(1); | |
| } | |
| } |
π€ Prompt for AI Agents
In apps/cli/src/commands/export.command.ts around lines 198 to 203, the catch
block exits without setting the command's lastResult, so programmatic
callers/tests can't inspect failure details; before calling process.exit(1) (and
preferably before spinner.fail), assign this.lastResult = { success: false,
error: extract relevant error fields (e.g. message and stack or serialized
error), code: optional error.code } so callers can inspect the failure, then
call spinner.fail and process.exit(1).
| private extractBriefId(input: string): string | null { | ||
| const raw = input?.trim() ?? ''; | ||
| if (!raw) return null; | ||
|
|
||
| const parseUrl = (s: string): URL | null => { | ||
| try { | ||
| return new URL(s); | ||
| } catch {} | ||
| try { | ||
| return new URL(`https://${s}`); | ||
| } catch {} | ||
| return null; | ||
| }; | ||
|
|
||
| const fromParts = (path: string): string | null => { | ||
| const parts = path.split('/').filter(Boolean); | ||
| const briefsIdx = parts.lastIndexOf('briefs'); | ||
| const candidate = | ||
| briefsIdx >= 0 && parts.length > briefsIdx + 1 | ||
| ? parts[briefsIdx + 1] | ||
| : parts[parts.length - 1]; | ||
| return candidate?.trim() || null; | ||
| }; | ||
|
|
||
| // Try URL parsing | ||
| const url = parseUrl(raw); | ||
| if (url) { | ||
| const qId = url.searchParams.get('id') || url.searchParams.get('briefId'); | ||
| const candidate = (qId || fromParts(url.pathname)) ?? null; | ||
| if (candidate) { | ||
| if (this.isLikelyId(candidate) || candidate.length >= 8) { | ||
| return candidate; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Check if it looks like a path | ||
| if (raw.includes('/')) { | ||
| const candidate = fromParts(raw); | ||
| if (candidate && (this.isLikelyId(candidate) || candidate.length >= 8)) { | ||
| return candidate; | ||
| } | ||
| } | ||
|
|
||
| // Return raw if it looks like an ID | ||
| return raw; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§Ή Nitpick | π΅ Trivial
π§© Analysis chain
Deduplicate brief ID parsing across commands
extractBriefId is duplicated here and in context.command.ts. Extract to a shared util to prevent drift.
Proposed utility (apps/cli/src/utils/brief-input.util.ts):
export function extractBriefId(input: string): string | null { /* move shared logic */ }
export function isLikelyBriefId(value: string): boolean { /* move regexes */ }Then replace method bodies here with calls to the util.
Find duplicates:
π Script executed:
#!/bin/bash
rg -nP --type=ts 'extractBriefId\s*\(' apps/cliLength of output: 393
Deduplicate briefβID parsing into a shared util
- Both
apps/cli/src/commands/export.command.tsandcontext.command.tsdefine identicalextractBriefId(and useisLikelyId). - Move both functions into
apps/cli/src/utils/brief-input.util.ts(exportingextractBriefIdandisLikelyBriefId), then import and delegate in each command.
π€ Prompt for AI Agents
In apps/cli/src/commands/export.command.ts around lines 238 to 284, the
extractBriefId (and its helper isLikelyId) are duplicated across
export.command.ts and context.command.ts; move the logic into a single shared
utility at apps/cli/src/utils/brief-input.util.ts exporting extractBriefId and
isLikelyBriefId, update both commands to import those functions and delegate to
them (replace local implementations), and adjust any references to isLikelyId to
use the new exported name; ensure the new util is exported with proper named
exports and update import paths in both command files so the project builds.
| task.subtasks.forEach((subtask) => { | ||
| const subIcon = STATUS_ICONS[subtask.status]; | ||
| console.log( | ||
| ` ${chalk.gray(`${task.id}.${subtask.id}`)} ${subIcon} ${chalk.gray(subtask.title)}` | ||
| ` ${chalk.gray(String(subtask.id))} ${subIcon} ${chalk.gray(subtask.title)}` | ||
| ); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Compact view: include parent id for subtask rows to avoid ambiguity.
Only showing subtask.id loses parent context (e.g., β2β under multiple parents). Prefer βparent.subtaskβ.
- console.log(
- ` ${chalk.gray(String(subtask.id))} ${subIcon} ${chalk.gray(subtask.title)}`
- );
+ console.log(
+ ` ${chalk.gray(`${task.id}.${subtask.id}`)} ${subIcon} ${chalk.gray(subtask.title)}`
+ );π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| task.subtasks.forEach((subtask) => { | |
| const subIcon = STATUS_ICONS[subtask.status]; | |
| console.log( | |
| ` ${chalk.gray(`${task.id}.${subtask.id}`)} ${subIcon} ${chalk.gray(subtask.title)}` | |
| ` ${chalk.gray(String(subtask.id))} ${subIcon} ${chalk.gray(subtask.title)}` | |
| ); | |
| }); | |
| task.subtasks.forEach((subtask) => { | |
| const subIcon = STATUS_ICONS[subtask.status]; | |
| console.log( | |
| ` ${chalk.gray(`${task.id}.${subtask.id}`)} ${subIcon} ${chalk.gray(subtask.title)}` | |
| ); | |
| }); |
π€ Prompt for AI Agents
In apps/cli/src/commands/list.command.ts around lines 246 to 251, subtask rows
currently print only subtask.id which loses parent context; change the displayed
id to include the parent task id (e.g., use task.id + '.' + subtask.id) so rows
show "parent.subtask" (keep existing spacing/formatting and STATUS_ICONS usage).
| ## 0.28.0-rc.2 | ||
|
|
||
| ### Minor Changes | ||
|
|
||
| - [#1273](https://github.com/eyaltoledano/claude-task-master/pull/1273) [`b43b7ce`](https://github.com/eyaltoledano/claude-task-master/commit/b43b7ce201625eee956fb2f8cd332f238bb78c21) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Add Codex CLI provider with OAuth authentication | ||
| - Added codex-cli provider for GPT-5 and GPT-5-Codex models (272K input / 128K output) | ||
| - OAuth-first authentication via `codex login` - no API key required | ||
| - Optional OPENAI_CODEX_API_KEY support | ||
| - Codebase analysis capabilities automatically enabled | ||
| - Command-specific settings and approval/sandbox modes | ||
|
|
||
| ### Patch Changes | ||
|
|
||
| - [#1277](https://github.com/eyaltoledano/claude-task-master/pull/1277) [`7b5a7c4`](https://github.com/eyaltoledano/claude-task-master/commit/7b5a7c4495a68b782f7407fc5d0e0d3ae81f42f5) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP connection errors caused by deprecated generateTaskFiles calls. Resolves "Cannot read properties of null (reading 'toString')" errors when using MCP tools for task management operations. | ||
|
|
||
| - [#1276](https://github.com/eyaltoledano/claude-task-master/pull/1276) [`caee040`](https://github.com/eyaltoledano/claude-task-master/commit/caee040907f856d31a660171c9e6d966f23c632e) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP server error when file parameter not provided - now properly constructs default tasks.json path instead of failing with 'tasksJsonPath is required' error. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add the final 0.28.0 section before shipping.
This PR is branded βRelease 0.28.0β, yet the changelog still stops at 0.28.0-rc.2. Please add the actual ## 0.28.0 entry (even if it rolls up the RC notes) so downstream tooling and humans see a tagged release note instead of the last RC.
π€ Prompt for AI Agents
In CHANGELOG.md around lines 3 to 18, the changelog ends at 0.28.0-rc.2 but the
release is 0.28.0; add a new top-level section header "## 0.28.0" (immediately
above or replacing the RC heading as preferred) containing the final release
notes β you can roll up the RC notes or copy them under the new header β and
ensure formatting matches existing sections so downstream tooling recognizes the
tagged release.
| ### Key Changes: | ||
| - **Unified AI Service**: Replaced separate generateText implementations with a single generateObjectService that handles structured data generation | ||
| - **JSON Mode Support**: Added proper JSON mode configuration for providers that support it (OpenAI, Anthropic, Google, Groq) | ||
| - **Schema Validation**: Integrated Zod schemas for all AI-generated content with automatic validation | ||
| - **Provider Compatibility**: Maintained compatibility with all existing providers while leveraging their native structured output capabilities | ||
| - **Improved Reliability**: Structured output generation reduces parsing errors and ensures consistent data formats | ||
|
|
||
| ### Technical Improvements: | ||
| - Centralized provider configuration in `ai-providers-unified.js` | ||
| - Added `generateObject` support detection for each provider | ||
| - Implemented proper error handling for schema validation failures | ||
| - Maintained backward compatibility with existing prompt structures | ||
|
|
||
| ### Bug Fixes: | ||
| - Fixed subtask ID numbering issue where AI was generating inconsistent IDs (101-105, 601-603) instead of sequential numbering (1, 2, 3...) | ||
| - Enhanced prompt instructions to enforce proper ID generation patterns | ||
| - Ensured subtasks display correctly as X.1, X.2, X.3 format |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix Markdown heading spacing.
### Key Changes, ### Technical Improvements, and ### Bug Fixes are missing blank lines around the headings, which is tripping markdownlint (MD022). Add an empty line both before and after each heading inside the bullet to quiet the lint and keep formatting consistent. Based on static analysis.
π§° Tools
πͺ markdownlint-cli2 (0.18.1)
46-46: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
53-53: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
59-59: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
π€ Prompt for AI Agents
In CHANGELOG.md around lines 46 to 62, the Markdown headings "### Key Changes",
"### Technical Improvements", and "### Bug Fixes" are missing blank lines before
and after them which triggers MD022; add a single empty line both above and
below each of these headings (so there's a blank line separating the previous
bullet paragraph and the heading, and another blank line between the heading and
the following list) to satisfy markdownlint and preserve current bullet
formatting.
| private mapStatusToDatabase( | ||
| status: string | ||
| ): Database['public']['Enums']['task_status'] { | ||
| switch (status) { | ||
| case 'pending': | ||
| return 'todo'; | ||
| case 'in-progress': | ||
| case 'in_progress': // Accept both formats | ||
| return 'in_progress'; | ||
| case 'done': | ||
| return 'done'; | ||
| default: | ||
| throw new Error( | ||
| `Invalid task status: ${status}. Valid statuses are: pending, in-progress, done` | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Status filter/update throws for valid task statuses
TaskStatusSchema and our domain model allow values like review, blocked, etc., but mapStatusToDatabase only handles pending | in-progress | done. Any call to getTasks({ status: 'blocked' }) or updateTask(...,{ status: 'review' }) now throws Invalid task status, breaking supported flows. Align the schema and mapperβeither trim the schema to DB-supported states or extend the mapper with a translation strategyβso we donβt reject legitimately requested statuses.
| const result = (await response.json()) as BulkTasksResponse; | ||
|
|
||
| if (result.failedCount > 0) { | ||
| const failedTasks = result.results | ||
| .filter((r) => !r.success) | ||
| .map((r) => `${r.externalId}: ${r.error}`) | ||
| .join(', '); | ||
| console.warn( | ||
| `Warning: ${result.failedCount} tasks failed to import: ${failedTasks}` | ||
| ); | ||
| } | ||
|
|
||
| console.log( | ||
| `Successfully exported ${result.successCount} of ${result.totalTasks} tasks to brief ${briefId}` | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surface partial failures to callers
When the bulk API reports failedCount > 0, we only log a warning and still return a success result (Line 175). That means the CLI (and any caller) will treat the export as fully successful, even though some tasks never made it into the brief. Users lose tasks silently.
Please propagate this state to the ExportResultβeither flip success to false (or add a partialβsuccess flag) and surface the failed task details in the returned payload so callers can react appropriately.
π€ Prompt for AI Agents
In packages/tm-core/src/services/export.service.ts around lines 404 to 418, the
bulk API failure branch only logs a warning and still returns a successful
ExportResult; change the returned ExportResult to reflect partial failures by
setting success = false (or add a partialSuccess boolean) and include
failedCount and failed task details (externalId and error strings) on the result
object so callers can detect and surface partial failures; update the
ExportResult type/interface accordingly and adjust any callers/tests that assume
a pure success to handle the new failure/partial-success payload.
eyaltoledano
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
What type of PR is this?
Description
Related Issues
How to Test This
# Example commands or stepsExpected result:
Contributor Checklist
npm run changesetnpm testnpm run format-check(ornpm run formatto fix)Changelog Entry
For Maintainers
Summary by CodeRabbit
New Features
Enhancements
Bug Fixes
Documentation