commonmarker-merge is a format-specific implementation of the *-merge gem family for Markdown files using the Commonmarker parser. It provides intelligent Markdown file merging using AST analysis.
Core Philosophy: Intelligent Markdown merging that preserves structure, formatting, and links while applying updates from templates.
Repository: https://github.com/kettle-rb/commonmarker-merge Current Version: 1.0.1 Required Ruby: >= 3.2.0 (currently developed against Ruby 4.0.1)
CRITICAL: AI agents can reliably read terminal output when commands run in the background and the output is polled afterward. However, each terminal command should be treated as a fresh shell with no shared state.
Use this pattern:
- Run commands with background execution enabled.
- Fetch the output afterward.
- Make every command self-contained — do not rely on a previous
cd,export, alias, or shell function.
CRITICAL: The canonical project environment now lives in mise.toml, with local overrides in .env.local loaded via dotenvy.
mise.toml or .env.local, mise may require trust to be refreshed before commands can load the project environment. That interactive trust screen can masquerade as missing terminal output, so commands may appear hung or silent until you handle it.
Recovery rule: If a mise exec command in this repo goes silent, appears hung, or terminal polling stops returning useful output, assume mise trust is needed first and recover with:
mise trust -C /home/pboling/src/kettle-rb/commonmarker-merge
mise exec -C /home/pboling/src/kettle-rb/commonmarker-merge -- bundle exec rspecDo this before spending time on unrelated debugging; in this workspace, silent mise commands are usually a trust problem.
mise trust -C /home/pboling/src/kettle-rb/commonmarker-merge✅ CORRECT:
mise exec -C /home/pboling/src/kettle-rb/commonmarker-merge -- bundle exec rspec✅ CORRECT:
eval "$(mise env -C /home/pboling/src/kettle-rb/commonmarker-merge -s bash)" && bundle exec rspec❌ WRONG:
cd /home/pboling/src/kettle-rb/commonmarker-merge
bundle exec rspec❌ WRONG:
cd /home/pboling/src/kettle-rb/commonmarker-merge && bundle exec rspecUse read_file, list_dir, grep_search, file_search instead of terminal commands for gathering information. Only use terminal for running tests, installing dependencies, and git operations.
This repo is a sibling project inside the /home/pboling/src/kettle-rb workspace, not a vendored dependency under another repo.
Run the plain command and inspect the full output afterward. Do not truncate test output.
Commonmarker::Merge::SmartMerger– Markdown-specific SmartMerger implementationCommonmarker::Merge::FileAnalysis– Markdown file analysis with section extractionCommonmarker::Merge::NodeWrapper– Wrapper for Commonmarker AST nodesCommonmarker::Merge::PartialTemplateMerger– Section-level partial mergesCommonmarker::Merge::MergeResult– Markdown-specific merge resultCommonmarker::Merge::ConflictResolver– Markdown conflict resolutionCommonmarker::Merge::FreezeNode– Markdown freeze block supportCommonmarker::Merge::DebugLogger– Commonmarker-specific debug logging
| Gem | Role |
|---|---|
ast-merge (~> 4.0) |
Base classes and shared infrastructure |
tree_haver (~> 5.0) |
Unified parser adapter (wraps Commonmarker) |
commonmarker |
CommonMark Markdown parser (MRI only) |
version_gem (~> 1.1) |
Version management |
commonmarker-merge uses the Commonmarker parser exclusively via TreeHaver's :commonmarker backend:
| Backend | Parser | Platform | Notes |
|---|---|---|---|
:commonmarker |
Commonmarker | MRI only | CommonMark parser, native extension |
lib/commonmarker/merge/
├── smart_merger.rb # Main SmartMerger implementation
├── partial_template_merger.rb # Section-level merging
├── file_analysis.rb # Markdown file analysis
├── node_wrapper.rb # AST node wrapper
├── merge_result.rb # Merge result object
├── conflict_resolver.rb # Conflict resolution
├── freeze_node.rb # Freeze block support
├── debug_logger.rb # Debug logging
└── version.rb
spec/commonmarker/merge/
├── smart_merger_spec.rb
├── partial_template_merger_spec.rb
├── file_analysis_spec.rb
└── integration/
# Full suite
mise exec -C /home/pboling/src/kettle-rb/commonmarker-merge -- bundle exec rspec
# Single file (disable coverage threshold check)
mise exec -C /home/pboling/src/kettle-rb/commonmarker-merge -- env K_SOUP_COV_MIN_HARD=false bundle exec rspec spec/commonmarker/merge/smart_merger_spec.rb
# Commonmarker backend tests
mise exec -C /home/pboling/src/kettle-rb/commonmarker-merge -- bundle exec rspec --tag commonmarkermise exec -C /home/pboling/src/kettle-rb/commonmarker-merge -- bin/rake coverage
mise exec -C /home/pboling/src/kettle-rb/commonmarker-merge -- bin/kettle-soup-cover -dmerge– Returns a String (the merged Markdown content)merge_result– Returns a MergeResult objectto_son MergeResult returns the merged content as a string
merge– Merges a template section into a specific location in destination- Used by
ast-merge-recipefor section-level updates
Heading-Based Sections:
# Section 1
Content for section 1
## Subsection 1.1
Nested content
# Section 2
Content for section 2Freeze Blocks:
<!-- commonmarker-merge:freeze -->
Custom content that should not be overridden
<!-- commonmarker-merge:unfreeze -->
Standard content that merges normallyLink Reference Preservation:
[link text][ref]
[ref]: https://example.comAvailable tags:
:commonmarker– Requires Commonmarker backend:markdown_parsing– Requires Markdown parser
✅ CORRECT:
RSpec.describe Commonmarker::Merge::SmartMerger, :commonmarker do
# Skipped if Commonmarker not available
end❌ WRONG:
before do
skip "Requires Commonmarker" unless defined?(CommonMarker) # DO NOT DO THIS
end- Heading-based structure: Sections matched by heading text
.textstrips formatting: When matching by text, backticks and other formatting are removed- Link references preserved: Reference-style links maintained during merge
- PartialTemplateMerger: Supports injecting template sections into specific locations
- Freeze blocks use HTML comments:
<!-- commonmarker-merge:freeze --> - MRI only: Commonmarker requires native extensions, MRI only
- Commonmarker requires MRI: Does not work on JRuby or TruffleRuby
- NEVER use manual skip checks – Use dependency tags (
:commonmarker) - Text matching strips formatting – Match on plain text, not markdown syntax
- Do NOT load vendor gems – They are not part of this project; they do not exist in CI
- Use
tmp/for temporary files – Never use/tmpor other system directories - Do NOT expect
cdto persist – Every terminal command is isolated; use a self-containedmise exec -C ... -- ...invocation. - Do NOT rely on prior shell state – Previous
cd,export, aliases, and functions are not available to the next command.
document # Root node
heading # # Heading
paragraph # Regular text
code_block # ```code```
list # - item or 1. item
link # [text](url)
image # Source: ### The `*-merge` Gem Family
.text: "The *-merge Gem Family\n"
# Backticks, bold, italic stripped in .text- Headings: Matched by heading text (stripped of formatting)
- Sections: Content from heading to next same-level heading
- Paragraphs: Position-based within sections
- Code blocks: Matched by language and content
- Lists: Can be merged or replaced
- Links: Reference-style links preserved
- Freeze blocks: Protect customizations from template updates