confpub-cli 1.16.0__tar.gz → 1.16.2__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 (101) hide show
  1. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/PKG-INFO +20 -1
  2. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/README.md +18 -0
  3. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/__init__.py +1 -1
  4. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/applier.py +31 -4
  5. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/assets.py +25 -9
  6. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/cli.py +82 -4
  7. confpub_cli-1.16.2/confpub/config.py +479 -0
  8. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/converter.py +112 -3
  9. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/front_matter.py +35 -0
  10. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/guide.py +55 -11
  11. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/html_macro_plugin.py +2 -2
  12. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/planner.py +31 -4
  13. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/publish.py +31 -4
  14. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/reverse_converter.py +21 -2
  15. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/SKILL.md +3 -0
  16. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/syntax-html-macro.md +79 -2
  17. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/workflow.md +8 -1
  18. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/pyproject.toml +1 -0
  19. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_assets.py +44 -0
  20. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_config.py +94 -0
  21. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_front_matter.py +23 -0
  22. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_html_macro_plugin.py +74 -0
  23. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_integration.py +10 -0
  24. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_publish.py +36 -0
  25. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_skill_installer.py +15 -0
  26. confpub_cli-1.16.0/confpub/config.py +0 -269
  27. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/.github/copilot-instructions.md +0 -0
  28. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/.github/workflows/publish.yml +0 -0
  29. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/.gitignore +0 -0
  30. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/AGENTS.md +0 -0
  31. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/CLAUDE.md +0 -0
  32. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/LICENSE +0 -0
  33. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/PRD.md +0 -0
  34. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/SCORE.md +0 -0
  35. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/__main__.py +0 -0
  36. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/confluence.py +0 -0
  37. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/envelope.py +0 -0
  38. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/errors.py +0 -0
  39. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/lockfile.py +0 -0
  40. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/macro_plugin.py +0 -0
  41. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/manifest.py +0 -0
  42. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/output.py +0 -0
  43. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/puller.py +0 -0
  44. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/py.typed +0 -0
  45. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/__init__.py +0 -0
  46. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/design-principles.md +0 -0
  47. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/design-styling.md +0 -0
  48. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/layouts.md +0 -0
  49. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/page-management.md +0 -0
  50. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/adr.md +0 -0
  51. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/api-docs.md +0 -0
  52. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/change-request.md +0 -0
  53. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/design-doc.md +0 -0
  54. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/meeting-notes.md +0 -0
  55. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/onboarding.md +0 -0
  56. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/post-mortem.md +0 -0
  57. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/raid-log.md +0 -0
  58. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/release-notes.md +0 -0
  59. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/retrospective.md +0 -0
  60. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/rfc.md +0 -0
  61. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/runbook.md +0 -0
  62. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/service-catalog.md +0 -0
  63. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/patterns/sprint-status.md +0 -0
  64. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/syntax-containers.md +0 -0
  65. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/syntax-formatting.md +0 -0
  66. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/syntax-macros.md +0 -0
  67. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_data/references/trust-scoring.md +0 -0
  68. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/skill_installer.py +0 -0
  69. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/trust/__init__.py +0 -0
  70. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/trust/anchors.py +0 -0
  71. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/trust/body_parser.py +0 -0
  72. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/trust/cache.py +0 -0
  73. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/trust/models.py +0 -0
  74. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/trust/profiles.py +0 -0
  75. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/trust/scoring.py +0 -0
  76. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/trust/tui.py +0 -0
  77. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/validator.py +0 -0
  78. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub/verifier.py +0 -0
  79. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/confpub.lock +0 -0
  80. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/__init__.py +0 -0
  81. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/conftest.py +0 -0
  82. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_applier.py +0 -0
  83. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_confluence.py +0 -0
  84. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_converter.py +0 -0
  85. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_envelope.py +0 -0
  86. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_errors.py +0 -0
  87. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_guide.py +0 -0
  88. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_lockfile.py +0 -0
  89. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_macro_plugin.py +0 -0
  90. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_manifest.py +0 -0
  91. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_output.py +0 -0
  92. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_planner.py +0 -0
  93. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_puller.py +0 -0
  94. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_reverse_converter.py +0 -0
  95. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_trust_cache.py +0 -0
  96. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_trust_cli.py +0 -0
  97. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_trust_models.py +0 -0
  98. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_trust_scoring.py +0 -0
  99. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_validator.py +0 -0
  100. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/tests/test_verifier.py +0 -0
  101. {confpub_cli-1.16.0 → confpub_cli-1.16.2}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: confpub-cli
