Skip to content

Conversation

@kaitranntt
Copy link
Collaborator

Summary

  • fix: transform command references when --prefix applied - Previously --prefix only moved directories but didn't update file contents. Now transforms /plan:fast/ck:plan:fast, etc.
  • feat: auto-remove deprecated hooks and MCP servers during merge - Automatically removes deprecated Claude Code settings during config merge

Changes

Prefix Content Transform

  • New content-transformer.ts for slash command reference transformation
  • Supports 16 command roots: plan, fix, code, review, cook, brainstorm, integrate, bootstrap, worktree, scout, test, debug, preview, kanban, journal, watzup
  • 26 unit tests covering transformations and edge cases

Deprecated Settings Removal

  • Auto-removes deprecated hooks from settings.json during merge
  • Auto-removes deprecated MCP servers
  • Configurable via merge engine

Test Plan

  • All tests pass (1975+ tests)
  • Typecheck passes
  • Lint passes
  • Build succeeds

kaitranntt and others added 5 commits January 5, 2026 20:58
Implements #292: When updating kits, settings that were previously
installed but are no longer shipped in the source will be automatically
removed from the user's destination settings.

Changes:
- Add hooksRemoved, mcpServersRemoved counters to MergeResult
- Add removedHooks, removedMcpServers arrays for detailed tracking
- mergeHooks: detect and remove deprecated hooks (in installed but not source)
- mergeMcp: detect and remove deprecated MCP servers
- Add comprehensive test coverage for removal scenarios

Safety: Only removes CK-managed entries (identified via installedSettings).
User-added entries (not in installedSettings) are preserved.
feat: Auto-remove deprecated hooks and MCP servers during merge
Previously --prefix only reorganized directory structure (commands/ → commands/ck/)
but didn't transform content inside files. This caused slash commands to fail
because files still referenced /plan:fast instead of /ck:plan:fast.

Changes:
- Add content-transformer.ts for command reference transformation
- Integrate into prefix-applier.ts after directory restructuring
- Transform patterns: /plan:, /fix:, /code:, /review:, /cook:, /brainstorm, etc.
- Add comprehensive unit tests (20 test cases)

Closes #294
Added 6 missing ClaudeKit commands to COMMAND_ROOTS:
- test, debug, preview, kanban, journal, watzup

These commands are referenced in engineer repo but weren't being
transformed when --prefix was applied.

Added 6 new tests to verify transformations.
fix: transform command references in file contents when --prefix applied
@claude
Copy link

claude bot commented Jan 8, 2026

PR Review: Prefix Content Transform and Deprecated Settings Removal

Summary

This is an excellent PR that addresses two important gaps in the ClaudeKit CLI functionality. The implementation is well-structured, thoroughly tested, and follows the project's code standards. The changes are additive and non-breaking, with strong attention to edge cases.


✅ Strengths

1. Architecture & Design

  • Clean separation of concerns: Content transformation is properly separated from directory restructuring in content-transformer.ts
  • Composable design: The regex pattern building approach is modular and maintainable
  • Defensive programming: Proper error handling for file I/O operations with graceful degradation
  • Type safety: Strong TypeScript types with clear interfaces for options and results

2. Test Coverage

  • Excellent coverage: 26 tests for content transformer + 150 tests for merge engine
  • Edge cases handled: URL false positives, already-prefixed commands, word boundaries, markdown formatting
  • Real-world scenarios: Tests include actual markdown and agent definition content
  • Regression protection: Tests verify both transformation logic and deprecation removal

3. Code Quality

  • Clear documentation: Comprehensive JSDoc comments explain the "why" not just the "what"
  • Consistent naming: Functions and variables follow project conventions
  • DRY principle: Pattern building is abstracted into reusable functions
  • Logging: Appropriate use of logger for debugging and user feedback

🔍 Potential Issues & Suggestions

1. Content Transformer - Regex Performance (Minor)

Location: content-transformer.ts:79-101

The current implementation creates 32 regex patterns (16 commands × 2 patterns each) and applies them sequentially on every file. For large files, this could be slow.

Suggestion: Consider combining patterns into a single regex with capture groups:

// Instead of 32 separate patterns, use one optimized pattern
const COMMAND_PATTERN = new RegExp(
  `(?<![\\w:])(/)(?:${COMMAND_ROOTS.join('|')})(?::|(?=[\\s\`"'\\)\\]}>.,;:!?]|$))`,
  'g'
);

This would reduce the number of passes over the content from 32 to 1, significantly improving performance for large files.

2. File Extension Detection Edge Case (Minor)

Location: content-transformer.ts:128-131

function shouldTransformFile(filename: string): boolean {
	const ext = filename.toLowerCase().slice(filename.lastIndexOf("."));
	return TRANSFORMABLE_EXTENSIONS.has(ext);
}

Issue: Files without extensions will return the entire filename as the extension.

  • README → extension becomes "readme" (lowercased filename)
  • .gitignore → extension becomes ".gitignore" (correct)

