From 690965df7dad1664b54989966553f08ca8ca5ee2 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 17 May 2026 17:43:27 +0000 Subject: [PATCH 1/5] v0.4 Phase 4: callout tags - Extend renderer.code to match `mdcms ` fence syntax (e.g. ```mdcms callout-info) - Extend parseMdcmsTag to capture body lines after the key-value block - Add renderCalloutTag: icon + title row, markdown body, colour CSS vars - Add hexToRgba helper for low-opacity background colour - Make themeConfig module-level so callout renderer can read callout defaults - Add callout CSS: left border, title row flex layout, icon fill - Add reusable message: key support with category-aware language resolution - Add aitranslation callout message to config.yml for test - Update home.md with full Phase 4 test cases https://claude.ai/code/session_01UP8Wo2CKPNhvvTkzX48CWF --- app/config.yml | 10 ++++ app/index.html | 135 +++++++++++++++++++++++++++++++++++++++++++--- app/pages/home.md | 98 ++++++++++++++++++--------------- 3 files changed, 192 insertions(+), 51 deletions(-) diff --git a/app/config.yml b/app/config.yml index 0da7820..d4f01c7 100644 --- a/app/config.yml +++ b/app/config.yml @@ -43,3 +43,13 @@ theme: theme.yml # presentational config — edit theme.yml to custo # ────────────────────────────────── # search: true # default-theme: system # light | dark | system + +# ────────────────────────────────── +# Reusable callout messages (optional) +# ────────────────────────────────── +callouts: + aitranslation: + type: warning + en: + title: "PLEASE NOTE:" + text: This page has been translated with artificial intelligence. It has not been reviewed by staff yet. diff --git a/app/index.html b/app/index.html index 9576974..30035d6 100644 --- a/app/index.html +++ b/app/index.html @@ -862,6 +862,32 @@ body { } .post-load-more:hover { background: var(--nav-hover-bg); } +/* ── Callout tags ──────────────────────────────────────── */ +.mdcms-callout { + border-left: 4px solid var(--callout-primary, var(--accent)); + background: var(--callout-bg, transparent); + border-radius: 0 0.4rem 0.4rem 0; + padding: 0.75rem 1rem; + margin: 1rem 0; +} +.mdcms-callout-title { + display: flex; + align-items: center; + gap: 0.45rem; + font-weight: 700; + color: var(--callout-primary, var(--accent)); + margin-bottom: 0.4rem; +} +.mdcms-callout-title .mdcms-icon svg { + fill: var(--callout-primary, var(--accent)); + width: 1.2em; + height: 1.2em; + display: block; +} +.mdcms-callout-body { margin: 0; } +.mdcms-callout-body > :first-child { margin-top: 0; } +.mdcms-callout-body > :last-child { margin-bottom: 0; } + @media print { .sidebar, .topbar, .scroll-top, .hamburger, .mobile-header, .theme-toggle, .search-container { display: none !important; } @@ -893,6 +919,7 @@ body { let searchIndex = []; let fuseInstance = null; let currentPage = null; + let themeConfig = {}; // Category state (phase 3) let categoriesUse = false; @@ -1367,8 +1394,11 @@ body { } else { codeText = code; codeLang = lang; } - if (codeLang === 'mdcms') { - const tag = parseMdcmsTag(codeText); + // Match both ```mdcms (type in content) and ```mdcms callout-info (type in fence) + if (codeLang && (codeLang === 'mdcms' || codeLang.startsWith('mdcms '))) { + const fenceType = codeLang === 'mdcms' ? '' : codeLang.slice('mdcms '.length).trim(); + const fullText = fenceType ? (fenceType + '\n' + (codeText || '')) : (codeText || ''); + const tag = parseMdcmsTag(fullText); const encoded = JSON.stringify(tag).replace(/&/g, '&').replace(/"/g, '"'); return '
'; } @@ -1487,11 +1517,18 @@ function fmtDatetime(dtStr) { var lines = text.trim().split('\n'); var tagName = lines[0].trim(); var options = {}; + var bodyStart = lines.length; for (var i = 1; i < lines.length; i++) { - var m = lines[i].match(/^\s*([a-z\-]+)\s*:\s*(.+)$/i); - if (m) options[m[1].toLowerCase()] = m[2].trim(); + var m = lines[i].match(/^\s*([a-z\-]+)\s*:\s*(.*)$/i); + if (m) { + options[m[1].toLowerCase()] = m[2].trim(); + } else { + bodyStart = i; + break; + } } - return { tagName: tagName, options: options }; + var body = lines.slice(bodyStart).join('\n').trim(); + return { tagName: tagName, options: options, body: body }; } function parsePostTagName(name) { @@ -1769,11 +1806,96 @@ function fmtDatetime(dtStr) { renderYear(); } + // Callout type defaults (fallback when theme.yml has no callouts block) + const CALLOUT_DEFAULTS = { + info: { icon: 'info', colour: '#2563EB' }, + warning: { icon: 'warning', colour: '#D97706' }, + success: { icon: 'success', colour: '#16A34A' }, + error: { icon: 'error', colour: '#DC2626' }, + }; + + function renderCalloutTag(container, tag) { + var typeMatch = tag.tagName.match(/^callout-(info|warning|success|error)$/); + var calloutType = typeMatch ? typeMatch[1] : 'info'; + + var opts = tag.options; + var msgKey = opts.message || null; + var title = opts.title || null; + var iconName = opts.icon || null; + var bodyMd = tag.body || ''; + + // Resolve message: key — config.yml callouts block + if (msgKey) { + var msgDefs = config.callouts || {}; + var msgDef = msgDefs[msgKey]; + if (msgDef) { + // Override callout type from message definition + if (msgDef.type) calloutType = msgDef.type; + // Language resolution: activeCategory → defaultCategoryCode → first key + var lang = activeCategory || defaultCategoryCode; + var langEntry = (lang && msgDef[lang]) || msgDef[defaultCategoryCode]; + if (!langEntry) { + var keys = Object.keys(msgDef).filter(function(k) { return k !== 'type'; }); + langEntry = msgDef[keys[0]]; + } + if (langEntry) { + title = langEntry.title || null; + bodyMd = langEntry.text || ''; + } + if (opts.title || tag.body) { + console.warn('[mdcms] callout: message: key takes precedence; inline title/body ignored.'); + } + } + } + + // Get callout colours/icon from theme.yml callouts block, then fallback + var themeCallouts = (themeConfig.callouts || {})[calloutType] || {}; + var fallback = CALLOUT_DEFAULTS[calloutType] || CALLOUT_DEFAULTS.info; + var primaryColour = themeCallouts['primary-colour'] || fallback.colour; + var bgColour = themeCallouts['background-colour'] || fallback.colour; + if (!iconName) iconName = themeCallouts.icon || fallback.icon; + + // Build element + container.className = 'mdcms-callout mdcms-callout-' + calloutType; + container.style.setProperty('--callout-primary', primaryColour); + container.style.setProperty('--callout-bg', hexToRgba(bgColour, 0.08)); + + if (title) { + var titleRow = document.createElement('div'); + titleRow.className = 'mdcms-callout-title'; + titleRow.appendChild(iconEl(iconName)); + var titleText = document.createElement('span'); + titleText.textContent = title; + titleRow.appendChild(titleText); + container.appendChild(titleRow); + } + + if (bodyMd) { + var bodyEl = document.createElement('div'); + bodyEl.className = 'mdcms-callout-body'; + bodyEl.innerHTML = marked.parse(bodyMd); + container.appendChild(bodyEl); + } + } + + function hexToRgba(hex, alpha) { + var h = hex.replace('#', ''); + if (h.length === 3) h = h[0]+h[0]+h[1]+h[1]+h[2]+h[2]; + var r = parseInt(h.substring(0,2), 16); + var g = parseInt(h.substring(2,4), 16); + var b = parseInt(h.substring(4,6), 16); + return 'rgba(' + r + ',' + g + ',' + b + ',' + alpha + ')'; + } + function hydrateMdcmsTags() { document.querySelectorAll('.mdcms-tag').forEach(function(tagEl) { try { var cfg = JSON.parse(tagEl.getAttribute('data-config')); - renderPostTag(tagEl, cfg); + if (/^callout-(info|warning|success|error)$/.test(cfg.tagName)) { + renderCalloutTag(tagEl, cfg); + } else { + renderPostTag(tagEl, cfg); + } } catch (e) { tagEl.textContent = 'Error rendering tag.'; } @@ -2508,7 +2630,6 @@ function fmtDatetime(dtStr) { if (link) link.href = `assets/images/${config.logo}`; } - let themeConfig = {}; if (config.theme) { try { const themeResp = await fetch(config.theme); diff --git a/app/pages/home.md b/app/pages/home.md index ccf41dc..d076ea1 100644 --- a/app/pages/home.md +++ b/app/pages/home.md @@ -3,65 +3,75 @@ title: Home sort: 100 --- -# MD-CMS +# Phase 4 — Callout Tags -This is the default startpage for MD-CMS. +Check each callout below. Each should show a coloured left border, an icon, a bold title in the accent colour, and a rendered body. -## Testing MD-CMS +--- -If you want to test `MD-CMS` you can grab `samplesite` from the repo and place the content in your website root. This page (`pages/home.md`) won't be replaced. +## Basic types -**Post listing tests** below contains various custom tags to display posts. There are no posts now, but if you download the `samplesite` it will fetch the posts in +```mdcms callout-info +title: Information +This is an **info** callout. Supports *italic*, `code`, and lists: -## Post listing tests - -## Reverse chronological (newest first) - -```mdcms -posts-created-reversechronological -limit: 3 -paginate: no +- Item one +- Item two ``` -## Chronological (oldest first) - -```mdcms -posts-created-chronological -limit: all -paginate: none +```mdcms callout-warning +title: Warning +Something needs your attention. This is a **warning** callout. ``` -## By year (reverse chrono) - -```mdcms -posts-created-reversechronological-byyear -limit: all -defaultyear: current -selectyear: yes -paginate: none +```mdcms callout-success +title: Success +The operation completed successfully. This is a **success** callout. ``` -## By year+month (chrono) - -```mdcms -posts-created-chronological-byyearmonth -limit: all -defaultyear: 2024 -selectyear: yes +```mdcms callout-error +title: Error +Something went wrong. This is an **error** callout. ``` -## Last 30 days +--- -```mdcms -posts-created-reversechronological-lastmonth -limit: all -paginate: none +## No title + +```mdcms callout-info +No title key here. The title row should not appear at all — just the body. ``` -## Paginated (2 per page) +--- -```mdcms -posts-created-reversechronological -limit: 2 -paginate: yes +## Markdown body + +```mdcms callout-warning +title: Rich body +- List item one +- List item two + +A paragraph with `inline code` and a [link](https://example.com). ``` + +--- + +## Custom icon override + +```mdcms callout-info +title: Info with warning icon +icon: warning +This info callout uses the warning icon instead of the default info icon. +``` + +--- + +## Config-defined message (message: key) + +```mdcms callout-warning +message: aitranslation +``` + +--- + +Toggle dark mode and check all four callout types still look correct. From b626d5e066463e560c1ca368c0ebdd9ebd83f831 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 17 May 2026 17:50:01 +0000 Subject: [PATCH 2/5] Add test_phase.py for Phase 4 - Phase 4 branch points to claude/debug-api-errors-gd730 - Phase 4 EXTRA_FILES checks out app/config.yml and app/pages/home.md from the branch (needed for message: key test and callout test cases) - Updated Phase 4 verify checklist covers all spec requirements: basic types, title row, no-title, markdown body, icon override, message: key, dark mode - Added EXTRA_FILES mechanism for per-phase content file checkout - Improved checklist formatting with section headers https://claude.ai/code/session_01UP8Wo2CKPNhvvTkzX48CWF --- test_phase.py | 223 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 test_phase.py diff --git a/test_phase.py b/test_phase.py new file mode 100644 index 0000000..9104574 --- /dev/null +++ b/test_phase.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python3 +""" +MD-CMS v0.4 phase test runner. + +Usage: + python3 test_phase.py [phase] + + phase: 1-7 (default: run all phases sequentially) + +Each phase fetches the corresponding branch, checks out the renderer and +content files for that phase, starts a local HTTP server, and opens the +browser. Press Enter when done to continue to the next phase. +""" + +import functools +import http.server +import subprocess +import sys +import threading +import time +import webbrowser +from pathlib import Path + +PORT = 8800 + +PHASES = { + 1: ("main", "theme.yml and colour system"), + 2: ("v0.4_phase2", "Icon system — local SVGs, no Google Fonts"), + 3: ("v0.4_phase3", "Asset validation in mdcms build"), + 4: ("claude/debug-api-errors-gd730", "Callout tags"), + 5: ("v0.4_phase5", "Table of contents tag"), + 6: ("v0.4_phase6", "Offline / fetch-deps"), + 7: ("v0.4_phase7", "PWA — service worker and manifest"), +} + +VERIFY = { + 1: [ + "Existing site renders correctly with theme.yml present", + "Missing theme: key falls back gracefully to hardcoded defaults", + "Accent colour and dark/light mode colours apply from theme.yml", + ], + 2: [ + "All UI icons render correctly from local SVG files (no Google Icons font)", + "Theme toggle, search, hamburger, nav arrows all show icons", + "Broken image displays for a missing icon (test by renaming one SVG)", + "Icon name normalisation: 'arrow-right' and 'Arrow Right' both resolve", + ], + 3: [ + "Run: python3 mdcms.py build --path app/ (NOT the installed mdcms command)", + "Warning printed for assets/images/missing-photo.png (referenced in pages/about.md)", + "No warning for assets/images/logo.png (file exists)", + "Build continues and completes after warnings", + ], + 4: [ + "── Basic types ─────────────────────────────────────────────────", + "callout-info, callout-warning, callout-success, callout-error all render", + "Each has: coloured left border + low-opacity background in the right colour", + "── Title row ───────────────────────────────────────────────────", + "Title row shows: icon (inlined SVG) + bold title text in the accent colour", + "Title text is correct for each type: Information / Warning / Success / Error", + "── No-title callout ────────────────────────────────────────────", + "Callout with no title key: no title row rendered, just the body", + "── Markdown body ───────────────────────────────────────────────", + "Body renders full markdown: bold, italic, lists, inline code, links", + "── Custom icon override ────────────────────────────────────────", + "icon: warning on a callout-info renders the warning SVG, not the info SVG", + "── Config-defined message: key ─────────────────────────────────", + "message: aitranslation resolves title 'PLEASE NOTE:' and body from config.yml", + "── Dark mode ───────────────────────────────────────────────────", + "Toggle dark mode: all four callout types still look correct", + "Colours adapt (border and background tint remain visible on dark background)", + ], + 5: [ + "TOC tag renders a section-grouped page list", + "Only pages visible for active category are listed", + "Draft pages are excluded", + "TOC page itself is excluded from the listing", + "Section headings and sort order are correct", + ], + 6: [ + "mdcms fetch-deps downloads JS/CSS to assets/required/vendors/", + "Patched index.html makes no external network requests", + "Fonts load correctly from local paths", + "Site loads fully offline after fetch-deps", + ], + 7: [ + "service-worker.js and manifest.json generated when pwa: yes", + "Full site accessible offline after one online visit", + "Cache updates correctly on new build deployment", + "Offline message displays when cache evicted", + ], +} + +# Files checked out from the phase branch on every phase switch. +# Renderer + presentational config. Content files (home.md, config.yml) are +# added per phase in EXTRA_FILES so the right test content is loaded. +RENDERER_FILES = [ + "app/index.html", + "app/theme.yml", + "app/assets/icons", + "mdcms.py", +] + +# Per-phase extra files to check out from the phase branch. +# Use this for content or config files that differ between phases. +EXTRA_FILES = { + 4: [ + "app/config.yml", # has callouts: block for message: key test + "app/pages/home.md", # has Phase 4 callout test cases + ], +} + + +def checkout_phase(phase: int) -> bool: + branch, _ = PHASES[phase] + repo_root = Path(__file__).parent + + print(f"\n Fetching branch {branch} from origin...") + result = subprocess.run( + ["git", "fetch", "origin", branch], + cwd=repo_root, + capture_output=True, + text=True, + ) + if result.returncode != 0: + print(f" ERROR fetching: {result.stderr.strip()}") + return False + + files = RENDERER_FILES + EXTRA_FILES.get(phase, []) + print(f" Checking out {len(files)} file groups from origin/{branch}...") + result = subprocess.run( + ["git", "checkout", f"origin/{branch}", "--"] + files, + cwd=repo_root, + capture_output=True, + text=True, + ) + if result.returncode != 0: + print(f" ERROR checking out files: {result.stderr.strip()}") + return False + + print(" Rebuilding nav.yml...") + result = subprocess.run( + ["python3", "mdcms.py", "build", "--path", "app/"], + cwd=repo_root, + capture_output=True, + text=True, + ) + if result.returncode != 0: + print(f" WARNING: mdcms build failed: {result.stderr.strip()}") + else: + out = result.stdout.strip() + if out: + print(f" {out}") + + print(" Ready.\n") + return True + + +def serve(app_dir: Path): + handler = functools.partial( + http.server.SimpleHTTPRequestHandler, + directory=str(app_dir), + ) + handler.log_message = lambda *a: None + with http.server.HTTPServer(("", PORT), handler) as httpd: + httpd.serve_forever() + + +def run_phase(phase: int): + branch, description = PHASES[phase] + + print("\n" + "=" * 62) + print(f" Phase {phase}: {description}") + print(f" Branch: {branch}") + print("=" * 62) + + repo_root = Path(__file__).parent + app_dir = repo_root / "app" + + if phase > 1: + if not checkout_phase(phase): + print(" Checkout failed — skipping this phase.") + return + + print(f" Serving app/ at http://localhost:{PORT}\n") + print(" Checklist:") + for item in VERIFY[phase]: + if item.startswith("──"): + print(f"\n {item}") + else: + print(f" [ ] {item}") + + t = threading.Thread(target=serve, args=(app_dir,), daemon=True) + t.start() + time.sleep(0.3) + webbrowser.open(f"http://localhost:{PORT}") + + print("\n Press Enter when done (Ctrl+C to abort)...") + try: + input() + except KeyboardInterrupt: + print("\n Aborted.") + + +def main(): + if len(sys.argv) == 2: + try: + phase = int(sys.argv[1]) + except ValueError: + print("Usage: python3 test_phase.py [1-7]") + sys.exit(1) + if phase not in PHASES: + print(f"Phase must be 1-7, got {phase}") + sys.exit(1) + run_phase(phase) + else: + for phase in sorted(PHASES): + run_phase(phase) + print(f"\n Phase {phase} done.") + + +if __name__ == "__main__": + main() From dd306b004ce1cbce7c936c4130f0f100436e7501 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 17 May 2026 18:08:37 +0000 Subject: [PATCH 3/5] Debug: add console.log to renderCalloutTag, set title color as inline style Helps diagnose why title row is not showing. Logging shows the raw tag data and whether the title branch is taken. Inline style bypasses any CSS custom-property cascade issues. https://claude.ai/code/session_01UP8Wo2CKPNhvvTkzX48CWF --- app/index.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/index.html b/app/index.html index 30035d6..0c47c25 100644 --- a/app/index.html +++ b/app/index.html @@ -1815,6 +1815,7 @@ function fmtDatetime(dtStr) { }; function renderCalloutTag(container, tag) { + console.log('[mdcms callout] tag:', tag.tagName, '| options:', JSON.stringify(tag.options), '| body:', (tag.body || '').slice(0, 60)); var typeMatch = tag.tagName.match(/^callout-(info|warning|success|error)$/); var calloutType = typeMatch ? typeMatch[1] : 'info'; @@ -1823,6 +1824,7 @@ function fmtDatetime(dtStr) { var title = opts.title || null; var iconName = opts.icon || null; var bodyMd = tag.body || ''; + console.log('[mdcms callout] title =', JSON.stringify(title), '| msgKey =', msgKey); // Resolve message: key — config.yml callouts block if (msgKey) { @@ -1861,13 +1863,17 @@ function fmtDatetime(dtStr) { container.style.setProperty('--callout-bg', hexToRgba(bgColour, 0.08)); if (title) { + console.log('[mdcms callout] creating title row:', title); var titleRow = document.createElement('div'); titleRow.className = 'mdcms-callout-title'; + titleRow.style.color = primaryColour; // bypass CSS var cascade titleRow.appendChild(iconEl(iconName)); var titleText = document.createElement('span'); titleText.textContent = title; titleRow.appendChild(titleText); container.appendChild(titleRow); + } else { + console.log('[mdcms callout] no title — skipping title row'); } if (bodyMd) { From cd1e6e14ce4bb7f908aec0b535984844e611b24e Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 17 May 2026 18:27:41 +0000 Subject: [PATCH 4/5] Fix missing icon broken image, clean up debug logs, expand test cases - iconEl: use actual icon filename as fallback so browser shows a visible broken image when the file is missing (was src="") - Remove debug console.log statements added for diagnosis - home.md: add test cases for message: override (with console warning) and missing icon (broken image should render) - home.md: add explanatory text for message: key test https://claude.ai/code/session_01UP8Wo2CKPNhvvTkzX48CWF --- app/index.html | 10 +++------- app/pages/home.md | 28 +++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/app/index.html b/app/index.html index 0c47c25..1cb851f 100644 --- a/app/index.html +++ b/app/index.html @@ -956,7 +956,8 @@ body { const svg = getIcon(name); const span = document.createElement('span'); span.className = 'mdcms-icon' + (className ? ' ' + className : ''); - span.innerHTML = svg || ''; + const filename = normaliseIconName(name); + span.innerHTML = svg || '[missing: ' + filename + ']'; return span; } @@ -1815,7 +1816,6 @@ function fmtDatetime(dtStr) { }; function renderCalloutTag(container, tag) { - console.log('[mdcms callout] tag:', tag.tagName, '| options:', JSON.stringify(tag.options), '| body:', (tag.body || '').slice(0, 60)); var typeMatch = tag.tagName.match(/^callout-(info|warning|success|error)$/); var calloutType = typeMatch ? typeMatch[1] : 'info'; @@ -1824,7 +1824,6 @@ function fmtDatetime(dtStr) { var title = opts.title || null; var iconName = opts.icon || null; var bodyMd = tag.body || ''; - console.log('[mdcms callout] title =', JSON.stringify(title), '| msgKey =', msgKey); // Resolve message: key — config.yml callouts block if (msgKey) { @@ -1863,17 +1862,14 @@ function fmtDatetime(dtStr) { container.style.setProperty('--callout-bg', hexToRgba(bgColour, 0.08)); if (title) { - console.log('[mdcms callout] creating title row:', title); var titleRow = document.createElement('div'); titleRow.className = 'mdcms-callout-title'; - titleRow.style.color = primaryColour; // bypass CSS var cascade + titleRow.style.color = primaryColour; titleRow.appendChild(iconEl(iconName)); var titleText = document.createElement('span'); titleText.textContent = title; titleRow.appendChild(titleText); container.appendChild(titleRow); - } else { - console.log('[mdcms callout] no title — skipping title row'); } if (bodyMd) { diff --git a/app/pages/home.md b/app/pages/home.md index d076ea1..3ed6b63 100644 --- a/app/pages/home.md +++ b/app/pages/home.md @@ -68,10 +68,36 @@ This info callout uses the warning icon instead of the default info icon. ## Config-defined message (message: key) -```mdcms callout-warning +The callout below uses `message: aitranslation` to pull its title and body from the `callouts:` block in `config.yml`. The type (`warning`) also comes from the config entry, not the tag name. + +```mdcms callout-info message: aitranslation ``` --- +## message: overrides inline content + +When `message:` is present, any inline `title:` or body text is ignored. A warning should appear in the browser console. + +```mdcms callout-info +message: aitranslation +title: This title should be ignored +This body text should also be ignored. Check the console for a warning. +``` + +--- + +## Missing icon + +This callout uses a non-existent icon name. A broken image should appear where the icon would be. + +```mdcms callout-info +title: Custom icon that does not exist +icon: nonexistent_icon +The icon to the left of this title should show as a broken image. +``` + +--- + Toggle dark mode and check all four callout types still look correct. From c6575293037e39f00eeb757c464323f86652d222 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 17 May 2026 18:39:56 +0000 Subject: [PATCH 5/5] Bump version to 0.3.6 https://claude.ai/code/session_01UP8Wo2CKPNhvvTkzX48CWF --- mdcms.py | 6 +++--- pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mdcms.py b/mdcms.py index 8b298cd..473c2f6 100644 --- a/mdcms.py +++ b/mdcms.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# mdcms v0.3.5 — CLI companion +# mdcms v0.3.6 — CLI companion # # Copyright 2026 Kristian Benestad # Apache License, Version 2.0 — https://www.apache.org/licenses/LICENSE-2.0 @@ -21,8 +21,8 @@ import certifi import click import yaml -CLI_VERSION = "0.3.5" -CLI_RELEASE_DATE = "16 May 2026" +CLI_VERSION = "0.3.6" +CLI_RELEASE_DATE = "17 May 2026" MIN_SUPPORTED_VERSION = "0.3" MARKER_RE = re.compile(r"mdcms v(\d+\.\d+)", re.IGNORECASE) diff --git a/pyproject.toml b/pyproject.toml index a139d27..74807ec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "mdcms" -version = "0.3.5" +version = "0.3.6" description = "MD-CMS — Markdown-based CMS companion CLI" readme = "README.md" license = { text = "Apache-2.0" }