lavish-axi 0.1.26 → 0.1.28

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
@@ -53,6 +53,7 @@ npx skills add kunchenguid/lavish-axi --skill lavish
53
53
 
54
54
  That is the entire setup - no npm install needed.
55
55
  The skill teaches your agent to run Lavish through `npx -y lavish-axi`, so the CLI comes along on demand.
56
+ Its frontmatter also includes Hermes Agent metadata, so Hermes-compatible harnesses can categorize and surface it as a first-class productivity skill.
56
57
 
57
58
  Then, in agents that expose skills as slash commands (Claude Code, for example), invoke it directly:
58
59
 
@@ -127,7 +128,10 @@ pnpm link
127
128
  ```
128
129
 
129
130
  - **File-path identity** - Sessions are keyed by the canonical HTML file path, so agents do not need opaque IDs.
130
- - **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. Before writing HTML, choose a design system in strict priority order: follow a user-requested look first; otherwise inspect the current project for a Tailwind or theme config, CSS variables or design tokens, a component library, brand assets, or existing styled pages and match what you find; only when both come up empty, run `lavish-axi design` for a copy-pasteable Tailwind CSS v4 + DaisyUI v5 CDN fallback.
131
+ - **Portable artifacts** - The artifact runs in an iframe while Lavish injects a small SDK for annotations, snapshots, and feedback controls.
132
+ 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.
133
+ Before writing HTML, choose a design system in strict priority order: follow a user-requested look first; otherwise inspect the current project for a Tailwind or theme config, CSS variables or design tokens, a component library, brand assets, or existing styled pages and match what you find; only when both come up empty, run `lavish-axi design` for a copy-pasteable Tailwind CSS v4 + DaisyUI v5 CDN fallback.
134
+ That fallback guidance recommends DaisyUI's `luxury` theme by default and warns not to `@apply` DaisyUI classes inside Tailwind browser-runtime style blocks.
131
135
  - **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.
132
136
  - **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">`.
133
137
  - **Feedback controls** - Native form controls (radios, checkboxes, inputs, selects, buttons, labels, contenteditable) are interactive automatically, so they do not need `data-lavish-action`; wire their handlers to `window.lavish.queuePrompt()` or `window.lavish.sendQueuedPrompts()` to send feedback.
@@ -140,6 +144,7 @@ pnpm link
140
144
  - **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.
141
145
  Set `LAVISH_AXI_IDLE_TIMEOUT_MS=0` or `off` to disable idle self-shutdown.
142
146
  - **Local-first state** - Session state stays under `.lavish-axi/` in the workspace.
147
+ - **Network binding** - The server binds to loopback (`127.0.0.1`) by default. Set `LAVISH_AXI_HOST` to bind elsewhere; a wildcard (`0.0.0.0` or `::`) binds every interface. Binding beyond loopback exposes an unauthenticated server that can read and serve arbitrary local files to anything that can reach it, so only do so on a trusted network. Set `LAVISH_AXI_LINK_HOST` to control the hostname written into generated session links (defaults to the bind address, or loopback when bound to a wildcard).
143
148
 
144
149
  ## CLI Reference
145
150
 
@@ -151,7 +156,7 @@ pnpm link
151
156
  | `lavish-axi end <html-file>` | End a session. |
152
157
  | `lavish-axi stop` | Shut down the background server. |
153
158
  | `lavish-axi playbook [id]` | List focused artifact guidance or show one playbook. |
154
- | `lavish-axi design` | Show the Tailwind + DaisyUI CDN fallback after user and project design sources come up empty. |
159
+ | `lavish-axi design` | Show the Tailwind + DaisyUI CDN fallback, including the `luxury` default theme and DaisyUI `@apply` warning. |
155
160
  | `lavish-axi setup hooks` | Install or repair optional SessionStart hooks for Claude Code, Codex, and OpenCode; restart the agent session afterward. |
156
161
  | `lavish-axi server` | Run the local Lavish Editor server. |
157
162
 
package/dist/cli.mjs CHANGED
@@ -70,11 +70,12 @@ function createDesignOutput() {
70
70
  other_design_systems: "If the user asks for a different design system (Bootstrap, custom CSS, plain HTML, etc.), use that instead - Lavish does not require DaisyUI."
71
71
  },