3
- Version: 1.16.0
3
+ Version: 1.16.2
4
4
  Summary: Agent-first CLI to publish Markdown to Confluence
5
5
  Project-URL: Homepage, https://github.com/ThomasRohde/confpub-cli
6
6
  Project-URL: Repository, https://github.com/ThomasRohde/confpub-cli.git
@@ -26,6 +26,7 @@ Classifier: Typing :: Typed
26
26
  Requires-Python: >=3.10
27
27
  Requires-Dist: atlassian-python-api>=3.41
28
28
  Requires-Dist: beautifulsoup4>=4.12
29
+ Requires-Dist: click>=8.0
29
30
  Requires-Dist: keyring>=24.0
30
31
  Requires-Dist: markdown-it-py[linkify,plugins]>=3.0
31
32
  Requires-Dist: markdownify>=0.14
@@ -505,6 +506,18 @@ Confluence strips `<style>`, `<script>`, `<iframe>`, and other tags from normal
505
506
 
506
507
  The macro name is selected from your Confluence type: `html` for Data Center/Server and `html-macro` as the Cloud fallback. Confluence Cloud HTML macro apps can register different macro keys, including `macro-html`, so override per publish with `--html-macro-name` or `html_macro_name` in front-matter when needed. To persist the setting, run `confpub config set html_macro_name macro-html` or set `CONFPUB_HTML_MACRO_NAME`.
507
508
 
509
+ Forge-based Cloud HTML apps, such as Appfire "HTML for Confluence", use a different storage shape (`ac:adf-extension`) rather than the classic `ac:structured-macro`. For those sites, also set `--html-macro-format forge-adf-extension` and provide the Forge `extension-key` and `extension-id` copied from a working macro:
510
+
511
+ ```bash
512
+ confpub config set html_macro_name macro-html
513
+ confpub config set html_macro_format forge-adf-extension
514
+ confpub config set html_macro_forge_extension_key "7dc8a3ac/.../static/macro-html"
515
+ confpub config set html_macro_forge_extension_id "ari:cloud:ecosystem::extension/7dc8a3ac/.../static/macro-html"
516
+ confpub config set html_macro_forge_cloud_id "CLOUD_ID"
517
+ confpub config set html_macro_forge_context_ids "ari:cloud:confluence:site/CLOUD_ID"
518
+ confpub config set html_macro_forge_account_id "ACCOUNT_ID"
519
+ ```
520
+
508
521
  ### Interactive JavaScript Applications
509
522
 
510
523
  `::: html` blocks can reference external JavaScript and CSS files. confpub automatically:
@@ -626,6 +639,12 @@ confpub guide --section commands # Just commands
626
639
  | `CONFPUB_SPACE` | Default space key |
627
640
  | `CONFPUB_SSL_VERIFY` | SSL verification (`true`/`false` or CA bundle path) |
628
641
  | `CONFPUB_HTML_MACRO_NAME` | HTML macro key for `::: html` blocks, if your Confluence Cloud app differs from the built-in fallback |
