lavish-axi 0.1.29 → 0.1.31
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 +6 -3
- package/dist/chrome-client.js +33 -4
- package/dist/cli.mjs +107 -17
- package/package.json +1 -1
- package/skills/lavish/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -130,12 +130,15 @@ pnpm link
|
|
|
130
130
|
- **File-path identity** - Sessions are keyed by the canonical HTML file path, so agents do not need opaque IDs.
|
|
131
131
|
- **Portable artifacts** - The artifact runs in an iframe while Lavish injects a small SDK for annotations, snapshots, and feedback controls.
|
|
132
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
|
|
133
|
+
Before writing HTML, choose a design system in strict priority order: follow a user-requested look first; otherwise inspect the project the artifact is about - the subject or product whose content or UI it represents, which may differ from your current working directory - and match that project's Tailwind or theme config, CSS variables or design tokens, component library, brand assets, or existing styled pages.
|
|
134
|
+
If the artifact previews, proposes, or mocks a specific app's UI, render it in that app's own design system so it faithfully shows the product, even when you are running in a different repo.
|
|
135
|
+
Only when both come up empty, run `lavish-axi design` for a copy-pasteable Tailwind CSS v4 + DaisyUI v5 CDN fallback.
|
|
134
136
|
That fallback guidance recommends DaisyUI's `luxury` theme by default and warns not to `@apply` DaisyUI classes inside Tailwind browser-runtime style blocks.
|
|
135
137
|
- **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.
|
|
136
138
|
- **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">`.
|
|
137
|
-
- **Feedback controls** - Native form controls (radios, checkboxes, inputs, selects, buttons, labels, contenteditable) are interactive automatically, so they do not need `data-lavish-action
|
|
138
|
-
|
|
139
|
+
- **Feedback controls** - Native form controls (radios, checkboxes, inputs, selects, buttons, labels, contenteditable) are interactive automatically, so they do not need `data-lavish-action`.
|
|
140
|
+
For reversible choices, let option clicks update local state, then queue exactly one final answer from a per-question submit or Queue answer button with `window.lavish.queuePrompt()`.
|
|
141
|
+
Mark only custom (non-native) clickable elements with `data-lavish-action` so Lavish does not annotate them, and use `data-lavish-question` or `queueKey` when pre-send updates for the same question should replace each other.
|
|
139
142
|
The browser chrome keeps editing actions in the overflow menu (copy path, reload artifact, copy DOM snapshot, end session) and can submit queued prompts with **Send & end session**, which delivers the prompts before ending the session.
|
|
140
143
|
- **Keyboard shortcuts** - In the chrome composer, Enter sends queued prompts and Shift+Enter inserts a newline.
|
|
141
144
|
In the annotation card, Enter queues the annotation, Shift+Enter inserts a newline, and Ctrl+Enter (Cmd+Enter on macOS) queues it and sends all queued prompts immediately.
|
package/dist/chrome-client.js
CHANGED
|
@@ -5,6 +5,7 @@ const sessionData = JSON.parse(sessionDataElement?.textContent || "{}");
|
|
|
5
5
|
const key = String(sessionData.key || "");
|
|
6
6
|
const filePath = String(sessionData.file || "");
|
|
7
7
|
const queueStorageKey = "lavish-axi:queued:" + key;
|
|
8
|
+
const internalQueueKeyField = "_lavishQueueKey";
|
|
8
9
|
const initialChat = Array.isArray(sessionData.initialChat) ? sessionData.initialChat : [];
|
|
9
10
|
|
|
10
11
|
const frame = /** @type {HTMLIFrameElement} */ (document.getElementById("artifact"));
|
|
@@ -212,6 +213,36 @@ function removeQueuedPrompt(index, event) {
|
|
|
212
213
|
render();
|
|
213
214
|
}
|
|
214
215
|
|
|
216
|
+
function promptQueueKey(prompt) {
|
|
217
|
+
return prompt && typeof prompt[internalQueueKeyField] === "string" ? prompt[internalQueueKeyField].trim() : "";
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function enqueuePrompt(prompt) {
|
|
221
|
+
if (!prompt || typeof prompt !== "object") return;
|
|
222
|
+
|
|
223
|
+
const queueKey = promptQueueKey(prompt);
|
|
224
|
+
if (queueKey) {
|
|
225
|
+
const index = queued.findIndex((item) => promptQueueKey(item) === queueKey);
|
|
226
|
+
if (index !== -1) {
|
|
227
|
+
queued[index] = prompt;
|
|
228
|
+
} else {
|
|
229
|
+
queued.push(prompt);
|
|
230
|
+
}
|
|
231
|
+
} else {
|
|
232
|
+
queued.push(prompt);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
persistQueuedPrompts();
|
|
236
|
+
render();
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function stripInternalPromptFields(prompt) {
|
|
240
|
+
if (!prompt || typeof prompt !== "object") return prompt;
|
|
241
|
+
const clean = { ...prompt };
|
|
242
|
+
delete clean[internalQueueKeyField];
|
|
243
|
+
return clean;
|
|
244
|
+
}
|
|
245
|
+
|
|
215
246
|
function postToFrame(message) {
|
|
216
247
|
if (frame.contentWindow) frame.contentWindow.postMessage(message, "*");
|
|
217
248
|
}
|
|
@@ -279,7 +310,7 @@ async function submitQueuedOnce() {
|
|
|
279
310
|
const response = await fetch("/api/" + key + "/prompts", {
|
|
280
311
|
method: "POST",
|
|
281
312
|
headers: { "content-type": "application/json" },
|
|
282
|
-
body: JSON.stringify({ prompts, domSnapshot: pendingSnapshot }),
|
|
313
|
+
body: JSON.stringify({ prompts: prompts.map(stripInternalPromptFields), domSnapshot: pendingSnapshot }),
|
|
283
314
|
});
|
|
284
315
|
if (!response.ok) throw new Error("failed to submit queued prompts");
|
|
285
316
|
for (const prompt of prompts) {
|
|
@@ -359,9 +390,7 @@ window.addEventListener("message", (event) => {
|
|
|
359
390
|
|
|
360
391
|
const msg = event.data || {};
|
|
361
392
|
if (msg.type === "lavish:queuePrompt") {
|
|
362
|
-
|
|
363
|
-
persistQueuedPrompts();
|
|
364
|
-
render();
|
|
393
|
+
enqueuePrompt(msg.prompt);
|
|
365
394
|
}
|
|
366
395
|
if (msg.type === "lavish:snapshot") {
|
|
367
396
|
const snapshotAction = snapshotRequests.shift() || "submit";
|
package/dist/cli.mjs
CHANGED
|
@@ -20,7 +20,7 @@ var DESIGN_CDN_URLS = {
|
|
|
20
20
|
var DESIGN_CDN_SNIPPET = `<link rel="stylesheet" href="${DESIGN_CDN_URLS.daisyui}">
|
|
21
21
|
<link rel="stylesheet" href="${DESIGN_CDN_URLS.daisyuiThemes}">
|
|
22
22
|
<script src="${DESIGN_CDN_URLS.tailwind}"></script>`;
|
|
23
|
-
var DESIGN_SYSTEM_HINT = "Lavish does not auto-inject any design system - artifacts stay portable so they render identically when opened directly without lavish-axi running. Before writing any HTML, decide the design direction in this strict priority order, and only move to the next step when the current one truly yields nothing: (1) if the user asked for a specific look or named design system, use that; (2) otherwise you must first inspect the
|
|
23
|
+
var DESIGN_SYSTEM_HINT = "Lavish does not auto-inject any design system - artifacts stay portable so they render identically when opened directly without lavish-axi running. Before writing any HTML, decide the design direction in this strict priority order, and only move to the next step when the current one truly yields nothing: (1) if the user asked for a specific look or named design system, use that; (2) otherwise you must first inspect the project the artifact is about - the subject or product whose content or UI it represents, which may differ from your current working directory - and match that project's design system: Tailwind or theme config, shared CSS variables or design tokens, component library, brand assets, or existing styled pages. If the artifact previews, proposes, or mocks a specific app's UI, render it in that app's own design system so it faithfully shows the product, even when you are running in a different repo; (3) only when both steps come up empty, use the Lavish-recommended Tailwind CSS browser runtime v4 + DaisyUI v5, available via CDN - run `lavish-axi design` for a copy-pasteable CDN snippet plus component reference, and prefer that CDN snippet over hand-writing styles unless explicitly instructed otherwise by the user. When you deliver the artifact, state which of the three design sources you used and why.";
|
|
24
24
|
var DAISYUI_THEMES = [
|
|
25
25
|
"light",
|
|
26
26
|
"dark",
|
|
@@ -61,7 +61,7 @@ var DAISYUI_THEMES = [
|
|
|
61
61
|
function createDesignOutput() {
|
|
62
62
|
return {
|
|
63
63
|
design: {
|
|
64
|
-
summary: "Use this Lavish CDN fallback only if (1) the user gave no design direction and (2) you already inspected the current
|
|
64
|
+
summary: "Use this Lavish CDN fallback only if (1) the user gave no design direction and (2) you already inspected the project the artifact is about - the subject or product whose content or UI it represents, which may differ from your current working directory - and found no design system or style conventions to match. If you have not checked the subject project yet, check first. Lavish does not auto-inject any design system; artifacts stay portable HTML. The strict priority order is: (1) a look or named design system the user asked for; (2) the subject project's design system or style conventions - look for a Tailwind or theme config, shared CSS variables or design tokens, a component library, brand assets, or existing styled pages. If the artifact previews, proposes, or mocks a specific app's UI, render it in that app's own design system so it faithfully shows the product, even when you are running in a different repo; (3) this Tailwind CSS browser runtime v4 + DaisyUI v5 + themes snippet - paste the CDN snippet below into your `<head>` and prefer the CDN snippet over hand-writing styles unless explicitly instructed otherwise by the user.",
|
|
65
65
|
cdn_snippet: DESIGN_CDN_SNIPPET,
|
|
66
66
|
cdn_urls: DESIGN_CDN_URLS,
|
|
67
67
|
versions: { tailwind: TAILWIND_BROWSER_VERSION, daisyui: DAISYUI_VERSION },
|
|
@@ -691,28 +691,31 @@ var PLAYBOOKS = [
|
|
|
691
691
|
],
|
|
692
692
|
structure: [
|
|
693
693
|
"Make each decision surface visible: what is being chosen, what the options mean, and what happens next.",
|
|
694
|
-
"
|
|
695
|
-
"
|
|
694
|
+
"Keep reversible selection state local in the artifact until the user explicitly submits that question.",
|
|
695
|
+
"Pair each question with a Submit or Queue answer control that sends exactly one prompt for the final answer.",
|
|
696
|
+
"Show selected state separately from queued state so the user trusts what will be sent back."
|
|
696
697
|
],
|
|
697
698
|
design_rules: [
|
|
698
699
|
"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.",
|
|
699
|
-
"
|
|
700
|
+
"For reversible choices, do not call window.lavish.queuePrompt() from radio change handlers or option click handlers. Those handlers should only update local selected state.",
|
|
701
|
+
"Use a per-question form submit or explicit Queue answer button to read the current values and call window.lavish.queuePrompt() exactly once for the final answer.",
|
|
700
702
|
"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.",
|
|
701
|
-
"
|
|
702
|
-
"Pass options such as tag, text, selector, target, or
|
|
703
|
-
"Call window.lavish.sendQueuedPrompts() when the control should immediately send
|
|
703
|
+
"Use data-lavish-question on a question wrapper or pass queueKey when multiple pre-send updates should replace the prior unsent answer for the same question.",
|
|
704
|
+
"Pass options such as tag, text, selector, target, data, queueKey, or element when they help the agent understand exactly what the user chose.",
|
|
705
|
+
"Call window.lavish.sendQueuedPrompts() only when the control should immediately send committed feedback instead of waiting for the user to press Send to Agent.",
|
|
704
706
|
"Make queued prompts specific enough that the agent can act without asking a follow-up question.",
|
|
705
707
|
"Keep native browser controls accessible and readable on mobile."
|
|
706
708
|
],
|
|
707
709
|
pitfalls: [
|
|
710
|
+
"Do not queue one prompt per radio change, checkbox toggle, dropdown change, or choice-button click when the user can still change their mind.",
|
|
708
711
|
"Do not create controls whose queued prompt is unclear or too vague to execute.",
|
|
709
|
-
"Do not hide the
|
|
712
|
+
"Do not hide the difference between selected locally and queued for the agent.",
|
|
710
713
|
"Do not require interaction for content the user only needs to read."
|
|
711
714
|
],
|
|
712
715
|
lavish_notes: [
|
|
713
716
|
"Lavish is strongest when the artifact becomes a focused review surface and not just a static page.",
|
|
714
|
-
`A native choice
|
|
715
|
-
|
|
717
|
+
`A native single-choice question should submit the final value: \`<form data-lavish-question="plan" onsubmit="event.preventDefault(); const choice = new FormData(event.currentTarget).get('plan'); if (choice) window.lavish.queuePrompt('Use the ' + choice + ' plan', { tag: 'choice', text: 'Plan: ' + choice, element: event.currentTarget, data: { question: 'plan', answer: choice } });"><label><input type="radio" name="plan" value="Starter"> Starter</label><label><input type="radio" name="plan" value="Pro"> Pro</label><button type="submit">Queue this answer</button></form>\`.`,
|
|
718
|
+
"A custom choice UI should make option buttons update local state, then use a separate Queue answer button with data-lavish-action to queue the final selected value.",
|
|
716
719
|
"Use window.lavish.queuePrompt for user intent, not internal analytics or UI-only state changes.",
|
|
717
720
|
"End input paths with an obvious way for the user to send feedback back to the agent."
|
|
718
721
|
]
|
|
@@ -765,7 +768,90 @@ import chokidar from "chokidar";
|
|
|
765
768
|
import express from "express";
|
|
766
769
|
|
|
767
770
|
// src/artifact-sdk.js
|
|
768
|
-
function
|
|
771
|
+
function deriveLavishQueueKey(element, options = {}) {
|
|
772
|
+
function stringValue(value) {
|
|
773
|
+
return value === null || value === void 0 ? "" : String(value);
|
|
774
|
+
}
|
|
775
|
+
function attributeValue(el, name) {
|
|
776
|
+
if (!el) return "";
|
|
777
|
+
if (el.getAttribute) {
|
|
778
|
+
const value = el.getAttribute(name);
|
|
779
|
+
if (value !== null && value !== void 0) return value;
|
|
780
|
+
}
|
|
781
|
+
return el[name] || "";
|
|
782
|
+
}
|
|
783
|
+
function tagName(el) {
|
|
784
|
+
return stringValue(el?.tagName || el?.nodeName).toLowerCase();
|
|
785
|
+
}
|
|
786
|
+
function closestElementMatching(el, selector) {
|
|
787
|
+
return el && el.closest ? el.closest(selector) : null;
|
|
788
|
+
}
|
|
789
|
+
function elementPath(el) {
|
|
790
|
+
const parts = [];
|
|
791
|
+
let node = el;
|
|
792
|
+
while (node && node.nodeType === 1 && parts.length < 6) {
|
|
793
|
+
let part = tagName(node) || "element";
|
|
794
|
+
const id = stringValue(attributeValue(node, "id") || node.id).trim();
|
|
795
|
+
if (id) {
|
|
796
|
+
part += `#${id}`;
|
|
797
|
+
parts.unshift(part);
|
|
798
|
+
break;
|
|
799
|
+
}
|
|
800
|
+
const parent2 = node.parentElement;
|
|
801
|
+
if (parent2 && parent2.children) {
|
|
802
|
+
const siblings = [...parent2.children].filter((child) => tagName(child) === tagName(node));
|
|
803
|
+
if (siblings.length > 1) part += `:nth-of-type(${siblings.indexOf(node) + 1})`;
|
|
804
|
+
}
|
|
805
|
+
parts.unshift(part);
|
|
806
|
+
node = parent2;
|
|
807
|
+
}
|
|
808
|
+
return parts.join(" > ");
|
|
809
|
+
}
|
|
810
|
+
function scopeKey(el) {
|
|
811
|
+
const scope2 = closestElementMatching(el, "form,fieldset") || el?.parentElement || el;
|
|
812
|
+
const tag2 = tagName(scope2) || "scope";
|
|
813
|
+
const explicit = stringValue(
|
|
814
|
+
attributeValue(scope2, "data-lavish-question") || attributeValue(scope2, "id") || attributeValue(scope2, "name")
|
|
815
|
+
).trim();
|
|
816
|
+
if (explicit) return `${tag2}:${explicit}`;
|
|
817
|
+
return elementPath(scope2) || tag2;
|
|
818
|
+
}
|
|
819
|
+
function controlIdentity(el) {
|
|
820
|
+
const identity = stringValue(attributeValue(el, "name") || attributeValue(el, "id") || el?.name).trim();
|
|
821
|
+
if (identity) return identity;
|
|
822
|
+
return elementPath(el);
|
|
823
|
+
}
|
|
824
|
+
function isKeyedInputType(type2) {
|
|
825
|
+
return !(/* @__PURE__ */ new Set(["button", "submit", "reset", "file", "image", "hidden", "radio", "checkbox"])).has(type2);
|
|
826
|
+
}
|
|
827
|
+
if (Object.hasOwn(options, "queueKey")) {
|
|
828
|
+
return stringValue(options.queueKey).trim();
|
|
829
|
+
}
|
|
830
|
+
const question = closestElementMatching(element, "[data-lavish-question]");
|
|
831
|
+
const questionKey = stringValue(attributeValue(question, "data-lavish-question")).trim();
|
|
832
|
+
if (questionKey) return `question:${questionKey}`;
|
|
833
|
+
const tag = tagName(element);
|
|
834
|
+
const type = stringValue(attributeValue(element, "type") || element?.type).toLowerCase();
|
|
835
|
+
const scope = scopeKey(element);
|
|
836
|
+
if (tag === "input" && type === "radio") {
|
|
837
|
+
const name = stringValue(attributeValue(element, "name") || element?.name).trim();
|
|
838
|
+
if (name) return `radio:${scope}:${name}`;
|
|
839
|
+
return "";
|
|
840
|
+
}
|
|
841
|
+
if (tag === "input" && type === "checkbox") {
|
|
842
|
+
const identity = controlIdentity(element);
|
|
843
|
+
const explicitValue = stringValue(element?.getAttribute ? element.getAttribute("value") : "").trim();
|
|
844
|
+
const option = explicitValue || stringValue(attributeValue(element, "id") || elementPath(element)).trim();
|
|
845
|
+
if (identity) return `checkbox:${scope}:${identity}:${option}`;
|
|
846
|
+
return "";
|
|
847
|
+
}
|
|
848
|
+
if (tag === "select" || tag === "textarea" || tag === "input" && isKeyedInputType(type)) {
|
|
849
|
+
const identity = controlIdentity(element);
|
|
850
|
+
if (identity) return `field:${scope}:${identity}`;
|
|
851
|
+
}
|
|
852
|
+
return "";
|
|
853
|
+
}
|
|
854
|
+
function createArtifactSdk(deriveQueueKey) {
|
|
769
855
|
let annotationMode = true;
|
|
770
856
|
let hovered = null;
|
|
771
857
|
let selected = null;
|
|
@@ -904,10 +990,13 @@ function createArtifactSdk() {
|
|
|
904
990
|
if (!annotationMode) closeCard();
|
|
905
991
|
}
|
|
906
992
|
function queuePrompt(prompt, options = {}) {
|
|
993
|
+
const originElement = options.element || document.activeElement || document.body;
|
|
907
994
|
const item = {
|
|
908
|
-
...context(
|
|
995
|
+
...context(originElement),
|
|
909
996
|
prompt: String(prompt || "")
|
|
910
997
|
};
|
|
998
|
+
const queueKey = typeof deriveQueueKey === "function" ? deriveQueueKey(originElement, options) : "";
|
|
999
|
+
if (queueKey) item._lavishQueueKey = String(queueKey);
|
|
911
1000
|
if (options.uid) item.uid = String(options.uid);
|
|
912
1001
|
if (options.selector) item.selector = String(options.selector);
|
|
913
1002
|
if (options.tag) item.tag = String(options.tag);
|
|
@@ -993,7 +1082,7 @@ function createArtifactSdk() {
|
|
|
993
1082
|
cancelButton.onclick = closeCard;
|
|
994
1083
|
sendButton.onclick = () => {
|
|
995
1084
|
const prompt = textarea.value.trim();
|
|
996
|
-
if (prompt) queuePrompt(prompt, c);
|
|
1085
|
+
if (prompt) queuePrompt(prompt, { ...c, queueKey: "" });
|
|
997
1086
|
closeCard();
|
|
998
1087
|
};
|
|
999
1088
|
textarea.addEventListener("keydown", (event) => {
|
|
@@ -1819,7 +1908,8 @@ function createSdkJs(key) {
|
|
|
1819
1908
|
return `(() => {
|
|
1820
1909
|
const key=${JSON.stringify(key)};
|
|
1821
1910
|
void key;
|
|
1822
|
-
|
|
1911
|
+
const deriveQueueKey=${deriveLavishQueueKey.toString()};
|
|
1912
|
+
(${createArtifactSdk.toString()})(deriveQueueKey);
|
|
1823
1913
|
})();`;
|
|
1824
1914
|
}
|
|
1825
1915
|
function escapeHtml(value) {
|
|
@@ -2004,7 +2094,7 @@ function normalizePagePath(path5) {
|
|
|
2004
2094
|
// src/cli.js
|
|
2005
2095
|
var COMMANDS = /* @__PURE__ */ new Set(["open", "poll", "end", "stop", "server", "playbook", "design", "setup"]);
|
|
2006
2096
|
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`.";
|
|
2007
|
-
var VERSION = "0.1.
|
|
2097
|
+
var VERSION = "0.1.31";
|
|
2008
2098
|
async function run(argv) {
|
|
2009
2099
|
await ensureStateDir();
|
|
2010
2100
|
const normalizedArgv = normalizeArgv(argv);
|
|
@@ -2591,7 +2681,7 @@ Examples:
|
|
|
2591
2681
|
`,
|
|
2592
2682
|
design: `Usage: lavish-axi design
|
|
2593
2683
|
|
|
2594
|
-
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. This CDN snippet is the design fallback, not the default: inspect the project before falling back. The strict priority order is: (1) if the user asked for a specific look or named design system, follow that; (2) otherwise,
|
|
2684
|
+
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. This CDN snippet is the design fallback, not the default: inspect the subject project before falling back. The strict priority order is: (1) if the user asked for a specific look or named design system, follow that; (2) otherwise, match the design system of the project the artifact is about, not necessarily your current working directory. If the artifact previews, proposes, or mocks a specific app's UI, use that app's own design system; (3) only when both come up empty, prefer the Lavish-recommended Tailwind + DaisyUI CDN snippet over hand-writing styles unless explicitly instructed otherwise by the user.
|
|
2595
2685
|
`,
|
|
2596
2686
|
setup: `Usage: lavish-axi setup hooks
|
|
2597
2687
|
|
package/package.json
CHANGED
package/skills/lavish/SKILL.md
CHANGED
|
@@ -66,5 +66,5 @@ One artifact often combines several playbooks (for example a plan that includes
|
|
|
66
66
|
- Run `npx -y lavish-axi end <html-file>` to end a session
|
|
67
67
|
- Run `npx -y lavish-axi stop` to shut down the background server (it also self-stops when idle or after the last session ends with nothing connected)
|
|
68
68
|
- Run `npx -y lavish-axi playbook <playbook_id>` for focused artifact guidance. One artifact often combines several playbooks (for example a plan that includes a comparison and a diagram), so read every playbook relevant to the artifact, not just one, for the best quality
|
|
69
|
-
- Lavish does not auto-inject any design system - artifacts stay portable so they render identically when opened directly without lavish-axi running. Before writing any HTML, decide the design direction in this strict priority order, and only move to the next step when the current one truly yields nothing: (1) if the user asked for a specific look or named design system, use that; (2) otherwise you must first inspect the
|
|
69
|
+
- Lavish does not auto-inject any design system - artifacts stay portable so they render identically when opened directly without lavish-axi running. Before writing any HTML, decide the design direction in this strict priority order, and only move to the next step when the current one truly yields nothing: (1) if the user asked for a specific look or named design system, use that; (2) otherwise you must first inspect the project the artifact is about - the subject or product whose content or UI it represents, which may differ from your current working directory - and match that project's design system: Tailwind or theme config, shared CSS variables or design tokens, component library, brand assets, or existing styled pages. If the artifact previews, proposes, or mocks a specific app's UI, render it in that app's own design system so it faithfully shows the product, even when you are running in a different repo; (3) only when both steps come up empty, use the Lavish-recommended Tailwind CSS browser runtime v4 + DaisyUI v5, available via CDN - run `npx -y lavish-axi design` for a copy-pasteable CDN snippet plus component reference, and prefer that CDN snippet over hand-writing styles unless explicitly instructed otherwise by the user. When you deliver the artifact, state which of the three design sources you used and why.
|
|
70
70
|
- Use lavish-axi when the user asks for a visual artifact, HTML explainer, interactive prototype, review surface, product or technical plan, comparison, report, or browser-based feedback loop
|