lavish-axi 0.1.18 → 0.1.19

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.
Files changed (3) hide show
  1. package/README.md +22 -1
  2. package/dist/cli.mjs +17 -8
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -51,6 +51,10 @@ Just tell your agent:
51
51
  Use `npx lavish-axi` to write a product or technical plan for what we discussed.
52
52
  ```
53
53
 
54
+ That works with zero setup - Lavish is an AXI, so any capable agent can run the CLI directly.
55
+
56
+ To make your agent reach for Lavish on its own (without you naming it every time), install the agent hooks as instructed below.
57
+
54
58
  ## Install
55
59
 
56
60
  **npm**
@@ -69,6 +73,23 @@ pnpm run build
69
73
  pnpm link
70
74
  ```
71
75
 
76
+ ## Set Up Agent Hooks (recommended)
77
+
78
+ Lavish does not install agent hooks automatically, which means your agent would not know to use it in a fresh session.
79
+
80
+ Run this once to opt in:
81
+
82
+ ```sh
83
+ lavish-axi setup hooks
84
+ ```
85
+
86
+ This installs a `SessionStart` hook for **Claude Code**, **Codex**, and **OpenCode** that feeds Lavish's ambient context (open sessions, visualization playbooks, and usage guidance) into your agent at the start of each session.
87
+ With the hook installed, your agent learns to turn complex responses into rich, reviewable HTML artifacts proactively - no need to mention `lavish-axi` by name.
88
+
89
+ **Restart your agent session after running this** so the new hook takes effect.
90
+
91
+ Prefer not to install hooks? Lavish still works fully as a plain CLI - just tell your agent to `npx lavish-axi <file.html>` as shown in the Quick Start.
92
+
72
93
  ## How It Works
73
94
 
74
95
  ```
@@ -98,7 +119,7 @@ pnpm link
98
119
  - **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. Choose a design system in priority order: follow a user-requested look first, match the current project's design system or conventions next, and otherwise run `lavish-axi design` for a copy-pasteable Tailwind CSS v4 + DaisyUI v5 CDN fallback.
99
120
  - **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
121
  - **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
- - **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.
122
+ - **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. Mark only custom (non-native) clickable elements with `data-lavish-action` so Lavish does not annotate them.
102
123
  - **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
124
  - **Precise targets** - Text annotations include selected text plus range anchors, so agents are not limited to whole-element selectors.
104
125
  - **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.
package/dist/cli.mjs CHANGED
@@ -642,7 +642,9 @@ var PLAYBOOKS = [
642
642
  "Show queued or selected state clearly so the user trusts what will be sent back."
643
643
  ],
644
644
  design_rules: [
645
- "Put data-lavish-action on any element that should act like a feedback control so Lavish does not annotate it and shows a pointer cursor instead.",
645
+ "Native form controls - radios, checkboxes, text inputs, selects, textareas, buttons, options, labels, and contenteditable regions - are interactive automatically: clicks toggle, focus, and type instead of annotating, so they do not need data-lavish-action. Build choice and option UIs from these whenever you can.",
646
+ "To turn a native control into agent feedback, wire its own change, click, or submit handler to window.lavish.queuePrompt() (for example a radio group's onchange, or a submit button that reads the selected values) - no marker required.",
647
+ "Put data-lavish-action only on custom (non-native) elements that should act like a feedback control - typically a styled div or span you made clickable - so Lavish does not annotate it and shows a pointer cursor instead.",
646
648
  "Call window.lavish.queuePrompt(prompt, options) from the control's click, change, or submit handler to queue a precise request for the agent.",
647
649
  "Pass options such as tag, text, selector, target, or data when they help the agent understand exactly what the user chose.",
648
650
  "Call window.lavish.sendQueuedPrompts() when the control should immediately send the queued feedback instead of waiting for the user to press Send to Agent.",
@@ -656,7 +658,8 @@ var PLAYBOOKS = [
656
658
  ],
657
659
  lavish_notes: [
658
660
  "Lavish is strongest when the artifact becomes a focused review surface and not just a static page.",
659
- `A minimal control looks like \`<div role="button" tabindex="0" data-lavish-action onclick="window.lavish.queuePrompt('Choose option A', { tag: 'choice', text: 'Option A' })">Choose option A</div>\`.`,
661
+ `A native choice looks like \`<label><input type="radio" name="plan" onchange="window.lavish.queuePrompt('Use the Pro plan', { tag: 'choice', text: 'Pro' })"> Pro</label>\` - it just works, no marker needed.`,
662
+ `A custom (non-native) control needs the marker: \`<div role="button" tabindex="0" data-lavish-action onclick="window.lavish.queuePrompt('Choose option A', { tag: 'choice', text: 'Option A' })">Choose option A</div>\`.`,
660
663
  "Use window.lavish.queuePrompt for user intent, not internal analytics or UI-only state changes.",