642
+ | `CONFPUB_HTML_MACRO_FORMAT` | HTML macro storage format: `classic` or `forge-adf-extension` |
643
+ | `CONFPUB_HTML_MACRO_FORGE_EXTENSION_KEY` | Forge HTML macro `extension-key` copied from a working macro |
644
+ | `CONFPUB_HTML_MACRO_FORGE_EXTENSION_ID` | Forge HTML macro `extension-id` copied from a working macro |
645
+ | `CONFPUB_HTML_MACRO_FORGE_CLOUD_ID` | Optional Forge `cloud-id` copied from a working macro |
646
+ | `CONFPUB_HTML_MACRO_FORGE_CONTEXT_IDS` | Optional Forge `context-ids` copied from a working macro |
647
+ | `CONFPUB_HTML_MACRO_FORGE_ACCOUNT_ID` | Optional Forge `account-id` copied from a working macro |
629
648
 
630
649
  ---
631
650
 
@@ -463,6 +463,18 @@ Confluence strips `<style>`, `<script>`, `<iframe>`, and other tags from normal
463
463
 
464
464
  The macro name is selected from your Confluence type: `html` for Data Center/Server and `html-macro` as the Cloud fallback. Confluence Cloud HTML macro apps can register different macro keys, including `macro-html`, so override per publish with `--html-macro-name` or `html_macro_name` in front-matter when needed. To persist the setting, run `confpub config set html_macro_name macro-html` or set `CONFPUB_HTML_MACRO_NAME`.
465
465
 
466
+ Forge-based Cloud HTML apps, such as Appfire "HTML for Confluence", use a different storage shape (`ac:adf-extension`) rather than the classic `ac:structured-macro`. For those sites, also set `--html-macro-format forge-adf-extension` and provide the Forge `extension-key` and `extension-id` copied from a working macro:
467
+
468
+ ```bash
469
+ confpub config set html_macro_name macro-html
470
+ confpub config set html_macro_format forge-adf-extension
471
+ confpub config set html_macro_forge_extension_key "7dc8a3ac/.../static/macro-html"
472
+ confpub config set html_macro_forge_extension_id "ari:cloud:ecosystem::extension/7dc8a3ac/.../static/macro-html"
473
+ confpub config set html_macro_forge_cloud_id "CLOUD_ID"
474
+ confpub config set html_macro_forge_context_ids "ari:cloud:confluence:site/CLOUD_ID"
475
+ confpub config set html_macro_forge_account_id "ACCOUNT_ID"
476
+ ```
477
+
466
478
  ### Interactive JavaScript Applications
467
479
 
468
480
  `::: html` blocks can reference external JavaScript and CSS files. confpub automatically:
@@ -584,6 +596,12 @@ confpub guide --section commands # Just commands
584
596
  | `CONFPUB_SPACE` | Default space key |
585
597
  | `CONFPUB_SSL_VERIFY` | SSL verification (`true`/`false` or CA bundle path) |
586
598
  | `CONFPUB_HTML_MACRO_NAME` | HTML macro key for `::: html` blocks, if your Confluence Cloud app differs from the built-in fallback |
599
+ | `CONFPUB_HTML_MACRO_FORMAT` | HTML macro storage format: `classic` or `forge-adf-extension` |
600
+ | `CONFPUB_HTML_MACRO_FORGE_EXTENSION_KEY` | Forge HTML macro `extension-key` copied from a working macro |
601
+ | `CONFPUB_HTML_MACRO_FORGE_EXTENSION_ID` | Forge HTML macro `extension-id` copied from a working macro |
602
+ | `CONFPUB_HTML_MACRO_FORGE_CLOUD_ID` | Optional Forge `cloud-id` copied from a working macro |
603
+ | `CONFPUB_HTML_MACRO_FORGE_CONTEXT_IDS` | Optional Forge `context-ids` copied from a working macro |
604
+ | `CONFPUB_HTML_MACRO_FORGE_ACCOUNT_ID` | Optional Forge `account-id` copied from a working macro |
587
605
 
588
606
  ---
589
607
 
@@ -1,3 +1,3 @@
1
1
  """confpub — Agent-first CLI to publish Markdown to Confluence."""
