lavish-axi 0.1.27 → 0.1.29
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
|
|
|
@@ -60,7 +61,7 @@ Then, in agents that expose skills as slash commands (Claude Code, for example),
|
|
|
60
61
|
/lavish let's discuss our plan here
|
|
61
62
|
```
|
|
62
63
|
|
|
63
|
-
Or just ask for anything that is easier to grasp visually - a plan, comparison, diagram, table,
|
|
64
|
+
Or just ask for anything that is easier to grasp visually - a plan, comparison, diagram, table, code view, or report - and the agent loads the skill on its own when it recognizes the task.
|
|
64
65
|
|
|
65
66
|
By default the skill lands in the current project's skills directory (`.claude/skills/`, for example); add `-g` to install it for all projects (`~/.claude/skills/`).
|
|
66
67
|
|
|
@@ -143,6 +144,7 @@ pnpm link
|
|
|
143
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.
|
|
144
145
|
Set `LAVISH_AXI_IDLE_TIMEOUT_MS=0` or `off` to disable idle self-shutdown.
|
|
145
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).
|
|
146
148
|
|
|
147
149
|
## CLI Reference
|
|
148
150
|
|
|
@@ -158,7 +160,7 @@ pnpm link
|
|
|
158
160
|
| `lavish-axi setup hooks` | Install or repair optional SessionStart hooks for Claude Code, Codex, and OpenCode; restart the agent session afterward. |
|
|
159
161
|
| `lavish-axi server` | Run the local Lavish Editor server. |
|
|
160
162
|
|
|
161
|
-
Known playbook IDs: `diagram`, `table`, `comparison`, `plan`, `
|
|
163
|
+
Known playbook IDs: `diagram`, `table`, `comparison`, `plan`, `code`, `input`, `slides`.
|
|
162
164
|
One artifact often combines several playbooks, such as a plan that includes a comparison and a diagram, so read every playbook relevant to the artifact for the best quality.
|
|
163
165
|
|
|
164
166
|
### Flags
|
package/dist/cli.mjs
CHANGED
|
@@ -474,6 +474,25 @@ import { mkdir } from "node:fs/promises";
|
|
|
474
474
|
import os from "node:os";
|
|
475
475
|
import path from "node:path";
|
|
476
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
|
+
}
|
|
477
496
|
function stateDir() {
|
|
478
497
|
return process.env.LAVISH_AXI_STATE_DIR || path.join(os.homedir(), ".lavish-axi");
|
|
479
498
|
}
|
|
@@ -602,31 +621,64 @@ var PLAYBOOKS = [
|
|
|
602
621
|
lavish_notes: ["A Lavish plan should make a plan and its uncertainties easy to annotate before code exists."]
|
|
603
622
|
},
|
|
604
623
|
{
|
|
605
|
-
id: "
|
|
606
|
-
use_when: "
|
|
624
|
+
id: "code",
|
|
625
|
+
use_when: "Render source code, code files, patches, PR diffs, and before/after code inside Lavish artifacts",
|
|
607
626
|
choose: [
|
|
608
|
-
"Use this
|
|
609
|
-
"Use
|
|
610
|
-
"
|
|
627
|
+
"Use this whenever an artifact shows source code: a snippet, full file, patch, PR diff, local change set, or before/after code.",
|
|
628
|
+
"Use File for one code file, FileDiff for old/new versions or parsed patch metadata, and CodeView only when several files or diffs need coordinated navigation.",
|
|
629
|
+
"Choose split layout for careful side-by-side review when width allows; choose unified layout when space is tight, changes are mostly additive, or mobile readability matters."
|
|
611
630
|
],
|
|
612
631
|
structure: [
|
|
613
|
-
"
|
|
614
|
-
"
|
|
615
|
-
"
|
|
632
|
+
"Place the path, language, and reason to inspect the code immediately before each rendered file or diff.",
|
|
633
|
+
"Keep evidence close to each claim with file paths, line references, or annotations next to the relevant code.",
|
|
634
|
+
"For multi-file changes, group files by user-facing area or task instead of dumping a raw patch in repository order."
|
|
616
635
|
],
|
|
617
636
|
design_rules: [
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
637
|
+
`Rendering MUST use @pierre/diffs, not hand-rolled <pre> blocks or another diff library. This verified no-build standalone HTML snippet renders one file and one split diff from esm.sh:
|
|
638
|
+
\`\`\`html
|
|
639
|
+
<div id="file"></div>
|
|
640
|
+
<div id="diff"></div>
|
|
641
|
+
<script type="module">
|
|
642
|
+
import { File, FileDiff } from "https://esm.sh/@pierre/diffs@1.2.10?bundle";
|
|
643
|
+
|
|
644
|
+
const theme = { light: "github-light", dark: "github-dark" };
|
|
645
|
+
const options = { theme, themeType: "dark", overflow: "wrap" };
|
|
646
|
+
const oldFile = {
|
|
647
|
+
name: "src/greeting.ts",
|
|
648
|
+
contents: "export function greet(name: string) {\\n return \\"Hello \\" + name;\\n}\\n\\nconsole.log(greet(\\"Lavish\\"));\\n",
|
|
649
|
+
};
|
|
650
|
+
const newFile = {
|
|
651
|
+
name: "src/greeting.ts",
|
|
652
|
+
contents: "export function greet(name: string) {\\n return \\"Hello, \\" + name + \\"!\\";\\n}\\n\\nconsole.log(greet(\\"Lavish\\"));\\n",
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
new File(options).render({
|
|
656
|
+
containerWrapper: document.querySelector("#file"),
|
|
657
|
+
file: newFile,
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
new FileDiff({ ...options, diffStyle: "split" }).render({
|
|
661
|
+
containerWrapper: document.querySelector("#diff"),
|
|
662
|
+
oldFile,
|
|
663
|
+
newFile,
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
</script>
|
|
667
|
+
\`\`\``,
|
|
668
|
+
"Pick a Shiki theme pair that matches the artifact's DaisyUI or Tailwind direction and light or dark mode; replace the GitHub pair above when the page is not GitHub-like.",
|
|
669
|
+
'Use FileDiff diffStyle: "split" for side-by-side review and diffStyle: "unified" for stacked reading; keep overflow: "wrap" unless horizontal alignment is essential.',
|
|
670
|
+
"Use @pierre/diffs line annotations, selections, and headers when calling out specific lines so notes stay attached to code."
|
|
621
671
|
],
|
|
622
672
|
pitfalls: [
|
|
623
|
-
"Do not
|
|
624
|
-
"Do not
|
|
625
|
-
"Do not
|
|
673
|
+
"Do not render code as static screenshots, plain <pre> blocks, or markdown pasted into HTML.",
|
|
674
|
+
"Do not choose an arbitrary default Shiki theme that clashes with the page palette or dark mode.",
|
|
675
|
+
"Do not show huge unrelated files when a focused render range, parsed patch file, or grouped summary would be clearer.",
|
|
676
|
+
"Do not separate a claim from the code lines that prove it."
|
|
626
677
|
],
|
|
627
678
|
lavish_notes: [
|
|
628
|
-
"A Lavish
|
|
629
|
-
"
|
|
679
|
+
"A Lavish code artifact should make each file, hunk, and relevant line easy to annotate precisely.",
|
|
680
|
+
"When a user action should trigger a fix, queue prompts that name the file path, line range, and desired change.",
|
|
681
|
+
"If the artifact combines code with a plan, table, or comparison, read those playbooks too and keep @pierre/diffs responsible for the code surface."
|
|
630
682
|
]
|
|
631
683
|
},
|
|
632
684
|
{
|
|
@@ -1229,7 +1281,9 @@ async function serve({
|
|
|
1229
1281
|
debug = false,
|
|
1230
1282
|
log = null,
|
|
1231
1283
|
pollHeartbeatMs = 15e3,
|
|
1232
|
-
idleTimeoutMs = resolveIdleTimeoutMs()
|
|
1284
|
+
idleTimeoutMs = resolveIdleTimeoutMs(),
|
|
1285
|
+
host = bindHost(),
|
|
1286
|
+
linkHost: linkHostName = linkHost()
|
|
1233
1287
|
}) {
|
|
1234
1288
|
const app = express();
|
|
1235
1289
|
const store = new SessionStore(stateFile2);
|
|
@@ -1259,7 +1313,7 @@ async function serve({
|
|
|
1259
1313
|
try {
|
|
1260
1314
|
const file = await canonicalFile(req.body.file);
|
|
1261
1315
|
const key = sessionKey(file);
|
|
1262
|
-
const url = `http://${
|
|
1316
|
+
const url = `http://${hostForUrl(linkHostName)}:${publicPort}/session/${key}`;
|
|
1263
1317
|
const existing = await store.findByKey(key);
|
|
1264
1318
|
const session = await store.upsertSession(file, url);
|
|
1265
1319
|
if (existing?.status === "ended") {
|
|
@@ -1532,8 +1586,11 @@ data: ${JSON.stringify({ state: computePresence(req.params.key, activePolls, del
|
|
|
1532
1586
|
app.use((error, req, res, _next) => {
|
|
1533
1587
|
res.status(500).json({ error: error instanceof Error ? error.message : String(error) });
|
|
1534
1588
|
});
|
|
1535
|
-
const httpServer = await new Promise((resolve) => {
|
|
1536
|
-
const s = app.listen(port,
|
|
1589
|
+
const httpServer = await new Promise((resolve, reject) => {
|
|
1590
|
+
const s = app.listen(port, host, () => {
|
|
1591
|
+
if (s.address()) resolve(s);
|
|
1592
|
+
});
|
|
1593
|
+
s.once("error", reject);
|
|
1537
1594
|
});
|
|
1538
1595
|
publicPort = httpServer.address().port;
|
|
1539
1596
|
let shuttingDown = false;
|
|
@@ -1947,7 +2004,7 @@ function normalizePagePath(path5) {
|
|
|
1947
2004
|
// src/cli.js
|
|
1948
2005
|
var COMMANDS = /* @__PURE__ */ new Set(["open", "poll", "end", "stop", "server", "playbook", "design", "setup"]);
|
|
1949
2006
|
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`.";
|
|
1950
|
-
var VERSION = "0.1.
|
|
2007
|
+
var VERSION = "0.1.29";
|
|
1951
2008
|
async function run(argv) {
|
|
1952
2009
|
await ensureStateDir();
|
|
1953
2010
|
const normalizedArgv = normalizeArgv(argv);
|
|
@@ -2195,11 +2252,11 @@ async function endCommand(args) {
|
|
|
2195
2252
|
}
|
|
2196
2253
|
async function stopCommand(args) {
|
|
2197
2254
|
const port = Number(flagValue(args, "--port") || defaultPort());
|
|
2198
|
-
const baseUrl = `http://${
|
|
2255
|
+
const baseUrl = `http://${hostForUrl(clientHost())}:${port}`;
|
|
2199
2256
|
return shutdownServerOnPort(port, { baseUrl, currentVersion: VERSION });
|
|
2200
2257
|
}
|
|
2201
2258
|
async function shutdownServerOnPort(port, {
|
|
2202
|
-
baseUrl = `http://${
|
|
2259
|
+
baseUrl = `http://${hostForUrl(clientHost())}:${port}`,
|
|
2203
2260
|
currentVersion = VERSION,
|
|
2204
2261
|
fetchHealth: healthFetcher = fetchHealth,
|
|
2205
2262
|
requestShutdown: shutdownRequester = requestShutdown,
|
|
@@ -2279,7 +2336,7 @@ function isHtmlPath(file) {
|
|
|
2279
2336
|
}
|
|
2280
2337
|
async function ensureServer({ forceRestart = false } = {}) {
|
|
2281
2338
|
const port = defaultPort();
|
|
2282
|
-
const baseUrl = `http://${
|
|
2339
|
+
const baseUrl = `http://${hostForUrl(clientHost())}:${port}`;
|
|
2283
2340
|
const existing = await fetchHealth(baseUrl);
|
|
2284
2341
|
if (existing && !shouldRestartServer(VERSION, existing, forceRestart)) {
|
|
2285
2342
|
return baseUrl;
|
|
@@ -2523,7 +2580,7 @@ Shut down the background Lavish Editor server. The server also stops itself when
|
|
|
2523
2580
|
`,
|
|
2524
2581
|
playbook: `Usage: lavish-axi playbook [playbook_id]
|
|
2525
2582
|
|
|
2526
|
-
List focused artifact guidance playbooks, or show one playbook by ID. Known IDs: diagram, table, comparison, plan,
|
|
2583
|
+
List focused artifact guidance playbooks, or show one playbook by ID. Known IDs: diagram, table, comparison, plan, code, input, slides.
|
|
2527
2584
|
|
|
2528
2585
|
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.
|
|
2529
2586
|
|
|
@@ -2543,6 +2600,8 @@ Install or repair agent SessionStart hooks for lavish-axi ambient context in Cla
|
|
|
2543
2600
|
server: `Usage: lavish-axi server [--port 4387] [--verbose]
|
|
2544
2601
|
|
|
2545
2602
|
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.
|
|
2603
|
+
|
|
2604
|
+
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.
|
|
2546
2605
|
`
|
|
2547
2606
|
};
|
|
2548
2607
|
|
|
Binary file
|
package/package.json
CHANGED
package/skills/lavish/SKILL.md
CHANGED
|
@@ -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
|
|
@@ -48,7 +53,7 @@ One artifact often combines several playbooks (for example a plan that includes
|
|
|
48
53
|
- `table` - Turn dense records into scan-friendly review surfaces
|
|
49
54
|
- `comparison` - Show options, tradeoffs, and current vs target behavior
|
|
50
55
|
- `plan` - Explain a product or technical plan before implementation
|
|
51
|
-
- `
|
|
56
|
+
- `code` - Render source code, code files, patches, PR diffs, and before/after code inside Lavish artifacts
|
|
52
57
|
- `input` - Must be used when the agent needs to collect user input on decisions, choices, preferences, triage, scope, or other structured feedback from within the artifact
|
|
53
58
|
- `slides` - Create a deliberate presentation when slides are requested
|
|
54
59
|
|