lavish-axi 0.1.13 → 0.1.15

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
@@ -97,7 +97,7 @@ pnpm link
97
97
  - **File-path identity** - Sessions are keyed by the canonical HTML file path, so agents do not need opaque IDs.
98
98
  - **Portable artifacts** - The artifact runs in an iframe while Lavish injects a small SDK for annotations, snapshots, and feedback controls. Lavish does not inject any design system, so the saved HTML file renders identically whether you open it through `lavish-axi` or directly in a browser. Run `lavish-axi design` for a copy-pasteable CDN snippet to opt in to Tailwind CSS v4 + DaisyUI v5, or use any other design system (or none).
99
99
  - **Local assets** - Copy local images, CSS, fonts, and scripts next to the HTML artifact and reference them with relative paths from that directory; root-prefixed paths such as `/assets/logo.png` will not resolve through Lavish's artifact route.
100
- - **Live reload** - Lavish watches the HTML artifact file by default. To also reload on sibling asset changes, add `data-lavish-live-reload-root` to the root element or `<meta name="lavish-live-reload" content="root">`.
100
+ - **Live reload** - Lavish watches the HTML artifact file by default and preserves the artifact iframe scroll position across reloads. To also reload on sibling asset changes, add `data-lavish-live-reload-root` to the root element or `<meta name="lavish-live-reload" content="root">`.
101
101
  - **Feedback controls** - Mark buttons, choices, and other interactive elements with `data-lavish-action` so Lavish does not annotate them, then call `window.lavish.queuePrompt()` or `window.lavish.sendQueuedPrompts()` from the control handler.
102
102
  - **Agent presence** - The browser shows when no agent is listening, keeps queued feedback for the next successful `lavish-axi poll` send even across reloads, and only blocks sending while the agent is working on delivered feedback.
103
103
  - **Precise targets** - Text annotations include selected text plus range anchors, so agents are not limited to whole-element selectors.
@@ -105,15 +105,16 @@ pnpm link
105
105
 
106
106
  ## CLI Reference
107
107
 
108
- | Command | Description |
109
- | ----------------------------- | ------------------------------------------------------------ |
110
- | `lavish-axi` | Show current sessions and usage guidance. |
111
- | `lavish-axi <html-file>` | Open or resume a Lavish Editor session. |
112
- | `lavish-axi poll <html-file>` | Long-poll until the user sends feedback or ends the session. |
113
- | `lavish-axi end <html-file>` | End a session. |
114
- | `lavish-axi playbook [id]` | List focused artifact guidance or show one playbook. |
115
- | `lavish-axi design` | Show CDN snippet + DaisyUI component reference (opt-in). |
116
- | `lavish-axi server` | Run the local Lavish Editor server. |
108
+ | Command | Description |
109
+ | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
110
+ | `lavish-axi` | Show current sessions and usage guidance. |
111
+ | `lavish-axi <html-file>` | Open or resume a Lavish Editor session. |
112
+ | `lavish-axi poll <html-file>` | Long-poll until the user sends feedback or ends the session. |
113
+ | `lavish-axi end <html-file>` | End a session. |
114
+ | `lavish-axi playbook [id]` | List focused artifact guidance or show one playbook. |
115
+ | `lavish-axi design` | Show CDN snippet + DaisyUI component reference (opt-in). |
116
+ | `lavish-axi setup hooks` | Install or repair optional SessionStart hooks for Claude Code, Codex, and OpenCode; restart the agent session afterward. |
117
+ | `lavish-axi server` | Run the local Lavish Editor server. |
117
118
 
118
119
  Known playbook IDs: `diagram`, `table`, `comparison`, `plan`, `diff`, `input`, `slides`.
119
120
 
@@ -24,6 +24,7 @@ let pendingSnapshot = "";
24
24
  let workingBubble = null;
25
25
  let submitQueuedPromise = null;
26
26
  let submitQueuedAgain = false;
27
+ let lastScroll = { x: 0, y: 0 };
27
28
 
