{"id":"mermaid","repo":"dutchakdev/paseo-plugin-mermaid","url":"https://github.com/dutchakdev/paseo-plugin-mermaid","package":"paseo-plugin-mermaid","npm":{"package":"paseo-plugin-mermaid","version":"0.2.0","integrity":"sha512-aKBABLFhVoXONkO6KRyEO0oXI/kyjry0mOhI7BJrRuwqwZ8rMUb/pNOwZ7RqSbb2AdCXy0At8F8fMo7hb9e7IA==","publishedAt":"2026-10-05T09:44:58.944Z","downloadsLast30Days":0},"name":"mermaid","description":"Render Mermaid diagrams inside the Paseo chat timeline","categories":["productivity"],"platforms":[],"caveats":["Supports flowcharts and sequence diagrams; unsupported diagram types fall back to source.","Messages containing diagrams use the plugin’s limited Markdown renderer for surrounding prose."],"images":["https://raw.githubusercontent.com/dutchakdev/paseo-plugin-mermaid/95cf07db794f6be3e121a41a7e774e3fdde3ccf5/docs/preview.svg"],"themes":[],"health":{"manifestValid":true,"hasReadme":true,"hasLicense":true,"hasTests":true,"hasTypecheckScript":true,"updatedRecently":true},"scannedAt":"2026-10-05T09:53:31.868Z","addedAt":"2026-10-05T09:50:44Z","npmSecurity":{"status":"passed","blockingFindings":0,"advisoryFindings":0,"scannedAt":"2026-10-05T09:53:20.848Z","version":"0.2.0","integrity":"sha512-aKBABLFhVoXONkO6KRyEO0oXI/kyjry0mOhI7BJrRuwqwZ8rMUb/pNOwZ7RqSbb2AdCXy0At8F8fMo7hb9e7IA=="},"version":"0.2.0","security":{"status":"passed","blockingFindings":0,"advisoryFindings":0,"scannedAt":"2026-10-05T09:53:20.848Z","commit":"95cf07db794f6be3e121a41a7e774e3fdde3ccf5"},"author":"dutchakdev","license":"MIT","paseoVersionRequirement":">=0.8.0","descriptionNodes":[{"type":"text","text":"Render Mermaid diagrams inside the Paseo chat timeline"}],"caveatNodes":[[{"type":"text","text":"Supports flowcharts and sequence diagrams; unsupported diagram types fall back to source."}],[{"type":"text","text":"Messages containing diagrams use the plugin’s limited Markdown renderer for surrounding prose."}]],"manifest":{"id":"mermaid","requirements":{"paseo":">=0.8.0"}},"repoMeta":{"stars":2,"defaultBranch":"main","pushedAt":"2026-10-05T09:40:18Z"},"owner":{"login":"dutchakdev","avatarUrl":"https://avatars.githubusercontent.com/u/1294321?v=4"},"installNotesHtml":"<pre><code class=\"language-sh\">paseo plugin install npm:paseo-plugin-mermaid   # Paseo 0.9 and newer\npaseo plugin ls          # expect: running\n</code></pre>\n<p>Paseo 0.8 has no npm sources, so install from Git there:\n<code>paseo plugin add dutchakdev/paseo-plugin-mermaid</code>. Either way,\n<code>paseo plugin update mermaid</code> pulls later releases. The plugin supports <strong>Paseo 0.8.x through 0.11.x, including betas</strong>, on both\nsides: the daemon compiles it, and the app checks its declared version range.\nIt has no server entry, so it starts no daemon process.</p>\n<p>The manifest remains <code>>=0.8.0</code>, which already admits 0.9.x, 0.10.x and 0.11.x. Paseo also checks a\nprerelease's stable version core, so <code>0.11.0-beta.3</code> satisfies this range; see\n<a href=\"https://paseo.sh/docs/plugins/reference#requirements\">version requirements</a>.\nThe development SDK stays pinned to 0.8.0; Paseo supplies the runtime modules.</p>\n<p>To work on it locally instead:</p>\n<pre><code class=\"language-sh\">git clone https://github.com/dutchakdev/paseo-plugin-mermaid.git\ncd paseo-plugin-mermaid\nnpm install\nnpm run typecheck &#x26;&#x26; npm test\npaseo plugin install \"$PWD\"\n</code></pre>\n<p>Plugins must be enabled daemon-wide first, under <strong>Settings → Plugins → Enable\nplugins</strong>.</p>","readmeText":"<h1 align=\"center\">paseo-plugin-mermaid</h1>\n\n<p align=\"center\">\n  Mermaid diagrams drawn inside the <a href=\"https://paseo.sh\">Paseo</a> chat timeline.<br>\n  When an agent replies with a <code>```mermaid</code> block, you get the drawing instead of the source.\n</p>\n\n<p align=\"center\">\n  <img src=\"https://img.shields.io/badge/Paseo-0.8.x%20%E2%80%93%200.11.x-3987e5\" alt=\"Supports Paseo 0.8.x through 0.11.x, including betas\">\n  <img src=\"https://img.shields.io/badge/tests-110-199e70\" alt=\"110 tests\">\n  <img src=\"https://img.shields.io/badge/dependencies-none-c98500\" alt=\"No runtime dependencies\">\n  <img src=\"https://img.shields.io/badge/license-MIT-9aa1a6\" alt=\"MIT licensed\">\n</p>\n\n<p align=\"center\">\n  <img src=\"docs/preview.svg\" alt=\"A flowchart and a sequence diagram rendered in a Paseo transcript\" width=\"920\">\n</p>\n\n<p align=\"center\"><sub>Generated by <code>npm run preview</code>: the diagram above comes from the plugin&apos;s own parser and layout, so the picture cannot drift from the code.</sub></p>\n\nBuilt on the plugin timeline API introduced in Paseo 0.8.\n\nPaseo draws Mermaid itself too, in an iframe inside a zoomable box with a\nfullscreen viewer. This plugin draws it inline instead: readable at the width of\nthe message, from the first streamed line, with the same controls above it for\nthe times the fitted drawing is not enough: zoom, fit to view, pop out, and the\nsource on demand.\n\n## Install\n\n```sh\npaseo plugin install npm:paseo-plugin-mermaid   # Paseo 0.9 and newer\npaseo plugin ls          # expect: running\n```\n\nPaseo 0.8 has no npm sources, so install from Git there:\n`paseo plugin add dutchakdev/paseo-plugin-mermaid`. Either way,\n`paseo plugin update mermaid` pulls later releases. The plugin supports **Paseo 0.8.x through 0.11.x, including betas**, on both\nsides: the daemon compiles it, and the app checks its declared version range.\nIt has no server entry, so it starts no daemon process.\n\nThe manifest remains `>=0.8.0`, which already admits 0.9.x, 0.10.x and 0.11.x. Paseo also checks a\nprerelease's stable version core, so `0.11.0-beta.3` satisfies this range; see\n[version requirements](https://paseo.sh/docs/plugins/reference#requirements).\nThe development SDK stays pinned to 0.8.0; Paseo supplies the runtime modules.\n\nTo work on it locally instead:\n\n```sh\ngit clone https://github.com/dutchakdev/paseo-plugin-mermaid.git\ncd paseo-plugin-mermaid\nnpm install\nnpm run typecheck && npm test\npaseo plugin install \"$PWD\"\n```\n\nPlugins must be enabled daemon-wide first, under **Settings → Plugins → Enable\nplugins**.\n\n## What it draws\n\n| Diagram | Supported |\n| ------- | --------- |\n| `flowchart` / `graph` | `TD`, `TB`, `BT`, `LR`, `RL` |\n| Node shapes | `[rect]`, `(round)`, `([stadium])`, `[[subroutine]]`, `{diamond}`, `((circle))`, `>asymmetric]` |\n| Edges | `-->`, `---`, `-.->`,  `-.-`, `==>`, `===` |\n| Edge labels | `-->|both|` and `-- forms -->` |\n| `sequenceDiagram` | participants, actors, notes |\n| Message arrows | `->`, `->>`, `-->`, `-->>`, `-x`, `--x`, `-)`, `--)` |\n\nNot supported yet: subgraphs, `style`/`classDef` directives, and the diagram types\nbeyond these two. Unrecognised lines are counted and reported under the drawing\nrather than dropped, and a diagram the parser cannot read at all falls back to\nshowing its source.\n\n## Controls\n\nEvery drawing carries a toolbar: `Zoom out · 100% · Zoom in · Fit to view · Pop out`\non the left and `Show code` on the right. The zoom model is the one Paseo's own\ndiagram box uses, so a reader who knows one knows the other.\n\n| Control | What it does |\n| ------- | ------------ |\n| **Zoom in / out** | Steps by ×1.25 and ÷1.25 between 25% and 400%. A button goes quiet at its limit. |\n| **100%** | The zoom relative to the fitted drawing. Fitted means scaled to the width of the row, grown a little when small, and never shrunk past the point where labels stop being readable. |\n| **Fit to view** | In the row: show the whole drawing across the row, even below the readability floor, for the wide ones that would otherwise scroll sideways. It never grows a drawing past 100%. In the pop-out: fit both axes of the window. Quiet once it is there. |\n| **Pop out** | Opens the drawing in a host modal, fitted to the window on both axes, with the same toolbar. Zoomed past the window, it scrolls on both axes. |\n| **Show code** | Swaps the drawing for its Mermaid source and quiets the zoom controls until you switch back. |\n\nZooming in the row makes the row taller and, past its width, scrolls it\nsideways; the transcript scrolls vertically as it always does, so nothing is\nclipped. On phones and narrow windows the button labels drop and the icons and\nthe percent stay.\n\n## How it works\n\n```mermaid\nflowchart TD\n    Msg([Message arrives]) --> Check{Has mermaid?}\n    Check -->|no| Paseo[Paseo renders it]\n    Check -->|yes| Split[[Split into segments]]\n    Split --> Text(Prose)\n    Split --> Src(Diagram source)\n    Text --> Md[Minimal markdown]\n    Src --> Parse{Which parser?}\n    Parse -->|flowchart| Layout[Layered layout]\n    Parse -->|sequence| Columns[Column layout]\n    Parse -.->|neither| Raw[Show source]\n    Layout --> Draw((Views))\n    Columns --> Draw\n```\n\nThree constraints shaped this plugin.\n\n**Mermaid itself cannot run here.** A Paseo client bundle may import only the modules the\napp provides: `react`, `react-native`, `@tanstack/react-query`, `zod` and the\n`@getpaseo/plugin` entries. There is no\nSVG, no canvas and no webview, and Mermaid needs a DOM. So the parser, the layout\nand the drawing are all written from scratch. Every line you see is a positioned\n`View`: node boxes, edge segments 1.5px thick, and arrowheads made from a View\nwith three transparent borders.\n\n**A transformer replaces the whole timeline entry.** Once a message contains a\ndiagram, the plugin owns the message. It is split into prose and diagram\nsegments, and each becomes its own item, so the text around the diagram keeps its\nplace. That prose goes through a small Markdown renderer covering headings,\nlists, emphasis and code — less than Paseo's own, which is why messages without a\ndiagram are left alone entirely.\n\n**Items store the source, not a parsed graph.** Parsing happens at render time.\nThe stored data stays small, and a later fix to the parser improves diagrams that\nwere sent months ago.\n\n**The fence is claimed while it is still open.** Paseo runs transformers on every\nstreaming update, and it renders `mermaid` fences itself as soon as one opens. A\ntransformer that waited for the closing ``` would leave the host drawing the\ndiagram for the whole stream and then swap renderers at the last line. An\nunfinished block is therefore taken over at once and drawn from whatever has\nparsed so far.\n\n**The drawing is fitted to the row.** A diagram's natural size is whatever its\nlabels happened to add up to, which is no basis for how big it should appear. The\nrow is measured, the drawing is scaled to fit, small diagrams are grown a little\nso they do not look lost, and shrinking stops at the point where labels would\nstop being readable. Only past that does it scroll sideways. The toolbar's zoom\nmultiplies that fit, which is why 100% is the fit itself and not the natural size.\n\n## Development\n\n```sh\nnpm run typecheck\nnpm test                 # 110 tests\npaseo plugin reload mermaid\n```\n\nThe parsers, the layout, the zoom model and the transform are pure functions\nwith no runtime dependencies, and that is where the tests are: bracket shapes,\noperator precedence (`-.->` must never read as `-.-` plus a stray `>`), cycles in\na flowchart, node overlap, arrow direction, zoom steps that land back on 100%,\nwhich toolbar controls are live, and the JSON round trip Paseo performs on item\ndata before rendering. The Views themselves are checked by `npm run typecheck`\nand by reloading the plugin.\n\n| File | Role |\n| ---- | ---- |\n| `shared/segment.ts` | splits a message into prose and diagram blocks |\n| `shared/flowchart.ts` | flowchart parser |\n| `shared/sequence.ts` | sequence diagram parser |\n| `shared/layout.ts` | layered layout, orthogonal edge routing, column layout |\n| `shared/markdown.ts` | the Markdown subset used for prose |\n| `shared/zoom.ts` | zoom steps, fit to view, and which controls are live |\n| `shared/transform.ts` | the timeline transform itself |\n| `client/diagram.tsx` | drawing, in Views, at natural size |\n| `client/viewer.tsx` | fitting, zoom and the source toggle, in the row and in the pop-out |\n| `client/toolbar.tsx` | the toolbar |\n| `client/markdown.tsx` | prose rendering |\n| `client/item.tsx` | the two timeline renderers |\n| `index.client.tsx` | registers the transformers and renderers; the only entry |\n\n## License\n\nMIT\n"}