72
72
  theme_usage: [
73
- 'Set the page theme with `<html data-theme="luxury">`.',
73
+ 'Default to `<html data-theme="luxury">` - it matches the Lavish look. Pick a different theme from the list below only when the user asked for one or the content clearly calls for it.',
74
74
  'Set a nested section theme with `<section data-theme="night">`.',
75
75
  "Prefer semantic colors such as `bg-base-100`, `bg-base-200`, `text-base-content`, `bg-primary`, `text-primary-content`, `alert-warning`, and `btn-primary` so themes remain readable.",
76
76
  "Avoid hardcoded Tailwind color names for text and surfaces unless the user asked for exact colors.",
77
- "Use Tailwind responsive prefixes such as `sm:`, `md:`, `lg:`, and `xl:` for layout changes."
77
+ "Use Tailwind responsive prefixes such as `sm:`, `md:`, `lg:`, and `xl:` for layout changes.",
78
+ 'Never `@apply` DaisyUI classes (such as `text-base-content/40`, `bg-base-200`, or `btn`) inside `<style type="text/tailwindcss">` - the Tailwind browser runtime does not know them, and one unknown utility aborts the entire compile, leaving the page with no Tailwind styles at all. Put DaisyUI classes directly on elements, or write plain CSS with theme variables such as `var(--color-base-200)`.'
78
79
  ],
79
80
  themes: DAISYUI_THEMES,
