beauticode-dsh 1.0.20 → 1.0.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beauticode-dsh",
3
- "version": "1.0.20",
3
+ "version": "1.0.21",
4
4
  "description": "Cordis plugin: image/video backgrounds for DeepSeek Harness web.",
5
5
  "type": "module",
6
6
  "main": "./index.mjs",
@@ -3,6 +3,13 @@ import path from "node:path";
3
3
  import { MAX_INLINE_DATA_URL_BYTES } from "./constants.js";
4
4
  import { isLocalBackgroundSource, resolveBackgroundImagePath, resolveBackgroundVideoPath, } from "./media-source.js";
5
5
  import { detectImageMime } from "./media-validation.js";
6
+ // Cold-first-access symptoms reported by the renderer while the OS is still
7
+ // scanning or caching a large local video. The stalled attempt itself warms
8
+ // the file and media pipeline, so one immediate retry usually renders.
9
+ const RETRYABLE_RENDER_VERIFY_PATTERN = /首帧|Range 探针/;
10
+ function isRetryableRenderVerifyFailure(status, reason) {
11
+ return status === "fail" && typeof reason === "string" && RETRYABLE_RENDER_VERIFY_PATTERN.test(reason);
12
+ }
6
13
  /**
7
14
  * Minimal baseline only — live Codex path injects packages/adapter-codex
8
15
  * renderer/background.css (full-window main-surface transparency).
@@ -115,17 +122,32 @@ export class ApplyTransaction {
115
122
  const payload = await measure("buildPayload", () => this.#buildPayload(manifest, staged, input.type === "video" ? input.startAt : undefined));
116
123
  runtimeVideoPath = payload.video?.localPath ?? null;
117
124
  await measure("hostApply", () => this.host.apply(payload));
118
- const verify = await measure("rendererVerify", () => this.host.verify({
125
+ let verify = await measure("rendererVerify", () => this.host.verify({
119
126
  generation: manifest.generation,
120
127
  media: manifest.background?.type ?? "clear",
121
128
  }, { deadlineMs: this.verifyDeadlineMs }));
129
+ if (verify.status !== "pass" &&
130
+ manifest.background?.type === "video" &&
131
+ isRetryableRenderVerifyFailure(verify.status, verify.reason)) {
132
+ await measure("hostApplyRetry", () => this.host.apply(payload));
133
+ verify = await measure("rendererVerifyRetry", () => this.host.verify({
134
+ generation: manifest.generation,
135
+ media: manifest.background?.type ?? "clear",
136
+ }, { deadlineMs: this.verifyDeadlineMs }));
137
+ }
122
138
  if (verify.status !== "pass") {
123
139
  await measure("rollback", () => this.#rollback(snapshot, staged));
124
140
  staged = null;
125
141
  snapshot = null;
142
+ // Field reports used to show only the renderer's final state.
143
+ // Appending the server-side phase costs shows which stage ate the
144
+ // deadline without needing the local import-timing log.
145
+ const phaseSummary = Object.entries(phases)
146
+ .map(([name, ms]) => `${name}=${ms}ms`)
147
+ .join(",");
126
148
  return {
127
149
  ok: false,
128
- error: `Live verify did not pass (${verify.status}): ${verify.reason}`,
150
+ error: `Live verify did not pass (${verify.status}): ${verify.reason};事务阶段=${phaseSummary}`,
129
151
  rolledBack: true,
130
152
  sourceMode,
131
153
  timings: timings(),
@@ -3,7 +3,7 @@ import path from "node:path";
3
3
  import { AsyncLocalStorage } from "node:async_hooks";
4
4
  import crypto from "node:crypto";
5
5
  import { COMMIT_MARKER_NAME, COMMIT_MARKER_STALE_MS, DEFAULT_VIDEO_BASENAME, MANIFEST_NAME, SAVED_META_NAME, SCHEMA_ID, } from "./constants.js";
6
- import { assertSafeBasename, MediaValidationError, validateImageFile, validateVideoFile, } from "./media-validation.js";
6
+ import { assertSafeBasename, MediaValidationError, validateImageFile, validateVideoFile, warmVideoFileReads, } from "./media-validation.js";
7
7
  import { copyFileAtomic, emptyDir, ensureDataLayout, isPathInsideRoot, resolveDataPaths, rmrf, } from "./paths.js";
8
8
  import { normalizeBackgroundEffects } from "./types.js";
9
9
  import { isLocalBackgroundSource, managedPrimaryFile, resolveBackgroundImagePath, resolveBackgroundVideoPath, } from "./media-source.js";
@@ -289,6 +289,10 @@ export class BackgroundStore {
289
289
  return null;
290
290
  if (isLocalBackgroundSource(manifest.background)) {
291
291
  await validateVideoFile(source, { mode: "fast" });
292
+ // Zero-copy local videos stream straight from the original path, so
293
+ // the first range reads happen under the renderer verify deadline.
294
+ // Warm the header and moov-tail before that clock starts.
295
+ await warmVideoFileReads(source);
292
296
  return source;
293
297
  }
294
298
  const cached = this.#runtimeVideoCache.get(manifest.generation);
@@ -222,6 +222,39 @@ export async function validateVideoFile(filePath, opts = {}) {
222
222
  ctimeMs: inspected.ctimeMs,
223
223
  };
224
224
  }
225
+ const WARM_VIDEO_HEAD_BYTES = 2 * 1024 * 1024;
226
+ const WARM_VIDEO_TAIL_BYTES = 4 * 1024 * 1024;
227
+ /**
228
+ * Best-effort warm read of the byte ranges a cold <video> pipeline requests
229
+ * first: the container header plus the file tail where non-faststart MP4s
230
+ * keep their moov atom. On a fresh machine the first read of a large local
231
+ * video can stall in a synchronous antivirus scan long past the renderer
232
+ * verify deadline; touching these regions during staging keeps that cost
233
+ * outside the timed apply. Warmup must never block or fail an import.
234
+ */
235
+ export async function warmVideoFileReads(filePath) {
236
+ try {
237
+ const handle = await fs.open(filePath, "r");
238
+ try {
239
+ const size = (await handle.stat()).size;
240
+ const headLength = Math.min(WARM_VIDEO_HEAD_BYTES, size);
241
+ const tailLength = Math.min(WARM_VIDEO_TAIL_BYTES, Math.max(0, size - headLength));
242
+ const buffer = Buffer.allocUnsafe(Math.max(headLength, tailLength, 1));
243
+ if (headLength > 0) {
244
+ await handle.read(buffer, 0, headLength, 0);
245
+ }
246
+ if (tailLength > 0) {
247
+ await handle.read(buffer, 0, tailLength, size - tailLength);
248
+ }
249
+ }
250
+ finally {
251
+ await handle.close();
252
+ }
253
+ }
254
+ catch {
255
+ /* Advisory only; correctness of the import does not depend on warmup. */
256
+ }
257
+ }
225
258
  /** Basename-only guard for names stored inside active/staging trees. */
226
259
  export function assertSafeBasename(name, label) {
227
260
  if (typeof name !== "string" || name.length < 1 || name.length > 128) {