Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,8 @@ There is **one** highlighter in the app: the Shiki instance `@pierre/diffs` alre

**Theming:** fences resolve the SAME theme the diff pane resolves, via `resolveFenceTheme` / `resolveSyntaxTheme` in `packages/ui/utils/syntaxTheme.ts` (keyed on `(colorTheme, resolvedMode)`; `packages/review-editor/hooks/usePierreTheme.ts` re-exports them). `useFenceTheme()` (`packages/ui/hooks/useFenceTheme.ts`) feeds the components and re-highlights on palette or mode change. Palettes with no Shiki counterpart fall back to `@pierre/diffs`' own `pierre-dark` / `pierre-light`. Consequence: code blocks follow the active palette in both light and dark instead of always rendering github-dark, so **do not add per-theme `.hljs-*`-style token CSS** — pick the right Shiki theme in `SHIKI_THEME_MAP` instead.

**Mermaid runtime (12.x, lazy):** `@plannotator/ui` pins `mermaid` exactly (12.0.0 since ui 0.40.0; Mermaid 12 lays flowchart/state/class/ER/requirement diagrams out with ELK by default and targets Safari 17.4+ / ES2024 — we take its defaults rather than pinning the 11.x ones). The runtime is loaded lazily on the first diagram through `packages/ui/utils/mermaid.ts`'s own `import('mermaid')`: `packages/editor/App.tsx` deliberately does NOT import `@plannotator/ui/utils/mermaid-eager` (it did through ui 0.39.0), so a plan with no diagram never downloads the ~2 MB runtime + ELK on the share portal or in a host build, and `tests/entry-assets.test.ts` fails if the eager import creeps back into either app. The single-file builds (`apps/hook`, `apps/review`, opencode, the compiled binary) still inline the runtime through `inlineDynamicImports`, so the lazy import saves nothing there and resolves from the bundle itself; the Mermaid 12 cost in those builds is the runtime's own growth. `MermaidBlock` shows the source fence under a "Rendering diagram" status until the first render lands (never the error panel as a placeholder), and `applyMermaidTheme` is keyed on the runtime object, so the lazily loaded runtime is themed on its first render exactly like an eagerly registered one. `mermaid-eager` stays exported for hosts that want the old startup registration.

**Diagram theming (Mermaid):** diagrams follow the palette and mode the same way fences do, through ONE dynamic mapping rather than per-palette themes. `packages/ui/utils/mermaidTheme.ts` reads the live CSS tokens off the document element (`readThemeTokens`: `--background`, `--foreground`, `--card`, `--border`, `--muted`, `--muted-foreground`, `--primary`, the accent tokens, `--font-sans`), derives a complete Mermaid `themeVariables` set for every diagram family from them (`buildMermaidThemeVariables(tokens, mode)`, pure; base theme `dark` under a dark resolved mode, `default` under light; node fill from `card`, borders from `border`, edges and arrowheads from `muted-foreground`, text from `foreground`/`card-foreground`, clusters from `muted`, twelve categorical fills for pie/git/mindmap/journey seeded from `primary`, `accent`, `success`, `warning`, `destructive` and normalized to one lightness per page polarity), and `MermaidBlock` runs the global `mermaid.initialize` through `applyMermaidTheme` once per `(palette, mode)` key from `useTheme()` before each render, re-rendering mounted diagrams when the key changes. Every colour handed to Mermaid is opaque hex (its colour library does not read `oklch()`), and a contrast guard (`ensureContrast`) repairs any text-on-fill pair under WCAG 4.5:1 or line-on-canvas pair under 3:1 (plus 0.1 headroom) by the smallest OKLab step toward `foreground`, then `background`, then pure black/white — guarding page-level text and lines against every surface they can cross (the `bg-muted/30` canvas over the document card and over the bare page, `card`, `muted`, `popover`, ER rows), not the page background alone; `mermaidTheme.test.ts` sweeps every palette in `packages/ui/themes` in both modes against that rule, so a new palette cannot regress it. The pure toolkit behind it is `packages/ui/utils/cssColor.ts`. **Host fallback:** with no theme tokens on the document `readThemeTokens` returns `undefined` and the runtime keeps the static `MERMAID_CONFIG` (still `securityLevel: 'strict'`, pinned) with no extra `initialize`, so a host without `ThemeProvider`/`theme.css` renders exactly as before. Do not add per-palette Mermaid themes or per-theme `.mermaid` CSS — extend the token mapping instead. `GraphvizBlock` already rewrites its SVG to `var(--foreground)` / `var(--muted-foreground)` / `var(--muted)` and needs no equivalent.

