feat: implement bundled rule packs (presets)#32
Conversation
- Add presets/ directory with meta.json registry - Implement PresetLoader and refactor to RulePackLoader - User rules shadow presets with same name - Rename Eval/Prompt terminology to Rule for consistency
- Make pack field required in PROMPT_FILE_SCHEMA - Add buildRuleName() helper for consistent rule name construction - Update rule names to follow PackName.RuleId.CriterionId pattern - Apply naming to both subjective and semi-objective evaluation paths - Update loadRuleFile() to require packName parameter - Use 'Default' pack for legacy loadRules() function in tests
update to main
- Add fileURLToPath and dirname imports for ESM compatibility - Define __filename and __dirname using import.meta.url - Fixes 'ReferenceError: __dirname is not defined' in built output - Affects commands.ts and validate-command.ts preset loading
…t quality issues - add pseudo-advice rule that catches vague guidance telling WHAT without explaining HOW - add repetition rule that identifies redundant sections wasting reader time - add directness rule that ensures sections immediately answer their header questions - group violations by criterion in orchestrator for better multi-criterion rule reporting - add ai-pattern test fixtures for buzzword and negation pattern detection
📝 WalkthroughWalkthroughAdds a preset-driven rule-pack system: new VectorLint presets and meta, PresetLoader and RulePackLoader that merge presets with user packs, renames prompt APIs to rule APIs (loadRules/loadRuleFile), threads packName through CLI/orchestrator for hierarchical rule naming, and updates schemas, file resolution, and tests. Changes
Sequence Diagram(s)sequenceDiagram
participant CLI as CLI (validate/commands)
participant PresetLdr as PresetLoader
participant RulePkgLdr as RulePackLoader
participant FS as File System
participant Loader as RuleLoader (loadRuleFile / loadRules)
participant Orch as Orchestrator
CLI->>PresetLdr: new PresetLoader(presetsDir)
CLI->>RulePkgLdr: new RulePackLoader(PresetLoader)
CLI->>RulePkgLdr: listAllPacks(userRulesPath)
RulePkgLdr->>PresetLdr: getAvailablePresets()
PresetLdr->>FS: read presets/meta.json
FS-->>PresetLdr: meta.json
PresetLdr-->>RulePkgLdr: preset entries
RulePkgLdr->>FS: scan userRulesPath for directories
FS-->>RulePkgLdr: user pack dirs
Note over RulePkgLdr: Merge presets (low priority) with user packs (high priority)
RulePkgLdr-->>CLI: ResolvedPack[] (name,path,isPreset)
loop for each pack in ResolvedPack[]
CLI->>RulePkgLdr: findRuleFiles(pack.path)
RulePkgLdr->>FS: recursive *.md scan
FS-->>RulePkgLdr: rule file paths
RulePkgLdr-->>CLI: file paths
CLI->>Loader: loadRuleFile(filePath, pack.name)
Loader-->>CLI: parsed Rule object
CLI->>Orch: process result (rule, packName)
Orch->>Orch: buildRuleName(packName, ruleId, criterionId)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
package.json (1)
21-25: Verify presets are included in the package distribution.The PR summary states "Updates packaging to include presets in package.json files array," but the
filesarray doesn't include thepresets/directory. This means presets won't be bundled with the published package, breaking the preset functionality for users.🔎 Proposed fix
"files": [ "dist", + "presets", "README.md", "LICENSE.md" ],tests/validator.test.ts (1)
60-73: Missing requiredpackfield in manual PromptFile construction.The
PromptFileobject constructed for testing is missing thepackfield, which is now required according to the updatedPROMPT_FILE_SCHEMAinsrc/schemas/prompt-schemas.ts. This test may fail validation or produce unintended behavior.🔎 Proposed fix
const p: PromptFile = { id: 'x', filename: 'x.md', fullPath: '/path/to/x.md', body: '', + pack: 'TestPack', meta: { id: 'x', name: 'X',src/cli/validate-command.ts (1)
85-88: Duplicate "no prompts found" checks.There are two checks for
prompts.length === 0: one inside the try block (lines 85-88) and another after warnings display (lines 103-106). The second check at lines 103-106 is unreachable because the first check already exits withprocess.exit(1).🔎 Proposed fix - remove the unreachable check
// Display loader warnings if (warnings.length) { printFileHeader('Loader'); for (const w of warnings) printValidationRow('warning', w); console.log(''); } - // Ensure at least one prompt was found - if (prompts.length === 0) { - console.error(`Error: no .md prompts found in ${rulesPath}`); - process.exit(1); - } - // Validate all prompts const result = validateAll(prompts);Also applies to: 103-106
🧹 Nitpick comments (11)
package.json (1)
38-39: Reconsider "vectorlint.ini.example" as a keyword.Keywords should represent searchable concepts or categories (e.g., "configuration", "ini"), not specific filenames. "vectorlint.ini.example" appears to be a filename and may not provide meaningful discoverability.
🔎 Suggested alternative
"presets", - "vectorlint.ini.example", + "configuration", "vectorlint"presets/VectorLint/repetition.md (3)
26-26: Consider LanguageTool suggestion (optional).Static analysis flagged the spelling of "CRITERIA," though this appears to be intentional formatting for the section header.
37-37: Minor style: word repetition (optional).LanguageTool noted repetition between "Explanations" and "explained" in close proximity. Consider rewording for variety, though the meaning is clear as written.
🔎 Possible alternative
-**Redundant Explanations**: A concept fully explained in one section is explained again later as if it's new information +**Redundant Explanations**: A concept fully described in one section is explained again later as if it's new information
39-39: Minor style: consider "same" instead of "exact same" (optional).LanguageTool suggests "exact same" may be wordy. "Same" alone would be sufficient, though this is a minor stylistic choice.
tests/fixtures/ai-pattern/negation-pattern.md (1)
145-151: Consider replacing hard tabs with spaces in the comparison table.The comparison table uses hard tabs which triggers markdownlint MD010 warnings. While this is a test fixture, replacing tabs with spaces or using proper Markdown table syntax would maintain consistency.
🔎 Example of Markdown table format
| Tool | Primary Focus | Context Awareness | Pricing Model | Best Use Case | |------|---------------|-------------------|---------------|---------------| | Graphite Agent | Complete platform | PR diff + context | $40/user/month | Teams wanting velocity | ...src/schemas/preset-schemas.ts (1)
8-12: Consider adding.min(1)constraint for the path field.The current schema allows empty strings for
path, which could cause issues during path resolution. A minimal constraint would prevent invalid entries.🔎 Optional refinement
export const PRESET_ENTRY_SCHEMA = z.object({ - path: z.string(), + path: z.string().min(1), description: z.string().optional(), });src/config/preset-loader.ts (1)
3-3: Missing.jsextension in import for ESM compatibility.Per project guidelines, TypeScript ESM requires explicit file extensions for imports. The import from
../schemas/preset-schemasshould include the.jsextension.🔎 Proposed fix
-import { PRESET_REGISTRY_SCHEMA, type PresetRegistry } from '../schemas/preset-schemas'; +import { PRESET_REGISTRY_SCHEMA, type PresetRegistry } from '../schemas/preset-schemas.js';src/cli/commands.ts (1)
110-113: Consider logging when presets provide rules.Currently, the warning only fires when
packs.length === 0. For debugging purposes, it might be helpful in verbose mode to also log which packs are from presets vs. user rules.src/boundaries/rule-pack-loader.ts (2)
4-4: Missing.jsextension in import for ESM compatibility.Per project guidelines for TypeScript ESM with explicit imports.
🔎 Proposed fix
-import { PresetLoader } from '../config/preset-loader'; +import { PresetLoader } from '../config/preset-loader.js';
71-73: Mixed sync/async filesystem access.The method uses synchronous
existsSyncfor the existence check but asyncfs.readdirfor directory traversal. Consider using the asyncfs.accessfor consistency, or keepexistsSyncsince it's a simple guard before the async work begins (acceptable pattern).src/cli/validate-command.ts (1)
63-83: Consider extracting shared pack-loading logic.The pack enumeration and rule loading logic (lines 63-83) is nearly identical to
commands.ts(lines 104-128). Consider extracting this into a shared utility function to reduce duplication.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (26)
package.jsonpresets/VectorLint/ai-pattern.mdpresets/VectorLint/directness.mdpresets/VectorLint/pseudo-advice.mdpresets/VectorLint/repetition.mdpresets/meta.jsonsrc/boundaries/eval-pack-loader.tssrc/boundaries/rule-pack-loader.tssrc/cli/commands.tssrc/cli/orchestrator.tssrc/cli/types.tssrc/cli/validate-command.tssrc/config/preset-loader.tssrc/prompts/prompt-loader.tssrc/schemas/preset-schemas.tssrc/schemas/prompt-schemas.tstests/evaluator.test.tstests/fixtures/ai-pattern/buzzword.mdtests/fixtures/ai-pattern/negation-pattern.mdtests/fixtures/ai-pattern/test.mdtests/preset-loader.test.tstests/prompt-loader-validation.test.tstests/rule-pack-e2e.test.tstests/rule-pack-loader.test.tstests/target.test.tstests/validator.test.ts
💤 Files with no reviewable changes (1)
- src/boundaries/eval-pack-loader.ts
🧰 Additional context used
📓 Path-based instructions (3)
src/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.ts: Use TypeScript ESM with explicit imports and narrow types
Use 2-space indentation; avoid trailing whitespace
Maintain strict TypeScript with noany; useunknown+ schema validation for external data
Use custom error types with proper inheritance; catch blocks useunknowntype
Files:
src/schemas/preset-schemas.tssrc/schemas/prompt-schemas.tssrc/boundaries/rule-pack-loader.tssrc/cli/types.tssrc/cli/commands.tssrc/config/preset-loader.tssrc/prompts/prompt-loader.tssrc/cli/validate-command.tssrc/cli/orchestrator.ts
src/boundaries/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Use Zod schemas for boundary validation of all external data (files, CLI, env, APIs) at system boundaries
Files:
src/boundaries/rule-pack-loader.ts
tests/**/*.test.ts
📄 CodeRabbit inference engine (AGENTS.md)
tests/**/*.test.ts: Write tests using Vitest framework with focus on config parsing, file discovery, schema/structured output, and locator
Use dependency injection in tests: mock providers; do not hit network in unit tests
Files:
tests/prompt-loader-validation.test.tstests/target.test.tstests/evaluator.test.tstests/rule-pack-e2e.test.tstests/preset-loader.test.tstests/rule-pack-loader.test.tstests/validator.test.ts
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Recursively load all `.md` files from within each rule pack; multiple packs can be used simultaneously
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Organize rules into subdirectories (packs) within RulesPath; use company names (e.g., Acme, TechCorp, Stripe) to indicate which style guide the rules implement
📚 Learning: 2025-12-28T19:43:51.176Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Applies to .vectorlint.ini : Use `[glob/pattern]` sections in `.vectorlint.ini` to specify which packs run on which files
Applied to files:
package.json
📚 Learning: 2025-12-28T19:43:51.176Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Applies to src/boundaries/**/*.ts : Use Zod schemas for boundary validation of all external data (files, CLI, env, APIs) at system boundaries
Applied to files:
src/schemas/preset-schemas.ts
📚 Learning: 2025-12-28T19:43:51.176Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Applies to src/boundaries/env-parser.ts : All environment variables must be validated via Zod schemas in `src/boundaries/env-parser.ts`
Applied to files:
src/schemas/preset-schemas.ts
📚 Learning: 2025-12-28T19:43:51.176Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Applies to src/**/*.ts : Maintain strict TypeScript with no `any`; use `unknown` + schema validation for external data
Applied to files:
src/schemas/preset-schemas.ts
📚 Learning: 2025-12-28T19:43:51.176Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Recursively load all `.md` files from within each rule pack; multiple packs can be used simultaneously
Applied to files:
src/boundaries/rule-pack-loader.tssrc/cli/commands.tstests/rule-pack-e2e.test.tssrc/prompts/prompt-loader.tssrc/cli/validate-command.tstests/rule-pack-loader.test.ts
📚 Learning: 2025-12-28T19:43:51.176Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Organize rules into subdirectories (packs) within RulesPath; use company names (e.g., Acme, TechCorp, Stripe) to indicate which style guide the rules implement
Applied to files:
src/boundaries/rule-pack-loader.tssrc/cli/commands.tstests/rule-pack-e2e.test.tssrc/cli/validate-command.tssrc/cli/orchestrator.ts
📚 Learning: 2025-12-28T19:43:51.176Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Applies to src/output/**/*.ts : IDs should be shown as `PromptId.CriterionId` in output
Applied to files:
tests/prompt-loader-validation.test.tstests/target.test.tstests/evaluator.test.tssrc/cli/types.tssrc/cli/orchestrator.tstests/validator.test.ts
📚 Learning: 2025-12-28T19:43:51.176Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Applies to tests/**/*.test.ts : Write tests using Vitest framework with focus on config parsing, file discovery, schema/structured output, and locator
Applied to files:
tests/prompt-loader-validation.test.tstests/target.test.tstests/rule-pack-e2e.test.tstests/preset-loader.test.tstests/rule-pack-loader.test.tstests/validator.test.ts
📚 Learning: 2025-12-28T19:43:51.176Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Keep directories cohesive; maintain acyclic dependencies (CLI → prompts/providers/output); optimize for discoverability
Applied to files:
tests/target.test.tstests/evaluator.test.tssrc/cli/commands.tstests/validator.test.ts
📚 Learning: 2025-12-28T19:43:51.176Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Applies to evals/**/*.md : Evals must include YAML frontmatter; the tool appends evidence instructions automatically
Applied to files:
tests/rule-pack-loader.test.ts
🧬 Code graph analysis (12)
src/boundaries/rule-pack-loader.ts (1)
src/config/preset-loader.ts (1)
PresetLoader(5-52)
tests/prompt-loader-validation.test.ts (1)
src/prompts/prompt-loader.ts (1)
loadRules(88-129)
tests/target.test.ts (1)
src/prompts/prompt-loader.ts (1)
loadRules(88-129)
tests/evaluator.test.ts (1)
src/prompts/prompt-loader.ts (1)
loadRules(88-129)
src/cli/commands.ts (3)
src/config/preset-loader.ts (1)
PresetLoader(5-52)src/boundaries/rule-pack-loader.ts (1)
RulePackLoader(12-92)src/prompts/prompt-loader.ts (1)
loadRuleFile(10-86)
tests/rule-pack-e2e.test.ts (2)
src/boundaries/rule-pack-loader.ts (1)
RulePackLoader(12-92)src/boundaries/scan-path-resolver.ts (1)
ScanPathResolver(18-72)
src/config/preset-loader.ts (1)
src/schemas/preset-schemas.ts (2)
PresetRegistry(12-12)PRESET_REGISTRY_SCHEMA(8-10)
tests/preset-loader.test.ts (1)
src/config/preset-loader.ts (1)
PresetLoader(5-52)
src/prompts/prompt-loader.ts (1)
src/schemas/prompt-schemas.ts (1)
PromptFile(64-64)
src/cli/validate-command.ts (3)
src/config/preset-loader.ts (1)
PresetLoader(5-52)src/boundaries/rule-pack-loader.ts (1)
RulePackLoader(12-92)src/prompts/prompt-loader.ts (1)
loadRuleFile(10-86)
tests/rule-pack-loader.test.ts (2)
src/boundaries/rule-pack-loader.ts (1)
RulePackLoader(12-92)src/config/preset-loader.ts (1)
PresetLoader(5-52)
tests/validator.test.ts (1)
src/prompts/prompt-loader.ts (1)
loadRules(88-129)
🪛 LanguageTool
presets/VectorLint/ai-pattern.md
[style] ~32-~32: This phrase is redundant. Consider using “outside”.
Context: ...ze. #### Important - Do not flag words outside of this list. ### 2. Negation Constrast F...
(OUTSIDE_OF)
[grammar] ~34-~34: Ensure spelling is correct
Context: ... outside of this list. ### 2. Negation Constrast Flag sentence that use artificial negati...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
presets/VectorLint/repetition.md
[grammar] ~26-~26: Ensure spelling is correct
Context: ...B'" which buries the section names. ## CRITERIA ### UNNECESSARY SECTION REPETITION Flag eve...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[style] ~37-~37: The words ‘Explanations’ and ‘explained’ are quite similar. Consider replacing ‘explained’ with a different word.
Context: ...dundant Explanations**: A concept fully explained in one section is explained again later...
(VERB_NOUN_SENT_LEVEL_REP)
[style] ~39-~39: ‘exact same’ might be wordy. Consider a shorter alternative.
Context: ...ctions use examples that illustrate the exact same point without revealing new dimensions ...
(EN_WORDINESS_PREMIUM_EXACT_SAME)
tests/fixtures/ai-pattern/negation-pattern.md
[grammar] ~82-~82: Ensure spelling is correct
Context: ... mind investing time in configuration. Greptile 4. Greptile (Best for Deep Context and RAG)...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[style] ~85-~85: Consider a different adjective to strengthen your wording.
Context: ...ation. Greptile 4. Greptile (Best for Deep Context and RAG) Category: Specialized ...
(DEEP_PROFOUND)
[style] ~90-~90: Consider a different adjective to strengthen your wording.
Context: ... uses this context to provide unusually deep analysis. When reviewing a PR, Greptile...
(DEEP_PROFOUND)
[style] ~155-~155: To elevate your writing, try using more descriptive phrasing here.
Context: ...repo querying: Choose Greptile. If your biggest challenge is understanding how changes ...
(BIGGEST_CHALLENGE)
🪛 markdownlint-cli2 (0.18.1)
presets/VectorLint/ai-pattern.md
81-81: Heading style
Expected: atx; Actual: setext
(MD003, heading-style)
tests/fixtures/ai-pattern/negation-pattern.md
145-145: Hard tabs
Column: 5
(MD010, no-hard-tabs)
145-145: Hard tabs
Column: 19
(MD010, no-hard-tabs)
145-145: Hard tabs
Column: 37
(MD010, no-hard-tabs)
145-145: Hard tabs
Column: 51
(MD010, no-hard-tabs)
146-146: Hard tabs
Column: 15
(MD010, no-hard-tabs)
146-146: Hard tabs
Column: 49
(MD010, no-hard-tabs)
146-146: Hard tabs
Column: 76
(MD010, no-hard-tabs)
146-146: Hard tabs
Column: 91
(MD010, no-hard-tabs)
147-147: Hard tabs
Column: 15
(MD010, no-hard-tabs)
147-147: Hard tabs
Column: 49
(MD010, no-hard-tabs)
147-147: Hard tabs
Column: 65
(MD010, no-hard-tabs)
147-147: Hard tabs
Column: 91
(MD010, no-hard-tabs)
148-148: Hard tabs
Column: 11
(MD010, no-hard-tabs)
148-148: Hard tabs
Column: 32
(MD010, no-hard-tabs)
148-148: Hard tabs
Column: 50
(MD010, no-hard-tabs)
148-148: Hard tabs
Column: 68
(MD010, no-hard-tabs)
149-149: Hard tabs
Column: 9
(MD010, no-hard-tabs)
149-149: Hard tabs
Column: 38
(MD010, no-hard-tabs)
149-149: Hard tabs
Column: 60
(MD010, no-hard-tabs)
149-149: Hard tabs
Column: 75
(MD010, no-hard-tabs)
150-150: Hard tabs
Column: 9
(MD010, no-hard-tabs)
150-150: Hard tabs
Column: 38
(MD010, no-hard-tabs)
150-150: Hard tabs
Column: 65
(MD010, no-hard-tabs)
150-150: Hard tabs
Column: 80
(MD010, no-hard-tabs)
151-151: Hard tabs
Column: 7
(MD010, no-hard-tabs)
151-151: Hard tabs
Column: 30
(MD010, no-hard-tabs)
151-151: Hard tabs
Column: 64
(MD010, no-hard-tabs)
151-151: Hard tabs
Column: 94
(MD010, no-hard-tabs)
🔇 Additional comments (27)
presets/VectorLint/pseudo-advice.md (1)
1-158: Well-structured preset with comprehensive guidance.The Pseudo-Advice Detector preset is thorough and well-organized:
- Clear metadata with appropriate semi-objective type and strictness
- Systematic instruction workflow for evaluators
- Concrete examples with AVOID/BETTER patterns
- Explicit "When Acceptable" guidance reduces false positives
tests/fixtures/ai-pattern/buzzword.md (1)
1-7: Appropriate test fixture for AI-pattern detection.This fixture effectively contains marketing buzzwords and AI-pattern language ("leverages", "revolutionize", "harness", "game-changers", "delve into deeper areas") that should trigger the VectorLint AI-pattern preset for testing purposes.
tests/validator.test.ts (1)
5-5: API migration to loadRules looks correct.The update from
loadPromptstoloadRulesis consistently applied across all test cases in this file, aligning with the refactored API surface.Also applies to: 31-31, 53-53
tests/fixtures/ai-pattern/test.md (1)
1-1: LGTM: Compact test fixture for AI-pattern detection.This fixture provides a condensed example of marketing language with buzzwords for testing the AI-pattern preset.
src/cli/types.ts (1)
94-101: All call sites correctly provide the packName field.Verification confirms that
ProcessCriterionParamshas been properly updated withpackNameas a required field. The single call site atsrc/cli/orchestrator.ts:577correctly provides all required fields includingpackName: promptFile.pack, which is then used inbuildRuleName()at line 236. No additional changes needed.src/schemas/prompt-schemas.ts (1)
57-57: No action needed. Thepackfield is correctly required because it is always assigned by theloadRuleFile()function based on thepackNameparameter, regardless of rule file content. The field is never sourced from external data or constructed conditionally—every code path that creates aPromptFileobject explicitly provides a pack value. Making the field required in the schema accurately reflects the actual runtime guarantee.presets/meta.json (1)
1-8: LGTM!The preset registry structure is valid and aligns with the
PRESET_REGISTRY_SCHEMA. The relative path will be correctly resolved byPresetLoader.getPresetPath().tests/target.test.ts (1)
5-5: LGTM!The API rename from
loadPromptstoloadRulesis correctly applied. The test logic remains unchanged and continues to validate target gating behavior appropriately.Also applies to: 13-13
tests/prompt-loader-validation.test.ts (1)
2-2: LGTM!All
loadPrompts→loadRulesrenames are consistently applied. The test coverage for prompt validation scenarios remains intact.Also applies to: 37-37, 52-52, 69-69, 82-82, 95-95, 111-111, 127-127
tests/evaluator.test.ts (1)
5-5: LGTM!The API rename is correctly applied, and the evaluation aggregation test continues to verify that all prompts are processed for all files.
Also applies to: 43-43
tests/preset-loader.test.ts (1)
1-95: LGTM!Comprehensive test coverage for
PresetLoaderincluding:
- Empty/missing registry handling
- Parsing and listing presets from
meta.json- Relative and absolute path resolution
- Error handling for invalid JSON and schema violations
The tests follow Vitest conventions and cover the key behaviors of the preset loading system.
src/schemas/preset-schemas.ts (1)
3-6: LGTM!The schema correctly defines the preset entry structure with Zod validation, aligning with boundary validation guidelines. The optional
descriptionfield provides flexibility while keepingpathrequired.src/prompts/prompt-loader.ts (2)
10-10: LGTM!The signature change from optional to required
packNameparameter enforces explicit pack identification. The returnedPromptFilenow includes thepackfield, enabling proper rule attribution in the preset/user rule shadowing system.Also applies to: 72-81
88-129: LGTM!The renamed
loadRulesfunction maintains backward compatibility by using'Default'as the pack name for simple directory-based loading. Error handling follows the strict TypeScript pattern withunknowntype and properinstanceofchecks.presets/VectorLint/directness.md (1)
1-11: Well-structured frontmatter and criteria definition.The YAML frontmatter is properly formatted with all required fields (
specVersion,type,severity,strictness,name,id,criteria). The criterionOpeningDirectnessis well-defined with bothnameandidfields.tests/rule-pack-loader.test.ts (2)
17-21: Mock PresetLoader implementation looks good.The mock correctly implements all three methods of the PresetLoader interface (
getAvailablePresets,getPresetPath,loadRegistry). The type assertion toPresetLoaderis appropriate for testing purposes.
76-92: Excellent test for shadowing behavior.This test correctly verifies the critical shadowing logic where user packs override presets with the same name. The assertions properly check that
isPresetisfalseand the path points to the user directory.src/config/preset-loader.ts (1)
16-32: Lazy-loading registry with proper validation.The implementation correctly:
- Uses early return for memoization
- Handles missing
meta.jsongracefully with an empty registry- Uses
unknowntype for parsed JSON and validates with Zod schema- Wraps errors with context message
This aligns well with the coding guidelines for boundary validation.
src/cli/commands.ts (1)
21-22: Correct ESM__dirnamederivation.The pattern using
fileURLToPath(import.meta.url)anddirname()is the standard approach for obtaining__dirnamein ESM modules. This is necessary for the presets path resolution.src/boundaries/rule-pack-loader.ts (1)
25-61: Clean implementation of pack shadowing with Map.The shadowing logic is well-implemented:
- Presets loaded first (lowest priority)
- User packs overwrite matching keys (highest priority)
- Graceful error handling when user path doesn't exist
This matches the PR objective of allowing user rules to override presets.
src/cli/validate-command.ts (1)
15-16: Consistent ESM__dirnamepattern.Same correct pattern as in
commands.tsfor deriving__dirnamein ESM modules.tests/rule-pack-e2e.test.ts (2)
74-76: Updated test correctly uses new RulePackLoader API.The test properly instantiates
RulePackLoaderwithout aPresetLoader(testing user-only packs scenario) and extracts pack names from the returned objects for compatibility withScanPathResolver.
83-88: Good verification of pack object structure.The test correctly verifies both the pack object retrieval (
packs.find(p => p.name === 'VectorLint')) and theisPresetflag. Usingpack.pathforfindRuleFilesaligns with the new API contract.src/cli/orchestrator.ts (4)
30-45: LGTM!Clean helper function that constructs hierarchical rule names following the documented pattern. The conditional inclusion of
criterionIdis handled correctly, and the implementation aligns well with the new pack-scoped naming scheme that extends the existingPromptId.CriterionIdpattern with pack context. Based on learnings, the original pattern wasPromptId.CriterionId; this now correctly prefixes withPackName.
576-588: LGTM!The subjective path correctly propagates
packNamefrompromptFile.packtoextractAndReportCriterion, maintaining consistency with the semi-objective path and enabling hierarchical rule naming for all criteria.
229-236: LGTM!The
packNameis correctly destructured and used to construct the hierarchical rule name viabuildRuleName. This properly integrates the pack context into criterion-level reporting.
487-561: LGTM!The refactored semi-objective path correctly:
- Groups violations by
criterionNamefor per-criterion reporting- Looks up
criterionIdfrommeta.criteriawith proper optional chaining- Constructs hierarchical rule names via
buildRuleName- Accumulates errors/warnings per group and returns the totals
The non-null assertion on line 494 is safe since the entry is created immediately before access. The
PromptFileinterface includes thepackproperty as a string, making its use inbuildRuleNamevalid.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
package.json (1)
21-25: Critical: Add "presets" directory to the files array.The PR introduces bundled rule packs in the
presets/directory, but this directory is not included in thefilesarray. This means the presets will not be published with the npm package, breaking the core feature of this PR.🔎 Proposed fix
"files": [ "dist", + "presets", "README.md", "LICENSE.md" ],
🧹 Nitpick comments (4)
src/cli/commands.ts (1)
23-24: ESLint naming convention violation for ESM compatibility variables.The
__filenameand__dirnamevariables violate the project'sUPPER_CASEnaming rule for module-level constants. This is a common ESM compatibility pattern, but the linter flags it. Consider either:
- Suppressing the lint rule for these specific lines, or
- Renaming to follow the convention (e.g.,
CURRENT_FILE,CURRENT_DIR)Option 1: Suppress lint rule (recommended for clarity)
-const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); +// eslint-disable-next-line @typescript-eslint/naming-convention +const __filename = fileURLToPath(import.meta.url); +// eslint-disable-next-line @typescript-eslint/naming-convention +const __dirname = dirname(__filename);package.json (1)
39-39: Reconsider the "vectorlint.ini.example" keyword.This appears to be a filename rather than a searchable keyword. Keywords should be generic terms that help users discover the package (e.g., "configuration", "ini-file"). Consider whether this specific filename adds value for package discovery.
tests/rule-pack-e2e.test.ts (2)
10-10: Update the test suite name to reflect new terminology.The suite name still references "Eval Pack System" but the codebase has migrated to "Rule Pack" terminology for consistency.
🔎 Proposed fix
-describe('Eval Pack System End-to-End', () => { +describe('Rule Pack System End-to-End', () => {
75-89: Consider testing preset integration in the end-to-end workflow.The
RulePackLoaderis instantiated without aPresetLoader, so these tests only exercise user pack loading. Since the PR's core feature is preset support with shadowing behavior, consider adding a test case that:
- Instantiates
RulePackLoaderwith aPresetLoader- Verifies preset packs are discovered alongside user packs
- Validates that user packs shadow presets with the same name
This would provide end-to-end coverage of the preset workflow described in the PR objectives.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
package.jsonsrc/cli/commands.tssrc/cli/orchestrator.tssrc/cli/types.tstests/rule-pack-e2e.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/cli/types.ts
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.ts: Use TypeScript ESM with explicit imports and narrow types
Use 2-space indentation; avoid trailing whitespace
Maintain strict TypeScript with noany; useunknown+ schema validation for external data
Use custom error types with proper inheritance; catch blocks useunknowntype
Files:
src/cli/commands.tssrc/cli/orchestrator.ts
tests/**/*.test.ts
📄 CodeRabbit inference engine (AGENTS.md)
tests/**/*.test.ts: Write tests using Vitest framework with focus on config parsing, file discovery, schema/structured output, and locator
Use dependency injection in tests: mock providers; do not hit network in unit tests
Files:
tests/rule-pack-e2e.test.ts
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Organize rules into subdirectories (packs) within RulesPath; use company names (e.g., Acme, TechCorp, Stripe) to indicate which style guide the rules implement
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Recursively load all `.md` files from within each rule pack; multiple packs can be used simultaneously
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Applies to .vectorlint.ini : Use `[glob/pattern]` sections in `.vectorlint.ini` to specify which packs run on which files
📚 Learning: 2025-12-28T19:43:51.176Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Recursively load all `.md` files from within each rule pack; multiple packs can be used simultaneously
Applied to files:
src/cli/commands.tstests/rule-pack-e2e.test.ts
📚 Learning: 2025-12-28T19:43:51.176Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Keep directories cohesive; maintain acyclic dependencies (CLI → prompts/providers/output); optimize for discoverability
Applied to files:
src/cli/commands.ts
📚 Learning: 2025-12-28T19:43:51.176Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Organize rules into subdirectories (packs) within RulesPath; use company names (e.g., Acme, TechCorp, Stripe) to indicate which style guide the rules implement
Applied to files:
src/cli/commands.tstests/rule-pack-e2e.test.tssrc/cli/orchestrator.ts
📚 Learning: 2025-12-28T19:43:51.176Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Applies to .vectorlint.ini : Use `[glob/pattern]` sections in `.vectorlint.ini` to specify which packs run on which files
Applied to files:
package.json
📚 Learning: 2025-12-28T19:43:51.176Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Applies to tests/**/*.test.ts : Write tests using Vitest framework with focus on config parsing, file discovery, schema/structured output, and locator
Applied to files:
tests/rule-pack-e2e.test.ts
📚 Learning: 2025-12-28T19:43:51.176Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.176Z
Learning: Applies to src/output/**/*.ts : IDs should be shown as `PromptId.CriterionId` in output
Applied to files:
src/cli/orchestrator.ts
🧬 Code graph analysis (2)
src/cli/commands.ts (3)
src/config/preset-loader.ts (1)
PresetLoader(5-52)src/boundaries/rule-pack-loader.ts (1)
RulePackLoader(12-92)src/prompts/prompt-loader.ts (1)
loadRuleFile(10-86)
tests/rule-pack-e2e.test.ts (2)
src/boundaries/rule-pack-loader.ts (1)
RulePackLoader(12-92)src/boundaries/scan-path-resolver.ts (1)
ScanPathResolver(18-72)
🪛 GitHub Check: ESLint
src/cli/commands.ts
[failure] 24-24:
Variable name __dirname must match one of the following formats: UPPER_CASE
[failure] 23-23:
Variable name __filename must match one of the following formats: UPPER_CASE
🔇 Additional comments (6)
src/cli/commands.ts (1)
116-136: LGTM! Clean integration of preset-aware rule loading.The iteration logic correctly:
- Uses
listAllPacksto get merged preset + user packs- Iterates using
pack.pathandpack.namefrom the resolved pack objects- Passes
pack.nametoloadRuleFilefor hierarchical namingThis aligns with the learnings about organizing rules into subdirectories (packs) and recursively loading
.mdfiles from each pack.src/cli/orchestrator.ts (5)
36-51: LGTM! Clean hierarchical rule name construction.The
buildRuleNamehelper correctly implements thePackName.RuleId.CriterionIdpattern documented in the learnings. The conditional inclusion ofcriterionIdhandles both criterion-specific and rule-level naming appropriately.
570-614: Well-structured grouped violation reporting.The grouping logic correctly:
- Groups violations by
criterionName(includingundefinedfor ungrouped)- Looks up
criterionIdfrom meta criteria for proper naming- Uses
buildRuleNameto construct hierarchical rule names per group- Accumulates error/warning counts per group
One minor observation: the non-null assertion on line 577 (
violationsByCriterion.get(criterionName)!) is safe given the precedinghas()check, but a singleMap.getwith fallback could be marginally cleaner.Optional: Slightly cleaner pattern without non-null assertion
for (const v of result.violations) { const criterionName = v.criterionName; - if (!violationsByCriterion.has(criterionName)) { - violationsByCriterion.set(criterionName, []); - } - violationsByCriterion.get(criterionName)!.push(v); + const group = violationsByCriterion.get(criterionName) ?? []; + group.push(v); + violationsByCriterion.set(criterionName, group); }
265-287: Correct integration ofpackNamefor criterion-level rule naming.The
packNameis properly destructured from params and used inbuildRuleNameto produce the hierarchicalPackName.RuleId.CriterionIdformat. This aligns with the output format requirements from the learnings (PromptId.CriterionId→ now extended to include pack scope).
668-675: Correctly threadspackNamethrough subjective evaluation path.The
promptFile.packis passed aspackNametoextractAndReportCriterion, ensuring consistent hierarchical naming across both semi-objective and subjective result processing paths.
633-645: Unable to verify the review comment due to repository access failure. Please provide the contents ofsrc/cli/orchestrator.tsor grant access to the repository to complete the verification.
- Add presets/ to package.json files array for npm publishing - Fix presetsDir path in commands.ts (../../presets → ../presets) - Fix presetsDir path in validate-command.ts (../../presets → ../presets)
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/cli/validate-command.ts (1)
63-65: Incorrect presets directory path resolution.Same issue as in
src/cli/commands.tsline 112: the path../presetsresolves incorrectly for npm-installed packages. When compiled todist/cli/validate-command.js, this will resolve to<packageRoot>/dist/presetsinstead of<packageRoot>/presets.🔎 Fix: Use correct relative path
- const presetsDir = path.resolve(__dirname, '../presets'); + const presetsDir = path.resolve(__dirname, '../../presets');
🧹 Nitpick comments (2)
src/cli/commands.ts (2)
23-24: ESLint naming warnings are false positives.The ESLint warnings about
__filenameand__dirnamenot matching UPPER_CASE format can be safely ignored. These are conventional Node.js identifiers, and using different names would harm readability. Consider adding an ESLint suppression comment if the warnings are disruptive.💡 Optional: suppress ESLint warnings
+// eslint-disable-next-line @typescript-eslint/naming-convention const __filename = fileURLToPath(import.meta.url); +// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = dirname(__filename);
112-136: Consider extracting preset loader initialization.The preset loader initialization pattern (lines 112-114) is duplicated in
src/cli/validate-command.ts(lines 63-65). Consider extracting this into a shared helper function to improve maintainability.💡 Example helper function
Create a new file
src/cli/preset-helpers.ts:import * as path from 'path'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; import { PresetLoader } from '../config/preset-loader'; import { RulePackLoader } from '../boundaries/rule-pack-loader'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); export function createRulePackLoader(): RulePackLoader { const presetsDir = path.resolve(__dirname, '../../presets'); const presetLoader = new PresetLoader(presetsDir); return new RulePackLoader(presetLoader); }Then use it in both command files:
- const presetsDir = path.resolve(__dirname, '../presets'); - const presetLoader = new PresetLoader(presetsDir); - const loader = new RulePackLoader(presetLoader); + const loader = createRulePackLoader();
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
package.jsonsrc/cli/commands.tssrc/cli/validate-command.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- package.json
🧰 Additional context used
📓 Path-based instructions (1)
src/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.ts: Use TypeScript ESM with explicit imports and narrow types
Use 2-space indentation; avoid trailing whitespace
Maintain strict TypeScript with noany; useunknown+ schema validation for external data
Use custom error types with proper inheritance; catch blocks useunknowntype
Files:
src/cli/commands.tssrc/cli/validate-command.ts
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Organize rules into subdirectories (packs) within RulesPath; use company names (e.g., Acme, TechCorp, Stripe) to indicate which style guide the rules implement
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Recursively load all `.md` files from within each rule pack; multiple packs can be used simultaneously
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Applies to .vectorlint.ini : Use `[glob/pattern]` sections in `.vectorlint.ini` to specify which packs run on which files
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Recursively load all `.md` files from within each rule pack; multiple packs can be used simultaneously
Applied to files:
src/cli/commands.tssrc/cli/validate-command.ts
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Keep directories cohesive; maintain acyclic dependencies (CLI → prompts/providers/output); optimize for discoverability
Applied to files:
src/cli/commands.ts
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Organize rules into subdirectories (packs) within RulesPath; use company names (e.g., Acme, TechCorp, Stripe) to indicate which style guide the rules implement
Applied to files:
src/cli/commands.tssrc/cli/validate-command.ts
🧬 Code graph analysis (2)
src/cli/commands.ts (3)
src/config/preset-loader.ts (1)
PresetLoader(5-52)src/boundaries/rule-pack-loader.ts (1)
RulePackLoader(12-92)src/prompts/prompt-loader.ts (1)
loadRuleFile(10-86)
src/cli/validate-command.ts (3)
src/config/preset-loader.ts (1)
PresetLoader(5-52)src/boundaries/rule-pack-loader.ts (1)
RulePackLoader(12-92)src/prompts/prompt-loader.ts (1)
loadRuleFile(10-86)
🪛 GitHub Check: ESLint
src/cli/commands.ts
[failure] 24-24:
Variable name __dirname must match one of the following formats: UPPER_CASE
[failure] 23-23:
Variable name __filename must match one of the following formats: UPPER_CASE
src/cli/validate-command.ts
[failure] 16-16:
Variable name __dirname must match one of the following formats: UPPER_CASE
[failure] 15-15:
Variable name __filename must match one of the following formats: UPPER_CASE
🔇 Additional comments (4)
src/cli/commands.ts (2)
4-5: LGTM! Proper ESM compatibility imports.These imports enable
__dirnameresolution in ESM modules, which is necessary for locating the presets directory relative to the compiled module location.
116-136: LGTM! Proper pack loading with preset shadowing support.The refactored pack loading correctly uses
listAllPacks()and threadspack.namethrough toloadRuleFile(), enabling the hierarchical rule naming scheme (PackName.RuleId.CriterionId) mentioned in the PR objectives.src/cli/validate-command.ts (2)
10-11: ESM compatibility correctly implemented; ESLint warnings are false positives.The ESM
__dirnameresolution is correctly implemented. The ESLint naming convention warnings can be safely ignored or suppressed as these are conventional Node.js identifiers.Also applies to: 15-16
67-83: LGTM! Consistent pack loading implementation.The validate command now correctly uses the refactored
RulePackLoaderwith preset support, maintaining consistency with the main command implementation.
- Make rulesPath optional in config schema (presets can provide rules) - Remove duplicate validation from config-loader.ts (schema is now single source of truth) - Update commands.ts and validate-command.ts to handle optional rulesPath - Update file-resolver.ts to skip rules exclusion when rulesPath is undefined - Update rule-pack-loader.ts to accept undefined userRulesPath - Rename vectorlint.ini.example to .vectorlint.ini.example and update with optional RulesPath instructions
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
src/cli/commands.ts (1)
113-113: Fix incorrect presets directory path resolution.The path resolution
'../presets'is incorrect for compiled code. When this file compiles todist/cli/commands.js,__dirnamebecomes<packageRoot>/dist/cli, sopath.resolve(__dirname, '../presets')resolves to<packageRoot>/dist/presets, which doesn't exist. The presets directory is at<packageRoot>/presets.This issue was flagged in a previous review but appears unresolved despite being marked as addressed in commit c5a2a91.
🔎 Fix: Use correct relative path to package root
- const presetsDir = path.resolve(__dirname, '../presets'); + const presetsDir = path.resolve(__dirname, '../../presets');This ensures that from
dist/cli/, going up two levels (../../) reaches the package root wherepresets/is located.Run the following script to verify the presets directory location and package.json configuration:
#!/bin/bash # Verify presets directory structure and packaging configuration echo "=== Checking presets directory exists at package root ===" ls -la presets/ 2>/dev/null || echo "ERROR: presets/ directory not found at package root" echo "" echo "=== Checking package.json files array includes presets ===" cat package.json | jq '.files' | grep -q '"presets"' && echo "✓ presets included in package.json" || echo "ERROR: presets not in package.json files array" echo "" echo "=== Checking compiled output structure ===" ls -la dist/cli/commands.js 2>/dev/null && echo "✓ Compiled file exists at dist/cli/commands.js" || echo "Note: Run build first to verify compiled structure"
🧹 Nitpick comments (2)
src/cli/commands.ts (1)
23-24: Consider suppressing ESLint rule for conventional Node.js variables.The variables
__filenameand__dirnameare conventional names in Node.js/ESM for module metadata. While ESLint expectsUPPER_CASEfor module-level constants, these specific names are idiomatic and widely recognized.🔎 Option 1: Suppress the rule inline (recommended)
+// eslint-disable-next-line @typescript-eslint/naming-convention const __filename = fileURLToPath(import.meta.url); +// eslint-disable-next-line @typescript-eslint/naming-convention const __dirname = dirname(__filename);🔎 Option 2: Rename to follow convention (less idiomatic)
-const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); +const CURRENT_FILENAME = fileURLToPath(import.meta.url); +const CURRENT_DIRNAME = dirname(CURRENT_FILENAME);Then update usage at Line 113.
src/cli/validate-command.ts (1)
15-16: Configure ESLint to allow Node.js ESM convention variables.
__filenameand__dirnameare the standard names used when replicating CommonJS globals in Node.js ESM modules (per Node.js documentation). The@typescript-eslint/naming-conventionrule currently flags these as violations.Add a filter exception to
eslint.config.mjsin the@typescript-eslint/naming-conventionrule:Configuration fix
{ selector: "variable", format: ["camelCase", "UPPER_CASE"], filter: { regex: "^__(filename|dirname)$", match: false } },Insert this as the first selector in the naming-convention array (before the existing variable rules).
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
.vectorlint.ini.examplesrc/boundaries/config-loader.tssrc/boundaries/rule-pack-loader.tssrc/cli/commands.tssrc/cli/types.tssrc/cli/validate-command.tssrc/scan/file-resolver.tssrc/schemas/config-schemas.ts
✅ Files skipped from review due to trivial changes (1)
- .vectorlint.ini.example
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.ts: Use TypeScript ESM with explicit imports and narrow types
Use 2-space indentation; avoid trailing whitespace
Maintain strict TypeScript with noany; useunknown+ schema validation for external data
Use custom error types with proper inheritance; catch blocks useunknowntype
Files:
src/cli/types.tssrc/boundaries/rule-pack-loader.tssrc/cli/commands.tssrc/boundaries/config-loader.tssrc/scan/file-resolver.tssrc/schemas/config-schemas.tssrc/cli/validate-command.ts
src/boundaries/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Use Zod schemas for boundary validation of all external data (files, CLI, env, APIs) at system boundaries
Files:
src/boundaries/rule-pack-loader.tssrc/boundaries/config-loader.ts
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Organize rules into subdirectories (packs) within RulesPath; use company names (e.g., Acme, TechCorp, Stripe) to indicate which style guide the rules implement
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Recursively load all `.md` files from within each rule pack; multiple packs can be used simultaneously
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Applies to src/output/**/*.ts : IDs should be shown as `PromptId.CriterionId` in output
Applied to files:
src/cli/types.ts
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Recursively load all `.md` files from within each rule pack; multiple packs can be used simultaneously
Applied to files:
src/boundaries/rule-pack-loader.tssrc/cli/commands.tssrc/cli/validate-command.ts
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Organize rules into subdirectories (packs) within RulesPath; use company names (e.g., Acme, TechCorp, Stripe) to indicate which style guide the rules implement
Applied to files:
src/boundaries/rule-pack-loader.tssrc/cli/commands.tssrc/cli/validate-command.ts
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Keep directories cohesive; maintain acyclic dependencies (CLI → prompts/providers/output); optimize for discoverability
Applied to files:
src/cli/commands.ts
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Applies to src/boundaries/**/*.ts : Use Zod schemas for boundary validation of all external data (files, CLI, env, APIs) at system boundaries
Applied to files:
src/boundaries/config-loader.tssrc/schemas/config-schemas.ts
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Applies to src/boundaries/env-parser.ts : All environment variables must be validated via Zod schemas in `src/boundaries/env-parser.ts`
Applied to files:
src/schemas/config-schemas.ts
🧬 Code graph analysis (4)
src/boundaries/rule-pack-loader.ts (1)
src/config/preset-loader.ts (1)
PresetLoader(5-52)
src/cli/commands.ts (4)
src/prompts/prompt-loader.ts (2)
PromptFile(8-8)loadRuleFile(10-86)src/schemas/prompt-schemas.ts (1)
PromptFile(64-64)src/config/preset-loader.ts (1)
PresetLoader(5-52)src/boundaries/rule-pack-loader.ts (1)
RulePackLoader(12-95)
src/scan/file-resolver.ts (1)
src/boundaries/file-section-parser.ts (1)
FilePatternConfig(2-6)
src/cli/validate-command.ts (3)
src/config/preset-loader.ts (1)
PresetLoader(5-52)src/boundaries/rule-pack-loader.ts (1)
RulePackLoader(12-95)src/prompts/prompt-loader.ts (1)
loadRuleFile(10-86)
🪛 GitHub Actions: Lint
src/boundaries/rule-pack-loader.ts
[error] 49-49: Command 'npm run lint' failed. ESLint: 'e' is defined but never used. (@typescript-eslint/no-unused-vars)
🪛 GitHub Check: ESLint
src/boundaries/rule-pack-loader.ts
[failure] 49-49:
'e' is defined but never used
src/cli/commands.ts
[failure] 24-24:
Variable name __dirname must match one of the following formats: UPPER_CASE
[failure] 23-23:
Variable name __filename must match one of the following formats: UPPER_CASE
src/cli/validate-command.ts
[failure] 16-16:
Variable name __dirname must match one of the following formats: UPPER_CASE
[failure] 15-15:
Variable name __filename must match one of the following formats: UPPER_CASE
🔇 Additional comments (9)
src/boundaries/config-loader.ts (1)
136-158: LGTM! Optional rulesPath implemented correctly.The implementation correctly handles optional
rulesPathby conditionally resolving the path only when provided, otherwise setting it toundefined. The logic properly handles both absolute and relative paths, and the comment clearly documents the optionality.src/cli/types.ts (2)
23-23: LGTM! Type correctly updated for optional rulesPath.The type change from
stringtostring | undefinedcorrectly reflects that rulesPath is now optional, aligning with the preset-driven rule loading approach.
90-90: LGTM! packName field supports hierarchical rule naming.The addition of
packName: stringenables the orchestrator to construct hierarchical rule names (e.g.,packName.ruleId.criterionId) for proper rule identification and reporting across preset and user-defined packs.src/schemas/config-schemas.ts (1)
5-5: LGTM! Schema correctly updated for optional rulesPath.The Zod schema properly makes
rulesPathoptional while maintaining validation requirements (min length 1 when present). This aligns with the boundary validation requirements and supports the preset-driven configuration approach.src/boundaries/rule-pack-loader.ts (2)
6-10: LGTM! ResolvedPack interface is well-defined.The interface clearly captures pack metadata with
name,path, andisPresetflag, supporting the preset shadowing logic and enabling callers to distinguish between preset and user-defined packs.
71-94: LGTM! File discovery logic is robust.The recursive directory scanning correctly identifies all
.mdrule files and provides clear error messages when the pack directory is inaccessible.src/cli/commands.ts (2)
105-109: LGTM! Correctly guards rulesPath existence check.The conditional check ensures the existence validation only runs when
rulesPathis provided, properly supporting the preset-only configuration scenario.
117-145: LGTM! Preset and user pack loading logic is well-structured.The implementation correctly:
- Loads both presets and user packs via
RulePackLoader- Provides helpful warnings when no packs are found
- Iterates through resolved packs using the pack object structure
- Loads rules with proper pack name context
- Handles the case where no rules are found with clear error messages
src/scan/file-resolver.ts (1)
12-64: LGTM! Optional rulesPath handling is well-implemented.The changes correctly handle the optional
rulesPathparameter throughout the function:
- Conditional exclusion of the rules subtree (lines 21-25)
- Proper guarding in the filtering logic (lines 60-61)
- Updated CLI argument handling with cleaner
existsSynccheck instead of try/catch- Correct extraction of
.patternfromFilePatternConfigobjects (line 49)The removal of the extension check at line 38 is safe because the deduplication step (lines 55-63) filters out disallowed extensions.
- Resolve --evals CLI path to absolute before use (config paths already absolute) - Remove unreachable duplicate prompts.length === 0 check after try block
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/cli/validate-command.ts (1)
15-16: Inline the directory resolution to fix ESLint violations.ESLint flags
__filenameand__dirnamefor not matching UPPER_CASE convention. Since these are used only once (line 66), inline the computation directly to eliminate the violation and reduce unnecessary variables.🔎 Proposed refactor to inline directory resolution
-const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); - /* * Registers the 'validate' command with Commander.Then on line 66:
- const presetsDir = path.resolve(__dirname, '../presets'); + const presetsDir = path.resolve(dirname(fileURLToPath(import.meta.url)), '../presets');
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/cli/validate-command.ts
🧰 Additional context used
📓 Path-based instructions (1)
src/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.ts: Use TypeScript ESM with explicit imports and narrow types
Use 2-space indentation; avoid trailing whitespace
Maintain strict TypeScript with noany; useunknown+ schema validation for external data
Use custom error types with proper inheritance; catch blocks useunknowntype
Files:
src/cli/validate-command.ts
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Recursively load all `.md` files from within each rule pack; multiple packs can be used simultaneously
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Organize rules into subdirectories (packs) within RulesPath; use company names (e.g., Acme, TechCorp, Stripe) to indicate which style guide the rules implement
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Applies to .vectorlint.ini : Use `[glob/pattern]` sections in `.vectorlint.ini` to specify which packs run on which files
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Recursively load all `.md` files from within each rule pack; multiple packs can be used simultaneously
Applied to files:
src/cli/validate-command.ts
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Organize rules into subdirectories (packs) within RulesPath; use company names (e.g., Acme, TechCorp, Stripe) to indicate which style guide the rules implement
Applied to files:
src/cli/validate-command.ts
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Applies to src/boundaries/env-parser.ts : All environment variables must be validated via Zod schemas in `src/boundaries/env-parser.ts`
Applied to files:
src/cli/validate-command.ts
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Keep directories cohesive; maintain acyclic dependencies (CLI → prompts/providers/output); optimize for discoverability
Applied to files:
src/cli/validate-command.ts
🧬 Code graph analysis (1)
src/cli/validate-command.ts (3)
src/config/preset-loader.ts (1)
PresetLoader(5-52)src/boundaries/rule-pack-loader.ts (1)
RulePackLoader(12-95)src/prompts/prompt-loader.ts (1)
loadRuleFile(10-86)
🪛 GitHub Check: ESLint
src/cli/validate-command.ts
[failure] 16-16:
Variable name __dirname must match one of the following formats: UPPER_CASE
[failure] 15-15:
Variable name __filename must match one of the following formats: UPPER_CASE
🔇 Additional comments (5)
src/cli/validate-command.ts (5)
4-6: LGTM! Import changes align with the refactoring.The imports correctly reflect the renamed APIs (RulePackLoader, loadRuleFile) and the new PresetLoader. The ESM utilities (fileURLToPath, dirname) are necessary for computing directory paths in ESM modules.
Also applies to: 10-11
42-45: LGTM! CLI path resolution is now correct.The code properly resolves CLI-provided paths to absolute paths using
path.resolve(process.cwd(), ...), ensuring that pack paths will be absolute when passed to the loader. The comment accurately explains that CLI paths need resolution while config paths are already absolute.
56-60: LGTM! Conditional existence check supports preset-only usage.The existence check correctly guards with
rulesPath &&to allow preset-only usage without requiring a local rules directory.
66-86: LGTM! Preset loading and pack iteration correctly implemented.The preset/rule pack loading follows the correct flow:
- Computes presetsDir relative to bundled output (correctly resolves to package root's presets/)
- Instantiates PresetLoader and RulePackLoader with proper dependencies
- Calls listAllPacks which merges presets and user packs with shadowing semantics
- Iterates over resolved packs with absolute paths (guaranteed by prior path.resolve on line 43-44)
- Loads rule files using the new loadRuleFile API with pack names
The comment on line 74 is accurate given that rulesPath is resolved to absolute before being passed to listAllPacks.
88-94: No issues found. The error message correctly references "RulesPath" and "RunRules," which are actual configuration field names used in config files (verified in src/boundaries/config-loader.ts, src/cli/init-command.ts, and src/boundaries/file-section-parser.ts).Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
src/boundaries/rule-pack-loader.tssrc/cli/commands.tssrc/cli/orchestrator.tssrc/cli/validate-command.tstests/preset-loader.test.tstests/rule-pack-loader.test.tstests/target.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- src/cli/commands.ts
- src/cli/validate-command.ts
- tests/preset-loader.test.ts
🧰 Additional context used
📓 Path-based instructions (3)
tests/**/*.test.ts
📄 CodeRabbit inference engine (AGENTS.md)
tests/**/*.test.ts: Write tests using Vitest framework with focus on config parsing, file discovery, schema/structured output, and locator
Use dependency injection in tests: mock providers; do not hit network in unit tests
Files:
tests/target.test.tstests/rule-pack-loader.test.ts
src/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.ts: Use TypeScript ESM with explicit imports and narrow types
Use 2-space indentation; avoid trailing whitespace
Maintain strict TypeScript with noany; useunknown+ schema validation for external data
Use custom error types with proper inheritance; catch blocks useunknowntype
Files:
src/boundaries/rule-pack-loader.tssrc/cli/orchestrator.ts
src/boundaries/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Use Zod schemas for boundary validation of all external data (files, CLI, env, APIs) at system boundaries
Files:
src/boundaries/rule-pack-loader.ts
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Recursively load all `.md` files from within each rule pack; multiple packs can be used simultaneously
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Organize rules into subdirectories (packs) within RulesPath; use company names (e.g., Acme, TechCorp, Stripe) to indicate which style guide the rules implement
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Applies to .vectorlint.ini : Use `[glob/pattern]` sections in `.vectorlint.ini` to specify which packs run on which files
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Applies to src/output/**/*.ts : IDs should be shown as `PromptId.CriterionId` in output
Applied to files:
tests/target.test.tssrc/cli/orchestrator.ts
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Applies to tests/**/*.test.ts : Write tests using Vitest framework with focus on config parsing, file discovery, schema/structured output, and locator
Applied to files:
tests/target.test.tstests/rule-pack-loader.test.ts
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Recursively load all `.md` files from within each rule pack; multiple packs can be used simultaneously
Applied to files:
tests/rule-pack-loader.test.tssrc/boundaries/rule-pack-loader.ts
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Applies to evals/**/*.md : Evals must include YAML frontmatter; the tool appends evidence instructions automatically
Applied to files:
tests/rule-pack-loader.test.ts
📚 Learning: 2025-12-28T19:43:51.189Z
Learnt from: CR
Repo: TRocket-Labs/vectorlint PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-28T19:43:51.189Z
Learning: Organize rules into subdirectories (packs) within RulesPath; use company names (e.g., Acme, TechCorp, Stripe) to indicate which style guide the rules implement
Applied to files:
src/boundaries/rule-pack-loader.tssrc/cli/orchestrator.ts
🧬 Code graph analysis (3)
tests/target.test.ts (1)
src/prompts/prompt-loader.ts (1)
loadRules(88-129)
tests/rule-pack-loader.test.ts (2)
src/boundaries/rule-pack-loader.ts (1)
RulePackLoader(12-95)src/config/preset-loader.ts (1)
PresetLoader(5-52)
src/boundaries/rule-pack-loader.ts (1)
src/config/preset-loader.ts (1)
PresetLoader(5-52)
🔇 Additional comments (13)
tests/target.test.ts (3)
5-5: LGTM! Function rename aligns with PR refactoring.The import correctly reflects the renamed function from
loadPromptstoloadRules.
13-16: LGTM! Defensive guards improve test robustness.The added runtime guards ensure tests fail fast with clear error messages if the setup doesn't produce expected results. This pattern makes debugging easier when tests fail.
37-38: LGTM! Consistent application of defensive guards.The optional chaining and runtime guards for criteria access are consistently applied across all test cases, ensuring uniform error handling throughout the test suite.
Also applies to: 59-60, 85-86, 107-108
src/boundaries/rule-pack-loader.ts (3)
6-10: LGTM! Well-defined interface.The
ResolvedPackinterface clearly captures the structure of a resolved rule pack with appropriate fields for name, path, and preset status.
25-64: LGTM! Shadowing logic correctly implements preset override behavior.The Map-based approach correctly implements the shadowing behavior where user rules override presets with matching names. Presets are loaded first (lines 28-37), then user packs overwrite them (lines 54-60), ensuring user definitions take precedence. The graceful handling of missing user paths (line 49) is appropriate.
71-94: LGTM! Recursive file discovery is correctly implemented.The recursive scanning logic correctly discovers all
.mdfiles within a pack directory, appropriately throws for inaccessible paths, and returns absolute file paths as expected.tests/rule-pack-loader.test.ts (3)
13-24: LGTM! Proper dependency injection in tests.The mock PresetLoader setup follows best practices for unit testing with dependency injection, avoiding network calls and external dependencies.
32-103: LGTM! Comprehensive test coverage for listAllPacks.The test suite thoroughly covers all key scenarios:
- Basic pack discovery
- Empty directory handling
- Preset-only scenarios
- Shadowing behavior (user packs override presets)
- Graceful handling of non-existent paths
The shadowing test (lines 78-96) correctly verifies that user packs with matching names override presets, which is the core feature of this PR.
105-184: LGTM! Thorough test coverage for findRuleFiles.The test cases comprehensively validate:
- Recursive
.mdfile discovery- Non-
.mdfile exclusion- Empty directory handling
- Error handling for non-existent paths
- Absolute path verification
The defensive guard at lines 179-182 ensures test clarity, consistent with the pattern in other test files.
src/cli/orchestrator.ts (4)
36-51: LGTM!The
buildRuleNamefunction correctly constructs hierarchical rule names in the formatPackName.RuleId.CriterionId(orPackName.RuleIdwhen no criterion). The implementation is clear and handles the optional criterion parameter appropriately.
667-667: Consistent threading ofpackNamefor hierarchical naming.The subjective processing path correctly passes
promptFile.packaspackNametoextractAndReportCriterion, enabling consistent hierarchical rule naming across both subjective and semi-objective evaluation paths.
265-265: No action needed —packNameis guaranteed to be defined.The
PromptFiletype requires apackfield via Zod schema (pack: z.string()), which is validated when the prompt file is loaded. This guarantees thatpackNameis always a non-empty string when passed toextractAndReportCriterionandbuildRuleName. The code is correct as written.Likely an incorrect or invalid review comment.
569-577: Semi-objective evaluators properly populatecriterionNameon violations.Verification confirms that all semi-objective evaluators inherit from
BaseEvaluator, which explicitly setscriterionName: item.descriptionon every violation object (src/evaluators/base-evaluator.ts:166). The type definition inSemiObjectiveResultincludes this property, and the orchestrator's usage at line 572 is safe due to the!isSubjectiveResult(result)type guard that narrows the result toSemiObjectiveResult.
* feat: implement bundled rule packs (presets) - Add presets/ directory with meta.json registry - Implement PresetLoader and refactor to RulePackLoader - User rules shadow presets with same name - Rename Eval/Prompt terminology to Rule for consistency * Add pack name to rule naming hierarchy - Make pack field required in PROMPT_FILE_SCHEMA - Add buildRuleName() helper for consistent rule name construction - Update rule names to follow PackName.RuleId.CriterionId pattern - Apply naming to both subjective and semi-objective evaluation paths - Update loadRuleFile() to require packName parameter - Use 'Default' pack for legacy loadRules() function in tests * bug: fix ESM __dirname compatibility in preset loading - Add fileURLToPath and dirname imports for ESM compatibility - Define __filename and __dirname using import.meta.url - Fixes 'ReferenceError: __dirname is not defined' in built output - Affects commands.ts and validate-command.ts preset loading * expand VectorLint preset with three new rules targeting common content quality issues - add pseudo-advice rule that catches vague guidance telling WHAT without explaining HOW - add repetition rule that identifies redundant sections wasting reader time - add directness rule that ensures sections immediately answer their header questions - group violations by criterion in orchestrator for better multi-criterion rule reporting - add ai-pattern test fixtures for buzzword and negation pattern detection * fix: correct presets directory path resolution for dist builds - Add presets/ to package.json files array for npm publishing - Fix presetsDir path in commands.ts (../../presets → ../presets) - Fix presetsDir path in validate-command.ts (../../presets → ../presets) * feat: make RulesPath optional in config - Make rulesPath optional in config schema (presets can provide rules) - Remove duplicate validation from config-loader.ts (schema is now single source of truth) - Update commands.ts and validate-command.ts to handle optional rulesPath - Update file-resolver.ts to skip rules exclusion when rulesPath is undefined - Update rule-pack-loader.ts to accept undefined userRulesPath - Rename vectorlint.ini.example to .vectorlint.ini.example and update with optional RulesPath instructions * fix: resolve CLI path and remove dead code in validate-command - Resolve --evals CLI path to absolute before use (config paths already absolute) - Remove unreachable duplicate prompts.length === 0 check after try block * chore: fix lint errors
Summary
Implements bundled rule packs (presets) that ship with VectorLint, allowing users to easily enable default rules while maintaining the ability to override them with custom rules. User-defined rules automatically shadow presets with the same name.
Changes
Breaking Changes
None - This is purely additive. Existing user rules continue to work unchanged.
Testing
Notes for Reviewers
The shadowing mechanism uses a Map where presets are loaded first, then user rules overwrite any matching keys. This ensures user control while providing sensible defaults.
Summary by CodeRabbit
New Features
New Rules
Documentation
Breaking / Notice
Tests
✏️ Tip: You can customize this high-level summary in your review settings.