M .gitignore => .gitignore +1 -1
@@ 1,5 1,5 @@
# Binary
-mdcx
+/mdcx
# Example/test Confluence documents (not part of the project)
0-root.xml
A CLAUDE.md => CLAUDE.md +52 -0
@@ 0,0 1,52 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Build & Test
+
+```bash
+just build # build binary to ./mdcx
+just install # go install to $GOPATH/bin
+just test # go test ./...
+just test-v # verbose tests
+go test ./converter/... -run TestRoundTrip # run specific tests
+```
+
+## Architecture
+
+**mdcx** converts Markdown ↔ Confluence storage-format XML with round-trip fidelity. The binary lives at `cmd/mdcx/`.
+
+### Package graph
+
+```
+cmd/mdcx/ CLI (cobra commands, package main)
+ ├─ converter Core bidirectional conversion
+ ├─ api Confluence REST client (pull/push)
+ ├─ template Marker-based embed/extract
+ └─ format XML pretty-printer + ANSI colorizer
+
+converter/
+ ├─ md2xml.go goldmark parser → confluence.Renderer → XML
+ └─ xml2md.go golang.org/x/net/html walker → Markdown
+
+confluence/
+ ├─ renderer.go goldmark NodeRenderer (registered at priority 100)
+ └─ elements.go Macro builders: CodeMacro, InfoPanel, etc.
+```
+
+### Key design decisions
+
+**Bidirectional round-trip preservation** — Confluence elements with no Markdown equivalent (inline comments, user mentions, attachment images, layout sections) survive round-trips via HTML `<span data-*>` attributes and `<!-- comment -->` markers. The md→xml renderer reconstructs proper `ac:*/ri:*` tags from these.
+
+**CDATA preprocessing** — `xml2md.go` replaces `<![CDATA[...]]>` with `<cdatacontent>` fake elements before parsing, because `golang.org/x/net/html` doesn't handle CDATA. The reverse direction uses `confluence.escapeCDATA()` to split `]]>` sequences.
+
+**Renderer state** — `confluence.Renderer` tracks `taskIDCounter`, `inTaskBody`, `inlineCommentDepth`, and pending attributes from HTML comments. This state is per-conversion and must remain consistent across the AST walk.
+
+**Template markers** — `<!-- MD_CONTENT_START -->` / `<!-- MD_CONTENT_END -->` delimit the editable region in Confluence pages. The `push --template` flow: fetch page → replace between markers → update with version increment.
+
+### Semantic mapping (non-obvious)
+
+- Markdown blockquotes → Confluence info panel macro (not `<blockquote>`)
+- Task lists detected by checkbox presence, rendered as `<ac:task-list>`
+- Code blocks → `<ac:structured-macro ac:name="code">` with CDATA body
+- XML namespaces (`ac:`, `ri:`) are string-constructed, not from an XML library
M README.md => README.md +6 -2
@@ 9,10 9,14 @@ Template-aware embedding preserves metadata tables, changelogs, inline comment m
## Install
```bash
-go install sourcecraft.dev/bigbes/confluence-md-utilities@latest
+go install sourcecraft.dev/bigbes/confluence-md-utilities/cmd/mdcx@latest
```
-Binary name is `mdcx`.
+Or build locally with [just](https://github.com/casey/just):
+
+```bash
+just install
+```
## Commands
R cmd/completions.go => cmd/mdcx/completions.go +1 -1
@@ 1,4 1,4 @@
-package cmd
+package main
import (
"github.com/spf13/cobra"
R cmd/convert.go => cmd/mdcx/convert.go +1 -1
@@ 1,4 1,4 @@
-package cmd
+package main
import (
"fmt"
R cmd/embed.go => cmd/mdcx/embed.go +1 -1
@@ 1,4 1,4 @@
-package cmd
+package main
import (
"fmt"
R => +1 -1
@@ 1,4 1,4 @@
package cmd
package main
import (
"fmt"
R cmd/fmt.go => cmd/mdcx/fmt.go +1 -1
@@ 1,4 1,4 @@
-package cmd
+package main
import (
"fmt"
R main.go => cmd/mdcx/main.go +1 -3
@@ 1,7 1,5 @@
package main
-import "sourcecraft.dev/bigbes/confluence-md-utilities/cmd"
-
func main() {
- cmd.Execute()
+ Execute()
}
R cmd/pull.go => cmd/mdcx/pull.go +1 -1
@@ 1,4 1,4 @@
-package cmd
+package main
import (
"fmt"
R cmd/push.go => cmd/mdcx/push.go +1 -1
@@ 1,4 1,4 @@
-package cmd
+package main
import (
"fmt"
R cmd/root.go => cmd/mdcx/root.go +1 -1
@@ 1,4 1,4 @@
-package cmd
+package main
import (
"fmt"
A justfile => justfile +17 -0
@@ 0,0 1,17 @@
+module_path := "sourcecraft.dev/bigbes/confluence-md-utilities"
+
+# Install mdcx binary locally
+install:
+ go install {{module_path}}/cmd/mdcx@latest
+
+# Build mdcx binary
+build:
+ go build -o mdcx ./cmd/mdcx
+
+# Run tests
+test:
+ go test ./...
+
+# Run tests with verbose output
+test-v:
+ go test -v ./...