lavish-axi 0.1.54 → 0.1.55

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/dist/cli.mjs CHANGED
@@ -7446,13 +7446,19 @@ var SessionStore = class {
7446
7446
  }
7447
7447
  session.layout_warnings = warnings;
7448
7448
  const userMessages = restoring ? [] : acceptedPrompts.filter((prompt) => prompt.tag === "message" && prompt.prompt).map((prompt) => ({ role: "user", text: prompt.prompt, at: (/* @__PURE__ */ new Date()).toISOString() }));
7449
- session.prompts = [...session.prompts || [], ...acceptedPrompts];
7449
+ const existingPrompts = Array.isArray(session.prompts) ? session.prompts : [];
7450
+ session.prompts = restoring ? [...acceptedPrompts, ...existingPrompts] : [...existingPrompts, ...acceptedPrompts];
7450
7451
  session.chat = [...session.chat || [], ...userMessages];
7451
7452
  if (restoring) {
7452
- session.artifact_failures = Array.isArray(payload.artifact_failures) ? JSON.parse(JSON.stringify(payload.artifact_failures)) : [];
7453
+ const restoredFailures = Array.isArray(payload.artifact_failures) ? JSON.parse(JSON.stringify(payload.artifact_failures)) : [];
7454
+ const existingFailures = Array.isArray(session.artifact_failures) ? session.artifact_failures : [];
7455
+ session.artifact_failures = mergeArtifactFailures(restoredFailures, existingFailures).failures;
7453
7456
  }
7454
7457
  session.pending_prompts = session.prompts.length;
7455
- session.dom_snapshot = String(payload.domSnapshot || payload.dom_snapshot || "");
7458
+ const restoredSnapshot = String(payload.domSnapshot || payload.dom_snapshot || "");
7459
+ if (!restoring || existingPrompts.length === 0 && !session.dom_snapshot) {
7460
+ session.dom_snapshot = restoredSnapshot;
7461
+ }
7456
7462
  session.status = shouldEndSession || alreadyEnded ? "ended" : session.prompts.length > 0 || restoring && Array.isArray(session.artifact_failures) && session.artifact_failures.length > 0 ? "feedback" : "open";
7457
7463
  if (shouldEndSession) session.ended_by = "user";
7458
7464
  session.updated_at = (/* @__PURE__ */ new Date()).toISOString();
@@ -7661,17 +7667,11 @@ var SessionStore = class {
7661
7667
  }
7662
7668
  const normalized = normalizeArtifactFailures(payload?.failures);
7663
7669
  const previous = Array.isArray(session.artifact_failures) ? session.artifact_failures : [];
7664
- const merged = [...previous];
7665
- let changed = false;
7666
- for (const failure of normalized) {
7667
- if (merged.some((item) => item.kind === failure.kind && item.detail === failure.detail)) continue;
7668
- merged.push(failure);
7669
- changed = true;
7670
- }
7670
+ const { failures, changed } = mergeArtifactFailures(previous, normalized);
7671
7671
  if (!changed) {
7672
7672
  return { session, changed: false };
7673
7673
  }
7674
- session.artifact_failures = merged.slice(-MAX_ARTIFACT_FAILURES);
7674
+ session.artifact_failures = failures;
7675
7675
  if (session.status !== "ended") session.status = "feedback";
7676
7676
  session.updated_at = (/* @__PURE__ */ new Date()).toISOString();
7677
7677
  await this.writeState(state);
@@ -7888,10 +7888,12 @@ function boundAttachmentRefs(normalized, options) {
7888
7888
  }
7889
7889
  }
7890
7890
  if (rejected.length) return rejected;
7891
- let requestRefs = 0;
7892
- for (const { prompt } of normalized) requestRefs += prompt.attachments?.length || 0;
7893
- if (requestRefs > MAX_REQUEST_ATTACHMENT_REFS) {
7894
- return [{ id: "", name: "", reason: "too-many-in-request" }];
7891
+ if (options.restore !== true) {
7892
+ let requestRefs = 0;
7893
+ for (const { prompt } of normalized) requestRefs += prompt.attachments?.length || 0;
7894
+ if (requestRefs > MAX_REQUEST_ATTACHMENT_REFS) {
7895
+ return [{ id: "", name: "", reason: "too-many-in-request" }];
7896
+ }
7895
7897
  }
7896
7898
  return rejected;
7897
7899
  }
@@ -7966,6 +7968,16 @@ function parsePassSequence(payload) {
7966
7968
  return { present, value: Number.isSafeInteger(value) && value > 0 ? value : null };
7967
7969
  }
7968
7970
  var ARTIFACT_FAILURE_KINDS = /* @__PURE__ */ new Set(["artifact-unavailable", "artifact-asset-unavailable"]);
7971
+ function mergeArtifactFailures(earlier, later) {
7972
+ const merged = Array.isArray(earlier) ? [...earlier] : [];
7973
+ let changed = false;
7974
+ for (const failure of Array.isArray(later) ? later : []) {
7975
+ if (merged.some((item) => item.kind === failure.kind && item.detail === failure.detail)) continue;
7976
+ merged.push(failure);
7977
+ changed = true;
7978
+ }
7979
+ return { failures: merged.slice(-MAX_ARTIFACT_FAILURES), changed };
7980
+ }
7969
7981
  function normalizeArtifactFailures(failures) {
7970
7982
  if (!Array.isArray(failures)) return [];
7971
7983
  return failures.filter((failure) => failure && typeof failure === "object" && !Array.isArray(failure)).map((failure) => ({
@@ -8637,25 +8649,43 @@ async function serve({
8637
8649
  async function restoreClosedFeedback(key, result) {
8638
8650
  if (result.status !== "feedback") return;
8639
8651
  const prompts = Array.isArray(result.prompts) ? result.prompts : [];
8640
- const session = await store.queuePrompts(
8641
- key,
8642
- {
8643
- dom_snapshot: result.dom_snapshot || "",
8644
- prompts,
8645
- ...Array.isArray(result.artifact_failures) ? { artifact_failures: result.artifact_failures } : {}
8646
- },
8647
- {
8648
- restore: true,
8649
- resolveAttachment: (sessionKeyValue, id) => resolveAttachment(attachmentStateRoot, sessionKeyValue, id),
8650
- maxPerPrompt: attachmentConfig.maxPerPrompt,
8651
- maxPromptBytes: attachmentConfig.maxPromptBytes
8652
- }
8653
- );
8654
- const restoredPrompts = prompts.length === 0 ? [] : session && !session.rejected && !session.conflict && Array.isArray(session.prompts) ? session.prompts.slice(-prompts.length) : null;
8652
+ let session = null;
8653
+ let restoreError = null;
8654
+ try {
8655
+ session = await store.queuePrompts(
8656
+ key,
8657
+ {
8658
+ dom_snapshot: result.dom_snapshot || "",
8659
+ prompts,
8660
+ ...Array.isArray(result.artifact_failures) ? { artifact_failures: result.artifact_failures } : {}
8661
+ },
8662
+ {
8663
+ restore: true,
8664
+ resolveAttachment: (sessionKeyValue, id) => resolveAttachment(attachmentStateRoot, sessionKeyValue, id),
8665
+ maxPerPrompt: attachmentConfig.maxPerPrompt,
8666
+ maxPromptBytes: attachmentConfig.maxPromptBytes
8667
+ }
8668
+ );
8669
+ } catch (error) {
8670
+ restoreError = error;
8671
+ }
8672
+ const restoredPrompts = prompts.length === 0 ? [] : session && !session.rejected && !session.conflict && Array.isArray(session.prompts) ? session.prompts.slice(0, prompts.length) : null;
8655
8673
  const restoredFailures = session && Array.isArray(session.artifact_failures) ? session.artifact_failures : null;
8656
- if (!restoredPrompts || JSON.stringify(restoredPrompts) !== JSON.stringify(prompts) || Array.isArray(result.artifact_failures) && JSON.stringify(restoredFailures) !== JSON.stringify(result.artifact_failures)) {
8674
+ const failuresRestored = !Array.isArray(result.artifact_failures) || Array.isArray(restoredFailures) && result.artifact_failures.every(
8675
+ (failure) => restoredFailures.some((restoredFailure) => JSON.stringify(restoredFailure) === JSON.stringify(failure))
8676
+ );
8677
+ const persistedNothing = !session || Boolean(session.rejected) || Boolean(session.conflict);
8678
+ if (restoreError) {
8679
+ writeLog(
8680
+ `[lavish] closed poll feedback restore failed; the batch was lost: ${restoreError?.message || restoreError}`
8681
+ );
8682
+ } else if (persistedNothing) {
8683
+ writeLog("[lavish] closed poll feedback restore was refused; nothing was persisted and the batch was lost");
8684
+ } else if (!restoredPrompts || JSON.stringify(restoredPrompts) !== JSON.stringify(prompts) || !failuresRestored) {
8657
8685
  writeLog("[lavish] closed poll feedback restore was incomplete; delivery was not marked");
8658
8686
  }
8687
+ const pendingAfterRestore = Array.isArray(restoredPrompts) && restoredPrompts.length > 0 || Array.isArray(restoredFailures) && restoredFailures.length > 0;
8688
+ if (pendingAfterRestore) events.emit("feedback", key);
8659
8689
  }
8660
8690
  const whiteboardStateRoot = path7.dirname(stateFile2);
8661
8691
  const allowedHostnames = buildAllowedHostnames({ host, linkHost: linkHostName, allowedHosts });
@@ -8800,6 +8830,10 @@ async function serve({
8800
8830
  responding = true;
8801
8831
  try {
8802
8832
  const result = await store.takeFeedback(key);
8833
+ if (requestClosed || req.destroyed || res.writableEnded) {
8834
+ await restoreClosedFeedback(key, result);
8835
+ return;
8836
+ }
8803
8837
  finishFeedbackDelivery(key, result);
8804
8838
  if (streamHeartbeat) {
8805
8839
  res.end(JSON.stringify(result));
@@ -10298,7 +10332,7 @@ var POLL_WAKE_PATH_RULES = Object.freeze([
10298
10332
  ]);
10299
10333
  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.";
10300
10334
  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.";
10301
- var VERSION = "0.1.54";
10335
+ var VERSION = "0.1.55";
10302
10336
  function detectInvokingAgent(env = process.env) {
10303
10337
  return ["CODEX_SANDBOX", "CODEX_THREAD_ID"].some((key) => Object.hasOwn(env, key)) ? "codex" : "generic";
10304
10338
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lavish-axi",
3
- "version": "0.1.54",
3
+ "version": "0.1.55",
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.54",
4
+ "version": "0.1.55",
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",