843654a5ed
* fix(security): XSS in threads plugin + invalid JSON in init template (S-7, F9) - threads plugin: stop interpolating raw authors.json text into a <script> body. Parse as JSON and re-serialise through scriptLiteral, which escapes </script, <!--, U+2028, and U+2029. Closes CWE-79 XSS in config.plugins.threads.authors for every page that loads the threads client. Add @docmd/utils as a runtime dependency. - init: missing comma between two navigation entries produced invalid JSON in the generated docmd.config.json, breaking the demo template inside the Docker image on first run. Adds scripts/probe-threads-xss.mjs — a regression probe that feeds attacker payloads (</script><script>, U+2028, non-object values) and asserts the output contains no breakout. * fix(0.8.11): cross-locale link, TUI error summary, docusaurus frontmatter, deploy node bump Targeted 0.8.11 backlog. Every fix here is non-breaking and verified against the full brute + feature test suites (543/543, 143/143, plus 5/5 in the threads XSS probe). Closes four open items from battle-test-reports/unified-issues.md. - M-5: cross-locale link to default locale prefix fr/index.md writing [English](/en/) produced a 404 because the default locale lives at root, not under its own prefix. Strip the default-locale prefix from absolute hrefs in the rendered markdown so cross-locale links point to the actual page. The strip runs before #167 relative-path rewrite so both passes see a clean path. Adds Test 3.5 in feature-integration.test.js with 6 assertions covering the fix and the no-regression for the online build (clean URLs without index.html suffix). - N-12: end-of-build error summary Previously the user saw "Build complete" and only later discovered plugin failures when downstream tools choked on a bad artifact. Now every failed plugin (load error or runtime error) is listed by name + hook + reason in the TUI before the build aborts, so the operator can grep for any of them. - T-Z14 / T-Z17: Docusaurus frontmatter translation Docusaurus-specific keys (id, sidebar_label) are now translated to docmd equivalents (drop id, sidebar_label -> nav_title) when running docmd migrate --docusaurus. Files that fail to parse keep their original content; a TUI line reports the count of files touched. - N-5 / N-8: deploy Dockerfile node version Bump packages/deployer/src/providers/docker.ts from node:20-alpine to node:22-alpine. Matches the 0.9.0 floor decision in repo memory and keeps the deployed image on the previous LTS (Node 22 is in maintenance until April 2027). Verified: - pnpm --filter @docmd/parser build: clean - pnpm --filter @docmd/core build: clean - node tests/runner.js --skip-setup: 543 passed, 0 failed - node tests/feature-integration.test.js: 143 passed (was 137) - node scripts/probe-threads-xss.mjs: all checks pass * chore(release): bump version 0.8.10 -> 0.8.11 Mechanical version bump across all 27 published packages, the monorepo root, the @docmd/api plugin registry, and the rust engine Cargo manifest + lock. Drops the 12-line duplicate comment block in parser/src/markdown-processor.ts (the code was correct; only the comment describing it was redundant). No functional changes. * fix(search): semantic search auto-detect + single source of truth (S-7 search) Three changes to fix the first-build semantic search failure: 1. client.ts: auto-detect semantic at runtime The client now probes for .docmd-search/manifest.json via a HEAD request, regardless of what data-semantic says on the modal. This fixes the first-build case where deps were installed in onPostBuild (after generateScripts already rendered the page without the data-semantic attribute). The probe is a single round-trip per page load — zero perf cost. 2. search plugin: onConfigResolved + searchConfig Added init capability. onConfigResolved computes a single searchConfig object (semanticRequested, docmdSearchInstalled, peersInstalled, semanticUsable, missingPeers) and stamps it on config._searchConfig. Every other hook reads from this same object — no more duplicate resolution checks across getAssets and generateScripts. 3. maybeReportPeerStatus: idempotent TUI block Emits per-dep [ DONE ]/@huggingface/transformers lines on the first build (or when the dep status changes). Suppressed on subsequent rebuilds when the status is unchanged. Silent when semantic was not requested. Verified: 543/543 tests pass. Minimal build with semantic:true emits .docmd-search-client.js and builds the semantic index on first run. * fix(search): move missing-deps warning after install attempt The per-dep TUI block was firing BEFORE ensureDocmdSearch tried to install the deps, so on first build the user saw: [ SKIP ] @huggingface/transformers [ SKIP ] onnxruntime-node Falling back to keyword search... [ DONE ] docmd-search installed successfully [ DONE ] Semantic search index built Now the warning only appears inside the !ready fallback path, after ensureDocmdSearch has genuinely failed to install., * Update plugins.generated.json