28
29
  function escapeHtml(value) {
29
30
  return String(value).replace(
@@ -244,6 +245,9 @@ window.addEventListener("message", (event) => {
244
245
  pendingSnapshot = msg.snapshot || "";
245
246
  submitQueued();
246
247
  }
248
+ if (msg.type === "lavish:scroll") {
249
+ lastScroll = { x: Number(msg.x) || 0, y: Number(msg.y) || 0 };
250
+ }
247
251
  if (msg.type === "lavish:sendQueuedPrompts") sendQueued();
248
252
  if (msg.type === "lavish:endSession") endSession();
249
253
  });
@@ -258,7 +262,11 @@ annotationButton.onclick = () => {
258
262
  sendButton.onclick = sendQueued;
259
263
  copyPathButton.onclick = copyFilePath;
260
264
  endButton.onclick = endSession;
261
- frame.addEventListener("load", () => postToFrame({ type: "lavish:setAnnotationMode", enabled: annotation }));
265
+ frame.addEventListener("load", () => {
266
+ postToFrame({ type: "lavish:setAnnotationMode", enabled: annotation });
267
+ // Replay the pre-reload scroll position so hot reloads don't jump the artifact to the top.
268
+ postToFrame({ type: "lavish:restoreScroll", x: lastScroll.x, y: lastScroll.y });
269
+ });
262
270
 
263
271
  const events = new EventSource("/events/" + key);
264
272
  events.addEventListener("reload", () => {
package/dist/cli.mjs CHANGED
@@ -7,7 +7,7 @@ import { access } from "node:fs/promises";
7
7
  import os2 from "node:os";
8
8
  import path4 from "node:path";
9
9
  import { fileURLToPath } from "node:url";
10
- import { AxiError, runAxiCli } from "axi-sdk-js";
10
+ import { AxiError, installSessionStartHooks, runAxiCli } from "axi-sdk-js";
11
11
 
12
12
  // src/design-reference.js
13
13
  var TAILWIND_BROWSER_VERSION = "4.2.4";
@@ -955,7 +955,22 @@ function createArtifactSdk() {
955
955
  if (msg.type === "lavish:requestSnapshot") {
956
956
  parent.postMessage({ type: "lavish:snapshot", snapshot: snapshot() }, "*");
957
957
  }
958
+ if (msg.type === "lavish:restoreScroll") {
959
+ window.scrollTo(Number(msg.x) || 0, Number(msg.y) || 0);
960
+ }
958
961
  });
962
+ let scrollFrame = 0;
963
+ window.addEventListener(
964
+ "scroll",
965
+ () => {
966
+ if (scrollFrame) return;
967
+ scrollFrame = window.requestAnimationFrame(() => {
968
+ scrollFrame = 0;
969
+ parent.postMessage({ type: "lavish:scroll", x: window.scrollX, y: window.scrollY }, "*");
970
+ });
971
+ },
972
+ { passive: true }
973
+ );
959
974
  document.addEventListener(
960
975
  "mouseover",
961
976
  (event) => {
@@ -1747,7 +1762,7 @@ var HttpTelemetryClient = class {
1747
1762
  await Promise.race([
1748
1763
  drained,
1749
1764
  new Promise((resolve) => {
1750
- setTimeout(resolve, timeoutMs).unref?.();
1765
+ setTimeout(resolve, timeoutMs);
1751
1766
  })
1752
1767
  ]);
1753
1768
  }
@@ -1820,9 +1835,9 @@ function normalizePagePath(path5) {
1820
1835
  }
1821
1836
 
1822
1837
  // src/cli.js
1823
- var COMMANDS = /* @__PURE__ */ new Set(["open", "poll", "end", "server", "playbook", "design"]);
1838
+ var COMMANDS = /* @__PURE__ */ new Set(["open", "poll", "end", "server", "playbook", "design", "setup"]);
1824
1839
  var DESCRIPTION = "Lavish Editor helps agents turn rich HTML artifacts into collaborative human review surfaces. Whenever you are about to give user a complex response that will be easier to understand via a rich / interactive page, consider using Lavish Editor. First generate an interactive HTML artifact according to user request, then run `lavish-axi <html-file>` so the user can visually review it, annotate elements or selected text, queue prompts, and send feedback back through `lavish-axi poll`.";
1825
- var VERSION = "0.1.13";
1840
+ var VERSION = "0.1.15";
1826
1841
  async function run(argv) {
1827
1842
  await ensureStateDir();
1828
1843
  const normalizedArgv = normalizeArgv(argv);
@@ -1841,7 +1856,6 @@ async function run(argv) {
1841
1856
  version: VERSION,
1842
1857
  argv: isTopLevelHelp ? [] : normalizedArgv,
1843
1858
  topLevelHelp: TOP_LEVEL_HELP,
1844
- hooks: { binaryNames: ["lavish-axi"] },
1845
1859
  home: async () => createHomeOutput({
1846
1860
  bin: process.argv[1] || "lavish-axi",
1847
1861
  sessions: isTopLevelHelp ? [] : await visibleSessions(),
@@ -1853,6 +1867,7 @@ async function run(argv) {
1853
1867
  end: endCommand,
1854
1868
  playbook: playbookCommand,
1855
1869
  design: designCommand,
1870
+ setup: setupCommand,
1856
1871
  server: serverCommand
1857
1872
  },
1858
1873
  getCommandHelp
@@ -2022,6 +2037,29 @@ async function playbookCommand(args) {
2022
2037
  async function designCommand() {
2023
2038
  return createDesignOutput();
2024
2039
  }
2040
+ async function setupCommand(args) {
2041
+ if (args.length !== 1 || args[0] !== "hooks") {
2042
+ throw new AxiError("Unknown setup action", "VALIDATION_ERROR", ["Run `lavish-axi setup hooks`"]);
2043
+ }
2044
+ const errors = [];
2045
+ installSessionStartHooks({
2046
+ marker: "lavish-axi",
2047
+ binaryNames: ["lavish-axi"],
2048
+ distEntrypoints: ["dist/cli.mjs", "bin/lavish-axi.js"],
2049
+ homeDir: resolveHookHomeDir(),
2050
+ onError: (message) => errors.push(message)
2051
+ });
2052
+ if (errors.length > 0) {
2053
+ throw new AxiError("Failed to install lavish-axi agent hooks", "SERVER_ERROR", errors);
2054
+ }
2055
+ return {
2056
+ hooks: { status: "installed", integrations: "Claude Code, Codex, OpenCode" },
2057
+ help: ["Restart your agent session to receive lavish-axi ambient context"]
2058
+ };
2059
+ }
2060
+ function resolveHookHomeDir(env = process.env, fallback = os2.homedir()) {
2061
+ return env.HOME || fallback;
2062
+ }
2025
2063
  async function serverCommand(args) {
2026
2064
  const port = Number(flagValue(args, "--port") || defaultPort());
2027
2065
  const debug = args.includes("--verbose") || process.env.LAVISH_AXI_DEBUG === "1";
@@ -2239,6 +2277,7 @@ Usage:
2239
2277
  lavish-axi end <html-file>
2240
2278
  lavish-axi playbook [playbook_id]
2241
2279
  lavish-axi design
2280
+ lavish-axi setup hooks
2242
2281
 
2243
2282
  ${DESIGN_SYSTEM_HINT}
2244
2283
 
@@ -2270,6 +2309,10 @@ Examples:
2270
2309
  design: `Usage: lavish-axi design
2271
2310
 
2272
2311
  Show a copy-pasteable CDN snippet for Tailwind CSS browser runtime v4 + DaisyUI v5 + themes, plus technical reference for DaisyUI components. Lavish artifacts stay portable HTML. Prefer the CDN snippet over hand-writing styles unless explicitly instructed otherwise by the user. If the user asks for another design system or plain HTML, follow that request.
2312
+ `,
2313
+ setup: `Usage: lavish-axi setup hooks
2314
+
2315
+ Install or repair agent SessionStart hooks for lavish-axi ambient context in Claude Code, Codex, and OpenCode. Restart your agent session afterward to receive the context.
2273
2316
  `,
2274
2317
  server: `Usage: lavish-axi server [--port 4387] [--verbose]
2275
2318
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lavish-axi",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "packageManager": "pnpm@11.1.1",
5
5
  "description": "HTML is the new markdown. Lavish is the new editor for your HTML artifacts.",
6
6
  "type": "module",
@@ -26,7 +26,7 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "@tailwindcss/browser": "4.2.4",
29
- "axi-sdk-js": "^0.1.6",
29
+ "axi-sdk-js": "^0.1.7",
30
30
  "chokidar": "^4.0.3",
31
31
  "daisyui": "^5.5.19",
32
32
  "express": "^5.2.1",