Conversation
) Co-authored-by: Ralph Khreish <Crunchyman-ralph@users.noreply.github.com> Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Fixes #542
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: e308cf4 The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
WalkthroughAdds a Claude Code plugin and marketplace metadata; migrates many in-repo Claude docs to plugin-based docs under the /taskmaster namespace; adds an RPG PRD template and docs/init wiring; surfaces changelog "What's New" highlights in CLI auto-update; threads complexity-report paths through expand-all; fixes cross-level dependency handling; and implements multiple auth/refresh, storage, test, and version-bump changes. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant CLI as CLI (task-master)
participant Updater as Auto-update utils
participant Repo as Remote (CHANGELOG.md)
User->>CLI: run command
CLI->>Updater: checkForUpdate(currentVersion)
Updater->>Updater: fetch latestVersion
alt update available
Updater->>Repo: GET CHANGELOG.md
Repo-->>Updater: changelog text
Updater->>Updater: parseChangelogHighlights(changelog, latestVersion)
Updater-->>CLI: { latestVersion, highlights[] }
CLI->>Updater: displayUpgradeNotification(currentVersion, latestVersion, highlights)
else up-to-date
Updater-->>CLI: no update
end
sequenceDiagram
autonumber
actor Dev as Developer
participant Tool as MCP Tool (/expand-all)
participant Path as Path Utils
participant Core as expandAllTasksDirect
participant Exp as expandTask
Dev->>Tool: run expand-all (with tag/opts)
Tool->>Path: resolveComplexityReportOutputPath(explicitPath?, { projectRoot, tag })
Path-->>Tool: complexityReportPath
Tool->>Core: expandAllTasksDirect({ ..., complexityReportPath })
loop per selected task
Core->>Exp: expandTask(taskId, { context: { complexityReportPath, ... }})
Exp-->>Core: expansion result
end
Core-->>Dev: expansion summary
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
🧰 Additional context used📓 Path-based instructions (1).changeset/*📄 CodeRabbit inference engine (.cursor/rules/new_features.mdc)
Files:
⏰ 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)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
src/profiles/claude.js (2)
8-23: Remove unused helper function.The
copyRecursiveSyncfunction is no longer called after the migration to plugin-based command distribution. This is dead code that should be removed to improve maintainability.Apply this diff to remove the unused function:
-// Helper function to recursively copy directory (adopted from Roo profile) -function copyRecursiveSync(src, dest) { - const exists = fs.existsSync(src); - const stats = exists && fs.statSync(src); - const isDirectory = exists && stats.isDirectory(); - if (isDirectory) { - if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true }); - fs.readdirSync(src).forEach((childItemName) => { - copyRecursiveSync( - path.join(src, childItemName), - path.join(dest, childItemName) - ); - }); - } else { - fs.copyFileSync(src, dest); - } -} -
26-37: Remove unused helper function.The
removeDirectoryRecursivefunction is no longer called after the migration to plugin-based command distribution. This is dead code that should be removed to improve maintainability.Apply this diff to remove the unused function:
-// Helper function to recursively remove directory -function removeDirectoryRecursive(dirPath) { - if (fs.existsSync(dirPath)) { - try { - fs.rmSync(dirPath, { recursive: true, force: true }); - return true; - } catch (err) { - log('error', `Failed to remove directory ${dirPath}: ${err.message}`); - return false; - } - } - return true; -} -packages/claude-code-plugin/commands/tm-main.md (1)
11-143: Add blank lines after headings to satisfy markdownlint.
markdownlint is complaining (MD022/MD031) because every###heading (and the fenced blocks later on) is immediately followed by content with no blank line. Insert an empty line after each heading/fence so the docs render correctly and the lint step passes.-### `/taskmaster:init` -- `init-project` - Initialize new project (handles PRD files intelligently) +### `/taskmaster:init` + +- `init-project` - Initialize new project (handles PRD files intelligently)Apply the same adjustment everywhere this pattern occurs.
tests/unit/commands.test.js (1)
281-361: Avoid dynamic imports in tests.
The coding guidelines explicitly forbid async/dynamic imports in tests—only use synchronous, top-level imports. Please switch to a static import (or another synchronous approach) so the suite stays deterministic.
As per coding guidelines-import { compareVersions } from '@tm/cli'; +import { compareVersions } from '@tm/cli'; +import { + displayUpgradeNotification, + parseChangelogHighlights +} from '../../apps/cli/src/utils/auto-update.js'; @@ -describe('Update check functionality', () => { - let displayUpgradeNotification; - let parseChangelogHighlights; - let consoleLogSpy; - - beforeAll(async () => { - // Import from @tm/cli instead of commands.js - const cliModule = await import('../../apps/cli/src/utils/auto-update.js'); - displayUpgradeNotification = cliModule.displayUpgradeNotification; - parseChangelogHighlights = cliModule.parseChangelogHighlights; - }); +describe('Update check functionality', () => { + let consoleLogSpy; </blockquote></details> </blockquote></details>
| - Comprehensive documentation at [docs.task-master.dev/capabilities/rpg-method](https://docs.task-master.dev/capabilities/rpg-method) | ||
| - Tool recommendations for code-context-aware PRD creation (Claude Code, Cursor, Gemini CLI, Codex/Grok) | ||
|
|
||
| The RPG template complements the existing `example_prd.txt` and provides a more structured approach for complex projects requiring clear module boundaries and dependency chains. No newline at end of file |
There was a problem hiding this comment.
Add final newline.
The file is missing a final newline character. Add one for proper formatting.
Apply this diff:
The RPG template complements the existing `example_prd.txt` and provides a more structured approach for complex projects requiring clear module boundaries and dependency chains.
+📝 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.
| The RPG template complements the existing `example_prd.txt` and provides a more structured approach for complex projects requiring clear module boundaries and dependency chains. | |
| The RPG template complements the existing `example_prd.txt` and provides a more structured approach for complex projects requiring clear module boundaries and dependency chains. | |
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
17-17: Files should end with a single newline character
(MD047, single-trailing-newline)
🤖 Prompt for AI Agents
In .changeset/nice-ways-hope.md at line 17, the file lacks a trailing newline;
open the file and add a final newline character at the end of the file so the
last line ends with a newline (ensure the file ends with '\n').
| "task-master-ai": minor | ||
| --- | ||
|
|
||
| Enhance `expand_all` to intelligently use complexity analysis recommendations when expanding tasks. |
There was a problem hiding this comment.
Remove trailing space.
Line 5 has a trailing space. Remove it for cleaner formatting.
Apply this diff:
-Enhance `expand_all` to intelligently use complexity analysis recommendations when expanding tasks.
+Enhance `expand_all` to intelligently use complexity analysis recommendations when expanding tasks.📝 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.
| Enhance `expand_all` to intelligently use complexity analysis recommendations when expanding tasks. | |
| Enhance `expand_all` to intelligently use complexity analysis recommendations when expanding tasks. |
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
5-5: Trailing spaces
Expected: 0 or 2; Actual: 1
(MD009, no-trailing-spaces)
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/smart-owls-relax.md around line 5, remove the trailing space at
the end of the line ("Enhance `expand_all` to intelligently use complexity
analysis recommendations when expanding tasks. ") so the line ends immediately
after the period; update the file to delete that trailing whitespace and save.
| ``` | ||
| claude-task-master/ | ||
| ├── .claude-plugin/ | ||
| │ └── marketplace.json # Marketplace manifest (at repo root) | ||
| │ | ||
| ├── packages/claude-code-plugin/ | ||
| │ ├── src/build.ts # Build tooling | ||
| │ └── [generated plugin files] | ||
| │ | ||
| └── assets/claude/ # Plugin source files | ||
| ├── commands/ | ||
| └── agents/ | ||
| ``` |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Add a language hint to the fenced block.
Markdownlint flags this block because the fence lacks a language. Tag it as text (or similar) so the linter passes and tooling can render it consistently.
-```
+```text
claude-task-master/
├── .claude-plugin/
│ └── marketplace.json # Marketplace manifest (at repo root)
│
├── packages/claude-code-plugin/
│ ├── src/build.ts # Build tooling
│ └── [generated plugin files]
│
└── assets/claude/ # Plugin source files
├── commands/
└── agents/
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 markdownlint-cli2 (0.18.1)</summary>
37-37: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
In CLAUDE_CODE_PLUGIN.md around lines 37 to 49 the fenced code block lacks a
language hint which triggers markdownlint; update the opening fence to include a
language tag such as "text" (e.g., replace withtext) so the block is
explicitly labeled and the linter/tooling renders it consistently.
</details>
<!-- fingerprinting:phantom:poseidon:sabertoothed -->
<!-- This is an auto-generated comment by CodeRabbit -->
| Show help for Task Master AI commands. | ||
|
|
||
| Arguments: $ARGUMENTS | ||
|
|
||
| Display help for Task Master commands. If arguments provided, show specific command help. | ||
|
|
||
| ## Task Master AI Command Help | ||
|
|
||
| ### Quick Navigation |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Promote the intro sentence to an H1.
The file starts with plain text, so markdownlint flags it. Make it the top-level heading and rename the duplicate heading below to keep the hierarchy clean.
-Show help for Task Master AI commands.
-
-Arguments: $ARGUMENTS
-
-Display help for Task Master commands. If arguments provided, show specific command help.
-
-## Task Master AI Command Help
+# Task Master AI Command Help
+
+Arguments: $ARGUMENTS
+
+Display help for Task Master commands. If arguments provided, show specific command help.
+
+## Overview📝 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.
| Show help for Task Master AI commands. | |
| Arguments: $ARGUMENTS | |
| Display help for Task Master commands. If arguments provided, show specific command help. | |
| ## Task Master AI Command Help | |
| ### Quick Navigation | |
| # Task Master AI Command Help | |
| Arguments: $ARGUMENTS | |
| Display help for Task Master commands. If arguments provided, show specific command help. | |
| ## Overview | |
| ### Quick Navigation |
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
1-1: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
🤖 Prompt for AI Agents
In packages/claude-code-plugin/commands/help.md around lines 1 to 9, the first
sentence is plain text and should be promoted to an H1; change "Show help for
Task Master AI commands." to "# Show help for Task Master AI commands." and
rename the duplicate "## Task Master AI Command Help" below to a lower-level
heading (e.g., "## Command Help" or "### Task Master AI Command Help") so the
Markdown heading hierarchy is correct and markdownlint no longer flags the file.
| "mcpServers": { | ||
| "task-master-ai": { | ||
| "type": "stdio", | ||
| "command": "npx", | ||
| "args": ["-y", "task-master-ai"] | ||
| } |
There was a problem hiding this comment.
Provide required API credentials for the MCP server.
The Task Master MCP server expects its API key environment variables in the config; without them the npx task-master-ai command will fail to authenticate, so the plugin won't work. Please add the documented env block (e.g., TASK_MASTER_API_KEY and related secrets) under this server entry. Based on learnings
🤖 Prompt for AI Agents
In packages/claude-code-plugin/mcp.json around lines 2 to 7, the Task Master MCP
server entry lacks required API credential environment variables; add an "env"
block under the "task-master-ai" server entry containing the documented keys
(e.g., TASK_MASTER_API_KEY and any related secrets like TASK_MASTER_API_SECRET
or TASK_MASTER_ORG_ID as required by the service) so that the "npx
task-master-ai" command can authenticate; ensure variable names match the
service docs, keep values empty or reference secure secret injection (do not
hardcode secrets), and validate the JSON structure after adding the env object.
| function onRemoveRulesProfile(targetDir) { | ||
| // Remove .claude directory recursively | ||
| const claudeDir = path.join(targetDir, '.claude'); | ||
| if (removeDirectoryRecursive(claudeDir)) { | ||
| log('debug', `[Claude] Removed .claude directory from ${claudeDir}`); | ||
| } | ||
| // Note: .claude directory (commands/agents) are now managed by Claude Code plugin | ||
| // We no longer remove them here - users should uninstall the plugin separately | ||
| log( | ||
| 'info', | ||
| '[Claude] To remove Task Master commands/agents, uninstall the plugin with: /plugin uninstall taskmaster' | ||
| ); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
🧩 Analysis chain
Consider migration guidance for orphaned .claude directories.
The plugin uninstall guidance is clear. However, users who previously installed Task Master will have orphaned .claude directories that won't be cleaned up by this removal process. Consider adding a note or cleanup step to help users migrate cleanly.
Optionally, you could add a check and informational message:
function onRemoveRulesProfile(targetDir) {
// Note: .claude directory (commands/agents) are now managed by Claude Code plugin
// We no longer remove them here - users should uninstall the plugin separately
log(
'info',
'[Claude] To remove Task Master commands/agents, uninstall the plugin with: /plugin uninstall taskmaster'
);
+
+ // Check for legacy .claude directory and inform user
+ const legacyClaudeDir = path.join(targetDir, '.claude');
+ if (fs.existsSync(legacyClaudeDir)) {
+ log(
+ 'info',
+ '[Claude] Found legacy .claude directory. You may safely remove it manually after uninstalling the plugin.'
+ );
+ }
// Clean up CLAUDE.md import🏁 Script executed:
#!/bin/bash
echo "Checking for fs import/require..."
grep -R -E "(require\(['\"]fs['\"]|import fs)" -n src/profiles/claude.js || echo "→ no fs import/require found"
echo "Checking for path import/require..."
grep -R -E "(require\(['\"]path['\"]|import path)" -n src/profiles/claude.js || echo "→ no path import/require found"Length of output: 119
Add migration guidance for legacy .claude directories.
Users upgrading from older versions may have orphaned .claude folders that aren’t removed by the new plugin uninstall process. In onRemoveRulesProfile, add a check and info log, for example:
function onRemoveRulesProfile(targetDir) {
// Note: .claude directory (commands/agents) are now managed by Claude Code plugin
// We no longer remove them here - users should uninstall the plugin separately
log(
'info',
'[Claude] To remove Task Master commands/agents, uninstall the plugin with: /plugin uninstall taskmaster'
);
+ // Inform users about any legacy .claude directory
+ const legacyClaudeDir = path.join(targetDir, '.claude');
+ if (fs.existsSync(legacyClaudeDir)) {
+ log(
+ 'info',
+ '[Claude] Found a legacy .claude directory. You may remove it manually after uninstalling the plugin.'
+ );
+ }
// Clean up CLAUDE.md import📝 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.
| function onRemoveRulesProfile(targetDir) { | |
| // Remove .claude directory recursively | |
| const claudeDir = path.join(targetDir, '.claude'); | |
| if (removeDirectoryRecursive(claudeDir)) { | |
| log('debug', `[Claude] Removed .claude directory from ${claudeDir}`); | |
| } | |
| // Note: .claude directory (commands/agents) are now managed by Claude Code plugin | |
| // We no longer remove them here - users should uninstall the plugin separately | |
| log( | |
| 'info', | |
| '[Claude] To remove Task Master commands/agents, uninstall the plugin with: /plugin uninstall taskmaster' | |
| ); | |
| function onRemoveRulesProfile(targetDir) { | |
| // Note: .claude directory (commands/agents) are now managed by Claude Code plugin | |
| // We no longer remove them here - users should uninstall the plugin separately | |
| log( | |
| 'info', | |
| '[Claude] To remove Task Master commands/agents, uninstall the plugin with: /plugin uninstall taskmaster' | |
| ); | |
| // Inform users about any legacy .claude directory | |
| const legacyClaudeDir = path.join(targetDir, '.claude'); | |
| if (fs.existsSync(legacyClaudeDir)) { | |
| log( | |
| 'info', | |
| '[Claude] Found a legacy .claude directory. You may remove it manually after uninstalling the plugin.' | |
| ); | |
| } | |
| // Clean up CLAUDE.md import | |
| … | |
| } |
🤖 Prompt for AI Agents
In src/profiles/claude.js around lines 108 to 114, the onRemoveRulesProfile
function currently tells users to uninstall the plugin but does not provide
guidance for legacy .claude directories; add a non-destructive migration check
that detects an existing .claude directory under the targetDir, logs an
informational message advising the user how to safely remove or back up that
legacy directory (include the full path in the message), and do not auto-delete
anything—only warn and show the recommended command(s) (for example: move, rm,
or backup instructions) so users upgrading from older versions can clean up
orphaned folders.
| beforeEach(async () => { | ||
| // Ensure a fresh module instance so ESM mocks apply to dynamic imports | ||
| jest.resetModules(); | ||
| originalExit = process.exit; | ||
| process.exit = jest.fn(); | ||
|
|
||
| // For ESM dynamic imports, use the same pattern | ||
| await jest.unstable_mockModule('../../scripts/modules/utils.js', () => ({ | ||
| log: mockLog, | ||
| readJSON: mockReadJSON, | ||
| writeJSON: mockWriteJSON, | ||
| taskExists: mockTaskExists, | ||
| formatTaskId: mockFormatTaskId, | ||
| findCycles: mockFindCycles, | ||
| traverseDependencies: jest.fn(() => []), | ||
| isSilentMode: jest.fn(() => true), | ||
| findProjectRoot: jest.fn(() => '/test'), | ||
| resolveEnvVariable: jest.fn(() => undefined), | ||
| isEmpty: jest.fn((v) => | ||
| v == null | ||
| ? true | ||
| : Array.isArray(v) | ||
| ? v.length === 0 | ||
| : typeof v === 'object' | ||
| ? Object.keys(v).length === 0 | ||
| : false | ||
| ), | ||
| enableSilentMode: jest.fn(), | ||
| disableSilentMode: jest.fn(), | ||
| getTaskManager: jest.fn(async () => ({})), | ||
| getTagAwareFilePath: jest.fn( | ||
| (basePath, _tag, projectRoot = '.') => basePath | ||
| ), | ||
| readComplexityReport: jest.fn(() => null) | ||
| })); | ||
|
|
||
| // Also mock transitive imports to keep dependency surface minimal | ||
| await jest.unstable_mockModule('../../scripts/modules/ui.js', () => ({ | ||
| displayBanner: jest.fn() | ||
| })); | ||
| await jest.unstable_mockModule( | ||
| '../../scripts/modules/task-manager/generate-task-files.js', | ||
| () => ({ default: jest.fn() }) | ||
| ); | ||
| // Set up test data that matches the issue report | ||
| // Clone fixture data before each test to prevent mutation issues | ||
| mockReadJSON.mockImplementation(() => | ||
| structuredClone(crossLevelDependencyTasks) | ||
| ); | ||
|
|
||
| // Configure mockTaskExists to properly validate cross-level dependencies | ||
| mockTaskExists.mockImplementation((tasks, taskId) => { | ||
| if (typeof taskId === 'string' && taskId.includes('.')) { | ||
| const [parentId, subtaskId] = taskId.split('.').map(Number); | ||
| const task = tasks.find((t) => t.id === parentId); | ||
| return ( | ||
| task && | ||
| task.subtasks && | ||
| task.subtasks.some((st) => st.id === subtaskId) | ||
| ); | ||
| } | ||
|
|
||
| const numericId = | ||
| typeof taskId === 'string' ? parseInt(taskId, 10) : taskId; | ||
| return tasks.some((task) => task.id === numericId); | ||
| }); | ||
|
|
||
| mockFormatTaskId.mockImplementation((id) => { | ||
| if (typeof id === 'string' && id.includes('.')) return id; // keep dot notation | ||
| return parseInt(id, 10); // normalize top-level task IDs to number | ||
| }); | ||
| }); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider reducing mock setup duplication.
The mock setup logic is duplicated between the main beforeEach (lines 82-151) and the cross-level tests' beforeEach (lines 954-1025). Specifically, the mockTaskExists and mockFormatTaskId implementations are nearly identical.
While the duplication ensures test isolation (which is good), consider extracting these common mock implementations into helper functions to improve maintainability.
Example refactor:
// At the top of the test file
const createMockTaskExists = () => {
return jest.fn((tasks, taskId) => {
if (typeof taskId === 'string' && taskId.includes('.')) {
const [parentId, subtaskId] = taskId.split('.').map(Number);
const task = tasks.find((t) => t.id === parentId);
return task && task.subtasks && task.subtasks.some((st) => st.id === subtaskId);
}
const numericId = typeof taskId === 'string' ? parseInt(taskId, 10) : taskId;
return tasks.some((task) => task.id === numericId);
});
};
// Then in beforeEach blocks:
mockTaskExists.mockImplementation(createMockTaskExists());Also applies to: 82-151
🤖 Prompt for AI Agents
In tests/unit/dependency-manager.test.js around lines 82-151 and 954-1025, the
mockTaskExists and mockFormatTaskId implementations are duplicated between the
main beforeEach and the cross-level beforeEach; extract these implementations
into reusable helpers at the top of the file (e.g., createMockTaskExists and
createMockFormatTaskId returning jest.fn implementations) and replace the inline
mockImplementation blocks in both beforeEach blocks with calls to those helpers
to DRY the setup while preserving test isolation.
🧹 Nitpick | 🔵 Trivial
Consider the implications of using unstable Jest APIs.
The test suite uses jest.unstable_mockModule() (lines 961-988) which is marked as unstable and may change in future Jest versions. While this is necessary for proper ESM mocking in the cross-level dependency tests, consider:
- Adding a comment documenting why the unstable API is necessary
- Monitoring Jest release notes for changes to this API
- Planning migration to stable APIs when available
🤖 Prompt for AI Agents
In tests/unit/dependency-manager.test.js around lines 954 to 1025, the test uses
jest.unstable_mockModule() (lines ~961-988) which is an unstable API; add a
short inline comment above those calls explaining why the unstable API is
required for ESM dynamic-import mocking in these cross-level dependency tests,
note that it may change in future Jest releases, and add a TODO to monitor Jest
release notes and plan migration to the stable API when available.
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/profiles/claude.js (1)
7-37: Remove unused helper functions.The
copyRecursiveSyncandremoveDirectoryRecursivefunctions are no longer used after the migration to plugin-based distribution. These functions were previously used for copying the.claudedirectory but are now dead code.Apply this diff to remove the unused code:
-// Helper function to recursively copy directory (adopted from Roo profile) -function copyRecursiveSync(src, dest) { - const exists = fs.existsSync(src); - const stats = exists && fs.statSync(src); - const isDirectory = exists && stats.isDirectory(); - if (isDirectory) { - if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true }); - fs.readdirSync(src).forEach((childItemName) => { - copyRecursiveSync( - path.join(src, childItemName), - path.join(dest, childItemName) - ); - }); - } else { - fs.copyFileSync(src, dest); - } -} - -// Helper function to recursively remove directory -function removeDirectoryRecursive(dirPath) { - if (fs.existsSync(dirPath)) { - try { - fs.rmSync(dirPath, { recursive: true, force: true }); - return true; - } catch (err) { - log('error', `Failed to remove directory ${dirPath}: ${err.message}`); - return false; - } - } - return true; -} -
|
|
||
| Add changelog highlights to auto-update notifications | ||
|
|
||
| When the CLI auto-updates to a new version, it now displays a "What's New" section. No newline at end of file |
There was a problem hiding this comment.
Add trailing newline for markdownlint compliance.
markdownlint (MD047) flags this file because it’s missing a trailing newline; please add one to keep CI green.
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
7-7: Files should end with a single newline character
(MD047, single-trailing-newline)
🤖 Prompt for AI Agents
In .changeset/auto-update-changelog-highlights.md around line 7, the file is
missing a trailing newline which triggers markdownlint MD047; fix this by adding
a single newline character at the end of the file so the file ends with a blank
line.
| "initialVersions": { | ||
| "task-master-ai": "0.28.0", | ||
| "@tm/cli": "", | ||
| "docs": "0.0.5", | ||
| "extension": "0.25.5", | ||
| "@tm/ai-sdk-provider-grok-cli": "", | ||
| "@tm/build-config": "", | ||
| "@tm/claude-code-plugin": "0.0.1", | ||
| "@tm/core": "" | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
Verify empty string versions in initialVersions.
Several packages have empty strings as their initialVersions:
@tm/cli@tm/ai-sdk-provider-grok-cli@tm/build-config@tm/core
Empty string versions may cause issues during pre-release version calculation. Typically, initialVersions should contain the actual starting version for each package (e.g., "0.0.0" or the current published version).
Please run the following script to verify the current versions of these packages and confirm whether empty strings are intentional:
Alternatively, verify the changeset documentation to confirm whether empty strings are supported for packages that don't have a published version yet.
🏁 Script executed:
#!/bin/bash
# Description: Check current versions of packages with empty initialVersions
echo "Checking package versions..."
for pkg in "packages/cli" "packages/ai-sdk-provider-grok-cli" "packages/build-config" "packages/core"; do
if [ -f "$pkg/package.json" ]; then
echo ""
echo "Package: $pkg"
jq -r '.name + " v" + .version' "$pkg/package.json"
fi
done
echo ""
echo "Verifying if empty strings are valid for changeset pre-release mode..."Length of output: 226
🏁 Script executed:
#!/bin/bash
echo "1) Listing all package.json under packages/:"
find packages -maxdepth 2 -type f -name package.json
echo -e "\n2) Inspecting package.json files for @tm/cli, @tm/core, ai-sdk-provider-grok-cli, build-config:"
for pkg in "@tm/cli" "@tm/core" "@tm/ai-sdk-provider-grok-cli" "@tm/build-config"; do
files=$(rg -l "\"name\": \"$pkg\"" -g 'packages/**/package.json')
if [ -z "$files" ]; then
echo "No package.json found for $pkg"
else
for file in $files; do
echo -e "\n-- $file --"
jq '{name: .name, version: .version}' "$file"
done
fi
doneLength of output: 615
Provide valid initialVersions entries or remove nonexistent packages
The .changeset/pre.json currently has empty strings for:
@tm/ai-sdk-provider-grok-cli@tm/build-config@tm/core
…and also lists@tm/cli, which isn’t in the workspace.
Set each to its actual published version (or use"0.0.0"for unpublished), and remove or correct the@tm/clientry.
🤖 Prompt for AI Agents
In .changeset/pre.json around lines 4-13, the initialVersions object contains
empty string values for @tm/ai-sdk-provider-grok-cli, @tm/build-config, and
@tm/core and an entry for @tm/cli which is not in the workspace; replace each
empty string with the actual published version (or use "0.0.0" if unpublished)
and either remove the @tm/cli key or correct it to the real workspace package
name/version so all entries are valid package versions.
| "task-master-ai": minor | ||
| --- | ||
|
|
||
| Enhance `expand_all` to intelligently use complexity analysis recommendations when expanding tasks. |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Remove trailing space.
Line 5 has a trailing space that should be removed for consistency with markdown best practices.
Apply this diff:
-Enhance `expand_all` to intelligently use complexity analysis recommendations when expanding tasks.
+Enhance `expand_all` to intelligently use complexity analysis recommendations when expanding tasks.📝 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.
| Enhance `expand_all` to intelligently use complexity analysis recommendations when expanding tasks. | |
| Enhance `expand_all` to intelligently use complexity analysis recommendations when expanding tasks. |
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)
5-5: Trailing spaces
Expected: 0 or 2; Actual: 1
(MD009, no-trailing-spaces)
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/smart-owls-relax.md around line 5, there is a trailing space at
the end of the line "Enhance `expand_all` to intelligently use complexity
analysis recommendations when expanding tasks. " — remove the trailing
whitespace so the line ends immediately after the period to comply with Markdown
formatting conventions.
| "plugins": [ | ||
| { | ||
| "name": "taskmaster", | ||
| "source": "./packages/claude-code-plugin", |
There was a problem hiding this comment.
🧩 Analysis chain
Verify plugin source path resolution.
The plugin source is specified as "./packages/claude-code-plugin", which is a relative path. Ensure that this path correctly resolves from the location of marketplace.json in the .claude-plugin/ directory to the actual plugin package.
Given the file structure, this should resolve to ../.claude-plugin/../packages/claude-code-plugin from the marketplace.json location, which may not be the intended path.
Run the following script to verify the path resolution:
🏁 Script executed:
#!/bin/bash
# Description: Verify the plugin source path exists and is accessible
MARKETPLACE_FILE=".claude-plugin/marketplace.json"
PLUGIN_SOURCE=$(jq -r '.plugins[0].source' "$MARKETPLACE_FILE")
echo "Marketplace file: $MARKETPLACE_FILE"
echo "Plugin source (as specified): $PLUGIN_SOURCE"
echo ""
# Resolve the path relative to marketplace.json location
MARKETPLACE_DIR=$(dirname "$MARKETPLACE_FILE")
RESOLVED_PATH="$MARKETPLACE_DIR/$PLUGIN_SOURCE"
echo "Resolved path: $RESOLVED_PATH"
echo ""
if [ -d "$RESOLVED_PATH" ]; then
echo "✓ Plugin source directory exists"
echo ""
echo "Contents:"
ls -la "$RESOLVED_PATH" | head -10
else
echo "✗ Plugin source directory does NOT exist"
echo ""
echo "Expected directory should contain:"
echo " - .claude-plugin/plugin.json"
echo " - package.json"
echo " - commands/"
echo " - agents/"
fiLength of output: 322
Fix plugin source path
In .claude-plugin/marketplace.json, change source from "./packages/claude-code-plugin" to "../packages/claude-code-plugin" so it correctly resolves to packages/claude-code-plugin.
🤖 Prompt for AI Agents
In .claude-plugin/marketplace.json around line 14, the "source" path is
incorrect; update the value from "./packages/claude-code-plugin" to
"../packages/claude-code-plugin" so the path correctly resolves to the
repository's packages/claude-code-plugin directory; save the file and run any
local validation or package resolution to confirm the plugin loads correctly.
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
| ## 🎉 New: Claude Code Plugin | ||
|
|
||
| Task Master AI commands and agents are now distributed as a proper Claude Code plugin: | ||
| - **49 slash commands** with clean naming (`/task-master-ai:command-name`) | ||
| - **3 specialized AI agents** (task-orchestrator, task-executor, task-checker) | ||
| - **MCP server integration** for deep Claude Code integration | ||
|
|
||
| **Installation:** | ||
|
|
||
| ```bash | ||
| /plugin marketplace add eyaltoledano/claude-task-master | ||
| /plugin install taskmaster@taskmaster | ||
| ``` |
There was a problem hiding this comment.
Add the missing blank line around the subheading.
markdownlint (MD022) is flagging the ## 🎉 New: Claude Code Plugin header because it isn’t separated from surrounding text by blank lines. Please insert an empty line before and after that heading to keep the changelog lint‑clean.
🤖 Prompt for AI Agents
In CHANGELOG.md around lines 15 to 27, the second-level heading "## 🎉 New:
Claude Code Plugin" is not separated from surrounding text which triggers
markdownlint MD022; insert a single blank line immediately before that heading
and another blank line immediately after it so the heading is isolated from the
preceding and following paragraphs and the lint error is resolved.
| ``` | ||
| claude-task-master/ | ||
| ├── .claude-plugin/ | ||
| │ └── marketplace.json # Marketplace manifest (at repo root) | ||
| │ | ||
| ├── packages/claude-code-plugin/ | ||
| │ ├── src/build.ts # Build tooling | ||
| │ └── [generated plugin files] | ||
| │ | ||
| └── assets/claude/ # Plugin source files | ||
| ├── commands/ | ||
| └── agents/ | ||
| ``` |
There was a problem hiding this comment.
Specify fenced code block language to satisfy markdownlint
markdownlint (MD040) flags this fenced block because it lacks an explicit language. Please add a language such as text to keep CI clean.
Apply this diff:
-```
+```text
claude-task-master/
├── .claude-plugin/
│ └── marketplace.json # Marketplace manifest (at repo root)
│
├── packages/claude-code-plugin/
│ ├── src/build.ts # Build tooling
│ └── [generated plugin files]
│
└── assets/claude/ # Plugin source files
├── commands/
└── agents/
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 markdownlint-cli2 (0.18.1)</summary>
37-37: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
In CLAUDE_CODE_PLUGIN.md around lines 37 to 49, the fenced code block lacks a
language spec which triggers markdownlint MD040; update the block by changing
the opening fence from totext so the snippet is fenced as text (i.e.,
replace the existing backticks with a backtick fence that includes "text"
immediately after the opening triple backticks).
</details>
<!-- fingerprinting:phantom:triton:sabertoothed -->
<!-- This is an auto-generated comment by CodeRabbit -->
| disableSilentMode | ||
| } from '../../../../scripts/modules/utils.js'; | ||
| import { createLogWrapper } from '../../tools/utils.js'; | ||
| import { resolveComplexityReportOutputPath } from '../../../../src/utils/path-utils.js'; |
There was a problem hiding this comment.
Use the MCP-specific path utilities wrapper.
The import should reference mcp-server/src/core/utils/path-utils.js instead of src/utils/path-utils.js. The MCP wrapper ensures proper logging integration with the FastMCP logger.
Apply this diff:
-import { resolveComplexityReportOutputPath } from '../../../../src/utils/path-utils.js';
+import { resolveComplexityReportOutputPath } from '../../utils/path-utils.js';Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In mcp-server/src/core/direct-functions/expand-all-tasks.js around line 11 the
import points to '../../../../src/utils/path-utils.js' but should use the
MCP-specific wrapper to integrate FastMCP logging; update the import path to
'../../../../core/utils/path-utils.js' (i.e.
mcp-server/src/core/utils/path-utils.js) so the module imports the MCP wrapper
instead of the top-level src utility.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (1)
images/hamster-hiring.pngis excluded by!**/*.png
📒 Files selected for processing (1)
README.md(1 hunks)
⏰ 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). (1)
- GitHub Check: update-docs
| ## Join Our Team | ||
|
|
||
| <a href="https://tryhamster.com" target="_blank"> | ||
| <img src="./images/hamster-hiring.png" alt="Join Hamster's founding team" /> | ||
| </a> | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
Harden external link; verify image exists
Add rel="noopener noreferrer" to the target="_blank" link to prevent reverse‑tabnabbing. Also confirm images/hamster-hiring.png is committed.
Proposed change:
-<a href="https://tryhamster.com" target="_blank">
+<a href="https://tryhamster.com" target="_blank" rel="noopener noreferrer">
<img src="./images/hamster-hiring.png" alt="Join Hamster's founding team" />
</a>Run to verify the image file:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Referencing occurrences in README:"
rg -n 'hamster-hiring\.png' -C2 README.md || true
echo -e "\nChecking file presence:"
fd -a 'hamster-hiring.png' -t f || { echo "ERROR: images/hamster-hiring.png not found"; exit 1; }
echo -e "\nFile details:"
fd -a 'hamster-hiring.png' -t f | xargs -I{} sh -c 'ls -lh "{}"; file "{}" || true'Length of output: 392
Add rel="noopener noreferrer" to external link
target="_blank" opens a new tab and can enable reverse-tabnabbing; include rel attributes for safety.
-<a href="https://tryhamster.com" target="_blank">
+<a href="https://tryhamster.com" target="_blank" rel="noopener noreferrer">
<img src="./images/hamster-hiring.png" alt="Join Hamster's founding team" />
</a>📝 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.
| ## Join Our Team | |
| <a href="https://tryhamster.com" target="_blank"> | |
| <img src="./images/hamster-hiring.png" alt="Join Hamster's founding team" /> | |
| </a> | |
| ## Join Our Team | |
| <a href="https://tryhamster.com" target="_blank" rel="noopener noreferrer"> | |
| <img src="./images/hamster-hiring.png" alt="Join Hamster's founding team" /> | |
| </a> |
🤖 Prompt for AI Agents
In README.md around lines 313 to 318 the external anchor uses target="_blank"
without rel attributes, which risks reverse-tabnabbing; update the anchor tag to
include rel="noopener noreferrer" (or rel="noopener noreferrer nofollow" if
desired) so the new tab cannot access the opener and to follow security best
practices.
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/cli/src/commands/context.command.ts (1)
129-141: Don’t gate on isAuthenticated(); attempt auto‑refresh firstUsing isAuthenticated() blocks flows when a refresh token is present but access token is expired. Call await getCredentials() to trigger auto‑refresh and proceed if non‑null.
Apply this diff (repeat the pattern for all gated blocks):
@@ - // Check authentication first - if (!this.authManager.isAuthenticated()) { - console.log(chalk.yellow('✗ Not authenticated')); - console.log(chalk.gray('\n Run "tm auth login" to authenticate first')); - - return { - success: false, - action: 'show', - message: 'Not authenticated' - }; - } + // Attempt auto-refresh; treat null as unauthenticated + const creds = await this.authManager.getCredentials(); + if (!creds) { + console.log(chalk.yellow('✗ Not authenticated')); + console.log(chalk.gray('\n Run "tm auth login" to authenticate first')); + return { success: false, action: 'show', message: 'Not authenticated' }; + } @@ - // Check authentication - if (!this.authManager.isAuthenticated()) { + // Attempt auto-refresh; treat null as unauthenticated + const creds = await this.authManager.getCredentials(); + if (!creds) { ui.displayError('Not authenticated. Run "tm auth login" first.'); process.exit(1); } @@ - // Check authentication - if (!this.authManager.isAuthenticated()) { + const creds = await this.authManager.getCredentials(); + if (!creds) { ui.displayError('Not authenticated. Run "tm auth login" first.'); process.exit(1); } @@ - // Check authentication - if (!this.authManager.isAuthenticated()) { + const creds = await this.authManager.getCredentials(); + if (!creds) { ui.displayError('Not authenticated. Run "tm auth login" first.'); process.exit(1); } @@ - // Check authentication - if (!this.authManager.isAuthenticated()) { + const creds = await this.authManager.getCredentials(); + if (!creds) { ui.displayError('Not authenticated. Run "tm auth login" first.'); process.exit(1); } @@ - // Check authentication - if (!this.authManager.isAuthenticated()) { + const creds = await this.authManager.getCredentials(); + if (!creds) { ui.displayError('Not authenticated. Run "tm auth login" first.'); process.exit(1); }Also applies to: 201-206, 281-285, 387-391, 433-437, 457-461
packages/tm-core/src/auth/auth-manager.ts (1)
55-57: Use existing logger instanceReuse this.logger instead of creating another logger.
- const logger = getLogger('AuthManager'); - logger.debug('No existing session to restore'); + this.logger.debug('No existing session to restore');
♻️ Duplicate comments (2)
CHANGELOG.md (1)
21-23: Insert blank lines around the subheading.We still need a blank line above and below
## 🎉 New: Claude Code Pluginto keep markdownlint happy (MD022). Please add the spacing..changeset/pre.json (1)
4-13: InvalidinitialVersionsentries will break pre-release.Changesets expects every
initialVersionsvalue to be a valid semver string for an actual workspace package. Empty strings cause the pre-enter flow to throw, and@tm/cliisn’t even part of the workspace, so the tooling can’t resolve it. Please give each package a real starting version (use"0.0.0"if it hasn’t shipped yet) and drop or correct the stray@tm/clientry before running the RC workflow."initialVersions": { "task-master-ai": "0.29.0-rc.0", - "@tm/cli": "", "docs": "0.0.5", "extension": "0.25.6-rc.0", - "@tm/ai-sdk-provider-grok-cli": "", - "@tm/build-config": "", + "@tm/ai-sdk-provider-grok-cli": "0.0.0", + "@tm/build-config": "0.0.0", "@tm/claude-code-plugin": "0.0.1", - "@tm/core": "" + "@tm/core": "0.0.0" },
📜 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 (18)
.changeset/config.json(1 hunks).changeset/pre.json(1 hunks).changeset/silent-bushes-grow.md(1 hunks)CHANGELOG.md(1 hunks)apps/cli/src/commands/auth.command.ts(5 hunks)apps/cli/src/commands/context.command.ts(10 hunks)apps/cli/src/commands/export.command.ts(1 hunks)package.json(2 hunks)packages/tm-core/package.json(1 hunks)packages/tm-core/src/auth/auth-manager.spec.ts(3 hunks)packages/tm-core/src/auth/auth-manager.ts(5 hunks)packages/tm-core/src/auth/credential-store.spec.ts(1 hunks)packages/tm-core/src/repositories/supabase/supabase-task-repository.ts(4 hunks)packages/tm-core/src/services/export.service.ts(3 hunks)packages/tm-core/src/storage/api-storage.ts(3 hunks)packages/tm-core/src/storage/storage-factory.ts(2 hunks)packages/tm-core/tests/auth/auth-refresh.test.ts(1 hunks)packages/tm-core/tests/integration/auth-token-refresh.test.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{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/tests/integration/auth-token-refresh.test.tspackages/tm-core/src/auth/credential-store.spec.tspackages/tm-core/tests/auth/auth-refresh.test.tspackages/tm-core/src/auth/auth-manager.spec.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/tests/integration/auth-token-refresh.test.tspackages/tm-core/src/auth/credential-store.spec.tspackages/tm-core/tests/auth/auth-refresh.test.tspackages/tm-core/src/auth/auth-manager.spec.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/tests/integration/auth-token-refresh.test.tspackages/tm-core/src/auth/credential-store.spec.tspackages/tm-core/tests/auth/auth-refresh.test.tspackages/tm-core/src/auth/auth-manager.spec.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/tests/integration/auth-token-refresh.test.tspackages/tm-core/tests/auth/auth-refresh.test.ts
**/*.{test,spec}.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{test,spec}.{js,jsx,ts,tsx}: NEVER use async/await in test functions unless testing actual asynchronous operations
Use synchronous top-level imports in tests; avoid dynamic await import()
Keep test bodies synchronous whenever possible
Files:
packages/tm-core/tests/integration/auth-token-refresh.test.tspackages/tm-core/src/auth/credential-store.spec.tspackages/tm-core/tests/auth/auth-refresh.test.tspackages/tm-core/src/auth/auth-manager.spec.ts
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
.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/silent-bushes-grow.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/silent-bushes-grow.md.changeset/pre.json.changeset/config.json
.changeset/**/*.md
📄 CodeRabbit inference engine (CLAUDE.md)
Changeset entries should be user-facing, describing the end-user impact rather than code specifics
Files:
.changeset/silent-bushes-grow.md
🧠 Learnings (3)
📚 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/{integration,e2e}/**/*.test.js : Properly mock session objects when required by functions, and reset environment variables between tests if modified.
Applied to files:
packages/tm-core/tests/integration/auth-token-refresh.test.ts
📚 Learning: 2025-09-26T19:10:32.906Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1252
File: tsconfig.json:22-28
Timestamp: 2025-09-26T19:10:32.906Z
Learning: In the eyaltoledano/claude-task-master repository, all internal tm/ package path mappings in tsconfig.json consistently point to TypeScript source files (e.g., "./packages/*/src/index.ts") rather than built JavaScript. This is intentional architecture because tsdown bundles internal packages directly from source during build time, eliminating the need for separate compilation of internal packages.
Applied to files:
package.json
📚 Learning: 2025-08-06T21:13:05.240Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1091
File: assets/claude/agents/task-orchestrator.md:69-78
Timestamp: 2025-08-06T21:13:05.240Z
Learning: For Claude agent instruction files in .claude/agents/ and assets/claude/agents/ directories, ignore markdownlint issues (like MD031 blanks-around-fences, MD040 fenced-code-language, MD041 missing top-level heading) as these files follow Claude's specific agent format requirements rather than standard markdown documentation conventions.
Applied to files:
CHANGELOG.md
🧬 Code graph analysis (5)
packages/tm-core/tests/integration/auth-token-refresh.test.ts (1)
packages/tm-core/src/auth/auth-manager.ts (1)
AuthManager(26-337)
packages/tm-core/src/auth/auth-manager.ts (4)
packages/tm-core/src/logger/factory.ts (1)
getLogger(23-44)packages/tm-core/src/auth/types.ts (3)
AuthCredentials(5-14)AuthConfig(39-43)UserContext(16-22)packages/tm-core/src/auth/credential-store.ts (1)
CredentialStore(21-265)packages/tm-core/src/clients/supabase-client.ts (1)
SupabaseAuthClient(16-312)
packages/tm-core/tests/auth/auth-refresh.test.ts (1)
packages/tm-core/src/auth/auth-manager.ts (1)
AuthManager(26-337)
apps/cli/src/commands/context.command.ts (1)
packages/tm-core/src/auth/types.ts (1)
UserContext(16-22)
apps/cli/src/commands/auth.command.ts (1)
packages/tm-core/src/auth/types.ts (1)
AuthCredentials(5-14)
🪛 markdownlint-cli2 (0.18.1)
.changeset/silent-bushes-grow.md
5-5: First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
CHANGELOG.md
35-35: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
⏰ 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 (18)
apps/cli/src/commands/export.command.ts (1)
106-106: LGTM! Context retrieval is now asynchronous.The change correctly awaits
getContext(), aligning with the broader shift to asynchronous authentication flows across the CLI..changeset/silent-bushes-grow.md (1)
1-5: LGTM! Changeset follows conventions.The changeset appropriately documents the authentication refresh token improvement as a patch-level change. The static analysis hint about missing a top-level heading is a false positive—changesets follow a specific frontmatter format and don't require markdown headings.
packages/tm-core/src/auth/auth-manager.spec.ts (2)
24-29: LGTM! Mock updated for async credential retrieval.The CredentialStore mock correctly adds
getInstanceandresetInstancestatic methods and updatesgetCredentialsto accept optional parameters, aligning with the new asynchronous credential handling pattern.Also applies to: 33-35
93-111: LGTM! Test properly handles async credential retrieval.The test correctly marks the function as
asyncand awaitsgetCredentials(), ensuring proper testing of the asynchronous authentication flow.packages/tm-core/src/services/export.service.ts (3)
108-108: LGTM! Context retrieval is now asynchronous.The changes correctly await
getContext(), aligning with the broader shift to asynchronous authentication flows.Also applies to: 235-235
382-382: LGTM! Credentials retrieval is now asynchronous.The change correctly awaits
getCredentials(), consistent with the asynchronous authentication pattern.
365-379: No remaining/tasks/bulkreferences. The endpoint was updated consistently; please ensure/ai/api/v1/briefs/${briefId}/tasksmatches the latest API spec.packages/tm-core/src/repositories/supabase/supabase-task-repository.ts (2)
50-58: LGTM! Brief ID retrieval is now asynchronous.The method signature correctly changed to
asyncand returnsPromise<string>, withgetContext()properly awaited. This aligns with the broader asynchronous authentication pattern.
64-64: LGTM! All call sites properly updated.All invocations of
getBriefIdOrThrow()correctly await the promise, ensuring proper asynchronous handling throughout the repository.Also applies to: 117-117, 160-160
apps/cli/src/commands/auth.command.ts (3)
146-152: LGTM! Status display enhanced with async handling and improved UX.The changes correctly make
displayStatus()asynchronous and awaitgetCredentials(). The enhanced expiration display with time remaining (hours/minutes) provides better user feedback compared to the previous implementation.Also applies to: 174-241
328-342: LGTM! Existing authentication check now asynchronous.The change correctly awaits
getCredentials()when checking for existing authentication, maintaining consistency with the asynchronous pattern.
493-495: LGTM! Public API signature updated for async credentials.The return type correctly changed to
Promise<AuthCredentials | null>, reflecting the asynchronous nature of credential retrieval.packages/tm-core/src/storage/storage-factory.ts (1)
75-89: LGTM! Deliberate use of synchronous credential retrieval.The changes correctly use
getCredentialsSync()instead of the async variant, which is appropriate for the storage factory initialization context. The added comment clearly documents the synchronous behavior and lack of auto-refresh, making the design decision explicit.Also applies to: 106-122
packages/tm-core/src/storage/api-storage.ts (3)
122-122: LGTM! Context retrieval is now asynchronous in cache loading.The change correctly awaits
getContext()when loading tags into cache, aligning with the asynchronous authentication pattern.
155-155: LGTM! Context retrieval is now asynchronous in task loading.The change correctly awaits
getContext()when loading tasks, ensuring proper asynchronous handling of authentication context.
321-321: LGTM! Context retrieval is now asynchronous in tag listing.The change correctly awaits
getContext()when listing tags, maintaining consistency with the asynchronous authentication flow.packages/tm-core/src/auth/credential-store.spec.ts (1)
42-289: Solid coverage; behavior matches CredentialStore semanticsScenarios and persistence checks look correct, including 30s skew and normalization. Temp FS isolation + singleton reset are clean.
packages/tm-core/tests/auth/auth-refresh.test.ts (1)
53-107: Good coverage of refresh semantics and concurrency dedupAssertions match the new async flow and single‑refresh guarantee.
Also applies to: 109-175
| return { | ||
| success: true, | ||
| action: 'select-brief', | ||
| context: this.authManager.getContext() || undefined, | ||
| context: (await this.authManager.getContext()) || undefined, | ||
| message: `Selected brief: ${selectedBrief.name}` | ||
| }; |
There was a problem hiding this comment.
Message uses possibly undefined selectedBrief.name
Briefs are displayed without a name; message may show “undefined”. Use the computed briefName or fall back to ID.
- message: `Selected brief: ${selectedBrief.name}`
+ message: `Selected brief: ${briefName}`
@@
- message: 'Cleared brief selection'
+ message: 'Cleared brief selection'Also applies to: 371-373
🤖 Prompt for AI Agents
In apps/cli/src/commands/context.command.ts around lines 353-358 (and also apply
same fix to lines 371-373), the user-facing message interpolates
selectedBrief.name which may be undefined; instead reference the computed
briefName variable (or fall back to selectedBrief.id) when building the message
string. Update the return objects to use `briefName ?? selectedBrief.id` (or the
local computed briefName) for the message template so it never shows "undefined"
and ensure the same change is applied to both return sites.
| import type { Session } from '@supabase/supabase-js'; | ||
| import { AuthManager } from '../../src/auth/auth-manager'; | ||
| import { CredentialStore } from '../../src/auth/credential-store'; | ||
| import type { AuthCredentials } from '../../src/auth/types'; |
There was a problem hiding this comment.
Tests access private field supabaseClient; will fail type-check
Spy on the client’s prototype instead of indexing a private field.
Apply these changes:
- Add import:
@@
-import type { Session } from '@supabase/supabase-js';
+import type { Session } from '@supabase/supabase-js';
+import { SupabaseAuthClient } from '../../src/clients/supabase-client';- Replace each spy like vi.spyOn(authManager['supabaseClient'], 'refreshSession') with:
-vi.spyOn(
- authManager['supabaseClient'],
- 'refreshSession'
-).mockImplementation(mockRefreshSession);
+vi.spyOn(SupabaseAuthClient.prototype, 'refreshSession')
+ .mockImplementation(mockRefreshSession);And analogous replacements for .mockResolvedValue(...) and .mockRejectedValue(...).
Optionally, for “Multiple Concurrent Calls,” assert single invocation to reflect refreshPromise coalescing:
- expect(mockRefreshSession).toHaveBeenCalled();
+ expect(mockRefreshSession).toHaveBeenCalledTimes(1);As per coding guidelines
Also applies to: 95-101, 128-131, 160-163, 196-199, 266-269, 293-297, 341-344, 371-374
🤖 Prompt for AI Agents
In packages/tm-core/tests/integration/auth-token-refresh.test.ts around lines
12-15, the tests access the private field authManager['supabaseClient'] which
breaks type-checking; import SupabaseClient from '@supabase/supabase-js' and
replace spies that index the private field (e.g.
vi.spyOn(authManager['supabaseClient'], 'refreshSession')) with spies on the
prototype (vi.spyOn(SupabaseClient.prototype, 'refreshSession')), then adjust
subsequent uses of .mockResolvedValue(. . .) and .mockRejectedValue(. . .) to
operate on that prototype spy (using
.mockResolvedValueOnce/.mockRejectedValueOnce where appropriate), and for the
“Multiple Concurrent Calls” test assert the prototype method was called exactly
once to reflect refreshPromise coalescing; apply the same replacements to the
other affected ranges (95-101, 128-131, 160-163, 196-199, 266-269, 293-297,
341-344, 371-374).
Co-authored-by: Claude noreply@anthropic.com# 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
Chores