80
81
  components: {
@@ -473,6 +474,25 @@ import { mkdir } from "node:fs/promises";
473
474
  import os from "node:os";
474
475
  import path from "node:path";
475
476
  var LOOPBACK_HOST = "127.0.0.1";
477
+ var IPV6_LOOPBACK_HOST = "::1";
478
+ var WILDCARD_BIND_LOOPBACK = /* @__PURE__ */ new Map([
479
+ ["0.0.0.0", LOOPBACK_HOST],
480
+ ["::", IPV6_LOOPBACK_HOST]
481
+ ]);
482
+ function bindHost(env = process.env) {
483
+ return env.LAVISH_AXI_HOST?.trim() || LOOPBACK_HOST;
484
+ }
485
+ function clientHost(env = process.env) {
486
+ const host = bindHost(env);
487
+ return WILDCARD_BIND_LOOPBACK.get(host) ?? host;
488
+ }
489
+ function linkHost(env = process.env) {
490
+ return env.LAVISH_AXI_LINK_HOST?.trim() || clientHost(env);
491
+ }
492
+ function hostForUrl(host) {
493
+ if (host.includes(":") && !host.startsWith("[")) return `[${host}]`;
494
+ return host;
495
+ }
476
496
  function stateDir() {
477
497
  return process.env.LAVISH_AXI_STATE_DIR || path.join(os.homedir(), ".lavish-axi");
478
498
  }
@@ -1228,7 +1248,9 @@ async function serve({
1228
1248
  debug = false,
1229
1249
  log = null,
1230
1250
  pollHeartbeatMs = 15e3,
1231
- idleTimeoutMs = resolveIdleTimeoutMs()
1251
+ idleTimeoutMs = resolveIdleTimeoutMs(),
1252
+ host = bindHost(),
1253
+ linkHost: linkHostName = linkHost()
1232
1254
  }) {
1233
1255
  const app = express();
1234
1256
  const store = new SessionStore(stateFile2);
@@ -1258,7 +1280,7 @@ async function serve({
1258
1280
  try {
1259
1281
  const file = await canonicalFile(req.body.file);
1260
1282
  const key = sessionKey(file);
1261
- const url = `http://${LOOPBACK_HOST}:${publicPort}/session/${key}`;
1283
+ const url = `http://${hostForUrl(linkHostName)}:${publicPort}/session/${key}`;
1262
1284
  const existing = await store.findByKey(key);
1263
1285
  const session = await store.upsertSession(file, url);
1264
1286
  if (existing?.status === "ended") {
@@ -1531,8 +1553,11 @@ data: ${JSON.stringify({ state: computePresence(req.params.key, activePolls, del
1531
1553
  app.use((error, req, res, _next) => {
1532
1554
  res.status(500).json({ error: error instanceof Error ? error.message : String(error) });
1533
1555
  });
1534
- const httpServer = await new Promise((resolve) => {
1535
- const s = app.listen(port, LOOPBACK_HOST, () => resolve(s));
1556
+ const httpServer = await new Promise((resolve, reject) => {
1557
+ const s = app.listen(port, host, () => {
1558
+ if (s.address()) resolve(s);
1559
+ });
1560
+ s.once("error", reject);
1536
1561
  });
1537
1562
  publicPort = httpServer.address().port;
1538
1563
  let shuttingDown = false;
@@ -1946,7 +1971,7 @@ function normalizePagePath(path5) {
1946
1971
  // src/cli.js
1947
1972
  var COMMANDS = /* @__PURE__ */ new Set(["open", "poll", "end", "stop", "server", "playbook", "design", "setup"]);
1948
1973
  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`.";
1949
- var VERSION = "0.1.26";
1974
+ var VERSION = "0.1.28";
1950
1975
  async function run(argv) {
1951
1976
  await ensureStateDir();
1952
1977
  const normalizedArgv = normalizeArgv(argv);
@@ -2194,11 +2219,11 @@ async function endCommand(args) {
2194
2219
  }
2195
2220
  async function stopCommand(args) {
2196
2221
  const port = Number(flagValue(args, "--port") || defaultPort());
2197
- const baseUrl = `http://${LOOPBACK_HOST}:${port}`;
2222
+ const baseUrl = `http://${hostForUrl(clientHost())}:${port}`;
2198
2223
  return shutdownServerOnPort(port, { baseUrl, currentVersion: VERSION });
2199
2224
  }
2200
2225
  async function shutdownServerOnPort(port, {
2201
- baseUrl = `http://${LOOPBACK_HOST}:${port}`,
2226
+ baseUrl = `http://${hostForUrl(clientHost())}:${port}`,
2202
2227
  currentVersion = VERSION,
2203
2228
  fetchHealth: healthFetcher = fetchHealth,
2204
2229
  requestShutdown: shutdownRequester = requestShutdown,
@@ -2278,7 +2303,7 @@ function isHtmlPath(file) {
2278
2303
  }
2279
2304
  async function ensureServer({ forceRestart = false } = {}) {
2280
2305
  const port = defaultPort();
2281
- const baseUrl = `http://${LOOPBACK_HOST}:${port}`;
2306
+ const baseUrl = `http://${hostForUrl(clientHost())}:${port}`;
2282
2307
  const existing = await fetchHealth(baseUrl);
2283
2308
  if (existing && !shouldRestartServer(VERSION, existing, forceRestart)) {
2284
2309
  return baseUrl;
@@ -2542,6 +2567,8 @@ Install or repair agent SessionStart hooks for lavish-axi ambient context in Cla
2542
2567
  server: `Usage: lavish-axi server [--port 4387] [--verbose]
2543
2568
 
2544
2569
  Run the local Lavish Editor server. Pass --verbose (or set LAVISH_AXI_DEBUG=1) to log session and watcher events to stderr. Detached server output is appended to ~/.lavish-axi/server.log, or LAVISH_AXI_STATE_DIR/server.log when set, for startup and crash diagnostics.
2570
+
2571
+ LAVISH_AXI_HOST sets the bind address (default 127.0.0.1; a wildcard 0.0.0.0 or :: binds every interface). Binding beyond loopback exposes an unauthenticated server that can read and serve arbitrary local files to anything that can reach it, so only do so on a trusted network. LAVISH_AXI_LINK_HOST sets the hostname written into generated session links (default: the bind address, or loopback when bound to a wildcard). LAVISH_AXI_NO_OPEN=1 (or --no-open) suppresses the local browser launch.
2545
2572
  `
2546
2573
  };
2547
2574
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lavish-axi",
3
- "version": "0.1.26",
3
+ "version": "0.1.28",
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",
@@ -2,6 +2,11 @@
2
2
  name: lavish
3
3
  description: Turn complex or visual agent responses into rich, reviewable HTML artifacts the user can annotate and send feedback on, using the lavish-axi CLI. Use when about to give a plan, comparison, diagram, table, code diff, report, or anything easier to grasp visually than as prose.
4
4
  argument-hint: <what the artifact should show>
5
+ author: Kun Chen (kunchenguid)
6
+ metadata:
7
+ hermes:
8
+ tags: [html, review, artifacts, visualization]
9
+ category: productivity
5
10
  ---
6
11
 
7
12
  # Lavish Editor