661
664
  "End input paths with an obvious way for the user to send feedback back to the agent."
662
665
  ]
@@ -779,7 +782,7 @@ function createArtifactSdk() {
779
782
  const text = selection.toString().trim().replace(/\s+/g, " ");
780
783
  if (range.collapsed || !text) return null;
781
784
  const ancestor = closestElement(range.commonAncestorContainer);
782
- if (isLavishUi(ancestor) || isLavishAction(ancestor)) return null;
785
+ if (isLavishUi(ancestor) || isLavishAction(ancestor) || isInteractiveControl(ancestor)) return null;
783
786
  const commonAncestorSelector = selector(ancestor);
784
787
  const target = {
785
788
  type: "text-range",
@@ -805,6 +808,9 @@ function createArtifactSdk() {
805
808
  function isLavishAction(el) {
806
809
  return !!(el && el.closest && el.closest("[data-lavish-action]"));
807
810
  }
811
+ function isInteractiveControl(el) {
812
+ return !!(el && el.closest && el.closest("button,input,select,textarea,option,optgroup,label,[contenteditable]:not([contenteditable='false'])"));
813
+ }
808
814
  function highlightElement(el) {
809
815
  if (!el) return;
810
816
  el.style.outline = "var(--lavish-annotate-outline,2px solid #f4c95d)";
@@ -837,7 +843,7 @@ function createArtifactSdk() {
837
843
  if (annotationMode && !style) {
838
844
  style = document.createElement("style");
839
845
  style.id = "lavish-cursor-style";
840
- style.textContent = ":root{--lavish-accent:#f4c95d;--lavish-annotate-outline:2px solid var(--lavish-accent);--lavish-annotate-offset:2px}*{cursor:default!important}[data-lavish-action],[data-lavish-action] *{cursor:pointer!important}";
846
+ style.textContent = ":root{--lavish-accent:#f4c95d;--lavish-annotate-outline:2px solid var(--lavish-accent);--lavish-annotate-offset:2px}*{cursor:default!important}[data-lavish-action],[data-lavish-action] *{cursor:pointer!important}input,textarea,[contenteditable]:not([contenteditable='false']){cursor:text!important}button,select,label,option,input[type='button'],input[type='submit'],input[type='reset'],input[type='checkbox'],input[type='radio'],input[type='file'],input[type='color'],input[type='range'],input[type='image']{cursor:pointer!important}";
841
847
  document.head.appendChild(style);
842
848
  }
843
849
  if (!annotationMode && style) style.remove();
@@ -971,7 +977,8 @@ function createArtifactSdk() {
971
977
  document.addEventListener(
972
978
  "mouseover",
973
979
  (event) => {
974
- if (!annotationMode || isLavishUi(event.target) || isLavishAction(event.target)) return;
980
+ if (!annotationMode || isLavishUi(event.target) || isLavishAction(event.target) || isInteractiveControl(event.target))
981
+ return;
975
982
  if (event.target === selected) return;
976
983
  if (hovered && hovered !== selected) clearHighlight(hovered);
977
984
  hovered = event.target;
@@ -992,7 +999,8 @@ function createArtifactSdk() {
992
999
  document.addEventListener(
993
1000
  "mouseup",
994
1001
  (event) => {
995
- if (!annotationMode || isLavishUi(event.target) || isLavishAction(event.target)) return;
1002
+ if (!annotationMode || isLavishUi(event.target) || isLavishAction(event.target) || isInteractiveControl(event.target))
1003
+ return;
996
1004
  const c = textSelectionContext(document.getSelection());
997
1005
  if (!c) return;
998
1006
  ignoreNextClick = true;
@@ -1003,7 +1011,8 @@ function createArtifactSdk() {
1003
1011
  document.addEventListener(
1004
1012
  "click",
1005
1013
  (event) => {
1006
- if (!annotationMode || isLavishUi(event.target) || isLavishAction(event.target)) return;
1014
+ if (!annotationMode || isLavishUi(event.target) || isLavishAction(event.target) || isInteractiveControl(event.target))
1015
+ return;
1007
1016
  event.preventDefault();
1008
1017
  event.stopPropagation();
1009
1018
  if (ignoreNextClick) {
@@ -1890,7 +1899,7 @@ function normalizePagePath(path5) {
1890
1899
  // src/cli.js
1891
1900
  var COMMANDS = /* @__PURE__ */ new Set(["open", "poll", "end", "stop", "server", "playbook", "design", "setup"]);
1892
1901
  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`.";
1893
- var VERSION = "0.1.18";
1902
+ var VERSION = "0.1.19";
1894
1903
  async function run(argv) {
1895
1904
  await ensureStateDir();
1896
1905
  const normalizedArgv = normalizeArgv(argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lavish-axi",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
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",