lavish-axi 0.1.86 → 0.1.88

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
@@ -212,7 +212,7 @@ pnpm link
212
212
  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.
213
213
  While editing a queued note, Enter saves it, Shift+Enter inserts a newline, and Escape discards the edit.
214
214
  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.
215
- In annotate mode a plain click on a link annotates it; Ctrl+click (Cmd+click on macOS) follows the link instead, opening it in a new tab as the browser normally would, without leaving annotate mode.
215
+ In annotate mode a plain click on a link annotates it; Ctrl+click (Cmd+click on macOS) follows the link instead, opening it in a new tab as the browser normally would, without leaving annotate mode. Off macOS, Meta+click (the Windows or Super key) annotates like a plain click.
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.
@@ -250,7 +250,7 @@ pnpm link
250
250
  Each library carries its author's terms (AWS Architecture Icons, for example, are covered by AWS's own usage terms), so check them before using one.
251
251
  - **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.
252
252
  Set `LAVISH_AXI_IDLE_TIMEOUT_MS=0` or `off` to disable idle self-shutdown.
253
- - **Server upgrades** - One background server serves every session, so upgrading `lavish-axi` while reviews are open makes the next `lavish-axi <html-file>` replace that server. Only the review page for the artifact being opened reloads itself once the replacement answers - and not even that one while you have unsent annotation text open, which gets the same banner instead so the reload is yours to make. Every other open review page keeps working and shows a banner reading "Lavish was updated. This page is running the previous version.", with a Check and reload button and a Dismiss button, so no page you are reading reloads on its own. After `lavish-axi stop` those pages say Lavish was stopped and to reload after you start it again, and a restart that only picks up a local build says that rather than claiming an update. An open review page whose server simply goes away - idle self-shutdown, a crash, a machine that slept - shows that same banner once reconnecting has failed for a few seconds, rather than retrying a dead server silently while looking fine; it clears itself if the server comes back, and dismissing it keeps it dismissed until then.
253
+ - **Server upgrades** - One background server serves every session, so upgrading `lavish-axi` while reviews are open makes the next `lavish-axi <html-file>` replace that server. Only a newer CLI replaces an older server: a CLI older than the running server uses it as is, so two installed versions on one machine do not restart each other's server. Releases up to and including 0.1.86 still replace a server of a different version, so this turn-by-turn restart stops only when both installed versions contain this fix. Only the review page for the artifact being opened reloads itself once the replacement answers - and not even that one while you have unsent annotation text open, which gets the same banner instead so the reload is yours to make. Every other open review page keeps working and shows a banner reading "Lavish was updated. This page is running the previous version.", with a Check and reload button and a Dismiss button, so no page you are reading reloads on its own. After `lavish-axi stop` those pages say Lavish was stopped and to reload after you start it again, and a restart that only picks up a local build says that rather than claiming an update. An open review page whose server simply goes away - idle self-shutdown, a crash, a machine that slept - shows that same banner once reconnecting has failed for a few seconds, rather than retrying a dead server silently while looking fine; it clears itself if the server comes back, and dismissing it keeps it dismissed until then.
254
254
  A page still using the legacy event stream reloads once when it reconnects to the replacement server, moving itself onto the current transport without retaining an HTTP connection. If unsent annotation text is open, it shows the neutral server-restarted banner instead and waits for you to reload.
255
255
  Every **Check and reload** control asks the server whether it is running before it navigates; while nothing answers, the page stays where it is and says so, and a check that gets no answer at all says that instead of guessing.
256
256
  In-flight `lavish-axi poll` commands end with an interrupted-poll error and are safe to re-run; queued feedback is never lost, and annotation text you have typed but not queued yet survives the reload as described under **Live reload**.
package/dist/cli.mjs CHANGED
@@ -6890,6 +6890,9 @@ function createArtifactSdk(deriveQueueKey, isNativeInteractive = isNativeInterac
6890
6890
  selected = null;
6891
6891
  if (hadCard) scheduleReviewStateReport();
6892
6892
  }
6893
+ function isApplePlatform() {
6894
+ return /Mac|iP(hone|ad|od)/.test(navigator.platform);
6895
+ }
6893
6896
  function showAnnotationCard(target, options2 = {}) {
6894
6897
  cancelPendingDraftRestore();
6895
6898
  const root = ensureShadow();
@@ -6913,7 +6916,7 @@ function createArtifactSdk(deriveQueueKey, isNativeInteractive = isNativeInterac
6913
6916
  const tableLabel = isTableCell ? [c.target?.rowLabel, c.target?.columnLabel].filter(Boolean).join(" \u2192 ") : "";
6914
6917
  const heading = c.tag === "text" ? "Annotate text" : tableLabel ? isCellItself ? "Annotate cell: " + escapeAnnotationText(tableLabel) : "Annotate &lt;" + c.tag + "&gt; in " + escapeAnnotationText(tableLabel) : c.tag === "mermaid-node" ? "Annotate node" + (nodeLabel ? ": " + escapeAnnotationText(nodeLabel) : "") : "Annotate &lt;" + c.tag + "&gt;";
6915
6918
  const placeholder = c.tag === "text" ? "Tell the agent what to change about this text..." : isCellItself ? "Tell the agent what to change about this table cell..." : c.tag === "mermaid-node" ? "Tell the agent what to change about this diagram node..." : "Tell the agent what to change about this element...";
6916
- const sendNowHint = /Mac|iP(hone|ad|od)/.test(navigator.platform) ? "\u2318" : "Ctrl";
6919
+ const sendNowHint = isApplePlatform() ? "\u2318" : "Ctrl";
6917
6920
  card.innerHTML = '<div class="lavish-heading">' + heading + '</div><textarea placeholder="' + placeholder + '"></textarea><div class="lavish-attachments" data-attachments hidden></div><div class="lavish-attach-row"><button class="lavish-attach" type="button"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="M21 15l-5-5L5 21"/></svg><span>Attach image</span></button><input class="lavish-attach-input" type="file" accept="' + ATTACHMENT_IMAGE_TYPES.accept + '" multiple hidden></div><div class="lavish-hint">Enter to queue &middot; ' + sendNowHint + '+Enter to send &middot; paste or drop an image</div><div class="lavish-row"><button class="lavish-cancel" type="button">Cancel</button><button class="lavish-send" type="button">Queue</button></div>';
6918
6921
  root.appendChild(card);
6919
6922
  function positionCard() {
@@ -7155,7 +7158,8 @@ function createArtifactSdk(deriveQueueKey, isNativeInteractive = isNativeInterac
7155
7158
  (event) => {
7156
7159
  if (!annotationMode || isLavishUi(event.target) || isLavishAction(event.target) || isInteractiveControl(event.target))
7157
7160
  return;
7158
- if ((event.ctrlKey || event.metaKey) && /** @type {Element} */
7161
+ const followModifier = isApplePlatform() ? event.metaKey : event.ctrlKey;
7162
+ if (followModifier && /** @type {Element} */
7159
7163
  event.target?.closest?.("a[href]")) {
7160
7164
  ignoreNextClick = false;
7161
7165
  return;
@@ -12774,7 +12778,7 @@ var AGENT_REPLY_INPUT_LIMIT_BYTES = AGENT_REPLY_JSON_LIMIT_BYTES - AGENT_REPLY_J
12774
12778
  var AGENT_REPLY_LIMIT_LABEL = "2 MB JSON request limit";
12775
12779
  var POLL_STATE_HEADER = "lavish-poll-state";
12776
12780
  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.";
12777
- var VERSION = "0.1.86";
12781
+ var VERSION = "0.1.88";
12778
12782
  function detectInvokingAgent(env = process.env) {
12779
12783
  return ["CODEX_SANDBOX", "CODEX_THREAD_ID"].some((key) => Object.hasOwn(env, key)) ? "codex" : "generic";
12780
12784
  }
@@ -14189,7 +14193,7 @@ async function ensureServer({ forceRestart = false, reloadKey = "" } = {}) {
14189
14193
  }
14190
14194
  }
14191
14195
  await startServer(port, { alsoListen });
14192
- const replacedForNetwork = Boolean(existing) && existing.app === "lavish-axi" && existing.network_stale === true && !forceRestart && typeof existing.version === "string" && existing.version === VERSION;
14196
+ const replacedForNetwork = Boolean(existing) && existing.app === "lavish-axi" && existing.network_stale === true && !forceRestart && typeof existing.version === "string" && !isServerOlderThanCli(VERSION, existing.version);
14193
14197
  let networkRestarted = replacedForNetwork;
14194
14198
  let raceRestarted = false;
14195
14199
  let deadline = Date.now() + 5e3;
@@ -14252,12 +14256,26 @@ function shouldRestartServer(currentVersion, healthBody, forceRestart = false) {
14252
14256
  if (forceRestart && healthBody.app === "lavish-axi") return true;
14253
14257
  if (healthBody.network_stale === true && healthBody.app === "lavish-axi") return true;
14254
14258
  if (typeof healthBody.version !== "string" || healthBody.version === "") return true;
14255
- return healthBody.version !== currentVersion;
14259
+ return isServerOlderThanCli(currentVersion, healthBody.version);
14260
+ }
14261
+ function isServerOlderThanCli(currentVersion, runningVersion) {
14262
+ if (runningVersion === currentVersion) return false;
14263
+ const current = parseReleaseVersion(currentVersion);
14264
+ const running = parseReleaseVersion(runningVersion);
14265
+ if (!current || !running) return true;
14266
+ for (let index = 0; index < 3; index += 1) {
14267
+ if (running[index] !== current[index]) return running[index] < current[index];
14268
+ }
14269
+ return false;
14270
+ }
14271
+ function parseReleaseVersion(version) {
14272
+ const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(String(version));
14273
+ return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
14256
14274
  }
14257
14275
  function serverReplacementReason(currentVersion, healthBody, forceRestart = false) {
14258
14276
  if (!shouldRestartServer(currentVersion, healthBody, forceRestart)) return "";
14259
14277
  const runningVersion = healthBody.version;
14260
- if (typeof runningVersion !== "string" || runningVersion === "" || runningVersion !== currentVersion) {
14278
+ if (typeof runningVersion !== "string" || runningVersion === "" || isServerOlderThanCli(currentVersion, runningVersion)) {
14261
14279
  return "upgrade";
14262
14280
  }
14263
14281
  return forceRestart ? "local-build" : "";
@@ -14273,7 +14291,7 @@ function shouldKillProcessOnPort(currentVersion, healthBody) {
14273
14291
  if (!healthBody || typeof healthBody !== "object") return false;
14274
14292
  if (typeof healthBody.version !== "string" || healthBody.version === "") return true;
14275
14293
  if (healthBody.app !== "lavish-axi") return false;
14276
- return healthBody.version !== currentVersion;
14294
+ return isServerOlderThanCli(currentVersion, healthBody.version);
14277
14295
  }
14278
14296
  async function canControlServerOnPort(baseUrl, healthBody, processMatchesLavish) {
14279
14297
  if (!healthBody || typeof healthBody !== "object") return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lavish-axi",
3
- "version": "0.1.86",
3
+ "version": "0.1.88",
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.86",
4
+ "version": "0.1.88",
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",