✨ Highlights

Drei koordinierte Fixes, die die Nachmeldungen zu #175 aus v0.8.15 schließen. Keine Breaking Changes, keine neuen Konfigurationsschlüssel, keine Pflichtmigration. Bestehende Projekte bauen und liefern unverändert.

🐛 Fix: Dev-Server respektiert die Produktions-URL

v0.8.15 leitet base automatisch aus dem Pfadanteil von url ab, sodass eine GitHub-Pages-Projektseite unter https://user.github.io/repo automatisch base = /repo/ erhält und subpath-bewusste Asset-URLs erzeugt. Der Dev-Server liefert das Ausgabeverzeichnis jedoch immer an der Wurzel (/) aus — somit lieferte jedes Asset auf localhost einen 404, sobald url einen Subpath enthielt.

Der bekannte Workaround war "base": "/", der den Dev-Betrieb reparierte, aber die Auto-Ableitung abschaltete und damit die Suche im Produktivdeploy brach. Beide Zustände waren je in einer Umgebung kaputt.

Der Fix: Im Dev-Modus wird base = / erzwungen, sobald der Wert automatisch abgeleitet wurde. Die Überschreibung greift nur, wenn:

  • isDev: true gesetzt ist (der Build-Pfad bleibt unangetastet)
  • _baseAutoDerived gesetzt ist (eine explizite base in der Konfiguration wird immer respektiert)
  • die Umgebungsvariable DOCMD_PROJECT_PREFIX fehlt (Workspace-Dev nutzt sie)

Anwender brauchen keinen base-Eintrag mehr in ihrer Konfiguration.

Schlüsselwort- und semantische Suche nutzen nun denselben Ausgabeordner:

  • Vorher: search-index.json lag an der Ausgabewurzel, die semantischen Dateien unter .docmd-search/.
  • Nachher: Beide liegen unter .docmd-search/. Standard-Locale: .docmd-search/search-index.json. Andere Locales: .docmd-search/<locale>/search-index.json.

Das hält die Ausgabewurzel sauber und vereinheitlicht den Vertrag, gegen den der Client lädt — Voraussetzung für den nächsten Fix.

🐛 Fix: Laufzeit-HEAD-Probe auf manifest.json entfernt

Der Suchclient hat bei jedem Seitenaufruf .docmd-search/manifest.json per HEAD angefordert, um den engen Fall abzufangen, dass semantische Abhängigkeiten mitten im Build installiert wurden. Auf jeder reinen Schlüsselwortsuche lieferte diese Probe einen 404 — genau der Fehler, den Anwender gemeldet hatten.

Der Fix: Der semantische Modus wird ausschließlich über das Build-zeit-Flag data-semantic am Suchmodal entschieden. Das Flag wird in onConfigResolved aus semanticUsable berechnet, sodass Build und Client übereinstimmen. Der seltene Mid-Build-Fall löst sich beim nächsten Rebuild (der Dev-Modus löst ihn automatisch aus).

🐛 Fix: Schlüsselwortindex wird immer als Fallback erzeugt

Nachdem die Laufzeit-Probe entfernt war, trat ein weiterer Race auf: Wenn die semantische Indizierung erfolgreich war, wurde der Schlüsselwort-search-index.json komplett übersprungen. War das data-semantic-Flag am Modal veraltet (war beim Rendern auf false gesetzt, weil die Abhängigkeiten noch nicht installiert waren), fiel der Client auf den Schlüsselwortmodus zurück und erhielt einen 404, weil kein Schlüsselwortindex existierte.

Der Fix: Der Schlüsselwortindex wird immer erzeugt, auch nach einem erfolgreichen semantischen Build. Der Index ist winzig (wenige KB bei den meisten Projekten) und dient als Laufzeit-Sicherheitsnetz. TUI-Meldungen werden unterdrückt, wenn Semantic bereits lief; das Log bleibt sauber.

🐛 Fix: data-semantic-Flag wird post-build gestempelt

Das Attribut data-semantic="true" am Suchmodal wird zur Renderzeit aus semanticUsable berechnet, das prüft, ob docmd-search auflösbar ist. Bei einer Neuinstallation werden die Abhängigkeiten in onPostBuild installiert — nachdem die Seiten bereits ohne das Flag gerendert wurden. Der Client bleibt dann im Schlüsselwortmodus, obwohl der semantische Index existiert.

Der Fix: Nachdem der semantische Index erfolgreich gebaut wurde, wird jede HTML-Seite nachbearbeitet, sodass das Modal data-semantic="true" trägt. Das schließt die Race, ohne die Laufzeit-HEAD-Probe zurückzubringen. Der Post-Build-Walk überspringt .docmd-search/ und node_modules/, um auch bei großen Seiten schnell zu bleiben.

🧰 Auto-Installation blockt Workspace-Sub-Projekte nicht mehr vorab

Die Vorab-Prüfung, die vor dem Spawnen des Paketmanagers nach package.json in cwd suchte, wurde entfernt. npm, pnpm, yarn und bun wandern selbst die Verzeichnisstruktur nach oben, um die Projektwurzel zu finden — die Vorab-Prüfung lag also in zwei Fällen falsch, die sie eigentlich abfangen sollte:

  1. Workspace-Sub-Projekte (z. B. docs/docmd-search/, wenn docs/package.json eine Ebene höher liegt).
  2. Jeder Fall, in dem ein Plugin oder Template installieren muss und die Projektwurzel mehrere Verzeichnisse tief liegt.

Der Fix: Der Spawn wird immer versucht. Der hilfreiche Hinweis „kein package.json gefunden" erscheint nur noch, wenn der Spawn tatsächlich scheitert und in keinem Vorgängerverzeichnis eine package.json existiert. Templates laufen über denselben Pfad wie Plugins.

