Merged
Conversation
Replace flat BUILT_IN_GLOBAL_TARGETS with a typed harness registry mapping harness names (claude, gemini, opencode, codex) to target paths. Add globalOverrides config field with closed-world key validation so each harness can receive tailored global rules on top of the shared global content. Key changes: - New harness registry in src/core/harness-registry.ts - globalOverrides field in Zod config schema with per-key validation - projects field is now optional (globals-only mode) - Per-harness content composition: shared global + override rules - Same-rule overlap detection within a harness (fails loudly) - Cross-harness rule reuse is allowed - Empty targets silently skipped (no auto-delete) - Unmatched override globs reported as warnings - Full backward compatibility with existing configs Closes #31 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…-only mode
- Reject `globalOverrides: {}` in config validation, matching the existing
behavior for `global: []` and `projects: []`.
- Fix misleading 'No projects configured; nothing to do.' verbose message
when only global rules are synced (no projects configured).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…abels - Document globalOverrides in README with config example and field descriptions - Note that projects is optional (globals-only config is valid) - Optimize syncGlobal to pre-glob shared global paths once and pass resolved paths to detectOverlap instead of re-globbing per harness - Accept pre-computed GlobResult in loadRules to avoid redundant globbing - Extract pattern warning logic into collect-pattern-warnings module - Parse globalOverrides prefix in unmatched pattern warnings to assign distinct source labels (e.g. 'in globalOverrides.claude' not 'in global') - Fix test mock sequence to match optimized glob call order - Use resetAllMocks in beforeEach to prevent mock leakage between tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
4e29858 to
853c24d
Compare
Move sharedPaths variable inside the if(hasOverrides) block where it is actually consumed. Hoists sharedResult to function scope so both the global loading and override detection blocks can access it. This makes the coupling between global glob results and overlap detection explicit, preventing future misuse of a silently-empty sharedPaths array. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the flat
BUILT_IN_GLOBAL_TARGETSarray with a typed harness registry and adds aglobalOverridesconfig field for per-harness rule customization.Closes #31
Changes
New: Harness Registry (
src/core/harness-registry.ts)claude,gemini,opencode,codex) to their target pathsConfig Schema (
src/config/config.ts)globalOverridesfield:Record<HarnessName, string[]>with closed-world key validationprojectsoptional — configs with onlyglobaland/orglobalOverridesare valid (globals-only mode)global,globalOverrides, orprojectsis specifiedglobalOverrides: {}rejected at parse time (matching existingglobal: []andprojects: []behavior)hasPositiveGlobhelper extracted for DRY validationGlobal Sync (
src/core/sync-global.ts)globalrules + harness-specific override rulesglobalOverrides.<harness>:prefixloadRulesto avoid redundant filesystem traversalPattern Warning Parsing (
src/cli/collect-pattern-warnings.ts)globalOverrides.<harness>:prefixed patterns into distinct source labels"global"as canonical source in machine-readable output (--json,--porcelain); maps to"global config"only in human-readable stderrRun Sync Command (
src/cli/run-sync-command.ts)projectsarray (?? []fallback)collectGlobalPatternWarningsfor structured warning parsingDocumentation
globalOverridesconfig example, field documentation, and globals-only modeBackward Compatibility
Existing configs without
globalOverridescontinue to work identically. Machine-readable output (--json,--porcelain) preserves"global"as the warning source label. All original tests pass unchanged (with minor type-safety adjustments for the now-optionalprojectsfield).Tests
14 new tests covering: