lavish-axi 0.1.89 → 0.1.92

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
@@ -216,7 +216,8 @@ pnpm link
216
216
  - **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 keeps human feedback actions available while the agent is working because the server queues them for the next poll. An agent reply concludes delivered work and returns presence to waiting (see the CLI Reference for reply and poll commands). A supervisor-owned process listener is shown as an external listener rather than an idle captain turn.
217
217
  - **Delivery receipts** - Every note you have sent carries three emoji under it that light up in turn: 👀 **Seen** when a `lavish-axi poll` takes the note, 🛠️ **Working** when the artifact file changes after that, and ✅ **Done** when the agent replies. A step that has not happened yet is the same emoji greyed out. All three come from what the server observes; the agent does nothing extra. Until 👀 lights, the row says why: no agent is listening, or the agent is busy and the note is delivered on its next poll. A note answered without touching the artifact goes Seen to Done with Working still grey. A reply marks every note the agent has seen as Done, not notes still waiting for a poll. Each emoji names its step and time on hover and to screen readers. Notes sent before receipts existed show no receipt row.
218
218
  In a Herdr-managed pane, set `LAVISH_AXI_HERDR_CHIME=1` to show a Herdr request notification and play its chime once an indefinite poll enters the waiting state. Immediate queued feedback and timed debug polls do not trigger a notification. The integration is off unless both `LAVISH_AXI_HERDR_CHIME` and Herdr's `HERDR_ENV` session marker equal `1`; leaving either unset or using any other value opts out. Notification delivery runs without blocking feedback: if Herdr is unavailable, rejects the notification, stalls, or fails, the poll continues unchanged.
219
- Closing the last review tab while a poll is active starts a 10-second reconnect grace period. A reload or quick reconnect keeps an active poll waiting; if every review stays disconnected, the poll returns `browser_disconnected` without ending the resumable session, and the agent asks whether to reopen or end it instead of acting uninvited.
219
+ Closing the last review tab while a poll is active starts a reconnect grace period, 10 seconds by default. A reload or quick reconnect keeps an active poll waiting; if every review stays disconnected, the poll returns `browser_disconnected` without ending the resumable session, and the agent asks whether to reopen or end it instead of acting uninvited.
220
+ A phone that locks its screen or backgrounds the tab drops the connection too, so set `LAVISH_AXI_DISCONNECT_GRACE_MS` on the server to a longer millisecond budget, or to `0` or `off` so a disconnect never ends the poll (it then waits for feedback, an end, or its own timeout). Empty or invalid values keep the 10-second default.
220
221
  The no-timeout poll always writes an immediate stderr banner so it is visibly not hung; it adds the periodic stderr wait ticks only in an interactive terminal, so when stderr is piped (as under agent harnesses) the captured output carries no tick noise. Stdout always stays reserved for the final response; if the poll is interrupted or times out before feedback arrives, re-run it because feedback remains queued until delivery. Poll delivery consumes the response, so read the complete response before truncating or filtering it.
221
222
  Codex-specific guidance keeps that poll attached to the active turn instead of hiding it in a background task, because completed background tasks may not resume the agent.
222
223
  - **Session end etiquette** - Lavish tracks who ended a session: a human clicking **End session** (or **Send & End**) in the browser is a user-initiated end, while `lavish-axi end <html-file>` is agent-initiated.
@@ -313,6 +314,19 @@ For flows, architecture, state, or sequence diagrams, open the diagram playbook
313
314
  | `lavish-axi server` | `--verbose` | Log session and watcher events to stderr; can also be enabled with `LAVISH_AXI_DEBUG=1`. Detached server output is appended with UTC timestamps to `~/.lavish-axi/server.log` (or `LAVISH_AXI_STATE_DIR/server.log`) for startup, shutdown-cause, and crash diagnostics. |
314
315
  | `lavish-axi server` | `--also-listen <host>` | Also listen on this concrete address (repeatable). The CLI passes it when it replaces a running server, so the replacement keeps every address the old one served; see One server per port. |
315
316
 
