lavish-axi 0.1.70 → 0.1.72

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
@@ -205,7 +205,7 @@ pnpm link
205
205
  - **Keyboard shortcuts** - In the chrome composer, Enter sends queued prompts and Shift+Enter inserts a newline.
206
206
  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. Escape closes the card, same as Cancel, but only while it is empty (no text, no attachment); with unsent text or an attachment present, Escape does nothing rather than risk discarding it.
207
207
  Cmd+I or Ctrl+I toggles between annotate and explore mode from either the browser chrome or the artifact iframe, including while focus is in a textarea or control.
208
- - **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. The agent's reply (`--agent-reply`) concludes delivered work and returns presence to waiting.
208
+ - **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.
209
209
  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.
210
210
  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.
211
211
  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.
@@ -266,29 +266,30 @@ pnpm link
266
266
  | `lavish-axi setup plugin` | Register the installed package as an [Agent Plugin](https://agent-plugins.org) in VS Code, Cursor, and GitHub Copilot CLI; opt-in, idempotent, no marketplace involved. Reload each client afterward. |
267
267
  | `lavish-axi server` | Run the local Lavish Editor server. |
268
268
 
269
- Known playbook IDs: `diagram`, `table`, `comparison`, `plan`, `code`, `input`, `slides`.
269
+ Known playbook IDs: `diagram`, `table`, `comparison`, `plan`, `code`, `input`, `explanation`, `slides`.
270
270
  One artifact often combines several playbooks, such as a plan that includes a comparison and a diagram, so agents must match against each `use_when` trigger and open every matching playbook before writing HTML.
271
271
  For flows, architecture, state, or sequence diagrams, open the diagram playbook for the recommended tooling and SVG guidance.
272
272
 
273
273
  ### Flags
274
274
 
275
- | Command | Flag | Description |
276
- | ------------------------ | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
277
- | `lavish-axi <html-file>` | `--no-open` | Ensure the server/session exists without opening another browser window. |
278
- | `lavish-axi <html-file>` | `--no-gate` | Skip the open-time layout curtain for this browser open. |
279
- | `lavish-axi <html-file>` | `--reopen` | Reopen a session the user explicitly ended from the browser; without it, a plain open refuses and explains why instead of reopening uninvited. |
280
- | `lavish-axi update` | `--check` | Report current vs latest npm version without installing an update. |
281
- | `lavish-axi export` | `--out <path>` | Write the export to a specific path instead of `<name>.export.html` next to the source. |
282
- | `lavish-axi share` | `--private` | Make the page private behind a password Lavish generates and returns once; hand it to viewers as a shared secret. |
283
- | `lavish-axi share` | `--password <pw>` | Make the third-party ht-ml.app page private with a password you supply; viewers must supply the password. An empty or whitespace-only value (an unquoted `$PW` that is unset) is refused rather than publishing a public page. |
284
- | `lavish-axi share` | `--site <site_id>` | Republish an existing page in place (with `--update-key`) instead of creating a new one; the URL does not change. |
285
- | `lavish-axi share` | `--update-key <key>` | The secret returned when the page was published; required to republish or unpublish it. |
286
- | `lavish-axi share` | `--unpublish` | Replace a published page with a locked placeholder (ht-ml.app cannot delete); takes `--site` and `--update-key` and no file. |
287
- | `lavish-axi share` | `--token <t>` | Attach an optional bearer token (`LAVISH_AXI_HTML_APP_TOKEN`) when creating a page; never required, and rejected on a republish or `--unpublish`, where the `update_key` is the credential. |
288
- | `lavish-axi poll` | `--agent-reply "..."` | Show the agent's reply in the existing browser chat, conclude delivered work, and return presence to waiting before polling again. |
289
- | `lavish-axi poll` | `--timeout-ms <ms>` | Test/debug escape hatch only; agents should normally omit it and leave the long poll running. |
290
- | `lavish-axi stop` | `--port <port>` | Shut down a server running on a non-default port. |
291
- | `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 to `~/.lavish-axi/server.log` (or `LAVISH_AXI_STATE_DIR/server.log`) for startup and crash diagnostics. |
275
+ | Command | Flag | Description |
276
+ | ------------------------ | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
277
+ | `lavish-axi <html-file>` | `--no-open` | Ensure the server/session exists without opening another browser window. |
278
+ | `lavish-axi <html-file>` | `--no-gate` | Skip the open-time layout curtain for this browser open. |
279
+ | `lavish-axi <html-file>` | `--reopen` | Reopen a session the user explicitly ended from the browser; without it, a plain open refuses and explains why instead of reopening uninvited. |
280
+ | `lavish-axi update` | `--check` | Report current vs latest npm version without installing an update. |
281
+ | `lavish-axi export` | `--out <path>` | Write the export to a specific path instead of `<name>.export.html` next to the source. |
282
+ | `lavish-axi share` | `--private` | Make the page private behind a password Lavish generates and returns once; hand it to viewers as a shared secret. |
283
+ | `lavish-axi share` | `--password <pw>` | Make the third-party ht-ml.app page private with a password you supply; viewers must supply the password. An empty or whitespace-only value (an unquoted `$PW` that is unset) is refused rather than publishing a public page. |
284
+ | `lavish-axi share` | `--site <site_id>` | Republish an existing page in place (with `--update-key`) instead of creating a new one; the URL does not change. |
285
+ | `lavish-axi share` | `--update-key <key>` | The secret returned when the page was published; required to republish or unpublish it. |
286
+ | `lavish-axi share` | `--unpublish` | Replace a published page with a locked placeholder (ht-ml.app cannot delete); takes `--site` and `--update-key` and no file. |
287
+ | `lavish-axi share` | `--token <t>` | Attach an optional bearer token (`LAVISH_AXI_HTML_APP_TOKEN`) when creating a page; never required, and rejected on a republish or `--unpublish`, where the `update_key` is the credential. |
288
+ | `lavish-axi poll` | `--agent-reply "..."` | Show a concise agent reply in the existing browser chat, conclude delivered work, and return presence to waiting before polling again. Keep replies concise by default. |
289
+ | `lavish-axi poll` | `--agent-reply-file <path>` | When a longer reply is genuinely necessary, read Markdown from a file (`-` for stdin) so newlines survive quoting. Use blank-line paragraphs, `- ` / `1. ` lists, and `## ` headings so the Conversation panel renders it scannably. The Markdown subset is under Feedback controls. Cannot be combined with `--agent-reply`. |
290
+ | `lavish-axi poll` | `--timeout-ms <ms>` | Test/debug escape hatch only; agents should normally omit it and leave the long poll running. |
291
+ | `lavish-axi stop` | `--port <port>` | Shut down a server running on a non-default port. |
292
+ | `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 to `~/.lavish-axi/server.log` (or `LAVISH_AXI_STATE_DIR/server.log`) for startup and crash diagnostics. |
292
293
 
293
294
  ## Development
294
295
 
package/dist/cli.mjs CHANGED
@@ -7,7 +7,16 @@ var __export = (target, all) => {
7
7
 
8
8
  // src/cli.js
9
9
  import { spawn, spawnSync } from "node:child_process";
10
- import { closeSync, existsSync as existsSync3, mkdirSync as mkdirSync2, openSync, readFileSync as readFileSync2, realpathSync, writeFileSync as writeFileSync2 } from "node:fs";
10
+ import {
11
+ closeSync,
12
+ createReadStream,
13
+ existsSync as existsSync3,
14
+ mkdirSync as mkdirSync2,
15
+ openSync,
16
+ readFileSync as readFileSync2,
17
+ realpathSync,
18
+ writeFileSync as writeFileSync2
19
+ } from "node:fs";
11
20
  import { access, readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
12
21
  import os3 from "node:os";
13
22
  import path8 from "node:path";
@@ -240,6 +249,38 @@ var PLAYBOOKS = [
240
249
  "End input paths with an obvious way for the user to send feedback back to the agent."
241
250
  ]
242
251
  },
252
+ {
253
+ id: "explanation",
254
+ use_when: "Explain an existing system, PR, incident, or decision to a reader who was not there - when the goal is understanding what is and why, not choosing a direction or inspecting a plan before implementation",
255
+ choose: [
256
+ "Use this when the reader needs to understand something that already exists: a PR's mechanism, an incident's root cause, an architecture, a past decision.",
257
+ "Use the plan playbook when the reader must inspect and approve an approach before implementation begins; use comparison when they must choose between options.",
258
+ "Combine with diagram for flows or architecture, table for evidence inventories, and code when the mechanism lives in specific lines."
259
+ ],
260
+ structure: [
261
+ "Lead with the one-sentence answer to the question the reader actually has, before any mechanism.",
262
+ "Then show only what changed or how it works - a flow or before/after of the relevant slice, not a diagram of the whole system.",
263
+ "Keep evidence (file paths, line references, links, commands) subordinate to the narrative: cited where a claim needs support, never inlined wholesale.",
264
+ "Make each claim its own section or annotation target so the reader can push back on exactly the part they disagree with.",
265
+ "End with what was deliberately left out and where to look next, not a summary that restates the piece."
266
+ ],
267
+ design_rules: [
268
+ "Define unfamiliar terms at first use; for the reader's starting point, follow the diagram playbook's assume-nothing rule rather than restating it here.",
269
+ "Name the question the explanation answers at the top, so the reader knows whether it is their question.",
270
+ "Put prose beside figures - inline SVG for the flow or before/after, HTML for the reasoning - per the diagram playbook.",
271
+ "Link evidence rather than pasting logs or diffs; inlined evidence buries the narrative and goes stale.",
272
+ "Distinguish verified claims (cited to files, commands, or links) from inference; label uncertain reasoning as a question."
273
+ ],
274
+ pitfalls: [
275
+ "Do not restate the PR body, diff, or ticket file-by-file; the source documents already exist and the reader can open them.",
276
+ "Do not bury the answer under a diagram of the entire system when the question is about one slice of it.",
277
+ "Do not present inferred reasoning as verified fact; cite or label it."
278
+ ],
279
+ lavish_notes: [
280
+ "A Lavish explanation should let the reader annotate the exact claim they doubt or want expanded.",
281
+ "When an explanation surfaces a disagreement, queue prompts that name the claim and the evidence gap."
282
+ ]
283
+ },
243
284
  {
244
285
  id: "slides",
245
286
  use_when: "Create a deliberate presentation when slides are requested",
@@ -11474,8 +11515,16 @@ var POLL_WAKE_PATH_RULES = Object.freeze([
11474
11515
  "If it returns browser_disconnected, the review window stayed disconnected past its reconnect grace period but the session remains resumable; ask the user whether to reopen or end it, and do neither uninvited."
11475
11516
  ]);
11476
11517
  var POLL_SEND_AND_END_RULE = "`Send & End` ends the session. Its final feedback is still delivered once. After that response, polling stops, and the agent must not reopen the session uninvited.";
11518
+ var POLL_AGENT_REPLY_RULE = "Keep the reply concise. Only when a longer reply is genuinely necessary, use Markdown structure - blank-line paragraphs, `- ` / `1. ` lists, `## ` headings - so it renders scannably instead of a wall of text, and pass that body with `--agent-reply-file <path>` (`-` reads stdin) so newlines survive quoting.";
11519
+ var POLL_AGENT_REPLY_HELP_POINTER = "The Conversation panel's Markdown subset is in README's Feedback controls bullet.";
11520
+ var POLL_AGENT_REPLY_NEXT_POINTER = "The Conversation panel's Markdown subset is in `lavish-axi poll --help` and README.";
11521
+ var POLL_VALUE_FLAGS = ["--agent-reply", "--agent-reply-file", "--timeout-ms"];
11522
+ var AGENT_REPLY_JSON_LIMIT_BYTES = 2 * 1024 * 1024;
11523
+ var AGENT_REPLY_JSON_ENVELOPE_BYTES = Buffer.byteLength(JSON.stringify({ text: "" }));
11524
+ var AGENT_REPLY_INPUT_LIMIT_BYTES = AGENT_REPLY_JSON_LIMIT_BYTES - AGENT_REPLY_JSON_ENVELOPE_BYTES;
11525
+ var AGENT_REPLY_LIMIT_LABEL = "2 MB JSON request limit";
11477
11526
  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.";
11478
- var VERSION = "0.1.70";
11527
+ var VERSION = "0.1.72";
11479
11528
  function detectInvokingAgent(env = process.env) {
11480
11529
  return ["CODEX_SANDBOX", "CODEX_THREAD_ID"].some((key) => Object.hasOwn(env, key)) ? "codex" : "generic";
11481
11530
  }
@@ -11632,7 +11681,7 @@ function createOpenOutput({
11632
11681
  session: { file, url, status },
11633
11682
  ...networkWarning ? { network_warning: networkWarning } : {},
11634
11683
  ...selfPaintWarning ? { self_paint_warning: selfPaintWarning } : {},
11635
- next_step: `${selfPaintPrefix}Do not respond to the user just yet. Now you must run \`lavish-axi poll ${file}\`. This command long-polls until the user sends feedback, ends the session, or leaves every review window disconnected past the reconnect grace period, and it stays silent the whole time - that is normal, never kill it. Layout issues the browser detects do not return this poll; they wait in the user's Layout issues inbox until the user queues them, then arrive as an ordinary tag "layout-warnings" prompt. Do not pass --timeout-ms during normal agent use. ${pollExecutionGuidance({ agent })} After applying feedback, run \`lavish-axi poll ${file} --agent-reply "<message for the user>"\` without --timeout-ms to show your response in Lavish Editor and wait for more feedback. If the user ends the session, stop polling and do not reopen it by re-running \`lavish-axi ${file}\` unless the user asks for further review or something genuinely important needs their visual attention - deliver routine updates directly in this conversation instead. When reopening is warranted, run \`lavish-axi ${file} --reopen\`.`
11684
+ next_step: `${selfPaintPrefix}Do not respond to the user just yet. Now you must run \`lavish-axi poll ${file}\`. This command long-polls until the user sends feedback, ends the session, or leaves every review window disconnected past the reconnect grace period, and it stays silent the whole time - that is normal, never kill it. Layout issues the browser detects do not return this poll; they wait in the user's Layout issues inbox until the user queues them, then arrive as an ordinary tag "layout-warnings" prompt. Do not pass --timeout-ms during normal agent use. ${pollExecutionGuidance({ agent })} After applying feedback, run \`lavish-axi poll ${file} --agent-reply "<message for the user>"\` without --timeout-ms to show a concise response in Lavish Editor and wait for more feedback. ${POLL_AGENT_REPLY_RULE} ${POLL_AGENT_REPLY_NEXT_POINTER} If the user ends the session, stop polling and do not reopen it by re-running \`lavish-axi ${file}\` unless the user asks for further review or something genuinely important needs their visual attention - deliver routine updates directly in this conversation instead. When reopening is warranted, run \`lavish-axi ${file} --reopen\`.`
11636
11685
  };
11637
11686
  }
11638
11687
  function createUserEndedOpenOutput({ file, url, networkWarning = void 0 }) {
@@ -11692,13 +11741,13 @@ function shouldOpenBrowser(args, env) {
11692
11741
  return !args.includes("--no-open") && env.LAVISH_AXI_NO_OPEN !== "1";
11693
11742
  }
11694
11743
  async function pollCommand(args) {
11695
- const file = firstPositionalArg(args, ["--agent-reply", "--timeout-ms"]);
11744
+ const file = firstPositionalArg(args, POLL_VALUE_FLAGS);
11696
11745
  if (!file) {
11697
11746
  throw new AxiError("HTML file path is required", "VALIDATION_ERROR", ["Run `lavish-axi poll <html-file>`"]);
11698
11747
  }
11748
+ const agentReply = await resolveAgentReply(args);
11699
11749
  const absolute = await canonicalFile(file);
11700
11750
  const baseUrl = await ensureServer();
11701
- const agentReply = flagValue(args, "--agent-reply");
11702
11751
  if (agentReply) {
11703
11752
  await postJson(`${baseUrl}/api/${sessionKey(absolute)}/agent-reply`, { text: agentReply });
11704
11753
  }
@@ -11816,7 +11865,7 @@ function createFeedbackNextStep(file, artifactFailures, sessionEnded, endedBy, p
11816
11865
  return `${failureNote}${layoutNote}${whiteboardNote}${attachmentNote}This was the last feedback before the Lavish Editor session ended. Stop polling ${file}. Deliver any remaining updates directly in this conversation, or run \`lavish-axi ${file}\` to open a fresh session if the user needs further visual review.`;
11817
11866
  }
11818
11867
  const prefix = count > 0 ? artifactFailuresPrefix(file, artifactFailures) : `Apply the requested changes to ${file}. `;
11819
- return `${prefix}${layoutNote}${whiteboardNote}${attachmentNote}Do not respond to the user just yet. Now you must run \`lavish-axi poll ${file} --agent-reply "<message for the user>"\` without --timeout-ms unless the user ended the session. The poll waits silently until the user sends more feedback, ends the session, or leaves every review window disconnected past the reconnect grace period - never kill it. ${pollExecutionGuidance({ agent })}`;
11868
+ return `${prefix}${layoutNote}${whiteboardNote}${attachmentNote}Do not respond to the user just yet. Now you must run \`lavish-axi poll ${file} --agent-reply "<message for the user>"\` without --timeout-ms unless the user ended the session. ${POLL_AGENT_REPLY_RULE} ${POLL_AGENT_REPLY_NEXT_POINTER} The poll waits silently until the user sends more feedback, ends the session, or leaves every review window disconnected past the reconnect grace period - never kill it. ${pollExecutionGuidance({ agent })}`;
11820
11869
  }
11821
11870
  function artifactFailuresPrefix(file, artifactFailures) {
11822
11871
  const count = artifactFailures.length;
@@ -12849,6 +12898,103 @@ function flagValue(args, flag) {
12849
12898
  }
12850
12899
  return null;
12851
12900
  }
12901
+ function inspectValueFlag(args, flag) {
12902
+ for (let i = 0; i < args.length; i += 1) {
12903
+ const arg = args[i];
12904
+ if (arg === "--") return { present: false };
12905
+ if (arg === flag) {
12906
+ return { present: true, value: i + 1 < args.length ? args[i + 1] : null, swallows: true };
12907
+ }
12908
+ if (arg.startsWith(`${flag}=`)) {
12909
+ return { present: true, value: arg.slice(flag.length + 1), swallows: false };
12910
+ }
12911
+ }
12912
+ return { present: false };
12913
+ }
12914
+ var AGENT_REPLY_FILE_HINT = "Pass --agent-reply-file <path>, or --agent-reply-file - to read stdin";
12915
+ function agentReplyTooLargeError() {
12916
+ return new AxiError(`Agent reply exceeds the ${AGENT_REPLY_LIMIT_LABEL}`, "VALIDATION_ERROR", [
12917
+ "Shorten the reply, then retry the same poll command"
12918
+ ]);
12919
+ }
12920
+ async function readAgentReplyStream(stream) {
12921
+ const chunks = [];
12922
+ let bytes = 0;
12923
+ for await (const value of stream) {
12924
+ const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
12925
+ bytes += chunk.length;
12926
+ if (bytes > AGENT_REPLY_INPUT_LIMIT_BYTES) {
12927
+ stream.destroy();
12928
+ throw agentReplyTooLargeError();
12929
+ }
12930
+ chunks.push(chunk);
12931
+ }
12932
+ const text = Buffer.concat(chunks, bytes).toString("utf8");
12933
+ if (Buffer.byteLength(JSON.stringify({ text })) > AGENT_REPLY_JSON_LIMIT_BYTES) {
12934
+ throw agentReplyTooLargeError();
12935
+ }
12936
+ return text;
12937
+ }
12938
+ async function resolveAgentReply(args, { createReadStreamFn = createReadStream, stdin = process.stdin, stdinIsTTY = process.stdin.isTTY === true } = {}) {
12939
+ const inline = inspectValueFlag(args, "--agent-reply");
12940
+ const fromFile = inspectValueFlag(args, "--agent-reply-file");
12941
+ if (inline.present && fromFile.present) {
12942
+ throw new AxiError("--agent-reply and --agent-reply-file cannot be combined", "VALIDATION_ERROR", [
12943
+ "Pass --agent-reply for a concise quoted reply, or --agent-reply-file <path> (`-` for stdin) when a longer Markdown body is necessary"
12944
+ ]);
12945
+ }
12946
+ if (fromFile.present) {
12947
+ return readAgentReplyFile(fromFile, { createReadStreamFn, stdin, stdinIsTTY });
12948
+ }
12949
+ if (!inline.present) return null;
12950
+ return inline.value || null;
12951
+ }
12952
+ async function readAgentReplyFile(fromFile, { createReadStreamFn, stdin, stdinIsTTY }) {
12953
+ if (fromFile.swallows && typeof fromFile.value === "string" && fromFile.value.startsWith("--")) {
12954
+ throw new AxiError(
12955
+ `--agent-reply-file was given no value: the next argument ${fromFile.value} is another flag, so it would have been used as the path`,
12956
+ "VALIDATION_ERROR",
12957
+ [AGENT_REPLY_FILE_HINT, "Use --agent-reply-file=<path> if the path itself starts with --"]
12958
+ );
12959
+ }
12960
+ const spec = fromFile.value;
12961
+ if (spec == null || !String(spec).trim()) {
12962
+ throw new AxiError("--agent-reply-file was given an empty value", "VALIDATION_ERROR", [AGENT_REPLY_FILE_HINT]);
12963
+ }
12964
+ let text;
12965
+ if (spec === "-") {
12966
+ if (stdinIsTTY) {
12967
+ throw new AxiError("--agent-reply-file - cannot read stdin from a terminal", "VALIDATION_ERROR", [
12968
+ "Pipe a Markdown body into stdin, or pass --agent-reply-file <path>"
12969
+ ]);
12970
+ }
12971
+ try {
12972
+ text = await readAgentReplyStream(stdin);
12973
+ } catch (error) {
12974
+ if (error instanceof AxiError) throw error;
12975
+ const detail = error instanceof Error ? error.message : String(error);
12976
+ throw new AxiError(`Cannot read --agent-reply-file stdin: ${detail}`, "VALIDATION_ERROR", [
12977
+ "Pipe a Markdown body into stdin, or pass --agent-reply-file <path>"
12978
+ ]);
12979
+ }
12980
+ } else {
12981
+ try {
12982
+ text = await readAgentReplyStream(createReadStreamFn(spec));
12983
+ } catch (error) {
12984
+ if (error instanceof AxiError) throw error;
12985
+ const detail = error instanceof Error ? error.message : String(error);
12986
+ throw new AxiError(`Cannot read --agent-reply-file ${spec}: ${detail}`, "VALIDATION_ERROR", [
12987
+ "Pass a UTF-8 Markdown file, or `-` to read stdin"
12988
+ ]);
12989
+ }
12990
+ }
12991
+ if (!String(text || "").trim()) {
12992
+ throw new AxiError("--agent-reply-file was empty", "VALIDATION_ERROR", [
12993
+ 'Write Markdown into the file, or pass --agent-reply "<message>" for a concise reply'
12994
+ ]);
12995
+ }
12996
+ return String(text);
12997
+ }
12852
12998
  function isValueFlagToken(arg, flags) {
12853
12999
  for (const flag of flags) {
12854
13000
  if (arg === flag || arg.startsWith(`${flag}=`)) return true;
@@ -12867,7 +13013,7 @@ function createTopLevelHelp({ agent = "generic" } = {}) {
12867
13013
  Usage:
12868
13014
  lavish-axi
12869
13015
  lavish-axi <html-file> [--no-open] [--no-gate] [--reopen]
12870
- lavish-axi poll <html-file> [--agent-reply "..."]
13016
+ lavish-axi poll <html-file> [--agent-reply "..."] [--agent-reply-file <path>]
12871
13017
  lavish-axi end <html-file>
12872
13018
  lavish-axi export <html-file> [--out <path>]
12873
13019
  lavish-axi share <html-file> [--private | --password <pw>] [--token <t>]
@@ -12891,9 +13037,16 @@ function createCommandHelp({ agent = "generic" } = {}) {
12891
13037
 
12892
13038
  Open or resume a Lavish Editor review session for an HTML artifact. Use --no-open when you need to ensure the server/session exists without opening another browser window. Use --no-gate to skip the open-time layout curtain for this browser open. If the user explicitly ended the session from the browser, this refuses to reopen it and returns guidance instead - pass --reopen to force it open when the user asks for further review or something important needs their visual attention. Sessions ended by the agent (\`lavish-axi end\`) reopen normally without the flag.
12893
13039
  `,
12894
- poll: `Usage: lavish-axi poll <html-file> [--agent-reply "..."]
13040
+ poll: `Usage: lavish-axi poll <html-file> [--agent-reply "..."] [--agent-reply-file <path>]
13041
+
13042
+ This command long-polls indefinitely for queued user prompts. It stays silent while it waits - that is normal, never kill it. Browser-detected layout issues do NOT return this poll: they are filed passively in the user's Layout issues inbox and arrive as an ordinary tag "layout-warnings" prompt only after the user selects them and queues the fixes. Warning lifecycle: an issue stays unresolved and counted while queued, becomes recurring if a newer artifact revision still shows it, and is resolved only after a newer artifact load plus a complete diagnostic pass at the same viewport no longer detects it. A failed or incomplete pass preserves it as unverified rather than clearing it. The only response that arrives without user action is artifact_failures - a fatal failure that made the review surface itself unusable. Do not pass --timeout-ms during normal agent use; it is for tests and debugging only. ${pollExecutionGuidance({ agent })} Use --agent-reply after applying prior feedback to display a concise response in Lavish Editor before waiting again. ${POLL_AGENT_REPLY_RULE} ${POLL_AGENT_REPLY_HELP_POINTER} Do not combine --agent-reply with --agent-reply-file.
13043
+
13044
+ Examples:
13045
+ lavish-axi poll report.html --agent-reply "Renamed the payment step."
13046
+ lavish-axi poll report.html --agent-reply-file reply.md
13047
+ lavish-axi poll report.html --agent-reply-file -
12895
13048
 
12896
- This command long-polls indefinitely for queued user prompts. It stays silent while it waits - that is normal, never kill it. Browser-detected layout issues do NOT return this poll: they are filed passively in the user's Layout issues inbox and arrive as an ordinary tag "layout-warnings" prompt only after the user selects them and queues the fixes. Warning lifecycle: an issue stays unresolved and counted while queued, becomes recurring if a newer artifact revision still shows it, and is resolved only after a newer artifact load plus a complete diagnostic pass at the same viewport no longer detects it. A failed or incomplete pass preserves it as unverified rather than clearing it. The only response that arrives without user action is artifact_failures - a fatal failure that made the review surface itself unusable. Do not pass --timeout-ms during normal agent use; it is for tests and debugging only. ${pollExecutionGuidance({ agent })} Use --agent-reply after applying prior feedback to display your response in Lavish Editor before waiting again. ${POLL_SEND_AND_END_RULE}
13049
+ ${POLL_SEND_AND_END_RULE}
12897
13050
  `,
12898
13051
  end: `Usage: lavish-axi end <html-file>
12899
13052
 
@@ -12924,7 +13077,7 @@ Shut down the background Lavish Editor server. The server also stops itself when
12924
13077
  `,
12925
13078
  playbook: `Usage: lavish-axi playbook [playbook_id]
12926
13079
 
12927
- List focused artifact guidance playbooks, or show one playbook by ID. Known IDs: diagram, table, comparison, plan, code, input, slides.
13080
+ List focused artifact guidance playbooks, or show one playbook by ID. Known IDs: diagram, table, comparison, plan, code, input, explanation, slides.
12928
13081
 
12929
13082
  ${PLAYBOOK_ROUTER_HELP}
12930
13083
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lavish-axi",
3
- "version": "0.1.70",
3
+ "version": "0.1.72",
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.70",
4
+ "version": "0.1.72",
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",