Impact: Low - these files won't match the extensions set anyway, but it's semantically incorrect.

Suggestion:

function shouldTransformFile(filename: string): boolean {
	const lastDot = filename.lastIndexOf(".");
	if (lastDot === -1 || lastDot === 0) return false; // no extension or dotfile
	const ext = filename.slice(lastDot).toLowerCase();
	return TRANSFORMABLE_EXTENSIONS.has(ext);
}

3. Merge Engine - Potential Memory Issue (Low Priority)

Location: merge-engine.ts:81-114

The removeDeprecatedFromEntries function creates new arrays and objects for every entry, even when no changes are made. For configurations with many hooks, this could be inefficient.

Current:

filtered.push({ ...entry, hooks: remainingHooks });

Suggestion: Only clone if changes were made:

if (remainingHooks.length === entry.hooks.length) {
	filtered.push(entry); // No changes, keep original reference
} else if (remainingHooks.length > 0) {
	filtered.push({ ...entry, hooks: remainingHooks });
}

4. Missing Error Boundary (Enhancement)

Location: prefix-applier.ts:124-129

The content transformation happens after successful directory reorganization but inside the try-catch. If transformation fails catastrophically, it could leave the system in an inconsistent state (directories moved but content not transformed).

Suggestion: Add a separate try-catch for content transformation:

try {
	const transformResult = await transformCommandReferences(claudeDir, {
		verbose: logger.isVerbose(),
	});
	// ... success logging
} catch (transformError) {
	logger.warn("Content transformation failed, but directory structure is correct");
	logger.debug(`Transform error: ${transformError}`);
	// Don't fail the entire operation
}

5. Test Gap: Multiple Replacements with Same Command (Minor)

The tests cover multiple different commands but not multiple instances of the same command:

Suggestion: Add a test case:

it("transforms multiple instances of same command", () => {
	const input = "Use /plan:fast first, then /plan:hard, then /plan:fast again";
	const { transformed, changes } = transformCommandContent(input);
	expect(changes).toBe(3);
	expect(transformed).toContain("/ck:plan:fast");
	expect(transformed).toContain("/ck:plan:hard");
});

🔒 Security Considerations

No security concerns identified

  • File operations use proper path joining (join()) to prevent path traversal
  • No user input is directly used in regex patterns (COMMAND_ROOTS is hardcoded)
  • File reading errors are caught and logged, preventing information disclosure
  • No execution of file contents or dynamic code generation

🎯 Performance Considerations

  1. File I/O: Sequential processing is fine for .claude/ directory size. If performance becomes an issue, consider parallel processing with Promise.all().

  2. Regex Compilation: Pattern building happens on every call. Consider memoization:

let cachedPatterns: Array<{ regex: RegExp; replacement: string }> | null = null;
function buildCommandPatterns() {
	if (cachedPatterns) return cachedPatterns;
	cachedPatterns = [...]; // build patterns
	return cachedPatterns;
}
  1. Memory: Current implementation loads entire file into memory. For very large files (unlikely in .claude/), consider streaming approaches.

📋 Additional Observations

Positive Patterns:

  • ✅ Proper use of logger.debug() vs logger.info() vs logger.verbose()
  • ✅ DRY run support for safe testing
  • ✅ Comprehensive inline comments explaining complex logic
  • ✅ Type definitions properly exported from commands-prefix.ts

Suggestions:

  1. Consider adding integration tests that verify the entire flow: ck init --prefix → check file contents
  2. Document the 16 supported commands somewhere visible (maybe in docs/)
  3. Consider adding metrics to track transformation performance in verbose mode

🎓 Code Standards Compliance

Passes all quality gates from CLAUDE.md:

  • Typecheck: All types properly defined
  • Tests: Comprehensive coverage (1975+ tests passing)
  • Lint: Code follows project conventions
  • Build: Successfully compiles

Follows project patterns:

  • Domain-driven structure (domains/config/merger/, services/transformers/)
  • Proper use of path aliases (@/shared, @/domains)
  • Logger integration for debugging
  • Cross-platform compatibility

📊 Final Assessment

Recommendation: ✅ APPROVE WITH MINOR SUGGESTIONS

This PR is production-ready. The identified issues are minor optimizations and edge cases that don't impact core functionality. The code is well-tested, follows best practices, and solves real user problems.

Priority of Suggestions:

  1. High: Add error boundary for content transformation (prevents potential inconsistency)
  2. Medium: Fix file extension detection edge case (correctness)
  3. Low: Regex performance optimization (premature optimization unless proven bottleneck)
  4. Optional: Memory optimization in merge engine (micro-optimization)

Merge Decision:

Ready to merge as-is, with optional follow-up PR for optimizations if needed.

Great work on the thorough testing and clean implementation! 🚀

@kaitranntt kaitranntt merged commit b8bf5b4 into main Jan 8, 2026
5 checks passed
@github-actions
Copy link

github-actions bot commented Jan 8, 2026

🎉 This PR is included in version 3.23.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants