Skip to content

fix: prioritize .taskmaster in parent directories over other project markers#1350

Closed
bjcoombs wants to merge 105 commits intoeyaltoledano:ralph/feat/implement.new.update-taskfrom
bjcoombs:fix/taskmaster-parent-priority
Closed

fix: prioritize .taskmaster in parent directories over other project markers#1350
bjcoombs wants to merge 105 commits intoeyaltoledano:ralph/feat/implement.new.update-taskfrom
bjcoombs:fix/taskmaster-parent-priority

Conversation

@bjcoombs
Copy link
Contributor

@bjcoombs bjcoombs commented Oct 27, 2025

Summary

Fixes #1349

This PR ensures that .taskmaster directories in parent folders are always found and used, even when subdirectories contain other project markers like .git, go.mod, or package.json.

Problem

When running task-master commands from subdirectories containing project markers (e.g., a Git repository or Go project), findProjectRoot() would stop at the first marker found instead of continuing to search for a parent .taskmaster directory.

Example scenario:

/project-root/
├── .taskmaster/          # Should be used from anywhere
└── sub-repo/
    ├── .git/            # Was causing early termination
    └── go.mod           # Was causing early termination

Running task-master list from sub-repo/ would create a new .taskmaster/ in sub-repo/ instead of finding the parent.

Solution

Implemented a two-pass search strategy in findProjectRoot():

First Pass (Lines 92-121)

  • Traverses ALL parent directories looking ONLY for Task Master markers:
    • .taskmaster/
    • .taskmaster/config.json
    • .taskmaster/tasks/tasks.json
    • Legacy Task Master files
  • Returns immediately if found

Second Pass (Lines 123-151)

  • Only runs if NO Task Master markers found in any parent
  • Searches for other project markers:
    • .git, .svn
    • package.json, go.mod, Cargo.toml
    • Other language-specific markers
  • Returns the first generic marker found

This guarantees that Task Master markers in parent directories always take precedence over generic project markers in subdirectories.

Changes Made

Core Changes

  • src/utils/path-utils.js: Modified findProjectRoot() function
    • Split project markers into two separate arrays
    • Implemented two-pass search strategy
    • Added detailed comments explaining the approach

MCP Server

  • No changes needed - MCP server imports from core src/utils/path-utils.js
  • Fix automatically applies to both CLI and MCP

Testing

Manual Testing

# Create test structure
mkdir -p /tmp/test-tm-root/sub-repo
cd /tmp/test-tm-root
task-master init
task-master add-task --prompt="Root task"

cd sub-repo
git init  # Create .git marker
echo "module test" > go.mod  # Create go.mod marker

# Before fix: Creates new .taskmaster in sub-repo/
# After fix: Finds parent .taskmaster
task-master list
# Should show: "Listing tasks from: /tmp/test-tm-root/.taskmaster/tasks/tasks.json"

Unit Tests

The existing test suite in tests/unit/path-utils-find-project-root.test.js covers basic traversal. Additional tests for this scenario should be added in a follow-up PR.

Use Cases Enabled

  1. Multi-repo monorepos: Single .taskmaster at root coordinating work across multiple Git repositories
  2. Microservices architectures: Central task tracking for multiple service repositories
  3. Git worktrees: Worktree directories with their own .git files can use parent .taskmaster
  4. Deep directory structures: Run commands from any depth without creating duplicate .taskmaster directories

Before This Fix

cd /project/sub-repo
task-master list
# Listing tasks from: /project/sub-repo/.taskmaster/tasks/tasks.json
# ⚠ No tasks found

After This Fix

cd /project/sub-repo
task-master list
# Listing tasks from: /project/.taskmaster/tasks/tasks.json
# [Shows tasks from parent project]

Backward Compatibility

Fully backward compatible

  • Projects with .taskmaster at root continue to work
  • Projects with Task Master in current directory continue to work
  • Only changes behavior when parent .taskmaster exists AND subdirectory has other markers
  • In that case, parent is now correctly found (desired behavior)

Checklist

  • Code changes implemented
  • Function documented with clear comments
  • No breaking changes
  • Maintains backward compatibility
  • Tested manually with multi-repo setup
  • Unit tests added (follow-up recommended)
  • MCP server compatibility verified

Related

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Fixed project root detection to properly traverse parent directories from nested paths.
  • Chores

    • Updated version numbers across multiple components to 0.29.0 and related packages.

Crunchyman-ralph and others added 30 commits September 18, 2025 01:48
eyaltoledano#1219)

Co-authored-by: Ralph Khreish <35776126+Crunchyman-ralph@users.noreply.github.com>
Co-authored-by: Max Tuzzolino <maxtuzz@Maxs-MacBook-Pro.local>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Max Tuzzolino <max.tuzsmith@gmail.com>
Co-authored-by: Ralph Khreish <35776126+Crunchyman-ralph@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Ralph Khreish <35776126+Crunchyman-ralph@users.noreply.github.com>
Co-authored-by: Ralph Khreish <35776126+Crunchyman-ralph@users.noreply.github.com>
Crunchyman-ralph and others added 20 commits October 8, 2025 15:30
…altoledano#1191)

Co-authored-by: Ralph Khreish <Crunchyman-ralph@users.noreply.github.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Fixes eyaltoledano#542
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Improves parent directory traversal in findProjectRoot() to correctly
locate Task Master projects when running commands from subdirectories.

Changes:
- Enhanced project marker detection with Task Master-specific markers prioritized
- Added error handling for permission errors during directory traversal
- Added safety check for filesystem root detection
- Expanded project marker list to support more project types
- Improved documentation and code comments

This fix enables Task Master to work seamlessly in multi-repo projects
where subdirectories need to reference a parent-level Task Master configuration.

Resolves issue where running task-master commands from subdirectories
would incorrectly create new .taskmaster directories instead of finding
the parent project's configuration.
- Document maxDepth limit (50 levels) in JSDoc
- Fix test assertion to verify current directory priority
- Add precise depth limit assertion in test
- Simplify changeset description to imperative mood
- Replace substring matching with exact path comparisons in mocks
- Make permission error test more explicit about error location
- Run formatter (biome) to ensure consistent code style

Addresses CodeRabbit review feedback
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Ralph Khreish <35776126+Crunchyman-ralph@users.noreply.github.com>
…markers

When running task-master commands from subdirectories that contain other
project markers (like .git, go.mod, package.json), findProjectRoot() would
stop at the first project marker found instead of continuing to search for
a .taskmaster directory in parent directories.

This fix implements a two-pass search strategy:
1. First pass: Search ALL parent directories for Task Master markers only
2. Second pass: If no Task Master markers found, search for other project markers

This ensures that a .taskmaster directory in a parent always takes precedence
over other project markers in subdirectories, enabling proper multi-repo
monorepo setups where a single .taskmaster tracks work across multiple repos.

Fixes: Task Master creating new .taskmaster directories in subdirectories
       instead of finding and using parent .taskmaster directory
@changeset-bot
Copy link

changeset-bot bot commented Oct 27, 2025

🦋 Changeset detected

Latest commit: 46dca92

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 27, 2025

Walkthrough

This PR consolidates a pre-release into stable version 0.29.0 by removing intermediate changeset entries and bumping package versions. It includes a significant enhancement to the findProjectRoot() function to implement a two-pass upward directory traversal that prioritizes Task Master markers over generic project markers, with comprehensive test coverage.

Changes

Cohort / File(s) Summary
Changeset Consolidation
.changeset/auto-update-changelog-highlights.md, .changeset/mean-planes-wave.md, .changeset/nice-ways-hope.md, .changeset/plain-falcons-serve.md, .changeset/silent-bushes-grow.md, .changeset/smart-owls-relax.md
Removed intermediate changelog entries that document features/fixes for the 0.29.0 release (auto-update enhancements, Claude Code plugin, RPG template, cross-level dependencies, refresh token improvements, expand-all enhancements).
Pre-release Configuration
.changeset/pre.json
Removed pre-release configuration file (mode: exit, tag: rc, initialVersions, and referenced changesets).
Project Root Resolution Logic
src/utils/path-utils.js
Enhanced findProjectRoot() to implement a two-pass traversal strategy: First pass searches parent directories for Task Master-specific markers (.taskmaster, config files); second pass searches for generic project markers (.git, package.json, etc.) if no Task Master markers found. Adds 50-level depth cap, permission-error tolerance, and fallback to process.cwd().
Path Resolution Tests
tests/unit/path-utils-find-project-root.test.js
Added comprehensive unit test suite covering parent directory traversal, permission error handling, multiple marker validation, fallback behavior, edge cases (empty startDir, relative paths, root traversal), and performance/depth limits.
Release Version Bumps
package.json, apps/extension/package.json, apps/docs/package.json, packages/claude-code-plugin/package.json
Updated versions: root 0.29.0-rc.1 → 0.29.0, extension 0.25.6-rc.0 → 0.25.6, docs 0.0.5 → 0.0.6, claude-code-plugin 0.0.1 → 0.0.2.
Changelog Updates
CHANGELOG.md, apps/extension/CHANGELOG.md, apps/docs/CHANGELOG.md, apps/cli/CHANGELOG.md, packages/build-config/CHANGELOG.md, packages/ai-sdk-provider-grok-cli/CHANGELOG.md, packages/tm-core/CHANGELOG.md, packages/claude-code-plugin/CHANGELOG.md
Added/updated changelog headers and entries for 0.29.0 release across packages, consolidating changesets into final release documentation.

Sequence Diagram(s)

sequenceDiagram
    participant StartDir as Starting Directory
    participant ParentDirs as Parent Directories
    participant TM as Task Master Markers<br/>(.taskmaster, config/)
    participant Generic as Generic Markers<br/>(.git, package.json, etc.)
    
    rect rgb(200, 220, 240)
    note over StartDir,TM: Pass 1: Search for Task Master Markers
    StartDir->>ParentDirs: Traverse upward from startDir (max 50 levels)
    ParentDirs->>TM: Check for Task Master-specific markers
    alt TM marker found
        TM->>StartDir: Return project root
    else No TM marker found
        TM->>Generic: Proceed to Pass 2
    end
    end
    
    rect rgb(240, 220, 200)
    note over ParentDirs,Generic: Pass 2: Search for Generic Markers (fallback)
    ParentDirs->>ParentDirs: Re-traverse from startDir upward
    ParentDirs->>Generic: Check for .git, package.json, go.mod, etc.
    alt Generic marker found
        Generic->>StartDir: Return project root
    else No markers found
        Generic->>StartDir: Fallback to process.cwd()
    end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Priority attention areas:
    • src/utils/path-utils.js: Two-pass marker resolution logic, depth limiting, permission-error tolerance, and fallback semantics—verify traversal order and priority hierarchy match issue Bug: findProjectRoot() prioritizes other project markers over parent .taskmaster directories #1349 requirements.
    • tests/unit/path-utils-find-project-root.test.js: Validate comprehensive test coverage for marker discovery scenarios, permission error handling, edge cases, and confirm fs.existsSync mocking logic is sound.
    • Multiple changelog consolidations and version bumps: Ensure version consistency and that no intermediate entries are accidentally duplicated or lost in the transition.

Possibly related PRs

