mkdocs2confluence 0.13.0__tar.gz → 0.13.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. {mkdocs2confluence-0.13.0/src/mkdocs2confluence.egg-info → mkdocs2confluence-0.13.6}/PKG-INFO +12 -4
  2. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/README.md +11 -3
  3. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/pyproject.toml +2 -2
  4. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6/src/mkdocs2confluence.egg-info}/PKG-INFO +12 -4
  5. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs2confluence.egg-info/SOURCES.txt +1 -0
  6. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/cli.py +7 -8
  7. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/skill_installer.py +20 -1
  8. mkdocs2confluence-0.13.6/src/mkdocs_to_confluence/skills/mkdocs-changelog/SKILL.md +126 -0
  9. mkdocs2confluence-0.13.6/src/mkdocs_to_confluence/skills/mkdocs-changelog/scripts/changelog_data.py +136 -0
  10. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_skill_installer.py +13 -2
  11. mkdocs2confluence-0.13.0/src/mkdocs_to_confluence/skills/mkdocs-changelog/SKILL.md +0 -78
  12. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/LICENSE +0 -0
  13. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/setup.cfg +0 -0
  14. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs2confluence.egg-info/dependency_links.txt +0 -0
  15. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs2confluence.egg-info/entry_points.txt +0 -0
  16. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs2confluence.egg-info/requires.txt +0 -0
  17. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs2confluence.egg-info/top_level.txt +0 -0
  18. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/__init__.py +0 -0
  19. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/compiler/__init__.py +0 -0
  20. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/compiler/models.py +0 -0
  21. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/compiler/page.py +0 -0
  22. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/emitter/__init__.py +0 -0
  23. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/emitter/xhtml.py +0 -0
  24. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/ir/__init__.py +0 -0
  25. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/ir/document.py +0 -0
  26. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/ir/nodes.py +0 -0
  27. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/ir/treeutil.py +0 -0
  28. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/loader/__init__.py +0 -0
  29. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/loader/config.py +0 -0
  30. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/loader/extra_css.py +0 -0
  31. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/loader/nav.py +0 -0
  32. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/loader/page.py +0 -0
  33. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/parser/__init__.py +0 -0
  34. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/parser/markdown.py +0 -0
  35. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/pdf/__init__.py +0 -0
  36. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/pdf/generator.py +0 -0
  37. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/pdf/render.py +0 -0
  38. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/preprocess/__init__.py +0 -0
  39. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/preprocess/abbrevs.py +0 -0
  40. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/preprocess/fence.py +0 -0
  41. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/preprocess/frontmatter.py +0 -0
  42. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/preprocess/icons.py +0 -0
  43. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/preprocess/includes.py +0 -0
  44. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/preprocess/linkdefs.py +0 -0
  45. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/preview/__init__.py +0 -0
  46. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/preview/render.py +0 -0
  47. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/preview/server.py +0 -0
  48. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/publisher/__init__.py +0 -0
  49. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/publisher/changelog.py +0 -0
  50. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/publisher/client.py +0 -0
  51. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/publisher/executor.py +0 -0
  52. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/publisher/http_retry.py +0 -0
  53. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/publisher/models.py +0 -0
  54. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/publisher/pipeline.py +0 -0
  55. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/publisher/planner.py +0 -0
  56. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/sync/__init__.py +0 -0
  57. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/sync/anchoring.py +0 -0
  58. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/sync/command.py +0 -0
  59. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/sync/comments.py +0 -0
  60. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/sync/github.py +0 -0
  61. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/sync/platform.py +0 -0
  62. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/sync/state.py +0 -0
  63. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/transforms/__init__.py +0 -0
  64. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/transforms/abbrevs.py +0 -0
  65. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/transforms/assets.py +0 -0
  66. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/transforms/editlink.py +0 -0
  67. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/transforms/footer.py +0 -0
  68. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/transforms/images.py +0 -0
  69. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/transforms/internallinks.py +0 -0
  70. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/src/mkdocs_to_confluence/transforms/mermaid.py +0 -0
  71. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_abbrevs.py +0 -0
  72. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_changelog_config.py +0 -0
  73. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_changelog_publish.py +0 -0
  74. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_children_macro.py +0 -0
  75. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_cli.py +0 -0
  76. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_editlink.py +0 -0
  77. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_emitter.py +0 -0
  78. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_extra_css.py +0 -0
  79. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_footer.py +0 -0
  80. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_frontmatter.py +0 -0
  81. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_icons.py +0 -0
  82. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_images.py +0 -0
  83. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_internallinks.py +0 -0
  84. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_ir.py +0 -0
  85. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_linkdefs.py +0 -0
  86. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_loader.py +0 -0
  87. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_mermaid.py +0 -0
  88. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_page_loader.py +0 -0
  89. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_parser.py +0 -0
  90. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_pdf.py +0 -0
  91. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_preprocess.py +0 -0
  92. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_preview.py +0 -0
  93. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_publish_client.py +0 -0
  94. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_publish_config.py +0 -0
  95. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_publish_pipeline.py +0 -0
  96. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_server.py +0 -0
  97. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_sync_anchoring.py +0 -0
  98. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_sync_command.py +0 -0
  99. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_sync_comments.py +0 -0
  100. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_sync_github.py +0 -0
  101. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_sync_state.py +0 -0
  102. {mkdocs2confluence-0.13.0 → mkdocs2confluence-0.13.6}/tests/test_treeutil.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkdocs2confluence
