Conversation
Create the loop module with TypeScript type definitions for: - LoopPreset: available preset loop prompts - LoopConfig: configuration options for loop execution - LoopIteration: result of a single loop iteration - LoopResult: overall result of loop execution - LoopCompletionMarker: marker for completion detection Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added types.spec.ts with compile-time type validation tests for all loop module types: LoopPreset, LoopConfig, LoopIteration, LoopResult, and LoopCompletionMarker. Task 1.2 was already implemented in 1.1. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Task 1.3 - interfaces were already implemented in types.ts during task 1.1. Tests verified in types.spec.ts. TypeScript compilation passes. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
LoopCompletionMarker was already implemented in types.ts from subtask 1.1. Tests exist in types.spec.ts. tsc --noEmit passes. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add presets module with: - PRESET_NAMES constant array with all 5 preset names - isValidPreset() type guard for validating preset names - getPresetPath() for getting preset file paths - loadPreset() async function for loading preset content Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add bundled preset markdown files for loop module: - default.md: standard task completion workflow - test-coverage.md: test coverage improvement workflow - linting.md: lint/type error fixing workflow - duplication.md: code duplication refactoring workflow - entropy.md: code smell cleanup workflow Each preset includes @ file references, process steps, completion markers (<loop-complete>), and single-task-per-iteration constraint. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add snapshot tests for all 5 preset files (default, test-coverage, linting, duplication, entropy) - Add structure validation tests verifying <loop-complete> markers, @ file references, numbered steps - Add default preset specific tests for <loop-blocked> marker - Add content consistency tests for single-task-per-iteration constraint, progress file reference - Update loadPreset tests to verify all presets load successfully Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create the base LoopProgressService with: - ProgressEntry interface for tracking iteration data - Constructor accepting projectRoot - getDefaultProgressPath() method returning .taskmaster/loop-progress.txt Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements method to create a new progress file with header containing timestamp, preset name, max iterations, and optional tag. Ensures parent directory exists before writing. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements method to append formatted progress entry lines to the progress file. Entry format: [timestamp] Iteration N (Task ID): note The task ID portion is optional. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- readProgress() reads file content, returns empty string if file missing - exists() checks file accessibility using fs/promises access() - Both methods handle errors gracefully without throwing - Added 7 unit tests covering existing/missing file/directory scenarios Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…gration tests Added exports for LoopProgressService class and ProgressEntry type to loop/index.ts. Added barrel export tests and comprehensive integration tests that verify the full workflow: initialize progress file, append multiple entries, and read back content. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements LoopCompletionService with parseOutput() method that detects <loop-complete> and <loop-blocked> markers in Claude output. Includes comprehensive test coverage for all marker patterns, edge cases, and case insensitivity. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ets module - Add isFilePath() to detect file paths vs preset names - Add resolvePrompt() to unify preset and custom file loading - Add loadCustomPrompt() for custom prompt file loading - Add PresetError class with typed error codes - Add error handling for missing files and empty content - Export new functions from loop module index - Add comprehensive tests for new functions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Presets are now embedded as string constants to avoid path resolution issues during bundling. This eliminates filesystem reads for built-in presets while maintaining the async API for backward compatibility. Custom prompt files still use filesystem reads. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add integration tests to verify preset content is accessible without filesystem dependencies, validating the inlined preset approach works in both development and bundled distribution contexts. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…e definitions - Created PromptGenerationOptions interface for prompt generation config - Added LoopPromptService class with dependency injection for LoopPresetService - Included protected getPresetService() method for internal access - Added unit tests for constructor and service instantiation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements iteration context generation with: - Loop iteration count (e.g., "Loop Iteration 3 of 10") - Progress file reference with @ syntax - Tasks file reference - Optional tag filter when config.tag is set Includes 7 unit tests covering all scenarios. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add resolvePrompt() method to LoopPresetService for DI-compatible prompt resolution - Implement generatePrompt() async method in LoopPromptService - Combines context header with preset/custom prompt content using double newline separator - Supports custom file prompts via optional readFile callback - Add 8 unit tests for generatePrompt covering various scenarios Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… module barrel - Create services/index.ts barrel file exporting all loop services - Add LoopPromptService and PromptGenerationOptions to loop/index.ts - Add barrel export tests for new exports in types.spec.ts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add snapshot tests for generated prompts from all 5 presets (default, test-coverage, linting, duplication, entropy). Tests use real LoopPresetService instead of mocks to verify actual prompt output. Includes tests for: - Snapshot tests for each preset with and without tag - Context header validation with real presets - Double newline separator verification - Loop completion marker presence - Iteration boundary handling (first, last, single, large counts) - Tag handling (included/omitted) - Custom progress file paths Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements task 7.1 - basic spawn mechanism with stdio capture: - LoopExecutorService class that spawns Claude CLI with prompts - Captures stdout/stderr output for completion marker detection - Integrates LoopCompletionService for parsing output - Process lifecycle management with stop() method - Comprehensive unit tests with mocked child_process Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement LoopService class as the main orchestrator for loop execution. The service constructor instantiates all sub-services with proper dependency injection: - LoopPresetService (standalone) - LoopProgressService (receives projectRoot) - LoopCompletionService (standalone) - LoopPromptService (receives presetService) - LoopExecutorService (receives completionService) Includes run() method stub, stop() method, and comprehensive unit tests. Exported from services/index.ts and loop/index.ts barrel files. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The run() method implementation was already complete from task 8.1. Verified: iteration tracking, completion detection, progress logging, sleep between iterations, and proper finalStatus returns. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added comprehensive tests for: - stop() method: sets isRunning to false and calls executorService.stop() - sleep() method: resolves after specified delay using fake timers - run() graceful exit: respects isRunning flag and handles mid-loop stop Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement LoopDomain as the public API facade for loop operations: - ConfigManager DI with projectRoot extraction - Lazy LoopService instantiation via run()/stop() - Config building with defaults (iterations=10, prompt='default', sleepSeconds=5) - Preset operations: isPreset(), resolvePrompt(), getAvailablePresets() - TasksDomain integration for checkAllTasksComplete() - Unit tests covering all facade methods Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Adds 58 unit tests covering: - Complete markers: position tests, various reasons - Blocked markers: position tests, various reasons - Case insensitivity: uppercase, mixed case - Edge cases: empty input, long output, newlines - Special characters: unicode, emoji, quotes - Malformed markers: partial tags, mismatched tags - extractCompletionReason method Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create apps/docs/capabilities/loop.mdx with Mintlify-compatible frontmatter, overview section explaining the Ralph Wiggum pattern (credited to Jeffrey Huntley, popularized by Matt Pocock), and basic usage examples for running autonomous Claude Code loops. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Documents all five built-in loop presets: default, test-coverage, linting, duplication, and entropy. Includes summary table, usage examples, detailed workflow descriptions, and completion criteria for each preset. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document how to create custom prompts including required structure, completion markers, file references with @ syntax, and best practices. Add progress file section explaining format, usage, and how to integrate with custom prompts for context continuity. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added loop_start and loop_presets to the standardTools array so they are available when TASK_MASTER_TOOLS=standard is set. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Updated .taskmaster/CLAUDE.md to reflect loop_start and loop_presets being added to the standard tier: - Standard tier now shows 16 tools (was 14) - Standard adds line now includes loop_start and loop_presets - Added Loop automation section to Essential MCP Tools Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add automated tests verifying loop tools (loop_start, loop_presets) are correctly registered in MCP tool tiers. Tests verify: - Loop tools registered in toolRegistry - Loop tools included in standardTools (TASK_MASTER_TOOLS=standard) - Loop tools excluded from coreTools (TASK_MASTER_TOOLS=core) - All tool tier utility functions work correctly Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reduce loop module complexity by merging 5 services into single LoopService: - Merge LoopCompletionService, LoopProgressService, LoopPromptService, LoopExecutorService, LoopPresetService logic into LoopService - Convert preset .md files to .ts files with exported constants - Remove TasksDomain integration (setTasksDomain, checkAllTasksComplete) - Remove LoopCompletionMarker type (inlined) - Simplify presets/index.ts to minimal PRESETS record + helpers Before: 6 service classes + 1 facade = 7 abstractions, ~1,754 lines After: 1 service class + 1 facade + presets = 3 abstractions, ~500 lines Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove loop_start and loop_presets MCP tools for now - can be added back later when needed. Updates: - Remove apps/mcp/src/tools/loop/ directory (4 files) - Remove loop imports/exports from tool-registry.js - Update standard tier from 16 to 14 tools - Update .taskmaster/CLAUDE.md documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove options that weren't needed: - CLI: Remove --status, --on-complete, --sleep options - LoopConfig: Remove onComplete and status fields - Keep --progress-file with default .taskmaster/progress.txt Update progress file behavior: - Keep init header on loop start - Remove per-iteration appends (AI handles progress updates) - Add final summary append when loop completes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 5ff28c9 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 |
📝 WalkthroughWalkthrough📝 WalkthroughAdds a new "loop" feature that runs Claude Code in iterative sandboxed tasks. Adds Loop domain/service/types/presets in tm-core, CLI command and scripts, progress tracking, presets, tests, docs, and wiring into TmCore and exports. Also updates some taskmaster config/metadata. Changes
Sequence Diagram(s)sequenceDiagram
participant CLI as CLI (task-master loop)
participant TmCore as TmCore / LoopDomain
participant LoopSvc as LoopService
participant Docker as Docker Sandbox
participant FS as Progress File (./.taskmaster/loop-progress.txt)
CLI->>TmCore: resolveIterations / build config
CLI->>TmCore: run(config)
TmCore->>LoopSvc: start run(config)
LoopSvc->>FS: init/append progress
LoopSvc->>Docker: spawn Claude Code (per-iteration prompt)
Docker-->>LoopSvc: iteration output (stdout)
LoopSvc->>FS: append iteration result
alt output contains <loop-complete> or <loop-blocked>
LoopSvc->>TmCore: return final LoopResult (status)
TmCore-->>CLI: present result
else continue until iterations exhausted
LoopSvc->>Docker: next iteration...
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
There was a problem hiding this comment.
This is the final PR Bugbot will review for you during this billing cycle
Your free Bugbot reviews will reset on February 9
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.
| - 1.1: Created loop module directory and types.ts. All types already implemented: LoopPreset, LoopConfig, LoopIteration, LoopResult, LoopCompletionMarker. index.ts barrel export also present. | ||
| - 1.2: Added types.spec.ts with compile-time type tests. LoopPreset/LoopConfig were already in types.ts from 1.1. tsc --noEmit passes. Native rollup module issue in env blocked vitest but types are correct. | ||
| - 1.3: LoopIteration and LoopResult interfaces already defined in types.ts (lines 38-63) from 1.1. Tests present in types.spec.ts (lines 69-129). tsc --noEmit passes. Marked done. | ||
| - 1.4: LoopCompletionMarker already defined in types.ts (lines 65-73) from 1.1. Tests in types.spec.ts (lines 131-149). tsc --noEmit passes. Marked done. |
There was a problem hiding this comment.
Development notes committed to loop progress file
Medium Severity
The .taskmaster/loop-progress.txt file contains implementation notes about creating types.ts and spec files, but this file is intended to track context from actual loop command executions, not development progress. According to the changeset, users need to "delete this file between loops to not pollute the agent with bad context." Shipping this file with development notes will pollute the agent context for new users when they first run the loop command.
| "modelId": "haiku", | ||
| "maxTokens": 200000, | ||
| "modelId": "opus", | ||
| "maxTokens": 32000, |
There was a problem hiding this comment.
Main model has fewer tokens than fallback model
Medium Severity
The main model configuration was changed from haiku with 200000 maxTokens to opus with only 32000 maxTokens. This results in the main model having half the token limit of the fallback model (which has 64000). This inverted relationship is unusual and the dramatic reduction from 200000 to 32000 tokens could cause response truncation. These changes appear unrelated to the loop feature being implemented and may be accidentally committed local development settings.
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
mcp-server/src/tools/tool-registry.js (1)
120-133: Critical: Loop tools missing from registration and standardTools.The test file expects
loop_startandloop_presetsto be:
- Registered in
toolRegistry(lines 19-27 of tool-registry.test.js)- Included in
standardTools(lines 29-35)- Resulting in
standardTools.lengthof 16 (line 52)However, neither tool exists in the codebase. No loop tool files are present in
mcp-server/src/tools/, andstandardToolscurrently contains only 14 tools. The tests will fail until these loop tools are created and registered.
🤖 Fix all issues with AI agents
In @.taskmaster/config.json:
- Around line 5-6: Revert the manual edits to config.json that changed "modelId"
to "opus" and reduced "maxTokens" to 32000; instead set the main model via the
supported workflow by running the models MCP/CLI (e.g., use the provided
task-master models command to set the main model) so the change is recorded
through the proper tooling, and double-check whether the "maxTokens" reduction
from 200000 to 32000 is intentional—if it is not, restore the original maxTokens
value through the same models workflow rather than editing "maxTokens" directly
in config.json.
In @apps/cli/src/commands/loop.command.ts:
- Around line 129-151: If isJson is true and checkSandboxAuth() returns false,
do not invoke runInteractiveAuth() or start an interactive flow; instead
return/throw/log a non-interactive error so CI isn't blocked. Also after calling
tmCore.loop.runInteractiveAuth() in non-JSON mode, re-run
tmCore.loop.checkSandboxAuth() and only print the "✓ Auth complete" success (or
exit/throw non-zero) if the re-check returns true; if the re-check fails, print
an error and exit/throw accordingly. Reference: handleSandboxAuth,
tmCore.loop.checkSandboxAuth, and tmCore.loop.runInteractiveAuth.
- Around line 54-127: Normalize tag and make progressFile absolute at the start
of execute: derive a local normalizedTag = options.tag || 'master' right after
computing projectRoot and use normalizedTag everywhere (displayCommandHeader
call, config.tag, and tasks.getNext/getCount calls) instead of options.tag; for
progressFile resolve it against projectRoot (e.g., path.resolve(projectRoot,
options.progressFile || '.taskmaster/progress.txt')) and use that resolved value
when building config passed to this.tmCore.loop.run; ensure no other call still
references options.tag or the un-resolved progressFile.
In @packages/tm-core/src/modules/tasks/tasks-domain.ts:
- Around line 171-185: The parent task counting logic is inconsistent with
subtasks: change the task check in the loop over result.tasks to treat a missing
task.status as 'pending' the same way subtasks do; update the condition that
currently uses "task.status === status" to use "task.status === status ||
(status === 'pending' && !task.status)" so both tasks and task.subtasks are
counted the same way when status is absent, keeping the rest of the
count/subtask logic unchanged.
In @scripts/loop.sh:
- Around line 5-8: The script currently only checks for an empty $1 but doesn't
validate it as a positive integer; update the early validation to ensure $1 is a
numeric, positive integer (reject zero, negatives, and non-digits) before
proceeding, and if validation fails print the usage message and exit non-zero;
implement this by adding a numeric check (e.g. a regex test against $1 or using
POSIX-safe digit checks) around the existing echo/exit block so the loop code
that uses $1 only runs when $1 is a valid positive integer.
In @tests/unit/mcp-server/tools/tool-registry.test.js:
- Around line 17-44: Tests fail because the loop tools are missing: implement
modules that register loop_start and loop_presets so toolRegistry and
standardTools include them (or remove the tests if intentional). Add two modules
that export registration functions which add entries named "loop_start" and
"loop_presets" to toolRegistry (matching the expected keys) and ensure those
names are pushed into the standardTools array so its length reflects the added
tools (making standardTools.length match the test expectation of 16).
🧹 Nitpick comments (14)
packages/tm-core/src/tm-core.ts (1)
222-226: Consider cleanup for LoopDomain in close() method.The
close()method handles cleanup forTasksDomainbut doesn't stop a potentially running loop. If a loop is in progress whenclose()is called, it may continue running.♻️ Suggested enhancement
async close(): Promise<void> { + if (this._loop) { + this._loop.stop(); + } if (this._tasks) { await this._tasks.close(); } }packages/tm-core/tests/integration/loop/loop-tmcore-access.test.ts (1)
85-156: Consider testing the run() method integration.The current tests cover static methods (isPreset, resolvePrompt, getAvailablePresets) and lifecycle queries (getIsRunning, stop), but don't exercise the main
run()method. While this might be intentional due to the complexity of spawning Claude Code processes, consider adding at least one test that verifies the run() method accepts valid configuration.Optional: Add run() method integration test
+ describe('Run Method Integration', () => { + it('should accept valid loop configuration', async () => { + tmCore = await createTmCore({ projectPath: testProjectDir }); + + // Verify run() method exists and accepts config + // Note: Not actually running the loop to avoid spawning processes in CI + expect(typeof tmCore.loop.run).toBe('function'); + }); + });Note: A full integration test that actually spawns processes would be valuable but may require additional CI infrastructure.
packages/tm-core/src/modules/loop/services/loop.service.spec.ts (1)
45-48: Minor: Redundant mock restoration.
consoleSpy.mockRestore()on line 47 is redundant sincevi.restoreAllMocks()on line 46 already restores all spies includingconsoleSpy.Suggested cleanup
afterEach(() => { vi.restoreAllMocks(); - consoleSpy.mockRestore(); });packages/tm-core/tests/integration/loop/loop-domain.test.ts (1)
165-170: Regex pattern may not match empty marker content.The regex
/<loop-complete>([^<]+)<\/loop-complete>/requires at least one character inside the tags due to+quantifier. If any preset has an empty marker like<loop-complete></loop-complete>, this test would fail even though the marker exists.Consider using
*instead of+if empty content should be valid:More permissive pattern
- const match = content.match(/<loop-complete>([^<]+)<\/loop-complete>/); + const match = content.match(/<loop-complete>([^<]*)<\/loop-complete>/); expect(match).toBeTruthy(); - expect(match![1].length).toBeGreaterThan(0); + // Content inside marker exists (may be empty for some presets) + expect(match).not.toBeNull();apps/cli/src/commands/loop.command.spec.ts (1)
328-332: Empty catch block could mask unexpected errors.The empty catch block catches all errors including unexpected ones. Consider asserting the specific error or using a more targeted approach.
More explicit error handling in test
try { await execute({}); } catch { - // Expected + // Expected - processExitSpy throws }Alternatively, you could use
expect(...).rejects.toThrow()pattern if the execute function propagates the error.packages/tm-core/src/modules/loop/services/loop.service.ts (2)
24-31: Duplicate PRESETS mapping violates DRY principle.This
PRESETSconstant duplicates the same mapping already defined and exported frompresets/index.ts. The service imports individual preset constants but creates its own mapping instead of importing the existingPRESETSexport.Import PRESETS from presets/index.ts
-import { DEFAULT_PRESET } from '../presets/default.js'; -import { DUPLICATION_PRESET } from '../presets/duplication.js'; -import { ENTROPY_PRESET } from '../presets/entropy.js'; -import { LINTING_PRESET } from '../presets/linting.js'; -import { TEST_COVERAGE_PRESET } from '../presets/test-coverage.js'; +import { PRESETS } from '../presets/index.js'; import type { LoopConfig, LoopIteration, LoopPreset, LoopResult } from '../types.js'; export interface LoopServiceOptions { projectRoot: string; } -/** Preset name to content mapping */ -const PRESETS: Record<LoopPreset, string> = { - default: DEFAULT_PRESET, - 'test-coverage': TEST_COVERAGE_PRESET, - linting: LINTING_PRESET, - duplication: DUPLICATION_PRESET, - entropy: ENTROPY_PRESET -};
91-93: Direct console.log usage violates coding guidelines.Per coding guidelines: "Do not add direct console.log calls outside the logging utility - use the central log function instead."
Consider using the project's logging utility for iteration headers and output display.
packages/tm-core/src/modules/loop/loop-domain.spec.ts (2)
144-153: Assertion on preset order may be fragile.The test asserts the exact order of presets returned by
getAvailablePresets(). IfObject.keys()order changes (though unlikely for string keys) or presets are reordered, this test would fail. Consider usingtoContainortoEqual(expect.arrayContaining([...]))for order-independent validation if order is not a contract.Order-independent assertion alternative
it('should return array of all preset names', () => { const presets = loopDomain.getAvailablePresets(); - expect(presets).toEqual([ - 'default', - 'test-coverage', - 'linting', - 'duplication', - 'entropy' - ]); + expect(presets).toHaveLength(5); + expect(presets).toEqual( + expect.arrayContaining([ + 'default', + 'test-coverage', + 'linting', + 'duplication', + 'entropy' + ]) + ); });However, if the order is intentional and part of the API contract, the current assertion is appropriate.
161-165: Content assertion may be fragile.The assertion
expect(content).toContain('task-master')depends on the specific text in the default preset. If the preset content is refactored, this test could break even though the functionality is correct.Consider asserting on structural properties (like presence of completion markers) rather than specific text content, which is already tested in line 164.
packages/tm-core/src/modules/loop/loop-domain.ts (2)
59-64: Silent catch block may hide unexpected errors.The empty catch block swallows all errors from
stop(), which could mask unexpected issues. Consider logging the error or being more specific about what errors are expected.Add minimal error logging
if (this.loopService?.isRunning) { try { this.loopService.stop(); - } catch { + } catch (e) { // Ignore stop errors, proceed with new service + // Note: stop() is designed to be safe, errors here are unexpected } }
183-184: Consider using path.join for cross-platform compatibility.The progress file path is constructed using string template with forward slash, which may cause issues on Windows. Consider using
path.join()for cross-platform path construction per coding guidelines.Use path.join for path construction
Add import at top:
import path from 'path';Then update buildConfig:
progressFile: - partial.progressFile ?? `${this.projectRoot}/.taskmaster/progress.txt`, + partial.progressFile ?? path.join(this.projectRoot, '.taskmaster', 'progress.txt'),apps/cli/src/commands/loop.command.ts (3)
30-52: Avoid baking preset names into CLI help text; prefer sourcing from tm-core (or a shared constant).
Hardcoding the preset list in the option description will drift as presets change. Consider importing a preset list/enum from@tm/core(if exposed) or a shared constant.
153-160: Make iteration validation strict (avoidparseIntaccepting “1.5” as 1).
If you want “positive integer”, validate withNumber()+Number.isInteger.Proposed patch
@@ private validateIterations(iterations: string): void { - const parsed = parseInt(iterations, 10); - if (isNaN(parsed) || parsed < 1) { + const parsed = Number(iterations); + if (!Number.isInteger(parsed) || parsed < 1) { throw new Error( `Invalid iterations: ${iterations}. Must be a positive integer.` ); } }
162-179: TightenstatusMaptyping to the known union.
Minor TS ergonomics: useRecord<LoopResult['finalStatus'], string>so missing statuses become compile-time errors.
| private async execute(options: LoopCommandOptions): Promise<void> { | ||
| const prompt = options.prompt || 'default'; | ||
| const progressFile = options.progressFile || '.taskmaster/progress.txt'; | ||
|
|
||
| try { | ||
| const projectRoot = path.resolve(getProjectRoot(options.project)); | ||
| this.tmCore = await createTmCore({ projectPath: projectRoot }); | ||
|
|
||
| // Get pending task count for default preset iteration resolution | ||
| const pendingTaskCount = | ||
| prompt === 'default' | ||
| ? await this.tmCore.tasks.getCount('pending', options.tag) | ||
| : undefined; | ||
|
|
||
| // Delegate iteration resolution logic to tm-core | ||
| const iterations = this.tmCore.loop.resolveIterations({ | ||
| userIterations: options.iterations | ||
| ? parseInt(options.iterations, 10) | ||
| : undefined, | ||
| preset: prompt, | ||
| pendingTaskCount | ||
| }); | ||
|
|
||
| this.validateIterations(String(iterations)); | ||
|
|
||
| if (!options.json) { | ||
| displayCommandHeader(this.tmCore, { | ||
| tag: options.tag || 'master', | ||
| storageType: this.tmCore.tasks.getStorageType() | ||
| }); | ||
| } | ||
|
|
||
| this.handleSandboxAuth(options.json); | ||
|
|
||
| if (!options.json) { | ||
| console.log(chalk.cyan('Starting Task Master Loop...')); | ||
| console.log(chalk.dim(`Preset: ${prompt}`)); | ||
| console.log(chalk.dim(`Max iterations: ${iterations}`)); | ||
|
|
||
| // Show next task only for default preset (other presets don't use Task Master tasks) | ||
| if (prompt === 'default') { | ||
| const nextTask = await this.tmCore.tasks.getNext(options.tag); | ||
| if (nextTask) { | ||
| console.log( | ||
| chalk.white( | ||
| `Next task to work on: ${chalk.white(nextTask.id)} - ${nextTask.title}` | ||
| ) | ||
| ); | ||
| } else { | ||
| console.log(chalk.yellow('No pending tasks found')); | ||
| } | ||
| } | ||
| console.log(); | ||
| } | ||
|
|
||
| const config: Partial<LoopConfig> = { | ||
| iterations, | ||
| prompt, | ||
| progressFile, | ||
| tag: options.tag | ||
| }; | ||
|
|
||
| const result = await this.tmCore.loop.run(config); | ||
|
|
||
| if (options.json) { | ||
| console.log(JSON.stringify(result, null, 2)); | ||
| } else { | ||
| this.displayResult(result); | ||
| } | ||
| } catch (error: unknown) { | ||
| displayError(error, { skipExit: true }); | ||
| process.exit(1); | ||
| } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check console.log vs display utility patterns in CLI commands
echo "=== Console.log usage in CLI commands ==="
rg -n --type=ts "console\.log\(" apps/cli/src/commands -C2
echo ""
echo "=== Display/logging utility imports in CLI commands ==="
rg -n --type=ts "from|import.*display|import.*log" apps/cli/src/commands/*.ts | head -40Repository: eyaltoledano/claude-task-master
Length of output: 50387
🏁 Script executed:
#!/bin/bash
# Check tm-core loop module for API signatures
echo "=== Loop module API signatures ==="
find packages/tm-core/src/modules/loop -type f -name "*.ts" 2>/dev/null | head -10
echo ""
echo "=== LoopConfig interface ==="
rg -n "export interface LoopConfig|export type LoopConfig" packages/tm-core/src -A10
echo ""
echo "=== Loop.run signature ==="
rg -n "run\s*\(|async run" packages/tm-core/src/modules/loop -B2 -A5Repository: eyaltoledano/claude-task-master
Length of output: 14156
🏁 Script executed:
#!/bin/bash
# Check resolveIterations and related methods
echo "=== resolveIterations method ==="
rg -n "resolveIterations" packages/tm-core/src -B2 -A8
echo ""
echo "=== Check getNext method signature ==="
rg -n "getNext\s*\(|async getNext" packages/tm-core/src -B2 -A5Repository: eyaltoledano/claude-task-master
Length of output: 9386
🏁 Script executed:
#!/bin/bash
# Check progressFile usage in loop service
echo "=== progressFile usage in loop service ==="
rg -n "progressFile" packages/tm-core/src/modules/loop/services/loop.service.ts -B2 -A3
echo ""
echo "=== Path handling for progressFile ==="
rg -n "initProgressFile|progressFile.*path|resolve.*progress" packages/tm-core/src/modules/loop -B2 -A5Repository: eyaltoledano/claude-task-master
Length of output: 3554
🏁 Script executed:
#!/bin/bash
# Check error handling pattern in other CLI commands
echo "=== process.exit vs process.exitCode in CLI commands ==="
rg -n "process\.exit|process\.exitCode" apps/cli/src/commands -B2 -A1 | head -60Repository: eyaltoledano/claude-task-master
Length of output: 3442
🏁 Script executed:
#!/bin/bash
# Check how displayCommandHeader defaults tag
echo "=== displayCommandHeader usage and tag handling ==="
rg -n "displayCommandHeader" apps/cli/src -B2 -A2Repository: eyaltoledano/claude-task-master
Length of output: 7393
Normalize tag at function entry, and resolve progressFile to absolute path.
options.tagis optional but used inconsistently:displayCommandHeaderreceivesoptions.tag || 'master', while later calls passoptions.tagdirectly. Normalize early to avoid tag mismatch in config and headers.progressFileis passed as-is to tm-core; if relative, it resolves against CWD rather thanprojectRoot. Resolve to absolute path before passing to ensure consistent behavior.
Proposed patch
private async execute(options: LoopCommandOptions): Promise<void> {
- const prompt = options.prompt || 'default';
- const progressFile = options.progressFile || '.taskmaster/progress.txt';
+ const prompt = options.prompt ?? 'default';
+ const tag = options.tag ?? 'master';
try {
const projectRoot = path.resolve(getProjectRoot(options.project));
this.tmCore = await createTmCore({ projectPath: projectRoot });
+ const progressFileInput =
+ options.progressFile ?? '.taskmaster/progress.txt';
+ const progressFile = path.isAbsolute(progressFileInput)
+ ? progressFileInput
+ : path.resolve(projectRoot, progressFileInput);
+
// Get pending task count for default preset iteration resolution
const pendingTaskCount =
prompt === 'default'
- ? await this.tmCore.tasks.getCount('pending', options.tag)
+ ? await this.tmCore.tasks.getCount('pending', tag)
: undefined;
@@ -77,7 +87,7 @@
if (!options.json) {
displayCommandHeader(this.tmCore, {
- tag: options.tag || 'master',
+ tag,
storageType: this.tmCore.tasks.getStorageType()
});
}
@@ -90,7 +100,7 @@
// Show next task only for default preset (other presets don't use Task Master tasks)
if (prompt === 'default') {
- const nextTask = await this.tmCore.tasks.getNext(options.tag);
+ const nextTask = await this.tmCore.tasks.getNext(tag);
if (nextTask) {
@@ -108,7 +118,7 @@
const config: Partial<LoopConfig> = {
iterations,
prompt,
progressFile,
- tag: options.tag
+ tag
};🤖 Prompt for AI Agents
In @apps/cli/src/commands/loop.command.ts around lines 54 - 127, Normalize tag
and make progressFile absolute at the start of execute: derive a local
normalizedTag = options.tag || 'master' right after computing projectRoot and
use normalizedTag everywhere (displayCommandHeader call, config.tag, and
tasks.getNext/getCount calls) instead of options.tag; for progressFile resolve
it against projectRoot (e.g., path.resolve(projectRoot, options.progressFile ||
'.taskmaster/progress.txt')) and use that resolved value when building config
passed to this.tmCore.loop.run; ensure no other call still references
options.tag or the un-resolved progressFile.
| for (const task of result.tasks) { | ||
| // Count the task if it matches the status | ||
| if (task.status === status) { | ||
| count++; | ||
| } | ||
|
|
||
| // Count subtasks with matching status | ||
| if (task.subtasks && task.subtasks.length > 0) { | ||
| for (const subtask of task.subtasks) { | ||
| // For pending, also count subtasks without status (default to pending) | ||
| if (subtask.status === status || (status === 'pending' && !subtask.status)) { | ||
| count++; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Inconsistent handling of missing status between tasks and subtasks.
Line 173 counts parent tasks only when task.status === status, but line 181 treats subtasks without a status as 'pending' when status === 'pending'. This inconsistency means parent tasks without an explicit status field won't be counted as 'pending', while subtasks without status will be.
Based on the codebase pattern shown in scripts/modules/task-manager/list-tasks.js (lines 1018, 1047), both tasks and subtasks should default to 'pending' when status is missing.
🔧 Proposed fix to handle missing status consistently
let count = 0;
for (const task of result.tasks) {
- // Count the task if it matches the status
- if (task.status === status) {
+ // Count the task if it matches the status (default to 'pending' if missing)
+ const taskStatus = task.status || 'pending';
+ if (taskStatus === status) {
count++;
}
// Count subtasks with matching status
if (task.subtasks && task.subtasks.length > 0) {
for (const subtask of task.subtasks) {
- // For pending, also count subtasks without status (default to pending)
- if (subtask.status === status || (status === 'pending' && !subtask.status)) {
+ // Default to 'pending' if status is missing
+ const subtaskStatus = subtask.status || 'pending';
+ if (subtaskStatus === status) {
count++;
}
}
}
}🤖 Prompt for AI Agents
In @packages/tm-core/src/modules/tasks/tasks-domain.ts around lines 171 - 185,
The parent task counting logic is inconsistent with subtasks: change the task
check in the loop over result.tasks to treat a missing task.status as 'pending'
the same way subtasks do; update the condition that currently uses "task.status
=== status" to use "task.status === status || (status === 'pending' &&
!task.status)" so both tasks and task.subtasks are counted the same way when
status is absent, keeping the rest of the count/subtask logic unchanged.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @packages/tm-core/src/modules/loop/loop-domain.ts:
- Line 64: Replace the direct console.warn call in loop-domain.ts (the line that
currently reads console.warn('Failed to stop previous loop service:', error))
with the project's central logging utility (e.g., call logger.warn or log.warn)
and pass the error as structured context; import or reference the existing
central logger used across the codebase (the same logger used elsewhere) so the
message becomes something like logger.warn('Failed to stop previous loop
service', { error }) and remove the console import/usage.
In @packages/tm-core/src/modules/loop/services/loop.service.ts:
- Line 238: Replace the direct console.log call (if (output)
console.log(output);) with the central logging utility: use the project logger
(e.g., logger.info(output) or this.logger.debug(output) depending on context)
and ensure the appropriate logger is imported or injected into the LoopService
class; remove console.log and prefer an info/debug level so the message flows
through the central logging pipeline.
🧹 Nitpick comments (3)
apps/cli/src/commands/loop.command.spec.ts (1)
50-50: Consider stricter typing for mockTmCore.Using
anytype reduces type safety. Consider defining a mock type or interface that matches the expected structure:type MockTmCore = { loop: { run: Mock; checkSandboxAuth: Mock; runInteractiveAuth: Mock; resolveIterations: Mock; }; tasks: { getStorageType: Mock; getNext: Mock; getCount: Mock; }; };packages/tm-core/src/modules/loop/services/loop.service.ts (1)
5-7: Avoid node: prefix for core module imports.Based on learnings, prefer bare imports for Node.js core modules instead of using the
node:scheme.♻️ Suggested refactor
-import { spawnSync } from 'node:child_process'; -import { appendFile, mkdir, readFile, writeFile } from 'node:fs/promises'; -import path from 'node:path'; +import { spawnSync } from 'child_process'; +import { appendFile, mkdir, readFile, writeFile } from 'fs/promises'; +import path from 'path';packages/tm-core/src/modules/loop/loop-domain.ts (1)
6-6: Avoid node: prefix for core module imports.Based on learnings, prefer bare imports for Node.js core modules instead of using the
node:scheme.♻️ Suggested refactor
-import path from 'node:path'; +import path from 'path';
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
packages/tm-core/src/modules/loop/presets/__snapshots__/presets.spec.ts.snapis excluded by!**/*.snap
📒 Files selected for processing (9)
apps/cli/src/commands/loop.command.spec.tsapps/cli/src/commands/loop.command.tspackages/tm-core/src/index.tspackages/tm-core/src/modules/loop/loop-domain.spec.tspackages/tm-core/src/modules/loop/loop-domain.tspackages/tm-core/src/modules/loop/presets/default.tspackages/tm-core/src/modules/loop/services/loop.service.spec.tspackages/tm-core/src/modules/loop/services/loop.service.tstests/unit/mcp-server/tools/tool-registry.test.js
🚧 Files skipped from review as they are similar to previous changes (3)
- tests/unit/mcp-server/tools/tool-registry.test.js
- packages/tm-core/src/modules/loop/presets/default.ts
- apps/cli/src/commands/loop.command.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)
TypeScript test files must achieve minimum code coverage thresholds: 80% lines/functions and 70% branches globally, 90% for utilities, and 85% for middleware; new features must meet or exceed these thresholds
Files:
packages/tm-core/src/modules/loop/services/loop.service.tspackages/tm-core/src/modules/loop/loop-domain.tsapps/cli/src/commands/loop.command.spec.tspackages/tm-core/src/index.tspackages/tm-core/src/modules/loop/loop-domain.spec.tspackages/tm-core/src/modules/loop/services/loop.service.spec.ts
**/*.{js,ts}
📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)
**/*.{js,ts}: Import and use specific getters from config-manager.js (e.g., getMainProvider(), getLogLevel(), getMainMaxTokens()) to access configuration values needed for application logic
Use isApiKeySet(providerName, session) from config-manager.js to check if a provider's key is available before potentially attempting an AI call
Do not add direct console.log calls outside the logging utility - use the central log function instead
Ensure silent mode is disabled in a finally block to prevent it from staying enabled
Do not access the global silentMode variable directly - use the exported silent mode control functions instead
Do not duplicate task ID formatting logic across modules - centralize formatting utilities
Use ContextGatherer class from utils/contextGatherer.js for AI-powered commands that need project context, supporting tasks, files, custom text, and project tree context
Use FuzzyTaskSearch class from utils/fuzzyTaskSearch.js for automatic task relevance detection with configurable search parameters
Use fuzzy search to supplement user-provided task IDs and display discovered task IDs to users for transparency
Do not replace explicit user task selections with fuzzy results - fuzzy search should supplement, not replace user selections
Use readJSON and writeJSON utilities for all JSON file operations instead of raw fs.readFileSync or fs.writeFileSync
Include error handling for JSON file operations and validate JSON structure after reading
Use path.join() for cross-platform path construction and path.resolve() for absolute paths, validating paths before file operations
Support both .env files and MCP session environment for environment variable resolution with fallbacks for missing values
Prefer updating the core function to accept an outputFormat parameter and check outputFormat === 'json' before displaying UI elements
Files:
packages/tm-core/src/modules/loop/services/loop.service.tspackages/tm-core/src/modules/loop/loop-domain.tsapps/cli/src/commands/loop.command.spec.tspackages/tm-core/src/index.tspackages/tm-core/src/modules/loop/loop-domain.spec.tspackages/tm-core/src/modules/loop/services/loop.service.spec.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Import modules with
.jsextension even in TypeScript source files for ESM compatibility
Files:
packages/tm-core/src/modules/loop/services/loop.service.tspackages/tm-core/src/modules/loop/loop-domain.tsapps/cli/src/commands/loop.command.spec.tspackages/tm-core/src/index.tspackages/tm-core/src/modules/loop/loop-domain.spec.tspackages/tm-core/src/modules/loop/services/loop.service.spec.ts
**/*.spec.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Place package and app test files in
packages/<package-name>/src/<module>/<file>.spec.tsorapps/<app-name>/src/<module>/<file>.spec.tsalongside source files
Files:
apps/cli/src/commands/loop.command.spec.tspackages/tm-core/src/modules/loop/loop-domain.spec.tspackages/tm-core/src/modules/loop/services/loop.service.spec.ts
**/*.{spec,test}.ts
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{spec,test}.ts: Always use.tsfor TypeScript tests, never.js
NEVER use async/await in test functions unless testing actual asynchronous operations; use synchronous top-level imports instead of dynamicawait import()
Files:
apps/cli/src/commands/loop.command.spec.tspackages/tm-core/src/modules/loop/loop-domain.spec.tspackages/tm-core/src/modules/loop/services/loop.service.spec.ts
apps/cli/**/*.{spec,test}.ts
📄 CodeRabbit inference engine (CLAUDE.md)
In unit tests for apps/cli, mock tm-core responses but use real Commander/chalk/inquirer/other npm packages to test display logic
Files:
apps/cli/src/commands/loop.command.spec.ts
apps/cli/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
CLI (@tm/cli) should be a thin presentation layer that calls tm-core methods and displays results; handle only CLI-specific concerns like argument parsing, output formatting, and user prompts
Files:
apps/cli/src/commands/loop.command.spec.ts
packages/tm-core/**/*.{spec,test}.ts
📄 CodeRabbit inference engine (CLAUDE.md)
In unit tests for @tm/core, mock only external I/O (Supabase, APIs, filesystem) and use real internal services
Files:
packages/tm-core/src/modules/loop/loop-domain.spec.tspackages/tm-core/src/modules/loop/services/loop.service.spec.ts
🧠 Learnings (25)
📓 Common learnings
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: assets/AGENTS.md:0-0
Timestamp: 2025-12-11T14:45:14.973Z
Learning: Applies to assets/**/CLAUDE.md : Update `CLAUDE.md` file with project-specific context, task summaries, and custom command examples for Claude Code integration
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1178
File: packages/tm-core/src/auth/config.ts:5-7
Timestamp: 2025-09-02T21:51:27.921Z
Learning: The user Crunchyman-ralph prefers not to use node: scheme imports (e.g., 'node:os', 'node:path') for Node.js core modules and considers suggestions to change bare imports to node: scheme as too nitpicky.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1069
File: .changeset/fix-tag-complexity-detection.md:0-0
Timestamp: 2025-08-02T15:33:22.656Z
Learning: For changeset files (.changeset/*.md), Crunchyman-ralph prefers to ignore formatting nitpicks about blank lines between frontmatter and descriptions, as he doesn't mind having them and wants to avoid such comments in future reviews.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1132
File: .github/workflows/weekly-metrics-discord.yml:81-93
Timestamp: 2025-08-13T22:10:46.958Z
Learning: Crunchyman-ralph ignores YAML formatting nitpicks about trailing spaces when there's no project-specific YAML formatter configured, preferring to focus on functionality over cosmetic formatting issues.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1132
File: .github/workflows/weekly-metrics-discord.yml:81-93
Timestamp: 2025-08-13T22:10:46.958Z
Learning: Crunchyman-ralph ignores YAML formatting nitpicks about trailing spaces when there's no project-specific YAML formatter configured, preferring to focus on functionality over cosmetic formatting issues.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1200
File: src/ai-providers/custom-sdk/grok-cli/language-model.js:96-100
Timestamp: 2025-09-19T16:06:42.182Z
Learning: The user Crunchyman-ralph prefers to keep environment variable names explicit (like GROK_CLI_API_KEY) rather than supporting multiple aliases, to avoid overlap and ensure clear separation between different CLI implementations.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1178
File: packages/tm-core/src/subpath-exports.test.ts:6-9
Timestamp: 2025-09-03T12:45:30.724Z
Learning: The user Crunchyman-ralph prefers to avoid overly nitpicky or detailed suggestions in code reviews, especially for test coverage of minor import paths. Focus on more substantial issues rather than comprehensive coverage of all possible edge cases.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1105
File: scripts/modules/supported-models.json:242-254
Timestamp: 2025-08-08T11:33:15.297Z
Learning: Preference: In scripts/modules/supported-models.json, the "name" field is optional. For OpenAI entries (e.g., "gpt-5"), Crunchyman-ralph prefers omitting "name" when the id is explicit enough; avoid nitpicks requesting a "name" in such cases.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1217
File: apps/cli/src/index.ts:16-21
Timestamp: 2025-09-18T16:35:35.147Z
Learning: The user Crunchyman-ralph considers suggestions to export types for better ergonomics (like exporting UpdateInfo type alongside related functions) as nitpicky and prefers not to implement such suggestions.
📚 Learning: 2025-11-24T22:09:45.455Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T22:09:45.455Z
Learning: Applies to apps/cli/**/*.{spec,test}.ts : In unit tests for apps/cli, mock tm-core responses but use real Commander/chalk/inquirer/other npm packages to test display logic
Applied to files:
apps/cli/src/commands/loop.command.spec.tspackages/tm-core/src/modules/loop/loop-domain.spec.tspackages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to **/*.test.js : When testing CLI commands built with Commander.js: test command action handlers directly rather than mocking the entire Commander chain; create simplified test-specific implementations of command handlers; explicitly handle all options including defaults and shorthand flags; include null/undefined checks for optional parameters; use fixtures for consistent sample data.
Applied to files:
apps/cli/src/commands/loop.command.spec.ts
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to **/*.test.{js,ts} : Test new features with both legacy and tagged task data formats; verify tag resolution behavior; test migration compatibility; ensure pre-migration projects are handled correctly
Applied to files:
apps/cli/src/commands/loop.command.spec.tspackages/tm-core/src/modules/loop/loop-domain.spec.tspackages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T22:09:45.455Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T22:09:45.455Z
Learning: Applies to packages/tm-core/**/*.{spec,test}.ts : In unit tests for tm/core, mock only external I/O (Supabase, APIs, filesystem) and use real internal services
Applied to files:
apps/cli/src/commands/loop.command.spec.tspackages/tm-core/src/modules/loop/loop-domain.spec.tspackages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Applies to **/*.test.ts : Unit tests must follow the describe/it pattern, use beforeEach for mock setup with jest.clearAllMocks(), include specific assertions with expect(), and test both success and error scenarios including edge cases
Applied to files:
apps/cli/src/commands/loop.command.spec.tspackages/tm-core/src/modules/loop/loop-domain.spec.tspackages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T22:09:45.455Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T22:09:45.455Z
Learning: Applies to **/tests/integration/**/*.{spec,test}.ts : In integration tests, use real tm-core and mock only external boundaries (APIs, DB, filesystem)
Applied to files:
apps/cli/src/commands/loop.command.spec.tspackages/tm-core/src/modules/loop/loop-domain.spec.tspackages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Applies to package.json : package.json scripts must include: 'test', 'test:watch', 'test:coverage', 'test:unit', 'test:integration', 'test:e2e', and 'test:ci' commands for testing framework integration
Applied to files:
apps/cli/src/commands/loop.command.spec.ts
📚 Learning: 2025-11-24T22:09:45.455Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T22:09:45.455Z
Learning: Applies to apps/mcp/**/*.{spec,test}.ts : In unit tests for apps/mcp, mock tm-core responses but use real MCP framework to test response formatting
Applied to files:
apps/cli/src/commands/loop.command.spec.tspackages/tm-core/src/modules/loop/loop-domain.spec.ts
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to tests/e2e/**/*.test.js : Locate end-to-end tests in `tests/e2e/` directory. Test complete workflows from a user perspective, focus on CLI commands as users would use them.
Applied to files:
apps/cli/src/commands/loop.command.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Applies to tests/e2e/**/*.test.ts : End-to-end tests must test complete user workflows across multiple API endpoints in sequence, verify state changes between workflow steps, use extended timeouts (30000ms), and validate final outcomes without mocking business logic
Applied to files:
apps/cli/src/commands/loop.command.spec.tspackages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to **/*.test.js : When testing UI functions: mock console output and verify correct formatting; test conditional output logic; use `toContain()` or `toMatch()` rather than exact `toBe()` for strings with emojis or formatting; create separate tests for different behavior modes; test structure of formatted output rather than exact string matching.
Applied to files:
apps/cli/src/commands/loop.command.spec.ts
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to **/*.test.js : For task file operations in tests: use test-specific file paths (e.g., 'test-tasks.json'); mock `readJSON` and `writeJSON` to avoid real file system interactions; verify file operations use correct paths; use different paths for each test; verify modifications on in-memory task objects passed to `writeJSON`.
Applied to files:
apps/cli/src/commands/loop.command.spec.ts
📚 Learning: 2025-09-26T19:05:47.555Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1252
File: packages/ai-sdk-provider-grok-cli/package.json:11-13
Timestamp: 2025-09-26T19:05:47.555Z
Learning: In the eyaltoledano/claude-task-master repository, internal tm/ packages use a specific export pattern where the "exports" field points to TypeScript source files (./src/index.ts) while "main" points to compiled output (./dist/index.js) and "types" points to source files (./src/index.ts). This pattern is used consistently across internal packages like tm/core and tm/ai-sdk-provider-grok-cli because they are consumed directly during build-time bundling with tsdown rather than being published as separate packages.
Applied to files:
packages/tm-core/src/index.ts
📚 Learning: 2025-10-08T19:57:00.982Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1282
File: packages/tm-core/src/utils/index.ts:16-34
Timestamp: 2025-10-08T19:57:00.982Z
Learning: For the tm-core package in the eyaltoledano/claude-task-master repository, the team prefers a minimal, need-based export strategy in index files rather than exposing all internal utilities. Exports should only be added when functions are actually consumed by other packages in the monorepo.
Applied to files:
packages/tm-core/src/index.ts
📚 Learning: 2025-11-24T18:04:43.972Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-24T18:04:43.972Z
Learning: Applies to **/{utils,utilities}/**/*.{js,ts} : Export all utility functions explicitly in logical groups and include configuration constants from utility modules
Applied to files:
packages/tm-core/src/index.ts
📚 Learning: 2025-11-24T22:09:45.455Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T22:09:45.455Z
Learning: Applies to **/tests/unit/packages/**/*.test.ts : Use isolated unit tests in `tests/unit/packages/<package-name>/` only when parallel placement isn't possible
Applied to files:
packages/tm-core/src/modules/loop/loop-domain.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Applies to tests/setup.ts : Create global test setup file that configures jest.setTimeout(10000), clears all mocks after each test with jest.clearAllMocks(), and initializes global test configuration
Applied to files:
packages/tm-core/src/modules/loop/loop-domain.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Applies to jest.config.js : Jest configuration must use ts-jest preset for TypeScript support, configure test environment as 'node', set roots to ['<rootDir>/src', '<rootDir>/tests'], and include testMatch patterns for both *.test.ts and *.spec.ts files with separate projects for unit, integration, and e2e tests
Applied to files:
packages/tm-core/src/modules/loop/loop-domain.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Applies to tests/fixtures/**/*.ts : Test fixture files must export reusable test data creators and constants (createTestUser, adminUser, invalidUser, etc.) for use across unit, integration, and e2e tests to ensure consistency
Applied to files:
packages/tm-core/src/modules/loop/loop-domain.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Test files must be organized with unit tests separate from integration and e2e tests using project configuration in jest.config.js to maintain clear test separation and different timeout/environment settings
Applied to files:
packages/tm-core/src/modules/loop/loop-domain.spec.tspackages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to **/*.test.js : Do not import or instantiate real AI service clients. Create fully mocked versions that return predictable responses. Mock the entire module with controlled behavior.
Applied to files:
packages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to **/*.test.js : Make async operations synchronous in tests. Mock async functions to return synchronous values when possible. Don't use real async/await or Promise resolution that might fail unpredictably.
Applied to files:
packages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Applies to **/*.integration.test.ts : Integration tests must use supertest for API endpoint testing, verify database state changes after operations, clean test data before each test, and include full request/response validation with expected HTTP status codes
Applied to files:
packages/tm-core/src/modules/loop/services/loop.service.spec.ts
📚 Learning: 2025-11-24T18:03:13.456Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/test_workflow.mdc:0-0
Timestamp: 2025-11-24T18:03:13.456Z
Learning: Applies to tests/teardown.ts : Global teardown file must be created to handle cleanup after all tests complete and prevent worker process leaks
Applied to files:
packages/tm-core/src/modules/loop/services/loop.service.spec.ts
🧬 Code graph analysis (5)
packages/tm-core/src/modules/loop/services/loop.service.ts (3)
packages/tm-core/src/index.ts (4)
LoopConfig(153-153)LoopResult(155-155)LoopIteration(154-154)LoopPreset(152-152)packages/tm-core/src/modules/loop/types.ts (4)
LoopConfig(18-29)LoopResult(50-59)LoopIteration(34-45)LoopPreset(8-13)packages/tm-core/src/modules/loop/presets/index.ts (1)
PRESETS(16-22)
packages/tm-core/src/modules/loop/loop-domain.ts (3)
packages/tm-core/src/modules/loop/services/loop.service.ts (1)
LoopService(20-251)packages/tm-core/src/modules/loop/types.ts (3)
LoopConfig(18-29)LoopResult(50-59)LoopPreset(8-13)packages/tm-core/src/modules/loop/presets/index.ts (2)
getPreset(34-36)PRESET_NAMES(27-27)
apps/cli/src/commands/loop.command.spec.ts (2)
apps/cli/src/commands/loop.command.ts (5)
LoopCommand(27-172)validateIterations(139-146)formatStatus(157-165)displayResult(148-155)execute(53-117)packages/tm-core/src/modules/loop/types.ts (1)
LoopResult(50-59)
packages/tm-core/src/modules/loop/loop-domain.spec.ts (2)
packages/tm-core/src/modules/loop/loop-domain.ts (1)
LoopDomain(20-192)packages/tm-core/src/modules/loop/types.ts (1)
LoopConfig(18-29)
packages/tm-core/src/modules/loop/services/loop.service.spec.ts (1)
packages/tm-core/src/modules/loop/services/loop.service.ts (5)
LoopServiceOptions(16-18)LoopService(20-251)parseCompletion(199-216)isPreset(169-171)buildContextHeader(184-189)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Test
- GitHub Check: Cursor Bugbot
- GitHub Check: Mintlify Validation (taskmaster-49ce32d5) - vale-spellcheck
🔇 Additional comments (9)
apps/cli/src/commands/loop.command.spec.ts (6)
1-46: LGTM! Mock structure aligns with coding guidelines.The mock setup correctly mocks
@tm/coreand utility functions while allowing real Commander usage, which aligns with the coding guideline to "mock tm-core responses but use real Commander/chalk/inquirer/other npm packages to test display logic."
106-131: LGTM! Comprehensive registration testing.The tests properly verify command name, description, registration on parent program, and custom name support.
133-170: LGTM! Thorough option parsing coverage.All CLI options are tested including defaults, short flags, and option presence. This ensures the Commander configuration is correct.
172-200: LGTM! Complete validation testing.The tests cover all error cases (non-numeric, negative, zero) and the valid case, ensuring robust input validation.
202-248: LGTM! Display logic well-tested.The tests properly verify status formatting for all cases and use
toContain()for string assertions, which aligns with the coding guideline for testing formatted output.
250-425: Excellent comprehensive integration testing!The execute integration tests provide exceptional coverage:
- Core functionality: config passing, display, error handling
- Default behavior: smart iteration defaults based on pending task count for default preset
- Edge cases: explicit iterations override, non-default preset fallback to 10
- Defensive testing: Line 369 verifies
getCountis NOT called for non-default presets- Optional features: progressFile, tag, sandbox auth, next task display
This thorough testing approach will catch regressions effectively.
packages/tm-core/src/index.ts (1)
150-157: LGTM! Export structure follows established patterns.The Loop module exports follow the same structure as other domain exports in this file, correctly separating type exports from value exports and using the
.jsextension for ESM compatibility.packages/tm-core/src/modules/loop/services/loop.service.spec.ts (1)
1-703: LGTM! Excellent test coverage.The test suite is comprehensive and follows best practices:
- Mocks only external I/O boundaries (child_process, fs/promises) per guidelines
- Tests constructor behavior, lifecycle, auth flows, iteration handling, and error scenarios
- Properly suppresses console output during tests
- Follows the describe/it pattern with beforeEach setup
packages/tm-core/src/modules/loop/loop-domain.spec.ts (1)
1-278: LGTM! Comprehensive domain test coverage.The test suite thoroughly validates LoopDomain behavior including:
- Configuration building with defaults and overrides
- Preset recognition and resolution
- Iteration resolution business logic
- Lifecycle management
Follows best practices by mocking only external boundaries (ConfigManager) while testing real domain logic.
| const output = (result.stdout || '') + (result.stderr || ''); | ||
|
|
||
| // Print output to console (spawnSync with pipe captures but doesn't display) | ||
| if (output) console.log(output); |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Use central logging utility instead of direct console.log.
Per coding guidelines, avoid direct console.log calls and use the central log function from the logging utility instead.
🤖 Prompt for AI Agents
In @packages/tm-core/src/modules/loop/services/loop.service.ts at line 238,
Replace the direct console.log call (if (output) console.log(output);) with the
central logging utility: use the project logger (e.g., logger.info(output) or
this.logger.debug(output) depending on context) and ensure the appropriate
logger is imported or injected into the LoopService class; remove console.log
and prefer an info/debug level so the message flows through the central logging
pipeline.
edb7c58 to
5ff28c9
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @packages/tm-core/src/modules/loop/services/loop.service.ts:
- Around line 79-80: Replace the direct console.log calls in LoopService with
the class logger: remove the standalone console.log() and the console.log(`━━━
Iteration ${i} of ${config.iterations} ━━━`) and instead call
this.logger.info(...) (or logger.info if the class uses a logger property named
logger) with the same messages so logging goes through the central logging
utility; ensure you use the existing logger instance used elsewhere in
loop.service.ts (e.g., this.logger) and preserve the same message formatting.
- Around line 237-238: Replace the direct console.log call that prints the
variable output with the central logging utility used by this module: call the
existing logger instance on the LoopService (e.g., this.logger.info(output) or
logger.info(output)) instead of console.log; if no logger instance is present on
LoopService, import the project’s central logger and use logger.info with a
clear context message and the output variable.
🧹 Nitpick comments (6)
tests/unit/mcp-server/tools/tool-registry.test.js (4)
6-16: Consider reducing brittleness from deep relative import (optional).The
../../../../mcp-server/...path is correct but fragile to directory reshuffles; if you have a stable internal alias/path mapping in this repo, using it would make tests less churny.
18-37: Avoid hardcoding tier counts in multiple places; prefer deriving from exports + use public accessor.If the exact numbers (7/14) are meant to be a guardrail, centralize them; otherwise, key assertions should be based on exported arrays to avoid churn. Also prefer
getToolRegistration()over directtoolRegistry[tool]indexing in tests.Proposed refactor
describe('tool-registry', () => { + const EXPECTED_CORE_COUNT = 7; + const EXPECTED_STANDARD_COUNT = 14; + describe('tool tier structure', () => { it('should have exactly 7 core tools', () => { - expect(coreTools.length).toBe(7); + expect(coreTools.length).toBe(EXPECTED_CORE_COUNT); }); it('should have exactly 14 standard tools', () => { - expect(standardTools.length).toBe(14); + expect(standardTools.length).toBe(EXPECTED_STANDARD_COUNT); }); @@ it('should have all standardTools registered in toolRegistry', () => { standardTools.forEach((tool) => { - expect(toolRegistry[tool]).toBeDefined(); + expect(getToolRegistration(tool)).toBeDefined(); }); }); });
40-54: Strengthen low-signal assertions; cross-check counts against exports + available tools.Right now
getAvailableTools()is only validated as “an array”. You can make these tests both stronger and less duplicated by asserting consistency relationships.Proposed refactor
describe('getAvailableTools', () => { it('should return all registered tool names', () => { const tools = getAvailableTools(); - expect(Array.isArray(tools)).toBe(true); + expect(Array.isArray(tools)).toBe(true); + expect(tools).toEqual(expect.arrayContaining(standardTools)); }); }); describe('getToolCounts', () => { it('should return correct counts', () => { const counts = getToolCounts(); - expect(counts.core).toBe(7); - expect(counts.standard).toBe(14); - expect(counts.total).toBeGreaterThanOrEqual(14); + expect(counts.core).toBe(coreTools.length); + expect(counts.standard).toBe(standardTools.length); + expect(counts.total).toBe(getAvailableTools().length); + expect(counts.total).toBeGreaterThanOrEqual(standardTools.length); }); });
110-130: “TASK_MASTER_TOOLS behavior simulation” doesn’t exercise real behavior—consider renaming or relocating.If filtering semantics live elsewhere (env parsing / tool selection), this block will give false confidence. Either rename it to reflect what it does (membership sanity checks) or move assertions to the module that actually implements TASK_MASTER_TOOLS filtering.
packages/tm-core/src/modules/loop/loop-domain.ts (1)
36-48: Consider reusing service instance for auth operations.Both
checkSandboxAuth()andrunInteractiveAuth()create newLoopServiceinstances. While not a significant issue, reusing a single instance would be more efficient.♻️ Optional optimization
export class LoopDomain { private readonly logger = getLogger('LoopDomain'); private loopService: LoopService | null = null; + private authService: LoopService | null = null; private readonly projectRoot: string; constructor(configManager: ConfigManager) { this.projectRoot = configManager.getProjectRoot(); } + private getAuthService(): LoopService { + if (!this.authService) { + this.authService = new LoopService({ projectRoot: this.projectRoot }); + } + return this.authService; + } + // ========== Sandbox Auth Operations ========== /** * Check if Docker sandbox auth is ready * @returns true if ready, false if auth needed */ checkSandboxAuth(): boolean { - const service = new LoopService({ projectRoot: this.projectRoot }); - return service.checkSandboxAuth(); + return this.getAuthService().checkSandboxAuth(); } /** * Run Docker sandbox session for user authentication * Blocks until user completes auth */ runInteractiveAuth(): void { - const service = new LoopService({ projectRoot: this.projectRoot }); - service.runInteractiveAuth(); + this.getAuthService().runInteractiveAuth(); }apps/cli/src/commands/loop.command.ts (1)
139-146: Validate iterations before passing to resolveIterations.The
validateIterations()method runs afterresolveIterations()(line 76). This means invalid user input could be parsed and processed before validation occurs. Consider validating the raw user input earlier.♻️ Suggested improvement
Move validation before calling resolveIterations:
try { const projectRoot = path.resolve(getProjectRoot(options.project)); this.tmCore = await createTmCore({ projectPath: projectRoot }); + // Validate user-provided iterations first + if (options.iterations) { + this.validateIterations(options.iterations); + } + // Get pending task count for default preset iteration resolution const pendingTaskCount = prompt === 'default' ? await this.tmCore.tasks.getCount('pending', options.tag) : undefined; // Delegate iteration resolution logic to tm-core const iterations = this.tmCore.loop.resolveIterations({ userIterations: options.iterations ? parseInt(options.iterations, 10) : undefined, preset: prompt, pendingTaskCount }); - this.validateIterations(String(iterations)); + // Final sanity check (shouldn't fail if resolveIterations works correctly) + if (!Number.isInteger(iterations) || iterations < 1) { + throw new Error(`Invalid resolved iterations: ${iterations}`); + }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
packages/tm-core/src/modules/loop/presets/__snapshots__/presets.spec.ts.snapis excluded by!**/*.snap
📒 Files selected for processing (9)
apps/cli/src/commands/loop.command.spec.tsapps/cli/src/commands/loop.command.tspackages/tm-core/src/index.tspackages/tm-core/src/modules/loop/loop-domain.spec.tspackages/tm-core/src/modules/loop/loop-domain.tspackages/tm-core/src/modules/loop/presets/default.tspackages/tm-core/src/modules/loop/services/loop.service.spec.tspackages/tm-core/src/modules/loop/services/loop.service.tstests/unit/mcp-server/tools/tool-registry.test.js
🚧 Files skipped from review as they are similar to previous changes (5)
- packages/tm-core/src/modules/loop/loop-domain.spec.ts
- packages/tm-core/src/index.ts
- packages/tm-core/src/modules/loop/presets/default.ts
- apps/cli/src/commands/loop.command.spec.ts
- packages/tm-core/src/modules/loop/services/loop.service.spec.ts
🧰 Additional context used
📓 Path-based instructions (10)
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)
TypeScript test files must achieve minimum code coverage thresholds: 80% lines/functions and 70% branches globally, 90% for utilities, and 85% for middleware; new features must meet or exceed these thresholds
Files:
packages/tm-core/src/modules/loop/services/loop.service.tspackages/tm-core/src/modules/loop/loop-domain.tsapps/cli/src/commands/loop.command.ts
**/*.{js,ts}
📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)
**/*.{js,ts}: Import and use specific getters from config-manager.js (e.g., getMainProvider(), getLogLevel(), getMainMaxTokens()) to access configuration values needed for application logic
Use isApiKeySet(providerName, session) from config-manager.js to check if a provider's key is available before potentially attempting an AI call
Do not add direct console.log calls outside the logging utility - use the central log function instead
Ensure silent mode is disabled in a finally block to prevent it from staying enabled
Do not access the global silentMode variable directly - use the exported silent mode control functions instead
Do not duplicate task ID formatting logic across modules - centralize formatting utilities
Use ContextGatherer class from utils/contextGatherer.js for AI-powered commands that need project context, supporting tasks, files, custom text, and project tree context
Use FuzzyTaskSearch class from utils/fuzzyTaskSearch.js for automatic task relevance detection with configurable search parameters
Use fuzzy search to supplement user-provided task IDs and display discovered task IDs to users for transparency
Do not replace explicit user task selections with fuzzy results - fuzzy search should supplement, not replace user selections
Use readJSON and writeJSON utilities for all JSON file operations instead of raw fs.readFileSync or fs.writeFileSync
Include error handling for JSON file operations and validate JSON structure after reading
Use path.join() for cross-platform path construction and path.resolve() for absolute paths, validating paths before file operations
Support both .env files and MCP session environment for environment variable resolution with fallbacks for missing values
Prefer updating the core function to accept an outputFormat parameter and check outputFormat === 'json' before displaying UI elements
Files:
packages/tm-core/src/modules/loop/services/loop.service.tspackages/tm-core/src/modules/loop/loop-domain.tstests/unit/mcp-server/tools/tool-registry.test.jsapps/cli/src/commands/loop.command.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Import modules with
.jsextension even in TypeScript source files for ESM compatibility
Files:
packages/tm-core/src/modules/loop/services/loop.service.tspackages/tm-core/src/modules/loop/loop-domain.tsapps/cli/src/commands/loop.command.ts
**/*.js
📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)
**/*.js: Always use isSilentMode() function to check current silent mode status instead of directly accessing the global silentMode variable or global.silentMode
Use try/finally block pattern when wrapping core function calls with enableSilentMode/disableSilentMode to ensure silent mode is always restored, even if errors occur
For functions that need to handle both a passed silentMode parameter and check global state, check both the function parameter and global state: const isSilent = options.silentMode || (typeof options.silentMode === 'undefined' && isSilentMode())
Functions should accept their dependencies as parameters rather than using globals to promote testability and explicit dependency injection
Define callbacks as separate functions for easier testing rather than inline functions
Files:
tests/unit/mcp-server/tools/tool-registry.test.js
tests/unit/**/*.js
📄 CodeRabbit inference engine (.cursor/rules/architecture.mdc)
Unit tests should be located in tests/unit/ and reflect the module structure with one test file per module
Files:
tests/unit/mcp-server/tools/tool-registry.test.js
**/*.test.{js,ts}
📄 CodeRabbit inference engine (.cursor/rules/new_features.mdc)
**/*.test.{js,ts}: Follow the mock-first-then-import pattern for Jest mocking; use jest.spyOn() for spy functions; clear mocks between tests; verify mocks with the pattern described intests.mdc
Test new features with both legacy and tagged task data formats; verify tag resolution behavior; test migration compatibility; ensure pre-migration projects are handled correctly
Files:
tests/unit/mcp-server/tools/tool-registry.test.js
**/*.{js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/test_workflow.mdc)
JavaScript test files using Jest must follow the same testing patterns as TypeScript files, include proper mocking of external dependencies, and achieve the same coverage thresholds
Files:
tests/unit/mcp-server/tools/tool-registry.test.js
**/*.test.js
📄 CodeRabbit inference engine (.cursor/rules/tests.mdc)
**/*.test.js: Never use asynchronous operations in tests. Always mock tests properly based on the way the tested functions are defined and used.
Follow Jest test file structure: 1) Imports, 2) Mock setup before importing modules under test, 3) Import modules after mocks, 4) Set up spies on mocked modules, 5) Describe suite with descriptive name, 6) Setup/teardown hooks, 7) Grouped tests for related functionality, 8) Individual test cases with clear descriptions using Arrange-Act-Assert pattern.
When testing CLI commands built with Commander.js: test command action handlers directly rather than mocking the entire Commander chain; create simplified test-specific implementations of command handlers; explicitly handle all options including defaults and shorthand flags; include null/undefined checks for optional parameters; use fixtures for consistent sample data.
Usejest.mock()before any imports. Jest hoists mock calls to the top of the file. Always declare mocks before importing modules being tested. Use factory pattern for complex mocks that need access to other variables.
When testing ES modules with dynamic imports, usejest.unstable_mockModule()beforeawait import(). Include__esModule: truein mock factories. Reset mock functions before dynamic import. Mock named and default exports as needed.
Mock file system operations usingmock-fslibrary. Mock API calls by providing jest.fn() implementations that return expected structures. Mock environment variables in test setup.
When testing functions with callbacks: get the callback from mock's call arguments usingmock.calls[index][argIndex]; execute it directly with test inputs; verify results match expectations.
For task file operations in tests: use test-specific file paths (e.g., 'test-tasks.json'); mockreadJSONandwriteJSONto avoid real file system interactions; verify file operations use correct paths; use different paths for each test; verify modifications on in-memory task objects passed t...
Files:
tests/unit/mcp-server/tools/tool-registry.test.js
tests/unit/**/*.test.js
📄 CodeRabbit inference engine (.cursor/rules/tests.mdc)
Locate unit tests in
tests/unit/directory. Test individual functions and utilities in isolation, mock all external dependencies, keep tests small and focused.
Files:
tests/unit/mcp-server/tools/tool-registry.test.js
apps/cli/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
CLI (@tm/cli) should be a thin presentation layer that calls tm-core methods and displays results; handle only CLI-specific concerns like argument parsing, output formatting, and user prompts
Files:
apps/cli/src/commands/loop.command.ts
🧠 Learnings (60)
📓 Common learnings
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: assets/AGENTS.md:0-0
Timestamp: 2025-12-11T14:45:14.973Z
Learning: Applies to assets/**/CLAUDE.md : Update `CLAUDE.md` file with project-specific context, task summaries, and custom command examples for Claude Code integration
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1178
File: packages/tm-core/src/auth/config.ts:5-7
Timestamp: 2025-09-02T21:51:27.921Z
Learning: The user Crunchyman-ralph prefers not to use node: scheme imports (e.g., 'node:os', 'node:path') for Node.js core modules and considers suggestions to change bare imports to node: scheme as too nitpicky.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1069
File: .changeset/fix-tag-complexity-detection.md:0-0
Timestamp: 2025-08-02T15:33:22.656Z
Learning: For changeset files (.changeset/*.md), Crunchyman-ralph prefers to ignore formatting nitpicks about blank lines between frontmatter and descriptions, as he doesn't mind having them and wants to avoid such comments in future reviews.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1132
File: .github/workflows/weekly-metrics-discord.yml:81-93
Timestamp: 2025-08-13T22:10:46.958Z
Learning: Crunchyman-ralph ignores YAML formatting nitpicks about trailing spaces when there's no project-specific YAML formatter configured, preferring to focus on functionality over cosmetic formatting issues.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1132
File: .github/workflows/weekly-metrics-discord.yml:81-93
Timestamp: 2025-08-13T22:10:46.958Z
Learning: Crunchyman-ralph ignores YAML formatting nitpicks about trailing spaces when there's no project-specific YAML formatter configured, preferring to focus on functionality over cosmetic formatting issues.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1200
File: src/ai-providers/custom-sdk/grok-cli/language-model.js:96-100
Timestamp: 2025-09-19T16:06:42.182Z
Learning: The user Crunchyman-ralph prefers to keep environment variable names explicit (like GROK_CLI_API_KEY) rather than supporting multiple aliases, to avoid overlap and ensure clear separation between different CLI implementations.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1178
File: packages/tm-core/src/subpath-exports.test.ts:6-9
Timestamp: 2025-09-03T12:45:30.724Z
Learning: The user Crunchyman-ralph prefers to avoid overly nitpicky or detailed suggestions in code reviews, especially for test coverage of minor import paths. Focus on more substantial issues rather than comprehensive coverage of all possible edge cases.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1105
File: scripts/modules/supported-models.json:242-254
Timestamp: 2025-08-08T11:33:15.297Z
Learning: Preference: In scripts/modules/supported-models.json, the "name" field is optional. For OpenAI entries (e.g., "gpt-5"), Crunchyman-ralph prefers omitting "name" when the id is explicit enough; avoid nitpicks requesting a "name" in such cases.
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1217
File: apps/cli/src/index.ts:16-21
Timestamp: 2025-09-18T16:35:35.147Z
Learning: The user Crunchyman-ralph considers suggestions to export types for better ergonomics (like exporting UpdateInfo type alongside related functions) as nitpicky and prefers not to implement such suggestions.
📚 Learning: 2025-11-24T18:04:43.972Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-24T18:04:43.972Z
Learning: Applies to **/*.{js,ts} : Do not add direct console.log calls outside the logging utility - use the central log function instead
Applied to files:
packages/tm-core/src/modules/loop/services/loop.service.tspackages/tm-core/src/modules/loop/loop-domain.tsapps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:01:06.077Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-11-24T18:01:06.077Z
Learning: Applies to mcp-server/src/core/direct-functions/*.js : Do not wrap unified AI service calls (generateTextService, generateObjectService) in silent mode; their logging is handled internally
Applied to files:
packages/tm-core/src/modules/loop/services/loop.service.tspackages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-11-24T17:57:31.417Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/ai_services.mdc:0-0
Timestamp: 2025-11-24T17:57:31.417Z
Learning: Applies to scripts/modules/task-manager/*.js, scripts/modules/commands.js : Centralize all LLM calls through `generateTextService` or `generateObjectService` from `ai-services-unified.js`
Applied to files:
packages/tm-core/src/modules/loop/services/loop.service.ts
📚 Learning: 2025-11-24T18:04:43.972Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-24T18:04:43.972Z
Learning: Applies to scripts/modules/task-manager/**/*.{js,ts} : Do not call AI-specific getters (like getMainModelId, getMainMaxTokens) from core logic functions in scripts/modules/task-manager/*. Instead, pass the role to the unified AI service
Applied to files:
packages/tm-core/src/modules/loop/services/loop.service.tspackages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-09-03T12:20:36.005Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1178
File: packages/tm-core/src/index.ts:56-57
Timestamp: 2025-09-03T12:20:36.005Z
Learning: The logger functionality in tm-core should only be available through the main package entry point (import { getLogger, createLogger, setGlobalLogger } from 'tm-core'), not as a separate subpath export like other modules such as auth or storage.
Applied to files:
packages/tm-core/src/modules/loop/services/loop.service.tspackages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-11-24T17:57:31.417Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/ai_services.mdc:0-0
Timestamp: 2025-11-24T17:57:31.417Z
Learning: Applies to scripts/modules/task-manager/*.js, scripts/modules/commands.js : Do not initialize AI clients (Anthropic, Perplexity, etc.) directly within core logic or MCP direct functions; use the unified service layer instead
Applied to files:
packages/tm-core/src/modules/loop/services/loop.service.tspackages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-11-24T18:01:06.077Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-11-24T18:01:06.077Z
Learning: Applies to mcp-server/src/core/direct-functions/*.js : Do not call or pass reportProgress in direct functions; use log.info() for internal progress reporting instead
Applied to files:
packages/tm-core/src/modules/loop/services/loop.service.tspackages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-11-24T18:02:49.782Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/telemetry.mdc:0-0
Timestamp: 2025-11-24T18:02:49.782Z
Learning: Applies to scripts/modules/task-manager/**/*.js : AI service functions in core logic (e.g., in scripts/modules/task-manager/) must call the appropriate AI service function (e.g., generateObjectService) and pass commandName and outputType in the params object
Applied to files:
packages/tm-core/src/modules/loop/services/loop.service.ts
📚 Learning: 2025-11-24T17:57:31.417Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/ai_services.mdc:0-0
Timestamp: 2025-11-24T17:57:31.417Z
Learning: Applies to scripts/modules/task-manager/*.js, scripts/modules/commands.js, scripts/modules/ai-services-unified.js : Do not import or call anything from deprecated AI service files (`ai-services.js`, `ai-client-factory.js`, `ai-client-utils.js`)
Applied to files:
packages/tm-core/src/modules/loop/services/loop.service.tspackages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-11-24T18:02:49.782Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/telemetry.mdc:0-0
Timestamp: 2025-11-24T18:02:49.782Z
Learning: Applies to scripts/modules/task-manager/**/*.js : Core logic functions with outputFormat parameter must check if outputFormat === 'text' and call displayAiUsageSummary(aiServiceResponse.telemetryData, 'cli') from scripts/modules/ui.js when applicable
Applied to files:
packages/tm-core/src/modules/loop/services/loop.service.tsapps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:01:06.077Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-11-24T18:01:06.077Z
Learning: Applies to mcp-server/src/core/direct-functions/*.js : Wrap core function calls and AI calls in try/catch blocks, log errors with appropriate severity and context, and return standardized error objects with code and message
Applied to files:
packages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-11-24T17:57:31.417Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/ai_services.mdc:0-0
Timestamp: 2025-11-24T17:57:31.417Z
Learning: Applies to scripts/modules/task-manager/*.js, scripts/modules/commands.js : Do not implement fallback or retry logic outside `ai-services-unified.js`; all fallback sequences and retry logic must be centralized in the unified service
Applied to files:
packages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-11-24T18:04:43.972Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-24T18:04:43.972Z
Learning: Applies to **/{utils,utilities}/**/*.{js,ts} : Log detailed error information using the log utility in catch blocks for file operations
Applied to files:
packages/tm-core/src/modules/loop/loop-domain.ts
📚 Learning: 2025-11-24T18:01:06.077Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-11-24T18:01:06.077Z
Learning: Applies to mcp-server/src/tools/index.js : Import and call tool registration functions in mcp-server/src/tools/index.js to register new MCP tools with the server
Applied to files:
tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to mcp-server/src/tools/index.js : Register MCP tools by importing and calling registration functions in `mcp-server/src/tools/index.js`
Applied to files:
tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T17:58:07.992Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/architecture.mdc:0-0
Timestamp: 2025-11-24T17:58:07.992Z
Learning: New MCP tools should be imported and registered in mcp-server/src/tools/index.js and tool definitions should be added to mcp.json
Applied to files:
tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:01:06.077Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-11-24T18:01:06.077Z
Learning: Applies to mcp-server/src/tools/*.js : Use camelCase with Tool suffix for tool registration functions (e.g., registerListTasksTool)
Applied to files:
tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to **/*.test.js : When testing CLI commands built with Commander.js: test command action handlers directly rather than mocking the entire Commander chain; create simplified test-specific implementations of command handlers; explicitly handle all options including defaults and shorthand flags; include null/undefined checks for optional parameters; use fixtures for consistent sample data.
Applied to files:
tests/unit/mcp-server/tools/tool-registry.test.jsapps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to **/*.test.js : For task file operations in tests: use test-specific file paths (e.g., 'test-tasks.json'); mock `readJSON` and `writeJSON` to avoid real file system interactions; verify file operations use correct paths; use different paths for each test; verify modifications on in-memory task objects passed to `writeJSON`.
Applied to files:
tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:01:06.077Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-11-24T18:01:06.077Z
Learning: Applies to mcp-server/src/tools/*.js : Include projectRoot as an optional parameter in tool definitions using zod schema
Applied to files:
tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to .cursor/mcp.json : Add new tool definitions to the tools array in `.cursor/mcp.json`
Applied to files:
tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to tests/unit/**/*.test.js : Locate unit tests in `tests/unit/` directory. Test individual functions and utilities in isolation, mock all external dependencies, keep tests small and focused.
Applied to files:
tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to mcp-server/src/tools/*.js : Create MCP tool definitions in `mcp-server/src/tools/` using kebab-case naming; use zod for parameter validation; make projectRoot optional as the HOF handles fallback; wrap execute method with `withNormalizedProjectRoot`
Applied to files:
tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:01:06.077Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-11-24T18:01:06.077Z
Learning: Applies to mcp-server/src/tools/*.js : Use snake_case for MCP tool names exposed to clients (e.g., list_tasks, set_task_status)
Applied to files:
tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:02:49.782Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/telemetry.mdc:0-0
Timestamp: 2025-11-24T18:02:49.782Z
Learning: Applies to mcp-server/src/tools/**/*.js : MCP tools in mcp-server/src/tools/ must call the corresponding direct function wrapper and pass the result object to handleApiResult(result, log) from mcp-server/src/tools/utils.js
Applied to files:
tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-10-11T22:32:11.922Z
Learnt from: rtmcrc
Repo: eyaltoledano/claude-task-master PR: 933
File: mcp-server/src/providers/agentllm-provider-tool-executor.js:289-329
Timestamp: 2025-10-11T22:32:11.922Z
Learning: In the Taskmaster codebase, when detecting agent-llm pending-interaction signals in tool results (agentllm-provider-tool-executor.js), the data is always stored in content[0], so there's no need to loop through all content items.
Applied to files:
tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T22:09:45.455Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T22:09:45.455Z
Learning: Applies to apps/mcp/**/*.{spec,test}.ts : In unit tests for apps/mcp, mock tm-core responses but use real MCP framework to test response formatting
Applied to files:
tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to **/*.test.{js,ts} : Test new features with both legacy and tagged task data formats; verify tag resolution behavior; test migration compatibility; ensure pre-migration projects are handled correctly
Applied to files:
tests/unit/mcp-server/tools/tool-registry.test.jsapps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:04:43.972Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-24T18:04:43.972Z
Learning: Applies to mcp-server/src/tools/**/*.{js,ts} : Use the withNormalizedProjectRoot Higher-Order Function to wrap tool execute methods, ensuring normalized project root is injected into args
Applied to files:
tests/unit/mcp-server/tools/tool-registry.test.js
📚 Learning: 2025-11-24T22:09:45.455Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T22:09:45.455Z
Learning: Applies to apps/cli/src/**/*.{ts,tsx} : CLI (tm/cli) should be a thin presentation layer that calls tm-core methods and displays results; handle only CLI-specific concerns like argument parsing, output formatting, and user prompts
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to scripts/modules/commands.js : All new user-facing commands should be added to `commands.js` following Commander.js patterns for subcommand structure and consistent option naming
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:04:43.972Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-24T18:04:43.972Z
Learning: Applies to scripts/modules/**/*.{js,ts} : Implement tag resolution functions (getTasksForTag, setTasksForTag, getCurrentTag) that provide backward compatibility with legacy format and default to master tag
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to scripts/modules/*.js : Design core logic to work with both legacy (flat tasks array) and tagged task data formats; use tag resolution functions (getTasksForTag, setTasksForTag) for task data access; support silent migration during feature usage
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:02:04.644Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tags.mdc:0-0
Timestamp: 2025-11-24T18:02:04.644Z
Learning: Use consistent tag resolution across all commands to ensure predictable behavior
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:02:36.388Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tasks.mdc:0-0
Timestamp: 2025-11-24T18:02:36.388Z
Learning: Applies to scripts/modules/task-manager.js : Extract tasks from PRD documents using AI within the current tag context (defaulting to "master"), providing clear prompts to guide AI task generation and validating/cleaning up AI-generated tasks
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:02:04.644Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tags.mdc:0-0
Timestamp: 2025-11-24T18:02:04.644Z
Learning: Applies to scripts/modules/task-manager/**/*.{js,mjs} : Pass context object `{ projectRoot, tag }` to all core functions that read or write tasks
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-07-18T08:29:52.384Z
Learnt from: mm-parthy
Repo: eyaltoledano/claude-task-master PR: 943
File: scripts/modules/task-manager/list-tasks.js:0-0
Timestamp: 2025-07-18T08:29:52.384Z
Learning: TODO comments about adding tag support to internal functions like readComplexityReport are obsolete in the boundary-first tag resolution pattern because report paths are already resolved at the CLI command boundary layer before reaching these functions.
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:02:04.644Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tags.mdc:0-0
Timestamp: 2025-11-24T18:02:04.644Z
Learning: Every command that reads or writes tasks.json must be tag-aware and support the tagged task lists system
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to scripts/modules/*.js : Process large task lists efficiently; minimize file I/O operations per feature execution; cache tag resolution results when appropriate; avoid keeping all tag data in memory simultaneously
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:01:44.169Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/new_features.mdc:0-0
Timestamp: 2025-11-24T18:01:44.169Z
Learning: Applies to mcp-server/src/core/direct-functions/*.js : In MCP direct functions, support explicit tag specification and use tag resolution for task data operations; default to current tag when not specified
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:04:43.972Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-24T18:04:43.972Z
Learning: Applies to **/*.{js,ts} : Prefer updating the core function to accept an outputFormat parameter and check outputFormat === 'json' before displaying UI elements
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-26T20:50:40.810Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1451
File: apps/cli/src/ui/components/brand-banner.component.ts:42-44
Timestamp: 2025-11-26T20:50:40.810Z
Learning: In apps/cli/**/*.{ts,tsx}: Do not import or use isSilentMode() from the legacy scripts/modules/utils.js. isSilentMode is legacy code that will be removed during migration. The apps/cli package should use environment variables like TM_HIDE_BANNER for controlling output instead of legacy silent mode patterns.
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:03:46.713Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/tests.mdc:0-0
Timestamp: 2025-11-24T18:03:46.713Z
Learning: Applies to **/*.test.js : When testing UI functions: mock console output and verify correct formatting; test conditional output logic; use `toContain()` or `toMatch()` rather than exact `toBe()` for strings with emojis or formatting; create separate tests for different behavior modes; test structure of formatted output rather than exact string matching.
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T17:58:07.992Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/architecture.mdc:0-0
Timestamp: 2025-11-24T17:58:07.992Z
Learning: Applies to mcp-server/src/core/direct-functions/*.js : Direct functions (mcp-server/src/core/direct-functions/*Direct functions) should implement silent mode to prevent console logs from interfering with structured JSON responses required by MCP, using enableSilentMode/disableSilentMode around core function calls and passing the MCP logger via standard wrapper pattern
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:02:49.782Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/telemetry.mdc:0-0
Timestamp: 2025-11-24T18:02:49.782Z
Learning: Applies to scripts/modules/commands.js : CLI commands in scripts/modules/commands.js must call core logic functions with outputFormat: 'text' and pass commandNameFromContext and outputType: 'cli' in the context, allowing the core function to handle displayAiUsageSummary internally rather than calling it from the command itself
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:04:43.972Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-24T18:04:43.972Z
Learning: Applies to mcp-server/src/core/direct-functions/**/*.{js,ts} : In direct functions that call core functions, ensure console output from the core function is suppressed to avoid breaking MCP JSON responses
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:01:06.077Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/mcp.mdc:0-0
Timestamp: 2025-11-24T18:01:06.077Z
Learning: Applies to mcp-server/src/**/*.js : Do not log entire large data structures or sensitive information in direct functions and tools
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-09-02T21:51:27.921Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1178
File: packages/tm-core/src/auth/config.ts:5-7
Timestamp: 2025-09-02T21:51:27.921Z
Learning: The user Crunchyman-ralph prefers not to use node: scheme imports (e.g., 'node:os', 'node:path') for Node.js core modules and considers suggestions to change bare imports to node: scheme as too nitpicky.
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-08-02T15:33:22.656Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1069
File: .changeset/fix-tag-complexity-detection.md:0-0
Timestamp: 2025-08-02T15:33:22.656Z
Learning: For changeset files (.changeset/*.md), Crunchyman-ralph prefers to ignore formatting nitpicks about blank lines between frontmatter and descriptions, as he doesn't mind having them and wants to avoid such comments in future reviews.
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-09-03T12:45:30.724Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1178
File: packages/tm-core/src/subpath-exports.test.ts:6-9
Timestamp: 2025-09-03T12:45:30.724Z
Learning: The user Crunchyman-ralph prefers to avoid overly nitpicky or detailed suggestions in code reviews, especially for test coverage of minor import paths. Focus on more substantial issues rather than comprehensive coverage of all possible edge cases.
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-09-03T12:16:15.866Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1178
File: packages/tm-core/package.json:13-64
Timestamp: 2025-09-03T12:16:15.866Z
Learning: For internal packages in the claude-task-master project, Crunchyman-ralph prefers pointing package.json "types" entries to src .ts files rather than dist .d.ts files for better developer experience (DX), as the packages are not being exported as SDKs.
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-09-18T16:35:35.147Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1217
File: apps/cli/src/index.ts:16-21
Timestamp: 2025-09-18T16:35:35.147Z
Learning: The user Crunchyman-ralph considers suggestions to export types for better ergonomics (like exporting UpdateInfo type alongside related functions) as nitpicky and prefers not to implement such suggestions.
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-09-26T19:28:42.612Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1252
File: packages/ai-sdk-provider-grok-cli/package.json:21-35
Timestamp: 2025-09-26T19:28:42.612Z
Learning: Crunchyman-ralph is concerned about preventing production failures when developers add external dependencies to internal packages but forget to add them to the root package.json in their tsdown bundling setup. He wants automated safety mechanisms to catch this during development or CI rather than discovering it in production.
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-09-19T16:06:42.182Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1200
File: src/ai-providers/custom-sdk/grok-cli/language-model.js:96-100
Timestamp: 2025-09-19T16:06:42.182Z
Learning: The user Crunchyman-ralph prefers to keep environment variable names explicit (like GROK_CLI_API_KEY) rather than supporting multiple aliases, to avoid overlap and ensure clear separation between different CLI implementations.
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-08-13T22:10:46.958Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1132
File: .github/workflows/weekly-metrics-discord.yml:81-93
Timestamp: 2025-08-13T22:10:46.958Z
Learning: Crunchyman-ralph ignores YAML formatting nitpicks about trailing spaces when there's no project-specific YAML formatter configured, preferring to focus on functionality over cosmetic formatting issues.
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-09-09T19:14:21.367Z
Learnt from: Crunchyman-ralph
Repo: eyaltoledano/claude-task-master PR: 1194
File: .github/workflows/ci.yml:21-21
Timestamp: 2025-09-09T19:14:21.367Z
Learning: User Crunchyman-ralph considers suggestions about adding safer default shell options (like bash -euo pipefail) to GitHub Actions workflows as too nitpicky and prefers not to implement them.
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T17:58:07.992Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/architecture.mdc:0-0
Timestamp: 2025-11-24T17:58:07.992Z
Learning: The Task Master CLI uses a modular architecture with distinct modules responsible for different aspects: commands.js (CLI command handling), task-manager.js (task data & core logic), dependency-manager.js (dependency management), ui.js (output formatting), ai-services-unified.js (unified AI service layer), config-manager.js (configuration management), utils.js (core utility functions), and mcp-server/ (MCP interface)
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:05:02.114Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: assets/.windsurfrules:0-0
Timestamp: 2025-11-24T18:05:02.114Z
Learning: Use the global CLI command `task-master` instead of `node scripts/dev.js` for all task management operations
Applied to files:
apps/cli/src/commands/loop.command.ts
📚 Learning: 2025-11-24T18:00:32.617Z
Learnt from: CR
Repo: eyaltoledano/claude-task-master PR: 0
File: .cursor/rules/glossary.mdc:0-0
Timestamp: 2025-11-24T18:00:32.617Z
Learning: Refer to commands.mdc for guidelines on implementing CLI commands using Commander.js
Applied to files:
apps/cli/src/commands/loop.command.ts
🧬 Code graph analysis (2)
packages/tm-core/src/modules/loop/loop-domain.ts (5)
packages/tm-core/src/index.ts (5)
LoopDomain(157-157)LoopConfig(153-153)LoopResult(155-155)LoopPreset(152-152)PRESET_NAMES(157-157)packages/tm-core/src/modules/loop/index.ts (7)
LoopDomain(7-7)LoopService(10-10)LoopConfig(16-16)LoopResult(18-18)LoopPreset(15-15)getPreset(25-25)PRESET_NAMES(24-24)packages/tm-core/src/modules/loop/services/loop.service.ts (1)
LoopService(20-251)packages/tm-core/src/modules/loop/types.ts (3)
LoopConfig(18-29)LoopResult(50-59)LoopPreset(8-13)packages/tm-core/src/modules/loop/presets/index.ts (2)
getPreset(34-36)PRESET_NAMES(27-27)
tests/unit/mcp-server/tools/tool-registry.test.js (1)
mcp-server/src/tools/tool-registry.js (6)
getAvailableTools(139-141)getToolCounts(147-153)getToolCategories(159-167)getToolRegistration(174-176)isValidTool(183-185)allTools(160-160)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Test
- GitHub Check: Cursor Bugbot
🔇 Additional comments (5)
tests/unit/mcp-server/tools/tool-registry.test.js (1)
56-108: These category/lookup validation tests look solid.Good coverage of the public API surface (
getToolCategories,getToolRegistration,isValidTool) without depending on tool ordering.packages/tm-core/src/modules/loop/loop-domain.ts (2)
59-73: LGTM! Excellent error handling and cleanup logic.The
run()method properly handles the case where a loop is already running by attempting cleanup before starting a new loop. The try-catch with logger.warn ensures that cleanup failures don't block the new loop from starting.
150-173: LGTM! Clear business logic for iteration resolution.The
resolveIterations()method has well-documented logic with clear priority ordering: user-provided iterations take precedence, then preset-specific logic for the default preset, and finally a sensible default of 10 iterations.apps/cli/src/commands/loop.command.ts (2)
53-117: LGTM! Well-structured command execution with proper delegation.The
execute()method follows the thin presentation layer pattern correctly:
- Delegates iteration resolution to tm-core
- Validates inputs appropriately
- Uses display utilities where available
- Handles errors with proper exit codes
- Conditional logic for default preset is clean
The use of
console.logwith chalk for CLI output is acceptable for the presentation layer, though you could optionally extract these into display utility functions for consistency.
119-137: LGTM! Clear authentication flow with good user feedback.The
handleSandboxAuth()method provides clear status messages to guide users through the authentication process, with appropriate color coding for different states.
What type of PR is this?
Description
Related Issues
How to Test This
# Example commands or stepsExpected result:
Contributor Checklist
npm run changesetnpm testnpm run format-check(ornpm run formatto fix)Changelog Entry
For Maintainers
Note
Adds an autonomous loop workflow that executes one task per iteration with fresh Claude sessions.
task-master loopCLI: Docker-sandboxed iterations, optional--tag,--progress-file, preset or custom prompts, iteration resolution, and result summaryLoopDomain/LoopServicewith preset resolution, prompt generation, progress logging, and<loop-complete>/<loop-blocked>detectiondefault,test-coverage,linting,duplication,entropy; inlined content with tests and snapshotsclaude-code: opus(32k); CLAUDE.md tool count corrected (42+); state currentTag switched toloopWritten by Cursor Bugbot for commit 5ff28c9. This will update automatically on new commits. Configure here.
Summary by CodeRabbit
New Features
Documentation
Tests
✏️ Tip: You can customize this high-level summary in your review settings.