Suggested reviewers

  • Crunchyman-ralph
  • eyaltoledano

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The PR contains significant changes beyond the scope of fixing issue #1349. While the core fix (src/utils/path-utils.js and its tests) directly addresses the issue, the changeset includes extensive release management activities: removal of six unrelated changeset files (auto-update-changelog-highlights, mean-planes-wave, nice-ways-hope, plain-falcons-serve, silent-bushes-grow, smart-owls-relax), updates to CHANGELOG.md documenting version 0.29.0 with multiple unrelated features, version bumps across multiple packages (docs 0.0.5→0.0.6, extension 0.25.6-rc.0→0.25.6, claude-code-plugin 0.0.1→0.0.2), and changes to root package.json (0.29.0-rc.1→0.29.0). These changelog/version changes represent a full release finalization that extends well beyond the stated objective of fixing #1349. Additionally, several CHANGELOG.md files contain malformed "## null" header sections that appear to be unintended. The PR description should be updated to clarify whether this is intended to be a release PR for version 0.29.0 (in which case it should be titled accordingly) or if the release management changes should be separated into a distinct release PR. Additionally, investigate the malformed "## null" headers in multiple CHANGELOG files (apps/cli/CHANGELOG.md, packages/ai-sdk-provider-grok-cli/CHANGELOG.md, packages/build-config/CHANGELOG.md, packages/tm-core/CHANGELOG.md) to determine if these are intentional or require correction before merge.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "fix: prioritize .taskmaster in parent directories over other project markers" directly and accurately reflects the core change in the pull request. The title clearly summarizes the main objective of the fix without extraneous details, properly identifying that the enhancement prioritizes .taskmaster markers in parent directory traversal over other project markers. This is the primary functional change evident in the modifications to src/utils/path-utils.js, which implements the two-pass search strategy described in the PR objectives.
Linked Issues Check ✅ Passed The PR implementation aligns with the requirements specified in issue #1349. The changeset implements the exact solution proposed: a two-pass search that first traverses parent directories looking only for Task Master-specific markers (.taskmaster, .taskmaster/config.json, etc.), and only searches for generic markers (.git, package.json, go.mod, etc.) if no Task Master markers are found. The modifications to src/utils/path-utils.js include the depth-capped traversal, error-tolerant checks, and comprehensive unit tests that validate this specific behavior. The JSDoc updates also reflect the new traversal strategy, documenting the intent to prioritize .taskmaster in parent directories.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is being reviewed by Cursor Bugbot

Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

expect(result).toBe('/project/subdir');

mockExistsSync.mockRestore();
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Test Fails Due to Incorrect Marker Priority

Test expectation contradicts the implementation's two-pass strategy. The test expects findProjectRoot('/project/subdir') to return /project/subdir when .git exists there and .taskmaster exists in parent /project. However, the implementation's FIRST PASS searches ALL parent directories for Task Master markers before checking other markers, so it will find /project/.taskmaster and return /project immediately. The test expects /project/subdir but the function will return /project, causing the test to fail. This contradicts the PR's stated goal of prioritizing .taskmaster in parent directories over other project markers in subdirectories.

Fix in Cursor Fix in Web

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
packages/tm-core/CHANGELOG.md (1)

3-7: Remove invalid "## null" changelog entries—these are release automation artifacts.

Lines 3, 5, and 7 contain three duplicate "## null" headers that must not remain in the repository. These are placeholders generated by changelog tooling and indicate a failure in version detection during the release process.

Apply this diff:

 # Changelog
 
-## null
-
-## null
-
-## null
-
 ## 0.26.1

After removing these entries, verify that your changelog generation tooling is correctly configured to produce valid version headers in future releases.

packages/build-config/CHANGELOG.md (1)

3-7: Remove invalid "## null" changelog entries—these are release automation artifacts affecting multiple packages.

Verification confirms three "## null" headers at lines 3, 5, and 7 in packages/build-config/CHANGELOG.md. This is part of a broader monorepo issue: similar malformed entries appear in packages/tm-core/CHANGELOG.md, packages/ai-sdk-provider-grok-cli/CHANGELOG.md, and apps/cli/CHANGELOG.md (11 instances total).

Apply this diff:

 # @tm/build-config
 
-## null
-
-## null
-
-## null
-
 ## 1.0.1

Fix the changelog generation process to prevent these artifacts across all packages and apps in the monorepo.

src/utils/path-utils.js (2)

206-223: Windows-incompatible legacy path checks; can mis-warn or miss-warn.

Using 'includes("tasks/tasks.json")' and 'includes("tasks/")' breaks on Windows and may flag a legacy root incorrectly for “tasks/tasks.json”.