3
- Version: 0.13.0
3
+ Version: 0.13.6
4
4
  Summary: Publish MkDocs Material pages to Confluence Cloud — admonitions, Mermaid diagrams, tabs, page properties and more
5
5
  Author: Anders Hybertz
6
6
  License: GPL-3.0-or-later
@@ -58,7 +58,10 @@ Dynamic: license-file
58
58
 
59
59
  A Python CLI tool that compiles MkDocs-flavoured Markdown into **native Confluence storage XHTML** and publishes it directly to Confluence Cloud. It is a **compiler/transpiler**, not an HTML converter — every construct maps to its native Confluence equivalent, so pages look and behave like hand-authored Confluence content.
60
60
 
61
- It also bridges the gap between Confluence reviewers and developers: the `sync-comments` command turns open Confluence page comments into GitHub pull request review threads, and auto-resolves them in Confluence when the PR is merged.
61
+ - **Publish** compiles your full `nav:` tree and pushes only changed pages (SHA-256 skip, no unnecessary version bumps or notifications).
62
+ - **What's New page** — designate a `CHANGELOG.md` with `confluence.changelog` and mk2conf publishes it as a pinned top-level page on every run, so Confluence readers always have one place to see what changed.
63
+ - **AI changelog skill** — `mk2conf install-skill` installs a bundled AI skill into your editor (Claude Code, Copilot, Cursor, Hermes) that analyses git changes to your docs and drafts a dated entry in `CHANGELOG.md` when the changes are significant.
64
+ - **Review bridge** — `sync-comments` turns open Confluence page comments into GitHub pull request review threads and auto-resolves them in Confluence when the PR is merged.
62
65
 