Ende-zu-Ende mit einem frischen Brutetest verifiziert, der @docmd/template-summer und plugins.search.semantic: true nutzt: Beide installieren sich beim ersten Build lautlos, Summer-CSS/-JS landen in site/assets/template/, und der semantische Index schreibt nach site/.docmd-search/.

🏗 Portable Deploys über kanonischen <base href>

Builds ohne --offline mit Subpath (siteRootAbs !== '/') emittieren jetzt genau ein <base href="/<repo>/">-Tag im <head>. Asset-URLs im Head nutzen einfach-relativen Pfad (assets/foo.css); das <base>-Tag verschiebt sie zur Laufzeit an die korrekte Stelle, unabhängig davon, wo die Site gehostet wird.

Warum das wichtig ist: Die vorherige Lösung codierte den Subpath in jede Asset-URL. Der Rename-Flow lief so — Repo umbenennen, der nächste Build gibt weiterhin /old-name/assets/... aus, bis config.url aktualisiert und neu gebaut wird. Mit <base> wird der Pfad einmal aus der Deploy-Stelle berechnet und uniform angewendet. Eine Site zwischen Repos, Hosts oder Ordner-Mounts zu verschieben erfordert keinen Eingriff in config.url, sofern url bereits für das aktuelle Deploy korrekt ist.

Drei-Modus-Grenze, um das sauber zu halten:

Modus <base> Assets
build (Subpath) emittiert einfach-relativ 'assets/foo.css'
build (Root-Deploy) keins (Dokument-Default) einfach-relativ 'assets/foo.css'
dev keins tiefenbewusst ./ oder ../
build --offline keins (file:// hat keinen Host) tiefenbewusst ./ oder ../

Der Kanonisierer (normaliseBaseTag in packages/parser/src/utils/url-utils.ts) entfernt jedes vorhandene <base>-Tag aus älteren Templates oder Drittanbieter-Plugins und fügt genau eines an der kanonischen Position direkt nach </title> ein. Die Deploy-Form wird an einer Stelle entschieden; Templates müssen nichts darüber wissen.

📂 Fix: Robuste Pfadauflösung für Offline-Assets

Offline-Builds (--offline) konnten bisher beliebige Nicht-Markdown-Asset-Dateien (z. B. PDFs, Bilder, JSON-Dateien in Unterverzeichnissen) fälschlicherweise mit /index.html versehen, was Downloads und Bilder unbrauchbar machte.

Der Fix: Der URL-Normalisierer verwendet nun eine robuste, zerstörungsfreie Prüfung, um festzustellen, ob ein Pfad einen Dateinamen mit einem Punkt enthält (was auf eine Asset-Datei hinweist). Dadurch wird sichergestellt, dass nur Ziel-Dateien (.md, .html etc.) verarbeitet werden und andere Dateierweiterungen unangetastet bleiben.

🧰 Verbesserter Consumer-Simulations-Workflow

Das Testen von Änderungen im Monorepo gegen echte Dokumentationsprojekte ist nun nahtlos möglich:

  • Der Fix: Die lokale Simulations-Engine (tools/sim.mjs) wurde mit der Spezifikation --source und der Unterstützung für den --doctor-Modus optimiert, um simulierte Consumer-Überprüfungen durchzuführen.
  • Verdrahtete Befehle: Die Befehle dev:sim, build:sim und doctor:sim wurden direkt zu docs/package.json hinzugefügt, wobei der Wrapper sim.mjs des Monorepos mit den Flags --regen-tars und --skip-monorepo-build verwendet wird.

🧹 Störende CLI-Umgebungswarnungen stummgeschaltet

Das Ausführen von npm- oder npx-Befehlen, die aus einem pnpm-Runner heraus gestartet wurden, konnte interne pnpm-Konfigurationen in die Umgebung lecken lassen, was dazu führte, dass npm lästige Warnungen über “Unknown env config” ausgab.

Der Fix: Die Spawning-Wrapper bereinigen nun die Umgebung, indem sie npm_config_npm_globalconfig, npm_config_verify_deps_before_run und npm_config__jsr_registry vor dem Ausführen von Unterbefehlen aus process.env entfernen.

🎨 Favicon-Fallback zur Vermeidung von 404-Konsolenfehlern

Webbrowser fragen automatisch /favicon.ico an der Wurzel einer Domain ab. Wenn für die Website kein Favicon konfiguriert war, führte dies zu einer 404-Antwort in der Browserkonsole.

Der Fix: Der Seitengenerator und das 404-Template fallen nun automatisch auf das Standard-assets/favicon.ico zurück, wenn config.favicon in der Workspace-Konfiguration nicht definiert ist.

📊 Verbesserte Prep-Pipeline und TUI-Zusammenfassungen

Die TUI der Monorepo-Wartungspipeline wurde verfeinert:

  • Terminal-Cursor-Up-Umschreiben: Der Status des Test-Runners aktualisiert nun die Zeile [ WAIT ] direkt vor Ort zu [ DONE ] oder [ FAIL ], wodurch doppelte Ausgabezeilen in Standard-Terminalemulatoren vermieden werden.
  • Präzise Zeit- und Ergebnisübersicht: Ganz am Ende der Prep-Ausführung berichtet eine prägnante, 2-3-zeilige Zusammenfassung die abgelaufene Gesamtzeit, den Erfolgsstatus und eine Liste der fehlgeschlagenen Abschnitte.

📦 Upgrade

upgrade
npx @docmd/core@0.8.16 build

Keine Konfigurationsänderung nötig. Wer als Workaround für v0.8.15 "base": "/" gesetzt hat, kann das entfernen — der Dev-Server passt sich nun automatisch an.