317
+ ## Telemetry
318
+
319
+ The npm release sends anonymous usage telemetry to an [Umami](https://umami.is) server at `https://a.kunchenguid.com`. The host and website ID are baked into the published bundle at build time, so telemetry is on by default for `npx -y lavish-axi`.
320
+
321
+ Each `lavish-axi` run sends two requests, except `lavish-axi --version` (also `-v` and `-V`), which sends none: a page view when the command starts, and a `command` event when it finishes. Both carry:
322
+
323
+ - the command name (for example `open`, `poll`, or `home` when you run it with no command), but not its arguments, file paths, artifact content, or prompts
324
+ - the Lavish version, `process.platform`, and `process.arch`
325
+
326
+ The `command` event also carries a `status` field: `success`, or `error` only when the CLI itself throws. A command that fails and sets a nonzero exit code is handled by the CLI framework, so it still reports `success`. No user identifier is sent. Requests time out after 1 second, and failures are ignored, so telemetry never changes what a command does.
327
+
328
+ Set `LAVISH_AXI_TELEMETRY=0` (or `false` or `off`) to turn it off. A build from source sends nothing unless `LAVISH_AXI_UMAMI_WEBSITE_ID` is set, and `LAVISH_AXI_UMAMI_HOST` overrides the host.
329
+
316
330
  ## Development
317
331
 
318
332
  ```sh
@@ -792,6 +792,7 @@ function replaceExpiredThumbnail(event) {
792
792
  chatLog.addEventListener("error", replaceExpiredThumbnail, true);
793
793
 
794
794
  const DEFAULT_SEND_HINT = "Write a message or annotate an element first.";
795
+ const EMPTY_END_HINT = "Nothing to send. To end without feedback, use End session in the More menu (⋮).";
795
796
 
796
797
  function showSendHint(message = DEFAULT_SEND_HINT, holdMs = 2600, focusInput = true) {
797
798
  sendHint.textContent = message;
@@ -1971,7 +1972,7 @@ function sendQueued(endAfter) {
1971
1972
  const shouldEnd = Boolean(endAfter && !chipsBlocked);
1972
1973
  const preparations = shouldEnd ? [...feedbackPreparations] : [];
1973
1974
  if (!queued.length && preparations.length === 0) {
1974
- if (!chipsBlocked && !sendFailureOwner) showSendHint();
1975
+ if (!chipsBlocked && !sendFailureOwner) showSendHint(endAfter ? EMPTY_END_HINT : DEFAULT_SEND_HINT);
1975
1976
  return;
1976
1977
  }
1977
1978
  if (!sendFailureOwner) hideSendHint(true);
@@ -2021,7 +2022,7 @@ function completeTerminalPreparation(terminal, results) {
2021
2022
  clearPreparationFailure("terminal");
2022
2023
  if (!terminal.prompts.length) {
2023
2024
  releaseTerminalSubmission(terminal);
2024
- if (!sendFailureOwner) showSendHint();
2025
+ if (!sendFailureOwner) showSendHint(EMPTY_END_HINT);
2025
2026
  return;
2026
2027
  }
2027
2028
  // Only make the reservation durable once every preparation has joined the exact
package/dist/cli.mjs CHANGED
@@ -585,7 +585,7 @@ function createDesignOutput() {
585
585
  playbooks: listPlaybooks()
586
586
  },
587
587
  design: {
588
- 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 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. Paint an explicit page background and readable text. " + DESIGN_PRIORITY_RULE + " Paste the CDN snippet below into your `<head>`.",
588
+ 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 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. Paint an explicit page background and readable text. " + DESIGN_PRIORITY_RULE + " Lavish adds only its SDK script to your file and never wraps a fragment, so start it with `<!doctype html>`: without one the page renders in quirks mode, where `<table>` text stops inheriting the color a wrapper theme sets. Paste the CDN snippet below into your `<head>`.",
589
589
  cdn_snippet: DESIGN_CDN_SNIPPET,
590
590
  cdn_urls: DESIGN_CDN_URLS,
591
591
  versions: { tailwind: TAILWIND_BROWSER_VERSION, daisyui: DAISYUI_VERSION },
@@ -10161,7 +10161,7 @@ var BIND_RECOVERY_DELAYS_MS = [1e3, 2e3, 5e3, 1e4, 3e4];
10161
10161
  var LOOPBACK_OWNER_PROBE_TIMEOUT_MS = 500;
10162
10162
  var WEBSOCKET_CLOSE_GRACE_MS = 250;
10163
10163
  var LIVE_EVENT_HEARTBEAT_MS = 3e4;
10164
- var BROWSER_DISCONNECT_GRACE_MS = 1e4;
10164
+ var DEFAULT_BROWSER_DISCONNECT_GRACE_MS = 1e4;
10165
10165
  var ARTIFACT_CONTENT_SECURITY_POLICY = "sandbox allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads";
10166
10166
  var ATTACHMENT_SWEEP_INTERVAL_MS = 60 * 6e4;
10167
10167
  var SHUTDOWN_REASONS = /* @__PURE__ */ new Set(["upgrade", "local-build", "stop"]);
@@ -10250,7 +10250,15 @@ function resolveIdleTimeoutMs(env = process.env) {
10250
10250
  if (raw === "0" || raw.toLowerCase() === "off") return null;
10251
10251
  const value = Number(raw);
10252
10252
  if (!Number.isFinite(value) || value <= 0) return DEFAULT_IDLE_TIMEOUT_MS;
10253
- return value;
10253
+ return Math.min(value, 2147483647);
10254
+ }
10255
+ function resolveBrowserDisconnectGraceMs(env = process.env) {
10256
+ const raw = env.LAVISH_AXI_DISCONNECT_GRACE_MS?.trim();
10257
+ if (raw === void 0 || raw === "") return DEFAULT_BROWSER_DISCONNECT_GRACE_MS;
10258
+ if (raw === "0" || raw.toLowerCase() === "off") return null;
10259
+ const value = Number(raw);
10260
+ if (!Number.isFinite(value) || value <= 0) return DEFAULT_BROWSER_DISCONNECT_GRACE_MS;
10261
+ return Math.min(value, 2147483647);
10254
10262
  }
10255
10263
  async function serve({
10256
10264
  env = process.env,
@@ -10261,7 +10269,7 @@ async function serve({
10261
10269
  log = null,
10262
10270
  pollHeartbeatMs = 15e3,
10263
10271
  liveEventHeartbeatMs = LIVE_EVENT_HEARTBEAT_MS,
10264
- browserDisconnectGraceMs = BROWSER_DISCONNECT_GRACE_MS,
10272
+ browserDisconnectGraceMs = resolveBrowserDisconnectGraceMs(env),
10265
10273
  idleTimeoutMs = resolveIdleTimeoutMs(),
10266
10274
  host = bindHost(env),
10267
10275
  hosts,
@@ -10353,6 +10361,7 @@ async function serve({
10353
10361
  }
10354
10362
  function scheduleBrowserDisconnect(key) {
10355
10363
  clearBrowserDisconnectTimer(key);
10364
+ if (browserDisconnectGraceMs === null) return;
10356
10365
  if (shuttingDown || hasLiveEventClient(key) || !activePolls.has(key)) return;
10357
10366
  const timer = setTimeout(() => {
10358
10367
  browserDisconnectTimers.delete(key);
@@ -12778,7 +12787,7 @@ var AGENT_REPLY_INPUT_LIMIT_BYTES = AGENT_REPLY_JSON_LIMIT_BYTES - AGENT_REPLY_J
12778
12787
  var AGENT_REPLY_LIMIT_LABEL = "2 MB JSON request limit";
12779
12788
  var POLL_STATE_HEADER = "lavish-poll-state";
12780
12789
  var CODEX_POLL_WAKE_PATH_GUIDANCE = "Codex detected: completed background tasks may not resume Codex automatically, so keep the poll attached to the active turn.";
12781
- var VERSION = "0.1.89";
12790
+ var VERSION = "0.1.92";
12782
12791
  function detectInvokingAgent(env = process.env) {
12783
12792
  return ["CODEX_SANDBOX", "CODEX_THREAD_ID"].some((key) => Object.hasOwn(env, key)) ? "codex" : "generic";
12784
12793
  }
@@ -12945,6 +12954,7 @@ function createHomeOutput({ bin, sessions, includeSessions = true, agent = "gene
12945
12954
  "Run `lavish-axi end <html-file>` to end a session as the agent - ending it this way still allows a plain reopen later. When the user ends it from the browser instead, a later `lavish-axi <html-file>` refuses to reopen it without `--reopen`",
12946
12955
  "Run `lavish-axi export <html-file> [--out <path>]` to write a portable copy of the artifact - one HTML file with its LOCAL assets inlined - so it opens with no Lavish server and no sibling files. Remote CDN/font references are left as links, so it needs network to render those. Users can also export from the browser chrome's overflow menu",
12947
12956
  "Run `lavish-axi share <html-file> [--private | --password <pw>]` to publish the artifact on ht-ml.app (https://ht-ml.app), a third-party hosting service not part of Lavish, and get back a visitable URL. Shares are PUBLIC by default, so anyone with the link can open them. Pass --private to publish a PRIVATE page behind a password Lavish generates and returns - hand the user that password with the URL and say it is a shared secret anyone they give it to can use; --password <pw> uses one you were already given instead. Local assets are inlined; remote refs load over the network. It also returns a secret update_key that can republish or lock the same URL later - run `lavish-axi share --help` before using it. Users can also publish from the browser chrome's overflow menu",
12957
+ "A request under a hostname Lavish does not answer to (a reverse-proxy name, a LAN IP) gets 403 `forbidden host`. Set `LAVISH_AXI_ALLOWED_HOSTS` in the environment that starts the server, running `lavish-axi stop` first if one is already up. See README's Allowed hosts section for the rules",
12948
12958
  "Run `lavish-axi stop` to shut down the background server (it also self-stops when idle or after the last session ends with nothing connected)",
12949
12959
  `Run \`lavish-axi playbook <playbook_id>\` for focused artifact guidance. ${PLAYBOOK_ROUTER_HELP}`,
12950
12960
  DESIGN_SYSTEM_HINT,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lavish-axi",
3
- "version": "0.1.89",
3
+ "version": "0.1.92",
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",
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "lavish-axi",
4
- "version": "0.1.89",
4
+ "version": "0.1.92",
5
5
  "description": "HTML is the new markdown. Lavish is the new editor for your HTML artifacts.",
6
6
  "author": {
7
7
  "name": "Kun Chen",