2
2
 
3
- __version__ = "1.16.0"
3
+ __version__ = "1.16.2"
@@ -12,7 +12,7 @@ from pathlib import Path
12
12
  from typing import Any
13
13
 
14
14
  from confpub.assets import AssetRef, discover_assets, rewrite_html_macro_urls, rewrite_image_urls, upload_assets
15
- from confpub.config import load_config, resolve_html_macro_name
15
+ from confpub.config import load_config, resolve_html_macro_settings
16
16
  from confpub.confluence import ConfluenceClient, build_page_url
17
17
  from confpub.converter import convert_markdown, fingerprint_content
18
18
  from confpub.errors import ERR_CONFLICT_FINGERPRINT, ERR_IO_FILE_NOT_FOUND, ConfpubError
@@ -28,6 +28,13 @@ def apply_plan(
28
28
  skip_fingerprint_check: bool = False,
29
29
  cascade: bool = False,
30
30
  html_macro_name: str | None = None,
31
+ html_macro_format: str | None = None,
32
+ html_macro_forge_extension_key: str | None = None,
33
+ html_macro_forge_extension_id: str | None = None,
34
+ html_macro_forge_environment: str | None = None,
35
+ html_macro_forge_cloud_id: str | None = None,
36
+ html_macro_forge_context_ids: str | None = None,
37
+ html_macro_forge_account_id: str | None = None,
31
38
  ) -> dict[str, Any]:
32
39
  """Apply a plan to Confluence.
33
40
 
@@ -39,8 +46,18 @@ def apply_plan(
39
46
  config = load_config()
40
47
  client = ConfluenceClient(config)
41
48
 
42
- # Resolve html_macro_name: explicit > config/env > platform default
43
- effective_html_macro = resolve_html_macro_name(config, html_macro_name)
49
+ # Resolve HTML macro settings: explicit > config/env > platform default.
50
+ html_macro_settings = resolve_html_macro_settings(
51
+ config,
52
+ name_override=html_macro_name,
53
+ format_override=html_macro_format,
54
+ forge_extension_key_override=html_macro_forge_extension_key,
55
+ forge_extension_id_override=html_macro_forge_extension_id,
56
+ forge_environment_override=html_macro_forge_environment,
57
+ forge_cloud_id_override=html_macro_forge_cloud_id,
58
+ forge_context_ids_override=html_macro_forge_context_ids,
59
+ forge_account_id_override=html_macro_forge_account_id,
60
+ )
44
61
 
45
62
  # Load or create lockfile
46
63
  lockfile_path = plan_dir / "confpub.lock"
@@ -90,7 +107,17 @@ def apply_plan(
90
107
 
91
108
  # Read and convert
92
109
  md_text = source_path.read_text(encoding="utf-8")
93
- storage = convert_markdown(md_text, html_macro_name=effective_html_macro)
110
+ storage = convert_markdown(
111
+ md_text,
112
+ html_macro_name=html_macro_settings.name,
113
+ html_macro_format=html_macro_settings.format,
114
+ html_macro_forge_extension_key=html_macro_settings.forge_extension_key,
115
+ html_macro_forge_extension_id=html_macro_settings.forge_extension_id,
116
+ html_macro_forge_environment=html_macro_settings.forge_environment,
117
+ html_macro_forge_cloud_id=html_macro_settings.forge_cloud_id,
118
+ html_macro_forge_context_ids=html_macro_settings.forge_context_ids,
119
+ html_macro_forge_account_id=html_macro_settings.forge_account_id,
120
+ )
94
121
 
95
122
  # Discover and process assets
96
123
  assets = discover_assets(md_text, source_path.parent, None)
@@ -9,6 +9,8 @@ from __future__ import annotations
9
9
 
10
10
  import glob
11
11
  import re
12
+ from html import escape as html_escape
13
+ from html import unescape as html_unescape
12
14
  from pathlib import Path
13
15
  from typing import Any
14
16
 
@@ -52,6 +54,10 @@ _LINK_HREF_RE = re.compile(r'<link\b[^>]*\bhref=["\']([^"\']+)["\']', re.IGNOREC
52
54
 
53
55
  # Regex to find local resource references in CDATA blocks (for rewriting)
54
56
  _CDATA_BLOCK_RE = re.compile(r"(<!\[CDATA\[)(.*?)(\]\]>)", re.DOTALL)
57
+ _ADF_BODY_CONTENT_RE = re.compile(
58
+ r'(<ac:adf-parameter key="__body-content">)(.*?)(</ac:adf-parameter>)',
59
+ re.DOTALL,
60
+ )
55
61
 
56
62
 
57
63
  def _is_local_path(src: str) -> bool:
@@ -215,10 +221,11 @@ def rewrite_html_macro_urls(
215
221
  is_cloud: bool,
216
222
  page_id: str,
217
223
  ) -> str:
218
- """Rewrite local file references inside HTML macro CDATA blocks to attachment URLs.
224
+ """Rewrite local file references inside HTML macro bodies to attachment URLs.
219
225
 
220
226
  Transforms script src and link href pointing to local files into full
221
- Confluence attachment download URLs.
227
+ Confluence attachment download URLs. Handles classic HTML macro CDATA
228
+ bodies and Forge ADF ``__body-content`` values.
222
229
  """