**Bundle note:** Pierre imports Shiki's full bundle, so every grammar and theme is already inlined in the single-file builds; reusing its shared highlighter costs no extra bytes and needs no CDN or runtime wasm fetch. The Oniguruma WASM engine is dead weight under `shiki-js` and is aliased to `build/shiki-wasm-stub.ts` in the review, hook and portal Vite configs (via `resolve.alias`, which — unlike `plugins` — is shared with Vite's worker build).
Expand Down
2 changes: 1 addition & 1 deletion apps/skills/extra/plannotator-visual-explainer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Three paths depending on content type. Each has its own references and structure

Always deliver via Plannotator's annotation UI. Do NOT use `open` or `xdg-open`.

For any deliverable that uses Mermaid, render every diagram with Mermaid 11 in both the light
For any deliverable that uses Mermaid, render every diagram with Mermaid 12 in both the light
and dark palettes before opening the annotation UI. Rendering is a hard gate: an exception,
empty SVG, or error output such as `aria-roledescription="error"` or `Syntax error in text`
means the explainer is not deliverable. Fix the diagram or theme configuration and rerun both
Expand Down
10 changes: 5 additions & 5 deletions apps/skills/extra/plannotator-visual-explainer/SKILL.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ describe("plannotator-visual-explainer Mermaid theming", () => {
);
});

test("renders representative Mermaid 11 diagrams in both palettes", async () => {
test("renders representative Mermaid 12 diagrams in both palettes", async () => {
const palettes = [captureMermaidConfig("light"), captureMermaidConfig("dark")];
const uiPackageDir = join(import.meta.dir, "../../../../packages/ui");
const renderProbe = String.raw`
Expand All @@ -92,8 +92,8 @@ describe("plannotator-visual-explainer Mermaid theming", () => {
import("mermaid/package.json", { with: { type: "json" } }),
]);

if (!String(mermaidPackage.version).startsWith("11.")) {
throw new Error("Expected Mermaid 11, received " + mermaidPackage.version);
if (!String(mermaidPackage.version).startsWith("12.")) {
throw new Error("Expected Mermaid 12, received " + mermaidPackage.version);
}

const palettes = JSON.parse(process.env.PLANNOTATOR_MERMAID_PALETTES ?? "[]");
Expand Down Expand Up @@ -184,12 +184,12 @@ describe("plannotator-visual-explainer Mermaid theming", () => {
throw new Error(`Mermaid render probe failed:\n${stderr || stdout}`);
}
expect(stdout).toMatch(
/Rendered 4 Mermaid 11\.[0-9.]+\.[0-9]+ SVGs without error signatures/,
/Rendered 4 Mermaid 12\.[0-9.]+\.[0-9]+ SVGs without error signatures/,
);
}, 20_000);

test("keeps Mermaid rendering as a pre-delivery gate", () => {
expect(skill).toContain("render every diagram with Mermaid 11");
expect(skill).toContain("render every diagram with Mermaid 12");
expect(skill).toContain('aria-roledescription="error"');
expect(skill).toContain("Syntax error in text");
expect(skill).toContain("the explainer is not deliverable");
Expand Down
35 changes: 25 additions & 10 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
"bugs": {
"url": "https://github.com/backnotprop/plannotator/issues"
},
"workspaces": ["apps/*", "packages/*"],
"workspaces": [
"apps/*",
"packages/*"
],
"scripts": {
"dev:hook": "bun run --cwd apps/hook dev",
"dev:portal": "bun run --cwd apps/portal dev",
Expand Down Expand Up @@ -51,5 +54,8 @@
"@types/node": "^25.5.2",
"@types/turndown": "^5.0.6",
"bun-types": "^1.4.0"
},
"overrides": {
"lodash-es": "4.18.1"
}
}
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@plannotator/core",
"version": "0.25.2",
"version": "0.25.3",
"type": "module",
"exports": {
"./agents": "./agents.ts",
Expand Down
Loading