lavish-axi 0.1.83 → 0.1.85

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -243,6 +243,10 @@ pnpm link
243
243
  The agent updates the artifact's Mermaid source, which remains authoritative.
244
244
  Flowchart, sequence, class, ER, and state diagrams convert to editable shapes; other diagram types are images that reviewers can draw and annotate.
245
245
  Lavish changes only the browser view, so saved, standalone, and exported artifacts still render plain Mermaid.
246
+ - **Whiteboard libraries** - Copy Excalidraw library files (`.excalidrawlib`, for example from [libraries.excalidraw.com](https://libraries.excalidraw.com)) into `~/.lavish-axi/excalidraw-libraries/`, or `LAVISH_AXI_STATE_DIR/excalidraw-libraries/` when set. Every whiteboard's library panel lists their items, and an item you drop on the canvas reaches the agent by name in the edit summary.
247
+ Agents run `lavish-axi libraries` to find item refs and can show a flowchart node as one of those icons by adding a `%% lavish-icon <node-id> <library-id>/<item name>` comment to the Mermaid source. Mermaid ignores the comment, so saved, exported, and shared copies, and whiteboards missing that library, show the plain node.
248
+ Lavish only reads that directory and never downloads libraries. Files over 10 MB, more than 25 MB or 5,000 items in total, and unreadable files are skipped; `lavish-axi libraries` lists each skip with its reason.
249
+ Each library carries its author's terms (AWS Architecture Icons, for example, are covered by AWS's own usage terms), so check them before using one.
246
250
  - **Server cleanup** - The detached server stops after the last session ends when nothing is connected, or after `LAVISH_AXI_IDLE_TIMEOUT_MS` (default 30 minutes) with no browser or poll connections.
247
251
  Set `LAVISH_AXI_IDLE_TIMEOUT_MS=0` or `off` to disable idle self-shutdown.
248
252
  - **Server upgrades** - One background server serves every session, so upgrading `lavish-axi` while reviews are open makes the next `lavish-axi <html-file>` replace that server. Only the review page for the artifact being opened reloads itself once the replacement answers - and not even that one while you have unsent annotation text open, which gets the same banner instead so the reload is yours to make. Every other open review page keeps working and shows a banner reading "Lavish was updated. This page is running the previous version.", with a Check and reload button and a Dismiss button, so no page you are reading reloads on its own. After `lavish-axi stop` those pages say Lavish was stopped and to reload after you start it again, and a restart that only picks up a local build says that rather than claiming an update. An open review page whose server simply goes away - idle self-shutdown, a crash, a machine that slept - shows that same banner once reconnecting has failed for a few seconds, rather than retrying a dead server silently while looking fine; it clears itself if the server comes back, and dismissing it keeps it dismissed until then.
@@ -272,6 +276,7 @@ pnpm link
272
276
  | `lavish-axi share <html-file>` | Publish the artifact (local assets inlined) to [ht-ml.app](https://ht-ml.app), a third-party host not part of Lavish, and print a visitable URL plus a secret update key; shares are public by default, `--private` locks one behind a generated password, and the same command republishes or unpublishes an existing page with `--site`/`--update-key`. |
273
277
  | `lavish-axi stop` | Shut down the background server. |
274
278
  | `lavish-axi playbook [id]` | List focused artifact guidance or show one playbook; agents must open each matching playbook before writing HTML. |
279
+ | `lavish-axi libraries` | List the Excalidraw libraries in the whiteboard library directory; `--search <text>` or `--library <id>` lists item refs for `%% lavish-icon` nodes. |
275
280
  | `lavish-axi design` | Show agent-facing design guidance, including optional CDN snippets and the whiteboard (Mermaid) opt-in snippet. |
276
281
  | `lavish-axi setup hooks` | Install or repair optional SessionStart hooks for Claude Code, Codex, OpenCode, and GitHub Copilot CLI; restart the agent session afterward. |
277
282
  | `lavish-axi setup plugin` | Register the installed package as an [Agent Plugin](https://agent-plugins.org) in VS Code, Cursor, and GitHub Copilot CLI; opt-in, idempotent, no marketplace involved. Reload each client afterward. |
@@ -3574,11 +3574,32 @@ function postToWhiteboard(index, placement, message) {
3574
3574
  else postToInlineWhiteboard(index, message);
3575
3575
  }
3576
3576
 
3577
- async function fetchMermaidSources() {
3577
+ async function fetchMermaidSourcesData() {
3578
3578
  const response = await fetch("/api/" + key + "/mermaid-sources");
3579
3579
  if (!response.ok) throw new Error("could not read the artifact's Mermaid sources");
3580
3580
  const data = await response.json();
3581
- return Array.isArray(data.sources) ? data.sources : [];
3581
+ return {
3582
+ sources: Array.isArray(data.sources) ? data.sources : [],
3583
+ librariesVersion: typeof data.libraries_version === "string" ? data.libraries_version : "",
3584
+ };
3585
+ }
3586
+
3587
+ async function fetchMermaidSources() {
3588
+ return (await fetchMermaidSourcesData()).sources;
3589
+ }
3590
+
3591
+ // Fetched per init so a frame converts with the libraries its source hash was
3592
+ // computed from; a failed fetch resolves null and the frame converts without
3593
+ // libraries.
3594
+ function fetchWhiteboardLibraries() {
3595
+ return fetch("/api/whiteboard-libraries")
3596
+ .then((response) => (response.ok ? response.json() : null))
3597
+ .then((data) =>
3598
+ Array.isArray(data?.libraries)
3599
+ ? { libraries: data.libraries, version: typeof data.version === "string" ? data.version : "" }
3600
+ : null,
3601
+ )
3602
+ .catch(() => null);
3582
3603
  }
3583
3604
 
3584
3605
  async function authenticateWhiteboardChannel(token) {
@@ -3607,11 +3628,17 @@ function whiteboardRecord(index) {
3607
3628
 
3608
3629
  async function handleWhiteboardReady(index, mode, isCurrent) {
3609
3630
  try {
3610
- const sources = await fetchMermaidSources();
3631
+ const librariesRequest = fetchWhiteboardLibraries();
3632
+ const { sources, librariesVersion } = await fetchMermaidSourcesData();
3611
3633
  const source = sources.find((item) => item.index === index);
3612
3634
  if (!source) throw new Error("this diagram's Mermaid source was not found in the artifact file");
3613
3635
  const savedResponse = await fetch("/api/" + key + "/whiteboard/" + index);
3614
3636
  const saved = savedResponse.ok ? (await savedResponse.json()).whiteboard : null;
3637
+ const librariesData = await librariesRequest;
3638
+ // A library file that changed between the two requests leaves the frame
3639
+ // with libraries that do not match this source hash: treat that like a
3640
+ // failed fetch, so the conversion's autosave is held.
3641
+ const librariesMatch = Boolean(librariesData) && (!librariesVersion || librariesData.version === librariesVersion);
3615
3642
  const record = whiteboardRecord(index);
3616
3643
  record.source = String(source.source || "");
3617
3644
  record.sourceHash = String(source.hash || "");
@@ -3624,6 +3651,8 @@ async function handleWhiteboardReady(index, mode, isCurrent) {
3624
3651
  source: record.source,
3625
3652
  sourceHash: record.sourceHash,
3626
3653
  saved,
3654
+ libraries: librariesData ? librariesData.libraries : [],
3655
+ librariesUnavailable: !librariesMatch,
3627
3656
  theme: whiteboardTheme(),
3628
3657
  });
3629
3658
  return true;