223
230
  if not uploaded_assets:
224
231
  return storage_format
@@ -236,11 +243,7 @@ def rewrite_html_macro_urls(
236
243
  asset = by_filename.get(Path(src).name)
237
244
  return asset
238
245
 
239
- def _rewrite_cdata(match: re.Match) -> str:
240
- prefix = match.group(1) # <![CDATA[
241
- content = match.group(2)
242
- suffix = match.group(3) # ]]>
243
-
246
+ def _rewrite_refs(content: str) -> str:
244
247
  def _rewrite_attr(attr_match: re.Match) -> str:
245
248
  full = attr_match.group(0)
246
249
  src = attr_match.group(1)
@@ -253,10 +256,23 @@ def rewrite_html_macro_urls(
253
256
  return full
254
257
 
255
258
  content = _SCRIPT_SRC_RE.sub(_rewrite_attr, content)
256
- content = _LINK_HREF_RE.sub(_rewrite_attr, content)
259
+ return _LINK_HREF_RE.sub(_rewrite_attr, content)
260
+
261
+ def _rewrite_cdata(match: re.Match) -> str:
262
+ prefix = match.group(1) # <![CDATA[
263
+ content = _rewrite_refs(match.group(2))
264
+ suffix = match.group(3) # ]]>
257
265
  return prefix + content + suffix
258
266
 
259
- return _CDATA_BLOCK_RE.sub(_rewrite_cdata, storage_format)
267
+ def _rewrite_adf_body(match: re.Match) -> str:
268
+ prefix = match.group(1)
269
+ content = html_unescape(match.group(2))
270
+ content = _rewrite_refs(content)
271
+ suffix = match.group(3)
272
+ return prefix + html_escape(content, quote=False) + suffix
273
+
274
+ storage_format = _CDATA_BLOCK_RE.sub(_rewrite_cdata, storage_format)
275
+ return _ADF_BODY_CONTENT_RE.sub(_rewrite_adf_body, storage_format)
260
276
 
261
277
 
262
278
  def upload_assets(
@@ -373,6 +373,13 @@ def page_publish(
373
373
  backup: bool = typer.Option(False, "--backup", help="Backup existing page before overwriting"),
374
374
  label: Optional[list[str]] = typer.Option(None, "--label", help="Label to apply (repeatable)"),
375
375
  html_macro_name: Optional[str] = typer.Option(None, "--html-macro-name", help="HTML macro name (html for DC; Cloud apps vary, default html-macro)"),
376
+ html_macro_format: Optional[str] = typer.Option(None, "--html-macro-format", help="HTML macro storage format: classic or forge-adf-extension"),
377
+ html_macro_forge_extension_key: Optional[str] = typer.Option(None, "--html-macro-forge-extension-key", help="Forge HTML macro extension-key copied from a working macro"),
378
+ html_macro_forge_extension_id: Optional[str] = typer.Option(None, "--html-macro-forge-extension-id", help="Forge HTML macro extension-id copied from a working macro"),
379
+ html_macro_forge_environment: Optional[str] = typer.Option(None, "--html-macro-forge-environment", help="Forge environment for the HTML macro (default PRODUCTION)"),
380
+ html_macro_forge_cloud_id: Optional[str] = typer.Option(None, "--html-macro-forge-cloud-id", help="Optional Forge cloud-id copied from a working macro"),
381
+ html_macro_forge_context_ids: Optional[str] = typer.Option(None, "--html-macro-forge-context-ids", help="Optional Forge context-ids copied from a working macro"),
382
+ html_macro_forge_account_id: Optional[str] = typer.Option(None, "--html-macro-forge-account-id", help="Optional Forge account-id copied from a working macro"),
376
383
  ) -> None:
377
384
  """Publish a single Markdown file to Confluence."""
378
385
  from pathlib import Path as _Path
@@ -439,6 +446,32 @@ def page_publish(
439
446
  # Resolve html_macro_name: CLI flag > front-matter > config/env/default in publish_page
440
447
  fm_html_macro = fm.html_macro_name if fm else None
441
448
  effective_html_macro = html_macro_name or fm_html_macro
449
+ fm_html_macro_format = fm.html_macro_format if fm else None
450
+ effective_html_macro_format = html_macro_format or fm_html_macro_format
451
+ fm_html_macro_forge_extension_key = fm.html_macro_forge_extension_key if fm else None
452
+ effective_html_macro_forge_extension_key = (
453
+ html_macro_forge_extension_key or fm_html_macro_forge_extension_key
454
+ )
455
+ fm_html_macro_forge_extension_id = fm.html_macro_forge_extension_id if fm else None
456
+ effective_html_macro_forge_extension_id = (
457
+ html_macro_forge_extension_id or fm_html_macro_forge_extension_id
458
+ )
459
+ fm_html_macro_forge_environment = fm.html_macro_forge_environment if fm else None
460
+ effective_html_macro_forge_environment = (
461
+ html_macro_forge_environment or fm_html_macro_forge_environment
462
+ )
463
+ fm_html_macro_forge_cloud_id = fm.html_macro_forge_cloud_id if fm else None
464
+ effective_html_macro_forge_cloud_id = (
465
+ html_macro_forge_cloud_id or fm_html_macro_forge_cloud_id
466
+ )
467
+ fm_html_macro_forge_context_ids = fm.html_macro_forge_context_ids if fm else None
468
+ effective_html_macro_forge_context_ids = (
469
+ html_macro_forge_context_ids or fm_html_macro_forge_context_ids
470
+ )
471
+ fm_html_macro_forge_account_id = fm.html_macro_forge_account_id if fm else None
472
+ effective_html_macro_forge_account_id = (
473
+ html_macro_forge_account_id or fm_html_macro_forge_account_id
474
+ )
442
475
 
443
476
  from confpub.publish import publish_page
444
477
  result = publish_page(
@@ -452,6 +485,13 @@ def page_publish(
452
485
  progress_callback=ctx,
453
486
  labels=merged_labels,
454
487
  html_macro_name=effective_html_macro,
488
+ html_macro_format=effective_html_macro_format,
489
+ html_macro_forge_extension_key=effective_html_macro_forge_extension_key,
490
+ html_macro_forge_extension_id=effective_html_macro_forge_extension_id,
491
+ html_macro_forge_environment=effective_html_macro_forge_environment,
492
+ html_macro_forge_cloud_id=effective_html_macro_forge_cloud_id,
493
+ html_macro_forge_context_ids=effective_html_macro_forge_context_ids,
494
+ html_macro_forge_account_id=effective_html_macro_forge_account_id,
455
495
  )
456
496
  ctx.result = result
457
497
  if not dry_run:
@@ -644,6 +684,13 @@ def plan_create(
644
684
  space: Optional[str] = typer.Option(None, "--space", help="Confluence space key (or CONFPUB_SPACE env var)"),
645
685
  parent: Optional[str] = typer.Option(None, "--parent", help="Override manifest parent"),
646
686
  html_macro_name: Optional[str] = typer.Option(None, "--html-macro-name", help="HTML macro name (html for DC; Cloud apps vary, default html-macro)"),
687
+ html_macro_format: Optional[str] = typer.Option(None, "--html-macro-format", help="HTML macro storage format: classic or forge-adf-extension"),
688
+ html_macro_forge_extension_key: Optional[str] = typer.Option(None, "--html-macro-forge-extension-key", help="Forge HTML macro extension-key copied from a working macro"),
689
+ html_macro_forge_extension_id: Optional[str] = typer.Option(None, "--html-macro-forge-extension-id", help="Forge HTML macro extension-id copied from a working macro"),
690
+ html_macro_forge_environment: Optional[str] = typer.Option(None, "--html-macro-forge-environment", help="Forge environment for the HTML macro (default PRODUCTION)"),
691
+ html_macro_forge_cloud_id: Optional[str] = typer.Option(None, "--html-macro-forge-cloud-id", help="Optional Forge cloud-id copied from a working macro"),
692
+ html_macro_forge_context_ids: Optional[str] = typer.Option(None, "--html-macro-forge-context-ids", help="Optional Forge context-ids copied from a working macro"),
693
+ html_macro_forge_account_id: Optional[str] = typer.Option(None, "--html-macro-forge-account-id", help="Optional Forge account-id copied from a working macro"),
647
694
  ) -> None:
648
695
  """Generate a plan artifact from a manifest."""
649
696
  with command_context("plan.create", target={"manifest": manifest}) as ctx:
@@ -655,6 +702,13 @@ def plan_create(
655
702
  space_override=space,
656
703
  parent_override=parent,
657
704
  html_macro_name=html_macro_name,
705
+ html_macro_format=html_macro_format,
706
+ html_macro_forge_extension_key=html_macro_forge_extension_key,
707
+ html_macro_forge_extension_id=html_macro_forge_extension_id,
708
+ html_macro_forge_environment=html_macro_forge_environment,
709
+ html_macro_forge_cloud_id=html_macro_forge_cloud_id,
710
+ html_macro_forge_context_ids=html_macro_forge_context_ids,
711
+ html_macro_forge_account_id=html_macro_forge_account_id,
658
712
  )
659
713
  ctx.result = result
660
714
 
@@ -678,6 +732,13 @@ def plan_apply(
678
732
  skip_fingerprint_check: bool = typer.Option(False, "--skip-fingerprint-check", help="Skip stale-state detection"),
679
733
  cascade: bool = typer.Option(False, "--cascade", help="Allow cascading deletes"),
680
734
  html_macro_name: Optional[str] = typer.Option(None, "--html-macro-name", help="HTML macro name (html for DC; Cloud apps vary, default html-macro)"),
735
+ html_macro_format: Optional[str] = typer.Option(None, "--html-macro-format", help="HTML macro storage format: classic or forge-adf-extension"),
736
+ html_macro_forge_extension_key: Optional[str] = typer.Option(None, "--html-macro-forge-extension-key", help="Forge HTML macro extension-key copied from a working macro"),
737
+ html_macro_forge_extension_id: Optional[str] = typer.Option(None, "--html-macro-forge-extension-id", help="Forge HTML macro extension-id copied from a working macro"),
738
+ html_macro_forge_environment: Optional[str] = typer.Option(None, "--html-macro-forge-environment", help="Forge environment for the HTML macro (default PRODUCTION)"),
739
+ html_macro_forge_cloud_id: Optional[str] = typer.Option(None, "--html-macro-forge-cloud-id", help="Optional Forge cloud-id copied from a working macro"),
740
+ html_macro_forge_context_ids: Optional[str] = typer.Option(None, "--html-macro-forge-context-ids", help="Optional Forge context-ids copied from a working macro"),
741
+ html_macro_forge_account_id: Optional[str] = typer.Option(None, "--html-macro-forge-account-id", help="Optional Forge account-id copied from a working macro"),
681
742
  ) -> None:
682
743
  """Apply a plan to Confluence."""
683
744
  with command_context("plan.apply", target={"plan": plan}) as ctx:
@@ -689,6 +750,13 @@ def plan_apply(
689
750
  skip_fingerprint_check=skip_fingerprint_check,
690
751
  cascade=cascade,
691
752
  html_macro_name=html_macro_name,
753
+ html_macro_format=html_macro_format,
754
+ html_macro_forge_extension_key=html_macro_forge_extension_key,
755
+ html_macro_forge_extension_id=html_macro_forge_extension_id,
756
+ html_macro_forge_environment=html_macro_forge_environment,
757
+ html_macro_forge_cloud_id=html_macro_forge_cloud_id,
758
+ html_macro_forge_context_ids=html_macro_forge_context_ids,
759
+ html_macro_forge_account_id=html_macro_forge_account_id,
692
760
  )
693
761
  ctx.result = result
694
762
 
@@ -718,7 +786,7 @@ def auth_inspect() -> None:
718
786
 
719
787
  @config_app.command("set")
720
788
  def config_set(
721
- key: str = typer.Argument(..., help="Configuration key (base_url, user, token, ssl_verify, html_macro_name)"),
789
+ key: str = typer.Argument(..., help="Configuration key (base_url, user, token, ssl_verify, html_macro_name, html_macro_format, html_macro_forge_extension_key, html_macro_forge_extension_id, html_macro_forge_environment, html_macro_forge_cloud_id, html_macro_forge_context_ids, html_macro_forge_account_id)"),
722
790
  value: str = typer.Argument(..., help="Configuration value"),
723
791
  ) -> None:
724
792
  """Set a configuration value."""
@@ -856,11 +924,21 @@ def comment_add(
856
924
  md_text = text
857
925
 
858
926
  from confpub.config import load_config as _load_comment_config
859
- from confpub.config import resolve_html_macro_name as _resolve_comment_html_macro_name
927
+ from confpub.config import resolve_html_macro_settings as _resolve_comment_html_macro_settings
860
928
  from confpub.converter import convert_markdown
861
929
  _comment_config = _load_comment_config()
862
- _comment_html_macro = _resolve_comment_html_macro_name(_comment_config)
863
- storage_body = convert_markdown(md_text, html_macro_name=_comment_html_macro)
930
+ _comment_html_macro = _resolve_comment_html_macro_settings(_comment_config)
931
+ storage_body = convert_markdown(
932
+ md_text,
933
+ html_macro_name=_comment_html_macro.name,
934
+ html_macro_format=_comment_html_macro.format,
935
+ html_macro_forge_extension_key=_comment_html_macro.forge_extension_key,
936
+ html_macro_forge_extension_id=_comment_html_macro.forge_extension_id,
937
+ html_macro_forge_environment=_comment_html_macro.forge_environment,
938
+ html_macro_forge_cloud_id=_comment_html_macro.forge_cloud_id,
939
+ html_macro_forge_context_ids=_comment_html_macro.forge_context_ids,
940
+ html_macro_forge_account_id=_comment_html_macro.forge_account_id,
941
+ )
864
942
 
865
943
  from confpub.confluence import build_client
866
944
  client = build_client()