-      if (
-        tasksPath.includes('tasks/tasks.json') &&
-        !tasksPath.includes('.taskmaster')
-      ) {
+      const normalized = path.normalize(tasksPath);
+      const legacyTasksInDir = path.join('tasks', 'tasks.json');
+      const inTaskmaster = normalized.split(path.sep).includes('.taskmaster');
+      if (normalized.endsWith(legacyTasksInDir) && !inTaskmaster) {
         logger.warn?.(
           `⚠️  DEPRECATION WARNING: Found tasks.json in legacy location '${tasksPath}'. Please migrate to the new .taskmaster directory structure. Run 'task-master migrate' to automatically migrate your project.`
         );
-      } else if (
-        tasksPath.endsWith('tasks.json') &&
-        !tasksPath.includes('.taskmaster') &&
-        !tasksPath.includes('tasks/')
-      ) {
+      } else if (
+        path.basename(normalized) === 'tasks.json' &&
+        !inTaskmaster &&
+        !normalized.includes(`${path.sep}tasks${path.sep}`)
+      ) {
         logger.warn?.(
           `⚠️  DEPRECATION WARNING: Found tasks.json in legacy root location '${tasksPath}'. Please migrate to the new .taskmaster directory structure. Run 'task-master migrate' to automatically migrate your project.`
         );
       }

465-469: Reuse TASKMASTER_REPORTS_DIR instead of hardcoding the path.

Avoid duplication and keep consistency with findComplexityReportPath.

- const defaultPath = path.join(projectRoot, '.taskmaster/reports', filename);
+ const defaultPath = path.join(projectRoot, TASKMASTER_REPORTS_DIR, filename);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5838184 and 46dca92.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (22)
  • .changeset/auto-update-changelog-highlights.md (0 hunks)
  • .changeset/fix-parent-directory-traversal.md (1 hunks)
  • .changeset/mean-planes-wave.md (0 hunks)
  • .changeset/nice-ways-hope.md (0 hunks)
  • .changeset/plain-falcons-serve.md (0 hunks)
  • .changeset/pre.json (0 hunks)
  • .changeset/silent-bushes-grow.md (0 hunks)
  • .changeset/smart-owls-relax.md (0 hunks)
  • CHANGELOG.md (1 hunks)
  • apps/cli/CHANGELOG.md (1 hunks)
  • apps/docs/CHANGELOG.md (1 hunks)
  • apps/docs/package.json (1 hunks)
  • apps/extension/CHANGELOG.md (1 hunks)
  • apps/extension/package.json (1 hunks)
  • package.json (1 hunks)
  • packages/ai-sdk-provider-grok-cli/CHANGELOG.md (1 hunks)
  • packages/build-config/CHANGELOG.md (1 hunks)
  • packages/claude-code-plugin/CHANGELOG.md (1 hunks)
  • packages/claude-code-plugin/package.json (1 hunks)
  • packages/tm-core/CHANGELOG.md (1 hunks)
  • src/utils/path-utils.js (1 hunks)
  • tests/unit/path-utils-find-project-root.test.js (1 hunks)
💤 Files with no reviewable changes (7)
  • .changeset/auto-update-changelog-highlights.md
  • .changeset/mean-planes-wave.md
  • .changeset/plain-falcons-serve.md
  • .changeset/silent-bushes-grow.md
  • .changeset/smart-owls-relax.md
  • .changeset/nice-ways-hope.md
  • .changeset/pre.json
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{md,mdx}

📄 CodeRabbit inference engine (CLAUDE.md)

Reference documentation at https://docs.task-master.dev rather than local file paths in content

Files:

  • packages/build-config/CHANGELOG.md
  • apps/docs/CHANGELOG.md
  • packages/ai-sdk-provider-grok-cli/CHANGELOG.md
  • apps/extension/CHANGELOG.md
  • packages/claude-code-plugin/CHANGELOG.md
  • CHANGELOG.md
  • packages/tm-core/CHANGELOG.md
  • apps/cli/CHANGELOG.md
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
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/path-utils-find-project-root.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/path-utils-find-project-root.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/path-utils-find-project-root.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/path-utils-find-project-root.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/path-utils-find-project-root.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/path-utils-find-project-root.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/path-utils-find-project-root.test.js
  • src/utils/path-utils.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/path-utils-find-project-root.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/path-utils-find-project-root.test.js
.changeset/*.md

📄 CodeRabbit inference engine (.cursor/rules/changeset.mdc)

.changeset/*.md: When running npm run changeset or npx changeset add, provide a concise summary of the changes for the CHANGELOG.md in 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.

Write changeset entries as user-facing summaries of what users get or what was fixed, not low-level implementation details

Files:

  • .changeset/fix-parent-directory-traversal.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-parent-directory-traversal.md
{src/utils/**,src/middleware/**}

📄 CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)

Test coverage for all code should meet or exceed 80% lines/functions and 70% branches globally; critical code (utils, middleware) should meet higher thresholds (90% utils, 85% middleware)

Files:

  • src/utils/path-utils.js
🧠 Learnings (8)
📚 Learning: 2025-09-22T19:45:04.337Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1232
File: packages/tm-core/package.json:50-51
Timestamp: 2025-09-22T19:45:04.337Z
Learning: In the eyaltoledano/claude-task-master project, Crunchyman-ralph intentionally omits version fields from internal/private packages in package.json files to prevent changesets from releasing new versions of these packages while still allowing them to be processed for dependency updates. The changesets warnings about missing versions are acceptable as they don't break the process and achieve the desired behavior of only releasing public packages.

Applied to files:

  • packages/claude-code-plugin/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, all packages with tm prefix are internal packages that are part of the monorepo structure and are not published externally.

Applied to files:

  • packages/claude-code-plugin/package.json
📚 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/claude-code-plugin/package.json
📚 Learning: 2025-09-22T19:45:13.323Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1232
File: packages/build-config/package.json:14-15
Timestamp: 2025-09-22T19:45:13.323Z
Learning: In the eyaltoledano/claude-task-master repository, Crunchyman-ralph intentionally omits version fields from internal packages (like tm/build-config) to prevent changesets from releasing new versions for these packages. This is the desired behavior for internal tooling packages that should not be published or versioned independently.

Applied to files:

  • packages/claude-code-plugin/package.json
📚 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:

  • tests/unit/path-utils-find-project-root.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 : Verify file operations use the correct paths in expect statements.

Applied to files:

  • tests/unit/path-utils-find-project-root.test.js
📚 Learning: 2025-08-06T21:16:02.300Z
Learnt from: Crunchyman-ralph
PR: eyaltoledano/claude-task-master#1095
File: .github/scripts/check-pre-release-mode.mjs:33-34
Timestamp: 2025-08-06T21:16:02.300Z
Learning: In the claude-task-master project, the .changeset directory is guaranteed to exist as part of the fundamental project structure, so validation checks for its existence are unnecessary.

Applied to files:

  • .changeset/fix-parent-directory-traversal.md
📚 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:

  • src/utils/path-utils.js
🧬 Code graph analysis (2)
tests/unit/path-utils-find-project-root.test.js (1)
src/utils/path-utils.js (1)
  • findProjectRoot (60-156)
src/utils/path-utils.js (2)
mcp-server/src/core/utils/path-utils.js (1)
  • findProjectRoot (202-204)
scripts/modules/config-manager.js (1)
  • rootDir (858-858)
🪛 LanguageTool
packages/build-config/CHANGELOG.md

[grammar] ~7-~7: Hier könnte ein Fehler sein.
Context: .../build-config ## null ## null ## null ## 1.0.1

(QB_NEW_DE)

apps/docs/CHANGELOG.md

[grammar] ~3-~3: Hier könnte ein Fehler sein.
Context: # docs ## 0.0.6 ## 0.0.5 ## 0.0.4 ## 0.0.3 ## 0.0.2 ## ...

(QB_NEW_DE)

packages/claude-code-plugin/CHANGELOG.md

[grammar] ~1-~1: Hier könnte ein Fehler sein.
Context: # @tm/claude-code-plugin ## 0.0.2

(QB_NEW_DE)


[grammar] ~3-~3: Hier könnte ein Fehler sein.
Context: # @tm/claude-code-plugin ## 0.0.2

(QB_NEW_DE)

🪛 markdownlint-cli2 (0.18.1)
packages/tm-core/CHANGELOG.md

7-7: Multiple headings with the same content

(MD024, no-duplicate-heading)

.changeset/fix-parent-directory-traversal.md

5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

apps/cli/CHANGELOG.md

17-17: Multiple headings with the same content

(MD024, no-duplicate-heading)

🔇 Additional comments (9)
apps/extension/CHANGELOG.md (1)

3-4: LGTM — changelog entry for 0.25.6 stable release is correctly formatted.

The new section header properly precedes the release candidate and maintains correct semantic versioning order.

apps/docs/package.json (1)

3-3: LGTM — version bump is consistent with the 0.0.6 changelog entry.

Version update aligns with the accompanying changelog and release scope.

apps/extension/package.json (1)

6-6: LGTM — RC promotion to stable 0.25.6 with appropriate dependency pins.

Version advancement and MCP SDK pinning are sound for extension stability.

apps/docs/CHANGELOG.md (1)

3-4: LGTM — changelog entry for 0.0.6 is correctly formatted.

Version header properly precedes the 0.0.5 entry and aligns with the package.json bump.

package.json (1)

3-3: LGTM — root package version correctly promoted to stable 0.29.0.

RC release is properly finalized with comprehensive test scripts already in place (test, test:watch, test:coverage, test:unit, test:integration, test:e2e, test:ci per coding guidelines).

packages/claude-code-plugin/package.json (1)

3-3: Confirm versioning policy for private tm/ packages.*

Repo learnings indicate internal packages often omit “version” to avoid unintended releases. If this remains private, consider removing the field or confirm intentional bump.

Based on learnings

src/utils/path-utils.js (2)

49-59: Two‑pass strategy matches the requirement.

Clear priority for parent .taskmaster; comments and return semantics are good.


153-156: Confirm fallback semantics when startDir is provided.

Function always falls back to process.cwd(), not the provided startDir. If callers pass a custom startDir, returning CWD may be surprising; consider returning the resolved startDir instead.

-  return process.cwd();
+  return path.resolve(startDir);
tests/unit/path-utils-find-project-root.test.js (1)

24-27: Make expectations cross‑platform.

Hardcoded '/project' will fail on Windows. Use path.resolve to build expected absolute paths.

- expect(result).toBe('/project');
+ expect(result).toBe(path.resolve('/project'));

Apply similarly for any '/project/subdir' expectations:

- expect(result).toBe('/project/subdir');
+ expect(result).toBe(path.resolve('/project/subdir'));

Also applies to: 39-42, 54-57, 70-73, 86-87, 124-127, 141-142, 169-170

⛔ Skipped due to learnings
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 : Verify file operations use the correct paths in expect statements.
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 `path.join()` for cross-platform path construction, `path.resolve()` for absolute paths, and validate paths before file operations.
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 : Use test-specific file paths (e.g., 'test-tasks.json') for all file operations in tests.

Comment on lines +1 to +7
---
"task-master-ai": patch
---

Enable Task Master commands to traverse parent directories to find project root from nested paths

Fixes #1301
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Fix issue reference and verify target package in changeset.


🏁 Script executed:

#!/bin/bash
# Map code to package to validate the correct changeset target
fd -a package.json | xargs -I{} sh -c 'echo {} && cat {} | jq -r ".name"'
echo "Files importing src/utils/path-utils.js:"
rg -n --pretty "from ['\"]\\.{0,2}/\\.?\\.\\./utils/path-utils\\.js['\"]|from ['\"][^'\"]*path-utils\\.js['\"]" -g '!**/dist/**'

Length of output: 5221


Update issue reference in changeset.

The package target "task-master-ai" is correct—src/utils/path-utils.js belongs to the root package and is imported across the monorepo. However, the issue reference must be corrected:

  • Update Fixes #1301Fixes #1349
---
"task-master-ai": patch
---

Enable Task Master commands to traverse parent directories to find project root from nested paths

Fixes #1349
🧰 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/fix-parent-directory-traversal.md lines 1-7: update the issue
reference in the changeset frontmatter body — change "Fixes #1301" to "Fixes
#1349" so the changeset correctly references the issue; make the single-line
replacement in that file and save.

Comment on lines 14 to 23
- Updated dependencies []:
- @tm/core@null

## null

### Patch Changes

- Updated dependencies []:
- @tm/core@null

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Remove invalid “## null” entries and duplicated patch sections.

These headings and “@tm/core@null” entries indicate a broken release artifact and duplicate content. Please drop these blocks or regenerate via changesets to restore valid versions.

-### Patch Changes
-- Updated dependencies []:
-  - @tm/core@null
-
-## null
-
-### Patch Changes
-
-- Updated dependencies []:
-  - @tm/core@null
+<!-- Removed invalid duplicate/null sections produced by a bad changeset -->

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

17-17: Multiple headings with the same content

(MD024, no-duplicate-heading)

🤖 Prompt for AI Agents
In apps/cli/CHANGELOG.md around lines 14 to 23, remove the invalid "## null"
heading, the duplicated "Patch Changes" block and the "@tm/core@null" dependency
entries (these are broken release artifacts); either delete these
duplicated/null blocks entirely or regenerate the changelog via changesets so
the file contains only valid version headings and real dependency versions, then
save and commit the cleaned changelog.

Comment on lines +3 to +85
## 0.29.0

### Minor Changes

- [#1286](https://github.com/eyaltoledano/claude-task-master/pull/1286) [`f12a16d`](https://github.com/eyaltoledano/claude-task-master/commit/f12a16d09649f62148515f11f616157c7d0bd2d5) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add changelog highlights to auto-update notifications

When the CLI auto-updates to a new version, it now displays a "What's New" section.

- [#1293](https://github.com/eyaltoledano/claude-task-master/pull/1293) [`3010b90`](https://github.com/eyaltoledano/claude-task-master/commit/3010b90d98f3a7d8636caa92fc33d6ee69d4bed0) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add Claude Code plugin with marketplace distribution

This release introduces official Claude Code plugin support, marking the evolution from legacy `.claude` directory copying to a modern plugin-based architecture.

## 🎉 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 (`/taskmaster: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
```

### The `rules add claude` command no longer copies commands and agents to `.claude/commands/` and `.claude/agents/`. Instead, it now
- Shows plugin installation instructions
- Only manages CLAUDE.md imports for agent instructions
- Directs users to install the official plugin

**Migration for Existing Users:**

If you previously used `rules add claude`:
1. The old commands in `.claude/commands/` will continue to work but won't receive updates
2. Install the plugin for the latest features: `/plugin install taskmaster@taskmaster`
3. remove old `.claude/commands/` and `.claude/agents/` directories

**Why This Change?**

Claude Code plugins provide:
- ✅ Automatic updates when we release new features
- ✅ Better command organization and naming
- ✅ Seamless integration with Claude Code
- ✅ No manual file copying or management

The plugin system is the future of Task Master AI integration with Claude Code!

- [#1285](https://github.com/eyaltoledano/claude-task-master/pull/1285) [`2a910a4`](https://github.com/eyaltoledano/claude-task-master/commit/2a910a40bac375f9f61d797bf55597303d556b48) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Add RPG (Repository Planning Graph) method template for structured PRD creation. The new `example_prd_rpg.txt` template teaches AI agents and developers the RPG methodology through embedded instructions, inline good/bad examples, and XML-style tags for structure. This template enables creation of dependency-aware PRDs that automatically generate topologically-ordered task graphs when parsed with Task Master.

Key features:
- Method-as-template: teaches RPG principles (dual-semantics, explicit dependencies, topological order) while being used
- Inline instructions at decision points guide AI through each section
- Good/bad examples for immediate pattern matching
- Flexible plain-text format with XML-style tags for parseability
- Critical dependency-graph section ensures correct task ordering
- Automatic inclusion during `task-master init`
- 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.

- [#1287](https://github.com/eyaltoledano/claude-task-master/pull/1287) [`90e6bdc`](https://github.com/eyaltoledano/claude-task-master/commit/90e6bdcf1c59f65ad27fcdfe3b13b9dca7e77654) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Enhance `expand_all` to intelligently use complexity analysis recommendations when expanding tasks.

The expand-all operation now automatically leverages recommendations from `analyze-complexity` to determine optimal subtask counts for each task, resulting in more accurate and context-aware task breakdowns.

Key improvements:
- Automatic integration with complexity analysis reports
- Tag-aware complexity report path resolution
- Intelligent subtask count determination based on task complexity
- Falls back to defaults when complexity analysis is unavailable
- Enhanced logging for better visibility into expansion decisions

When you run `task-master expand --all` after `task-master analyze-complexity`, Task Master now uses the recommended subtask counts from the complexity analysis instead of applying uniform defaults, ensuring each task is broken down according to its actual complexity.

### Patch Changes

- [#1191](https://github.com/eyaltoledano/claude-task-master/pull/1191) [`aaf903f`](https://github.com/eyaltoledano/claude-task-master/commit/aaf903ff2f606c779a22e9a4b240ab57b3683815) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix cross-level task dependencies not being saved

Fixes an issue where adding dependencies between subtasks and top-level tasks (e.g., `task-master add-dependency --id=2.2 --depends-on=11`) would report success but fail to persist the changes. Dependencies can now be created in both directions between any task levels.

- [#1299](https://github.com/eyaltoledano/claude-task-master/pull/1299) [`4c1ef2c`](https://github.com/eyaltoledano/claude-task-master/commit/4c1ef2ca94411c53bcd2a78ec710b06c500236dd) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve refresh token when authenticating

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing changelog entry for the main fix (PR #1350).

Per the PR objectives, PR #1350 addresses a critical bug (#1349) where findProjectRoot() failed to prioritize .taskmaster directories in parent folders over other project markers (.git, go.mod, etc.). This fix implements a two-pass search strategy and is fundamental to the v0.29.0 release.

However, this fix is not documented in the 0.29.0 changelog section (lines 3–85). The section includes entries for PRs #1286, #1293, #1285, #1287, #1191, and #1299, but PR #1350 and its resolution of issue #1349 are absent.

Action: Add a changelog entry for PR #1350 (or confirm if this was intentionally omitted as part of a changeset consolidation). If included, consider placing it in the Patch Changes section with a clear description of the fix and its impact on nested repository workflows (monorepos, microservices, git worktrees).

Example entry:

- [#1350](…) — Fix: Prioritize `.taskmaster` directories in parent folders over generic project markers (.git, go.mod, etc.), ensuring correct detection in nested repository setups.
🤖 Prompt for AI Agents
In CHANGELOG.md around lines 3 to 85, the 0.29.0 release notes are missing a
changelog entry for PR #1350 which fixes issue #1349 (findProjectRoot() failing
to prioritize .taskmaster directories); add a concise Patch Changes entry for PR
#1350 placed with the other patch entries (after the existing patch bullets)
using the repo PR/commit link and text like: "- [#1350](<PR link or commit>) —
Fix: Prioritize `.taskmaster` directories in parent folders over generic project
markers (.git, go.mod, etc.), ensuring correct root detection in nested
repository setups (monorepos, worktrees)." Ensure the wording mentions the
impact on nested repository workflows and follow the existing bullet style.

Comment on lines 3 to 5
## null

## null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Remove invalid "## null" changelog entries—these are release automation artifacts.

Lines 3 and 5 contain two duplicate "## null" headers, which are invalid placeholders from changelog tooling failure (same issue across multiple CHANGELOG files in this PR).

Apply this diff to remove the invalid entries:

 # @tm/ai-sdk-provider-grok-cli
 
-## null
-
-## null

This is part of a broader changelog generation issue affecting packages/tm-core/CHANGELOG.md, packages/build-config/CHANGELOG.md, and this file. Fix the root cause in the release tooling to prevent recurrence.


🏁 Script executed:

#!/bin/bash
# Check if the target file exists and view its content
if [ -f "packages/ai-sdk-provider-grok-cli/CHANGELOG.md" ]; then
  echo "=== packages/ai-sdk-provider-grok-cli/CHANGELOG.md ===" 
  cat "packages/ai-sdk-provider-grok-cli/CHANGELOG.md"
else
  echo "File not found: packages/ai-sdk-provider-grok-cli/CHANGELOG.md"
fi

echo -e "\n=== Checking other CHANGELOG files mentioned ==="
for file in "packages/tm-core/CHANGELOG.md" "packages/build-config/CHANGELOG.md"; do
  if [ -f "$file" ]; then
    echo -e "\n$file:"
    cat "$file"
  else
    echo "$file not found"
  fi
done

Length of output: 2736


Remove invalid "## null" changelog entries—these are confirmed release automation artifacts.

Verification confirms two "## null" entries exist on lines 3 and 5 of packages/ai-sdk-provider-grok-cli/CHANGELOG.md. The same pattern appears in packages/tm-core/CHANGELOG.md and packages/build-config/CHANGELOG.md (three entries each), indicating a systemic release automation issue.

Apply the proposed diff to remove the invalid entries:

 # @tm/ai-sdk-provider-grok-cli
 
-## null
-
-## null

Additionally, fix the root cause in the release tooling to prevent this recurrence in future runs, and clean up the duplicate entries in the other CHANGELOG files.

📝 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.

Suggested change
## null
## null
# @tm/ai-sdk-provider-grok-cli
🤖 Prompt for AI Agents
packages/ai-sdk-provider-grok-cli/CHANGELOG.md lines 3-5: remove the two invalid
"## null" headings at those lines so the changelog contains only valid entries;
also scan and remove the duplicate "## null" headings in
packages/tm-core/CHANGELOG.md and packages/build-config/CHANGELOG.md (three
each) to clean up the files; then update the release automation (the changelog
generation script) to validate heading values before writing (skip or abort on
null/empty release titles) and add a unit or integration check that prevents
emitting "null" headings in future runs.

Comment on lines +1 to +3
# @tm/claude-code-plugin

## 0.0.2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Add a one‑line user‑facing note for 0.0.2.

Briefly describe what changed so consumers understand the bump (e.g., “chore: align metadata; no runtime changes”).

🧰 Tools
🪛 LanguageTool

[grammar] ~1-~1: Hier könnte ein Fehler sein.
Context: # @tm/claude-code-plugin ## 0.0.2

(QB_NEW_DE)


[grammar] ~3-~3: Hier könnte ein Fehler sein.
Context: # @tm/claude-code-plugin ## 0.0.2

(QB_NEW_DE)

🤖 Prompt for AI Agents
In packages/claude-code-plugin/CHANGELOG.md lines 1 to 3, the 0.0.2 entry lacks
a one-line user-facing note; add a concise description of the change (e.g.,
"chore: align metadata; no runtime changes" or similar) directly beneath the "##
0.0.2" heading so consumers understand the version bump.

Comment on lines 89 to 91
const maxDepth = 50; // Reasonable limit to prevent infinite loops
let depth = 0;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Extract maxDepth to a module constant for reuse and clarity.

Minor readability/maintainability improvement.

-const maxDepth = 50; // Reasonable limit to prevent infinite loops
+const MAX_PARENT_TRAVERSAL_DEPTH = 50; // Reasonable limit to prevent infinite loops
+const maxDepth = MAX_PARENT_TRAVERSAL_DEPTH;
📝 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.

Suggested change
const maxDepth = 50; // Reasonable limit to prevent infinite loops
let depth = 0;
const MAX_PARENT_TRAVERSAL_DEPTH = 50; // Reasonable limit to prevent infinite loops
const maxDepth = MAX_PARENT_TRAVERSAL_DEPTH;
let depth = 0;
🤖 Prompt for AI Agents
In src/utils/path-utils.js around lines 89 to 91, the local variable maxDepth is
declared inline; extract it to a module-level constant (e.g., const
MAX_TRAVERSE_DEPTH = 50) so it can be reused and improves clarity. Move the
declaration to the top of the module, replace the inline maxDepth usage with the
new constant name, and update any related references or tests to use the
constant.

Comment on lines +92 to +121
// FIRST PASS: Traverse ALL parent directories looking ONLY for Task Master markers
// This ensures that a .taskmaster in a parent directory takes precedence over
// other project markers (like .git, go.mod, etc.) in subdirectories
let searchDir = currentDir;
depth = 0;
while (searchDir !== rootDir && depth < maxDepth) {
for (const marker of taskmasterMarkers) {
const markerPath = path.join(searchDir, marker);
try {
if (fs.existsSync(markerPath)) {
// Found a Task Master marker - this is our project root
return searchDir;
}
} catch (error) {
// Ignore permission errors and continue searching
continue;
}
}

// Move up one directory level
const parentDir = path.dirname(searchDir);

// Safety check: if dirname returns the same path, we've hit the root
if (parentDir === searchDir) {
break;
}

searchDir = parentDir;
depth++;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider scanning the filesystem root as well.

Current loop condition skips the root itself, so markers at “/” (or drive root) won’t be detected. Switch to a do/while or check currentDir before breaking.

-while (searchDir !== rootDir && depth < maxDepth) {
+while (depth < maxDepth) {
+  // check searchDir ...
   ...
-  const parentDir = path.dirname(searchDir);
-  if (parentDir === searchDir || parentDir === rootDir) break;
+  const parentDir = path.dirname(searchDir);
+  if (parentDir === searchDir) break; // reached real root
   searchDir = parentDir;
   depth++;
}

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/utils/path-utils.js around lines 92 to 121, the current while loop stops
when searchDir equals rootDir and therefore never checks the root directory for
Task Master markers; modify the loop so the root directory is included — either
convert the loop to a do/while that checks markers first then moves up, or keep
the while but perform a final check of searchDir === rootDir before breaking;
ensure depth and permission-error handling remain the same and return searchDir
if a marker is found at the filesystem root.

Comment on lines +6 to +12
import { jest } from '@jest/globals';
import path from 'path';
import fs from 'fs';

// Import the function to test
import { findProjectRoot } from '../../src/utils/path-utils.js';

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Optional: Use ESM-friendly module mocking to isolate fs.

Consider jest.unstable_mockModule('fs', ...) with dynamic import of path-utils to avoid reliance on global spy state; keeps tests hermetic.

🤖 Prompt for AI Agents
In tests/unit/path-utils-find-project-root.test.js around lines 6-12, the test
currently imports fs and then uses global spies which can leak state; update the
test to use ESM-friendly module mocking by calling
jest.unstable_mockModule('fs', () => ({ ...mockedFsObjects })) before importing
the module under test, then dynamically import '../../src/utils/path-utils.js'
(await import(...)) so the mocked fs is used at module evaluation time; ensure
you provide the necessary mocked fs functions (e.g., statSync, existsSync,
readdirSync) and restore/reset mocks between tests to keep them hermetic.

Comment on lines +91 to +109
test('should find markers at current directory before checking parent', () => {
const mockExistsSync = jest.spyOn(fs, 'existsSync');

mockExistsSync.mockImplementation((checkPath) => {
const normalized = path.normalize(checkPath);
// .git exists at /project/subdir, .taskmaster exists at /project
if (normalized.includes('/project/subdir/.git')) return true;
if (normalized.includes('/project/.taskmaster')) return true;
return false;
});

const result = findProjectRoot('/project/subdir');

// Should find /project/subdir first because .git exists there,
// even though .taskmaster is earlier in the marker array
expect(result).toBe('/project/subdir');

mockExistsSync.mockRestore();
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Test contradicts new priority: parent .taskmaster must win.

With two‑pass search, parent “.taskmaster” should be preferred over current‑dir “.git”. Update expectation.

-      // Should find /project/subdir first because .git exists there,
-      // even though .taskmaster is earlier in the marker array
-      expect(result).toBe('/project/subdir');
+      // Parent .taskmaster should take precedence over current-dir generic markers
+      expect(result).toBe(path.resolve('/project'));
🤖 Prompt for AI Agents
In tests/unit/path-utils-find-project-root.test.js around lines 91 to 109, the
test currently expects the subdirectory '/project/subdir' to be returned but the
new two‑pass priority requires the parent marker '.taskmaster' to win over
current-dir '.git'; update the assertion to expect '/project' (and optionally
rename the test description to reflect that parent marker wins) so the test
aligns with the updated search priority.

Comment on lines +200 to +219
test('should not exceed max depth limit', () => {
const mockExistsSync = jest.spyOn(fs, 'existsSync');

// Track how many times existsSync is called
let callCount = 0;
mockExistsSync.mockImplementation(() => {
callCount++;
return false; // Never find a marker
});

// Create a very deep path
const deepPath = '/a/'.repeat(100) + 'deep';
const result = findProjectRoot(deepPath);

// Should stop after max depth (50) and not check 100 levels
// Each level checks multiple markers, so callCount will be high but bounded
expect(callCount).toBeLessThan(1000); // Reasonable upper bound
// With 18 markers and max depth of 50, expect around 900 calls maximum
expect(callCount).toBeLessThanOrEqual(50 * 18);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Depth-bound assertion is brittle to marker count changes.

Tying the upper bound to “18 markers” will break when marker sets evolve. Relax the bound or compute dynamically.

- expect(callCount).toBeLessThanOrEqual(50 * 18);
+ // Allow headroom for future marker additions (two passes * 50 levels * <= 16 markers per pass ~= 1600)
+ expect(callCount).toBeLessThan(1600);

@bjcoombs bjcoombs changed the base branch from main to ralph/feat/implement.new.update-task October 27, 2025 11:21
@bjcoombs bjcoombs marked this pull request as draft October 27, 2025 11:22
@bjcoombs
Copy link
Contributor Author

Closing to recreate with clean branch based on latest upstream/main

@bjcoombs bjcoombs closed this Oct 27, 2025
@Crunchyman-ralph
Copy link
Collaborator

@bjcoombs please base off upstream/next

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: findProjectRoot() prioritizes other project markers over parent .taskmaster directories

10 participants