63
66
  > **Zensical compatible** — [Zensical](https://zensical.org/) is the modern successor to MkDocs + Material for MkDocs. Since it uses the same `mkdocs.yml` format and Python Markdown extensions, your Zensical project works with mk2conf today with no changes required.
64
67
 
@@ -128,12 +131,15 @@ mk2conf preview --page index.md --watch
128
131
  # Dry-run: see what would be published
129
132
  mk2conf publish --dry-run
130
133
 
131
- # Publish all nav pages
134
+ # Publish all nav pages (and the changelog page if configured)
132
135
  mk2conf publish
133
136
 
134
137
  # Export a section to PDF
135
138
  mk2conf pdf --section Guide --out guide.pdf
136
139
 
140
+ # Install the changelog AI skill into your editor
141
+ mk2conf install-skill
142
+
137
143
  # Sync Confluence comments to GitHub PR review threads
138
144
  mk2conf sync-comments
139
145
  ```
@@ -173,6 +179,8 @@ confluence:
173
179
  - Partial runs (`--page` / `--section`) skip the changelog page, consistent with other publish behaviour.
174
180
  - Omit the key, or set it to an empty string, to disable the feature entirely.
175
181
 
182
+ Run `mk2conf install-skill` once after setting `changelog:` to install the changelog AI skill into your AI tool (Claude Code, Copilot, Cursor, Hermes). The skill analyses git changes to your docs since the last `CHANGELOG.md` commit and drafts an entry when the changes qualify as significant.
183
+
176
184
  **Your first publish:**
177
185
 
178
186
  ```bash
@@ -188,7 +196,7 @@ mk2conf publish # go live
188
196
 
189
197
  | | |
190
198
  |---|---|
191
- | [docs/commands.md](docs/commands.md) | Full flag reference for all four commands |
199
+ | [docs/commands.md](docs/commands.md) | Full flag reference for all five commands |
192
200
  | [docs/features.md](docs/features.md) | Supported Markdown / Material features and known limitations |
193
201
  | [Setup.md](Setup.md) | Development environment setup |
194
202
 
@@ -16,7 +16,10 @@
16
16
 
17
17
  A Python CLI tool that compiles MkDocs-flavoured Markdown into **native Confluence storage XHTML** and publishes it directly to Confluence Cloud. It is a **compiler/transpiler**, not an HTML converter — every construct maps to its native Confluence equivalent, so pages look and behave like hand-authored Confluence content.
18
18
 
19
- It also bridges the gap between Confluence reviewers and developers: the `sync-comments` command turns open Confluence page comments into GitHub pull request review threads, and auto-resolves them in Confluence when the PR is merged.
19
+ - **Publish** compiles your full `nav:` tree and pushes only changed pages (SHA-256 skip, no unnecessary version bumps or notifications).
20
+ - **What's New page** — designate a `CHANGELOG.md` with `confluence.changelog` and mk2conf publishes it as a pinned top-level page on every run, so Confluence readers always have one place to see what changed.
21
+ - **AI changelog skill** — `mk2conf install-skill` installs a bundled AI skill into your editor (Claude Code, Copilot, Cursor, Hermes) that analyses git changes to your docs and drafts a dated entry in `CHANGELOG.md` when the changes are significant.
22
+ - **Review bridge** — `sync-comments` turns open Confluence page comments into GitHub pull request review threads and auto-resolves them in Confluence when the PR is merged.
20
23
 
21
24
  > **Zensical compatible** — [Zensical](https://zensical.org/) is the modern successor to MkDocs + Material for MkDocs. Since it uses the same `mkdocs.yml` format and Python Markdown extensions, your Zensical project works with mk2conf today with no changes required.
22
25
 
@@ -86,12 +89,15 @@ mk2conf preview --page index.md --watch
86
89
  # Dry-run: see what would be published
87
90
  mk2conf publish --dry-run
88
91
 
89
- # Publish all nav pages
92
+ # Publish all nav pages (and the changelog page if configured)
90
93
  mk2conf publish
91
94
 
92
95
  # Export a section to PDF
93
96
  mk2conf pdf --section Guide --out guide.pdf
94
97
 
98
+ # Install the changelog AI skill into your editor
99
+ mk2conf install-skill
100
+
95
101
  # Sync Confluence comments to GitHub PR review threads
96
102
  mk2conf sync-comments
97
103
  ```
@@ -131,6 +137,8 @@ confluence:
131
137
  - Partial runs (`--page` / `--section`) skip the changelog page, consistent with other publish behaviour.
132
138
  - Omit the key, or set it to an empty string, to disable the feature entirely.
133
139
 
140
+ Run `mk2conf install-skill` once after setting `changelog:` to install the changelog AI skill into your AI tool (Claude Code, Copilot, Cursor, Hermes). The skill analyses git changes to your docs since the last `CHANGELOG.md` commit and drafts an entry when the changes qualify as significant.
141
+
134
142
  **Your first publish:**
135
143
 
136
144
  ```bash
@@ -146,7 +154,7 @@ mk2conf publish # go live
146
154
 
147
155
  | | |
148
156
  |---|---|
149
- | [docs/commands.md](docs/commands.md) | Full flag reference for all four commands |
157
+ | [docs/commands.md](docs/commands.md) | Full flag reference for all five commands |
150
158
  | [docs/features.md](docs/features.md) | Supported Markdown / Material features and known limitations |
151
159
  | [Setup.md](Setup.md) | Development environment setup |
152
160
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mkdocs2confluence"
3
- version = "0.13.0"
3
+ version = "0.13.6"
4
4
  description = "Publish MkDocs Material pages to Confluence Cloud — admonitions, Mermaid diagrams, tabs, page properties and more"
5
5
  readme = "README.md"
6
6
  license = { text = "GPL-3.0-or-later" }
@@ -68,7 +68,7 @@ build-backend = "setuptools.build_meta"
68
68
  where = ["src"]
69
69
 
70
70
  [tool.setuptools.package-data]
71
- "mkdocs_to_confluence" = ["skills/**/*.md"]
71
+ "mkdocs_to_confluence" = ["skills/**/*.md", "skills/**/*.py"]
72
72
 
73
73
  [tool.ruff]
74
74
  line-length = 120
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkdocs2confluence
3
- Version: 0.13.0
3
+ Version: 0.13.6
4
4
  Summary: Publish MkDocs Material pages to Confluence Cloud — admonitions, Mermaid diagrams, tabs, page properties and more
5
5
  Author: Anders Hybertz
6
6
  License: GPL-3.0-or-later
@@ -58,7 +58,10 @@ Dynamic: license-file
58
58
 
59
59
  A Python CLI tool that compiles MkDocs-flavoured Markdown into **native Confluence storage XHTML** and publishes it directly to Confluence Cloud. It is a **compiler/transpiler**, not an HTML converter — every construct maps to its native Confluence equivalent, so pages look and behave like hand-authored Confluence content.
60
60
 
61
- It also bridges the gap between Confluence reviewers and developers: the `sync-comments` command turns open Confluence page comments into GitHub pull request review threads, and auto-resolves them in Confluence when the PR is merged.
61
+ - **Publish** compiles your full `nav:` tree and pushes only changed pages (SHA-256 skip, no unnecessary version bumps or notifications).
62
+ - **What's New page** — designate a `CHANGELOG.md` with `confluence.changelog` and mk2conf publishes it as a pinned top-level page on every run, so Confluence readers always have one place to see what changed.
63
+ - **AI changelog skill** — `mk2conf install-skill` installs a bundled AI skill into your editor (Claude Code, Copilot, Cursor, Hermes) that analyses git changes to your docs and drafts a dated entry in `CHANGELOG.md` when the changes are significant.
64
+ - **Review bridge** — `sync-comments` turns open Confluence page comments into GitHub pull request review threads and auto-resolves them in Confluence when the PR is merged.
62
65
 
63
66
  > **Zensical compatible** — [Zensical](https://zensical.org/) is the modern successor to MkDocs + Material for MkDocs. Since it uses the same `mkdocs.yml` format and Python Markdown extensions, your Zensical project works with mk2conf today with no changes required.
64
67
 
@@ -128,12 +131,15 @@ mk2conf preview --page index.md --watch
128
131
  # Dry-run: see what would be published
129
132
  mk2conf publish --dry-run
130
133
 
131
- # Publish all nav pages
134
+ # Publish all nav pages (and the changelog page if configured)
132
135
  mk2conf publish
133
136
 
134
137
  # Export a section to PDF
135
138
  mk2conf pdf --section Guide --out guide.pdf
136
139
 
140
+ # Install the changelog AI skill into your editor
141
+ mk2conf install-skill
142
+
137
143
  # Sync Confluence comments to GitHub PR review threads
138
144
  mk2conf sync-comments
139
145
  ```
@@ -173,6 +179,8 @@ confluence:
173
179
  - Partial runs (`--page` / `--section`) skip the changelog page, consistent with other publish behaviour.
174
180
  - Omit the key, or set it to an empty string, to disable the feature entirely.
175
181
 
182
+ Run `mk2conf install-skill` once after setting `changelog:` to install the changelog AI skill into your AI tool (Claude Code, Copilot, Cursor, Hermes). The skill analyses git changes to your docs since the last `CHANGELOG.md` commit and drafts an entry when the changes qualify as significant.
183
+
176
184
  **Your first publish:**
177
185
 
178
186
  ```bash
@@ -188,7 +196,7 @@ mk2conf publish # go live
188
196
 
189
197
  | | |
190
198
  |---|---|
191
- | [docs/commands.md](docs/commands.md) | Full flag reference for all four commands |
199
+ | [docs/commands.md](docs/commands.md) | Full flag reference for all five commands |
192
200
  | [docs/features.md](docs/features.md) | Supported Markdown / Material features and known limitations |
193
201
  | [Setup.md](Setup.md) | Development environment setup |
194
202
 
@@ -48,6 +48,7 @@ src/mkdocs_to_confluence/publisher/models.py
48
48
  src/mkdocs_to_confluence/publisher/pipeline.py
49
49
  src/mkdocs_to_confluence/publisher/planner.py
50
50
  src/mkdocs_to_confluence/skills/mkdocs-changelog/SKILL.md
51
+ src/mkdocs_to_confluence/skills/mkdocs-changelog/scripts/changelog_data.py
51
52
  src/mkdocs_to_confluence/sync/__init__.py
52
53
  src/mkdocs_to_confluence/sync/anchoring.py
53
54
  src/mkdocs_to_confluence/sync/command.py
@@ -544,7 +544,7 @@ def _cmd_publish(args: argparse.Namespace) -> None:
544
544
  print(f"Dry run: would publish {len(pages)} page(s) to {conf_config.base_url}")
545
545
  for page in pages:
546
546
  print(f" {page.docs_path} → '{page.title}'")
547
- if conf_config.changelog_file and not partial:
547
+ if conf_config.changelog_file:
548
548
  from mkdocs_to_confluence.publisher.changelog import _extract_title
549
549
  cl_path = config.docs_dir / conf_config.changelog_file
550
550
  cl_title = _extract_title(cl_path) or "What's New"
@@ -580,13 +580,12 @@ def _cmd_publish(args: argparse.Namespace) -> None:
580
580
  prune=getattr(args, "prune", False) and not partial,
581
581
  quiet=args.quiet,
582
582
  )
583
- # Changelog is a pinned top-level page always publish on full runs,
584
- # skip on partial runs (--page / --section) like all other publish behaviour.
585
- if not partial:
586
- publish_changelog(
587
- config, conf_config, client, space_id,
588
- space_key=conf_config.space_key, quiet=args.quiet,
589
- )
583
+ # Changelog is a pinned top-level page independent of the nav
584
+ # always publish it when it has updates, even on partial runs.
585
+ publish_changelog(
586
+ config, conf_config, client, space_id,
587
+ space_key=conf_config.space_key, quiet=args.quiet,
588
+ )
590
589
  except ConfluenceError as exc:
591
590
  print(f"error: {exc}", file=sys.stderr)
592
591
  sys.exit(1)
@@ -14,6 +14,21 @@ def _read_skill() -> str:
14
14
  return files("mkdocs_to_confluence").joinpath(f"skills/{_SKILL_NAME}/SKILL.md").read_text(encoding="utf-8")
15
15
 
16
16
 
17
+ def _read_script() -> str:
18
+ from importlib.resources import files
19
+ return files("mkdocs_to_confluence").joinpath(
20
+ f"skills/{_SKILL_NAME}/scripts/changelog_data.py"
21
+ ).read_text(encoding="utf-8")
22
+
23
+
24
+ def _install_script(project_dir: Path) -> Path:
25
+ """Write changelog_data.py to .mk2conf/scripts/ and return its path."""
26
+ dest = project_dir / ".mk2conf" / "scripts" / "changelog_data.py"
27
+ dest.parent.mkdir(parents=True, exist_ok=True)
28
+ dest.write_text(_read_script(), encoding="utf-8")
29
+ return dest
30
+
31
+
17
32
  def _strip_front_matter(content: str) -> str:
18
33
  return _FRONT_MATTER_RE.sub("", content).lstrip("\n")
19
34
 
@@ -38,6 +53,10 @@ def install_skill(
38
53
  content_full = _read_skill()
39
54
  content_body = _strip_front_matter(content_full)
40
55
 
56
+ # Always install the data script to a fixed project-local path so every
57
+ # AI tool's skill file can reference it unconditionally.
58
+ _install_script(project_dir)
59
+
41
60
  installed: list[tuple[str, Path]] = []
42
61
  explicit = tool is not None
43
62
 
@@ -66,7 +85,7 @@ def install_skill(
66
85
  if _want("claude"):
67
86
  claude_dir = project_dir / ".claude"
68
87
  if explicit or claude_dir.exists():
69
- dest = claude_dir / "commands" / "changelog.md"
88
+ dest = claude_dir / "commands" / "mk2conf-changelog.md"
70
89
  dest.parent.mkdir(parents=True, exist_ok=True)
71
90
  dest.write_text(content_body, encoding="utf-8")
72
91
  installed.append(("claude", dest))
@@ -0,0 +1,126 @@
1
+ ---
2
+ name: mkdocs-changelog
3
+ description: Analyse doc changes since the last CHANGELOG.md update and draft a major-change entry if the changes qualify.
4
+ version: "1.2.0"
5
+ tags: [documentation, git, changelog, mkdocs, confluence]
6
+ specificity: context-specific
7
+ tool_agnostic: true
8
+ authors: [Anders Hybertz]
9
+ tested_on: []
10
+ ---
11
+
12
+ # MkDocs Changelog Entry
13
+
14
+ Analyse git changes to the docs directory since the last `CHANGELOG.md` commit. If any changes qualify as **MAJOR**, draft a dated changelog entry in the collapsible format and prepend it to `CHANGELOG.md`. If not, explain why and exit without modifying any file.
15
+
16
+ ## When to Use
17
+
18
+ - After making one or more documentation changes and before running `mk2conf publish`
19
+ - Any point in the writing flow when you want to assess whether a "What's New" entry is warranted
20
+
21
+ ## Steps
22
+
23
+ 1. **Extract git data** — run the bundled data script to get structured, deterministic input:
24
+
25
+ ```
26
+ python .mk2conf/scripts/changelog_data.py --docs-dir <docs_dir>
27
+ ```
28
+
29
+ The script prints a JSON object to stdout. Use this as your sole source of truth for
30
+ commits, changed files, and contributors. Do not run git commands yourself.
31
+
32
+ If the script is missing, tell the user to run `mk2conf install-skill` first.
33
+
34
+ 2. **Read the existing changelog** — read `<docs_dir>/CHANGELOG.md` for context on what
35
+ was previously recorded.
36
+
37
+ 3. **Decide: is this MAJOR?**
38
+
39
+ **MAJOR criteria — any one of these qualifies:**
40
+ - A new top-level documentation area or section added (a new folder or nav section that didn't exist before)
41
+ - A significant area deleted or substantially restructured (not just moved or renamed)
42
+ - A fundamental definition, concept, or policy changed in a way that affects how readers understand the subject
43
+
44
+ **NOT major — do not draft an entry for:**
45
+ - Typo fixes, grammar corrections, spelling
46
+ - Formatting, diagram adjustments, image swaps
47
+ - Small additions (a paragraph, a note, a clarification) that do not change the substance
48
+ - Rewordings that preserve the original meaning
49
+ - Internal restructuring with no reader-facing impact
50
+
51
+ 4. **If NOT MAJOR** — report what was found, explain in one sentence why it did not qualify,
52
+ and stop. Do not modify any file.
53
+
54
+ 5. **If MAJOR** — draft an entry using the collapsible format below and prepend it to
55
+ `CHANGELOG.md`. The previous latest entry (if any) must be converted from `???+` to `???`
56
+ so only the new entry is expanded by default.
57
+
58
+ ## Entry format
59
+
60
+ The latest entry uses `???+` (expanded by default on Material, always visible on Confluence).
61
+ All older entries use `???` (collapsed, showing only the date and title as the trigger).
62
+
63
+ ```markdown
64
+ ???+ note "YYYY-MM-DD — Brief title describing the major change"
65
+
66
+ ### Added
67
+ - …
68
+
69
+ ### Changed
70
+ - …
71
+
72
+ ### Deprecated
73
+ - …
74
+
75
+ ### Removed
76
+ - …
77
+
78
+ ### Fixed
79
+ - …
80
+
81
+ ### Security
82
+ - …
83
+
84
+ Contributors: Name One, Name Two
85
+ ```
86
+
87
+ Rules for the entry:
88
+
89
+ - Date is the `date` field from the script output (`YYYY-MM-DD`)
90
+ - Title is a brief, reader-facing description — not a git commit message
91
+ - No version numbers — dates only
92
+ - **Include only sections that have actual content** — omit any empty section entirely
93
+ - Section meanings: `Added` (new content), `Changed` (updated content), `Deprecated`
94
+ (content being phased out), `Removed` (deleted content), `Fixed` (corrected errors or
95
+ misleading information), `Security` (security-related documentation updates)
96
+ - `Contributors:` line — include when the `contributors` array from the script output has
97
+ **more than one name**. Omit when there is only one contributor.
98
+ - Content inside the admonition block must be indented with **4 spaces**
99
+ - When prepending, convert the previous `???+` opener to `???` first
100
+
101
+ ## CHANGELOG.md structure
102
+
103
+ If `CHANGELOG.md` does not exist yet, create it with this header before the first entry:
104
+
105
+ ```markdown
106
+ # Changelog
107
+
108
+ All notable changes to this documentation are recorded here.
109
+ The format is inspired by [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
110
+ ```
111
+
112
+ ## Pitfalls
113
+
114
+ - **Do not draft an entry for every change.** The changelog is for readers who want to know
115
+ what fundamentally changed — not a git log. When in doubt, do not draft.
116
+ - **Do not commit.** Always leave the file for the user to review. The user runs `git add`
117
+ and `git commit` themselves before publishing.
118
+ - **The script is the only source of git data.** Do not interpret commit messages or diffs
119
+ yourself — the script output is deterministic and already scoped to the docs directory.
120
+ - **4-space indent is required** inside the admonition block. 2-space or tab indent will
121
+ break both Material rendering and the Confluence compile step.
122
+
123
+ ## Verification
124
+
125
+ After drafting, show the user the proposed entry in the terminal and remind them to review
126
+ `CHANGELOG.md` before committing and running `mk2conf publish`.
@@ -0,0 +1,136 @@
1
+ #!/usr/bin/env python3
2
+ """Extract changelog-relevant git data and print it as JSON.
3
+
4
+ Usage (run from the project root):
5
+ python .mk2conf/scripts/changelog_data.py [--docs-dir docs]
6
+
7
+ Output is a JSON object on stdout. Nothing is written to disk.
8
+ No external dependencies — stdlib only.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import argparse
14
+ import json
15
+ import subprocess
16
+ import sys
17
+ from datetime import date
18
+
19
+
20
+ def _run(args: list[str]) -> str:
21
+ """Run a git command and return stripped stdout. Returns '' on error."""
22
+ try:
23
+ result = subprocess.run(
24
+ args,
25
+ capture_output=True,
26
+ text=True,
27
+ check=False,
28
+ )
29
+ return result.stdout.strip()
30
+ except FileNotFoundError:
31
+ return ""
32
+
33
+
34
+ def _baseline_commit(changelog_path: str) -> str | None:
35
+ """Return the SHA of the last commit that touched changelog_path, or None."""
36
+ sha = _run(["git", "log", "--follow", "-1", "--format=%H", "--", changelog_path])
37
+ return sha or None
38
+
39
+
40
+ def _root_commit() -> str:
41
+ """Return the SHA of the very first commit in the repo."""
42
+ return _run(["git", "rev-list", "--max-parents=0", "HEAD"])
43
+
44
+
45
+ def _commits_since(baseline: str) -> list[dict[str, str]]:
46
+ """Return commits reachable from HEAD but not from baseline (exclusive)."""
47
+ sep = "\x1f" # unit separator — safe delimiter
48
+ fmt = f"%H{sep}%s{sep}%aN{sep}%as" # sha, subject, author name, date
49
+ raw = _run(["git", "log", f"{baseline}..HEAD", f"--format={fmt}"])
50
+ if not raw:
51
+ return []
52
+ commits = []
53
+ for line in raw.splitlines():
54
+ parts = line.split(sep)
55
+ if len(parts) != 4: # noqa: PLR2004
56
+ continue
57
+ sha, subject, author, commit_date = parts
58
+ commits.append({"sha": sha, "subject": subject, "author": author, "date": commit_date})
59
+ return commits
60
+
61
+
62
+ def _changed_files(baseline: str, docs_dir: str) -> dict[str, list[str]]:
63
+ """Return files changed in docs_dir since baseline, grouped by status."""
64
+ raw = _run([
65
+ "git", "diff", "--name-status", f"{baseline}..HEAD", "--", docs_dir,
66
+ ])
67
+ added: list[str] = []
68
+ modified: list[str] = []
69
+ deleted: list[str] = []
70
+ if not raw:
71
+ return {"added": added, "modified": modified, "deleted": deleted}
72
+ for line in raw.splitlines():
73
+ parts = line.split("\t", maxsplit=1)
74
+ if len(parts) != 2: # noqa: PLR2004
75
+ continue
76
+ status, path = parts[0].strip(), parts[1].strip()
77
+ if status.startswith("A"):
78
+ added.append(path)
79
+ elif status.startswith("D"):
80
+ deleted.append(path)
81
+ elif status.startswith("M") or status.startswith("R") or status.startswith("C"):
82
+ modified.append(path)
83
+ return {"added": added, "modified": modified, "deleted": deleted}
84
+
85
+
86
+ def _contributors(commits: list[dict[str, str]]) -> list[str]:
87
+ """Return unique contributor names from commits, preserving first-seen order."""
88
+ seen: set[str] = set()
89
+ result: list[str] = []
90
+ for c in commits:
91
+ name = c["author"]
92
+ if name and name not in seen:
93
+ seen.add(name)
94
+ result.append(name)
95
+ return result
96
+
97
+
98
+ def main() -> None:
99
+ parser = argparse.ArgumentParser(description="Extract git changelog data as JSON.")
100
+ parser.add_argument(
101
+ "--docs-dir",
102
+ default="docs",
103
+ help="Path to the MkDocs docs directory, relative to project root (default: docs)",
104
+ )
105
+ args = parser.parse_args()
106
+
107
+ docs_dir: str = args.docs_dir
108
+ changelog_rel = f"{docs_dir}/CHANGELOG.md"
109
+
110
+ # Baseline: last commit touching CHANGELOG.md, or root commit if none
111
+ baseline = _baseline_commit(changelog_rel) or _root_commit()
112
+ if not baseline:
113
+ print(
114
+ "error: could not determine a baseline commit — is this a git repository?",
115
+ file=sys.stderr,
116
+ )
117
+ sys.exit(1)
118
+
119
+ commits = _commits_since(baseline)
120
+ changes = _changed_files(baseline, docs_dir)
121
+ contributors = _contributors(commits)
122
+
123
+ output = {
124
+ "date": date.today().isoformat(),
125
+ "baseline_commit": baseline,
126
+ "commits": commits,
127
+ "contributors": contributors,
128
+ "changes": changes,
129
+ "docs_dir": docs_dir,
130
+ }
131
+
132
+ print(json.dumps(output, indent=2, ensure_ascii=False))
133
+
134
+
135
+ if __name__ == "__main__":
136
+ main()
@@ -45,7 +45,7 @@ def test_install_skill_claude(tmp_path: Path) -> None:
45
45
  assert len(installed) == 1
46
46
  name, dest = installed[0]
47
47
  assert name == "claude"
48
- assert dest == tmp_path / ".claude" / "commands" / "changelog.md"
48
+ assert dest == tmp_path / ".claude" / "commands" / "mk2conf-changelog.md"
49
49
  content = dest.read_text(encoding="utf-8")
50
50
  # Frontmatter stripped for Claude Code
51
51
  assert "name: mkdocs-changelog" not in content
@@ -115,9 +115,20 @@ def test_install_skill_explicit_tool_ignores_detection(tmp_path: Path) -> None:
115
115
  assert dest.exists()
116
116
 
117
117
 
118
+ def test_install_skill_copies_script(tmp_path: Path) -> None:
119
+ """The data script is always installed to .mk2conf/scripts/ regardless of tool."""
120
+ install_skill(project_dir=tmp_path, tool="claude")
121
+
122
+ script = tmp_path / ".mk2conf" / "scripts" / "changelog_data.py"
123
+ assert script.exists(), ".mk2conf/scripts/changelog_data.py should be created"
124
+ content = script.read_text(encoding="utf-8")
125
+ assert "changelog_data" in content
126
+ assert "import json" in content
127
+
128
+
118
129
  def test_install_skill_overwrites_existing(tmp_path: Path) -> None:
119
130
  (tmp_path / ".claude").mkdir()
120
- dest = tmp_path / ".claude" / "commands" / "changelog.md"
131
+ dest = tmp_path / ".claude" / "commands" / "mk2conf-changelog.md"
121
132
  dest.parent.mkdir(parents=True, exist_ok=True)
122
133
  dest.write_text("old content", encoding="utf-8")
123
134
 
@@ -1,78 +0,0 @@
1
- ---
2
- name: mkdocs-changelog
3
- description: Analyse doc changes since the last CHANGELOG.md update and draft a major-change entry if the changes qualify.
4
- version: "1.0.0"
5
- tags: [documentation, git, changelog, mkdocs, confluence]
6
- specificity: context-specific
7
- tool_agnostic: true
8
- authors: [Anders Hybertz]
9
- tested_on: []
10
- ---
11
-
12
- # MkDocs Changelog Entry
13
-
14
- Analyse git changes to the docs directory since the last `CHANGELOG.md` commit. If any changes qualify as **MAJOR**, draft a dated changelog entry and prepend it to `CHANGELOG.md`. If not, explain why and exit without modifying any file.
15
-
16
- ## When to Use
17
-
18
- - After making one or more documentation changes and before running `mk2conf publish`
19
- - Any point in the writing flow when you want to assess whether a "What's New" entry is warranted
20
-
21
- ## Steps
22
-
23
- 1. **Find the baseline** — run `git log --follow -1 --format="%H" -- <docs_dir>/CHANGELOG.md` to get the last commit that touched `CHANGELOG.md`. If no commit is found, use the root commit as the baseline.
24
-
25
- 2. **Collect doc changes** — run `git diff <baseline>..HEAD -- <docs_dir>/` to see everything that changed in the docs directory since that baseline.
26
-
27
- 3. **Read the existing changelog** — read `<docs_dir>/CHANGELOG.md` for context on what was previously recorded.
28
-
29
- 4. **Decide: is this MAJOR?**
30
-
31
- **MAJOR criteria — any one of these qualifies:**
32
- - A new top-level documentation area or section added (a new folder or nav section that didn't exist before)
33
- - A significant area deleted or substantially restructured (not just moved or renamed)
34
- - A fundamental definition, concept, or policy changed in a way that affects how readers understand the subject
35
-
36
- **NOT major — do not draft an entry for:**
37
- - Typo fixes, grammar corrections, spelling
38
- - Formatting, diagram adjustments, image swaps
39
- - Small additions (a paragraph, a note, a clarification) that do not change the substance
40
- - Rewordings that preserve the original meaning
41
- - Internal restructuring with no reader-facing impact
42
-
43
- 5. **If NOT MAJOR** — report what was found, explain in one sentence why it did not qualify, and stop. Do not modify any file.
44
-
45
- 6. **If MAJOR** — draft an entry using this format and prepend it to `CHANGELOG.md`:
46
-
47
- ```markdown
48
- ## YYYY-MM-DD — Brief title describing the major change
49
-
50
- One or two sentences summarising what fundamentally changed and why it matters to readers.
51
-
52
- ### Added
53
- - …
54
-
55
- ### Changed
56
- - …
57
-
58
- ### Removed
59
- - …
60
- ```
61
-
62
- Rules for the entry:
63
- - Date is today's date in `YYYY-MM-DD` format
64
- - Sections (`Added`, `Changed`, `Removed`) are included only when non-empty
65
- - No version numbers — dates only
66
- - Title is a brief, reader-facing description (not a git commit message)
67
-
68
- Prepend the entry above any existing entries in `CHANGELOG.md`. Do not commit — the user reviews, edits if needed, and commits manually.
69
-
70
- ## Pitfalls
71
-
72
- - **Do not draft an entry for every change.** The changelog is for readers who want to know what fundamentally changed, not a git log. When in doubt, do not draft.
73
- - **Do not commit.** Always leave the file for the user to review. The user runs `git add` and `git commit` themselves before publishing.
74
- - **If CHANGELOG.md does not exist yet**, create it with just the new entry (no header needed).
75
-
76
- ## Verification
77
-
78
- After drafting, show the user the proposed entry in the terminal and remind them to review `CHANGELOG.md` before committing and running `mk2conf publish`.