fix: prioritize .taskmaster in parent directories over other project markers#1350
Conversation
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>
…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
…dano#1286) Co-authored-by: Claude <noreply@anthropic.com>
…edano#1287) Co-authored-by: Claude <noreply@anthropic.com>
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 detectedLatest 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 |
WalkthroughThis 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 Changes
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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(); | ||
| }); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.1After 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.1Fix 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
⛔ Files ignored due to path filters (1)
package-lock.jsonis 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.mdapps/docs/CHANGELOG.mdpackages/ai-sdk-provider-grok-cli/CHANGELOG.mdapps/extension/CHANGELOG.mdpackages/claude-code-plugin/CHANGELOG.mdCHANGELOG.mdpackages/tm-core/CHANGELOG.mdapps/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.jssrc/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 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.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.
| --- | ||
| "task-master-ai": patch | ||
| --- | ||
|
|
||
| Enable Task Master commands to traverse parent directories to find project root from nested paths | ||
|
|
||
| Fixes #1301 |
There was a problem hiding this comment.
🧩 Analysis chain
Fix issue reference and verify target package in changeset.
- Update “Fixes Bug: Task Master doesn't traverse parent directories from subdirectories #1301” → “Fixes Bug: findProjectRoot() prioritizes other project markers over parent .taskmaster directories #1349”.
- Ensure frontmatter targets the package that ships findProjectRoot (likely @tm/core), not a different app.
🏁 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 #1301→Fixes #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.
| - Updated dependencies []: | ||
| - @tm/core@null | ||
|
|
||
| ## null | ||
|
|
||
| ### Patch Changes | ||
|
|
||
| - Updated dependencies []: | ||
| - @tm/core@null | ||
|
|
There was a problem hiding this comment.
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.
| ## 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 | ||
|
|
There was a problem hiding this comment.
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.
| ## null | ||
|
|
||
| ## null |
There was a problem hiding this comment.
🧩 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
-
-## nullThis 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
doneLength 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
-
-## nullAdditionally, 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.
| ## 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.
| # @tm/claude-code-plugin | ||
|
|
||
| ## 0.0.2 |
There was a problem hiding this comment.
🧹 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.
| const maxDepth = 50; // Reasonable limit to prevent infinite loops | ||
| let depth = 0; | ||
|
|
There was a problem hiding this comment.
🧹 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.
| 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.
| // 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++; | ||
| } |
There was a problem hiding this comment.
🧹 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.
| 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'; | ||
|
|
There was a problem hiding this comment.
🧹 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.
| 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(); | ||
| }); |
There was a problem hiding this comment.
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.
| 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); | ||
|
|
There was a problem hiding this comment.
🧹 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);|
Closing to recreate with clean branch based on latest upstream/main |
|
@bjcoombs please base off upstream/next |
Summary
Fixes #1349
This PR ensures that
.taskmasterdirectories in parent folders are always found and used, even when subdirectories contain other project markers like.git,go.mod, orpackage.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.taskmasterdirectory.Example scenario:
Running
task-master listfromsub-repo/would create a new.taskmaster/insub-repo/instead of finding the parent.Solution
Implemented a two-pass search strategy in
findProjectRoot():First Pass (Lines 92-121)
.taskmaster/.taskmaster/config.json.taskmaster/tasks/tasks.jsonSecond Pass (Lines 123-151)
.git,.svnpackage.json,go.mod,Cargo.tomlThis guarantees that Task Master markers in parent directories always take precedence over generic project markers in subdirectories.
Changes Made
Core Changes
findProjectRoot()functionMCP Server
src/utils/path-utils.jsTesting
Manual Testing
Unit Tests
The existing test suite in
tests/unit/path-utils-find-project-root.test.jscovers basic traversal. Additional tests for this scenario should be added in a follow-up PR.Use Cases Enabled
.taskmasterat root coordinating work across multiple Git repositories.gitfiles can use parent.taskmaster.taskmasterdirectoriesBefore This Fix
After This Fix
Backward Compatibility
✅ Fully backward compatible
.taskmasterat root continue to work.taskmasterexists AND subdirectory has other markersChecklist
Related
Summary by CodeRabbit
Release Notes
Bug Fixes
Chores