@openclaw/diffs 2026.10.5-beta.4 → 2026.10.10-beta.2

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/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as getServedViewerAsset, r as VIEWER_RUNTIME_PATH } from "./.setup/viewer-assets-C646cpoV.mjs";
1
+ import { a as getServedViewerAsset, r as VIEWER_RUNTIME_PATH } from "./.setup/viewer-assets-D_VrsDqE.mjs";
2
2
  import { buildPluginConfigSchema, definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
3
3
  import { mapPluginConfigIssues } from "openclaw/plugin-sdk/extension-shared";
4
4
  import { asFiniteNumber, asNonArrayRecord, asOptionalRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -580,7 +580,6 @@ const SWEEP_FALLBACK_AGE_MS = 864e5;
580
580
  const CLEANUP_INTERVAL_MS = 3e5;
581
581
  const CLEANUP_CONCURRENCY = 4;
582
582
  const MAX_DECODED_HTML_BYTES = 67108864;
583
- const ARTIFACT_ID_ATTEMPTS = 8;
584
583
  const VIEWER_PREFIX = "/plugins/diffs/view";
585
584
  const EMPTY_BLOB = /* @__PURE__ */ new Uint8Array();
586
585
  const gzipAsync = promisify(gzip);
@@ -646,34 +645,24 @@ var DiffArtifactStore = class {
646
645
  format,
647
646
  ...params.context ? { context: params.context } : {}
648
647
  };
649
- for (let attempt = 0; attempt < ARTIFACT_ID_ATTEMPTS; attempt += 1) {
650
- const id = crypto.randomBytes(10).toString("hex");
651
- if (!await this.registerIfAbsentWithCleanup(id, EMPTY_BLOB, metadata, ttlMs)) continue;
652
- const artifactDir = this.artifactDir(id);
653
- try {
654
- await fs$1.mkdir(this.rootDir, { recursive: true });
655
- await fs$1.mkdir(artifactDir);
656
- const entry = await this.blobStore.lookup(id);
657
- if (!entry || !isRenderedFileMetadata(entry.metadata)) throw new Error(`Diff file artifact expired before materialization: ${id}`);
658
- this.renderingFileIds.add(id);
659
- this.scheduleCleanup();
660
- return {
661
- id,
662
- filePath: path.join(artifactDir, `preview.${format}`),
663
- expiresAt: resolveEntryExpiresAt(entry),
664
- ...params.context ? { context: params.context } : {}
665
- };
666
- } catch (error) {
667
- await this.blobStore.delete(id).catch(() => false);
668
- await fs$1.rm(artifactDir, {
669
- recursive: true,
670
- force: true
671
- }).catch(() => {});
672
- if (isFileExists(error)) continue;
673
- throw error;
674
- }
648
+ const entry = await this.registerUnique(EMPTY_BLOB, metadata, ttlMs);
649
+ const id = entry.key;
650
+ const artifactDir = this.artifactDir(id);
651
+ try {
652
+ await fs$1.mkdir(this.rootDir, { recursive: true });
653
+ await fs$1.mkdir(artifactDir);
654
+ } catch (error) {
655
+ await this.blobStore.delete(id).catch(() => false);
656
+ throw error;
675
657
  }
676
- throw new Error("Failed to allocate a unique diff file artifact id.");
658
+ this.renderingFileIds.add(id);
659
+ this.scheduleCleanup();
660
+ return {
661
+ id,
662
+ filePath: path.join(artifactDir, `preview.${format}`),
663
+ expiresAt: resolveEntryExpiresAt(entry),
664
+ ...params.context ? { context: params.context } : {}
665
+ };
677
666
  }
678
667
  async completeFileArtifact(id) {
679
668
  try {
@@ -737,9 +726,8 @@ var DiffArtifactStore = class {
737
726
  if (orphanCleanup.hasError) throw orphanCleanup.firstError;
738
727
  }
739
728
  async registerUnique(bytes, metadata, ttlMs) {
740
- for (let attempt = 0; attempt < ARTIFACT_ID_ATTEMPTS; attempt += 1) {
741
- const id = crypto.randomBytes(10).toString("hex");
742
- if (!await this.registerIfAbsentWithCleanup(id, bytes, metadata, ttlMs)) continue;
729
+ const id = crypto.randomBytes(10).toString("hex");
730
+ if (await this.registerIfAbsentWithCleanup(id, bytes, metadata, ttlMs)) {
743
731
  const entry = await this.blobStore.lookup(id);
744
732
  if (entry) return entry;
745
733
  }
@@ -756,7 +744,6 @@ var DiffArtifactStore = class {
756
744
  }
757
745
  async deleteExpiredFile(entry) {
758
746
  if (!isRenderedFileMetadata(entry.metadata) || this.renderingFileIds.has(entry.key)) return;
759
- if (await this.blobStore.lookup(entry.key)) return;
760
747
  await fs$1.rm(this.artifactDir(entry.key), {
761
748
  recursive: true,
762
749
  force: true
@@ -824,9 +811,6 @@ function isArtifactContext(value) {
824
811
  ]);
825
812
  return Object.entries(context).every(([key, entry]) => allowed.has(key) && (entry === void 0 || typeof entry === "string"));
826
813
  }
827
- function isFileExists(error) {
828
- return error instanceof Error && "code" in error && error.code === "EEXIST";
829
- }
830
814
  function isFileNotFound(error) {
831
815
  return error instanceof Error && "code" in error && error.code === "ENOENT";
832
816
  }
@@ -1610,7 +1594,7 @@ const MAX_TITLE_BYTES = 1024;
1610
1594
  const MAX_PATH_BYTES = 2048;
1611
1595
  const MAX_LANG_BYTES = 128;
1612
1596
  const MAX_DIFF_ARTIFACT_TTL_SECONDS = 21600;
1613
- const loadDiffsBrowserRuntime = createLazyRuntimeModule(() => import("./.setup/browser.runtime-BfvyJ76b.mjs"));
1597
+ const loadDiffsBrowserRuntime = createLazyRuntimeModule(() => import("./.setup/browser.runtime-DP8xInXM.mjs"));
1614
1598
  const DiffsToolSchema = Type.Object({
1615
1599
  before: Type.Optional(Type.String({ description: "Original text content." })),
1616
1600
  after: Type.Optional(Type.String({ description: "Updated text content." })),
@@ -1890,9 +1874,9 @@ function registerDiffsPlugin(api) {
1890
1874
  start: () => store.startCleanup(),
1891
1875
  stop: () => store.stopCleanup()
1892
1876
  });
1893
- const resolveCurrentPluginConfig = () => resolveLivePluginConfigObject(api.runtime.config?.current ? () => api.runtime.config.current() : void 0, "diffs", api.pluginConfig) ?? {};
1877
+ const resolveCurrentPluginConfig = () => resolveLivePluginConfigObject(() => api.runtime.config.current(), "diffs", api.pluginConfig) ?? {};
1894
1878
  const resolveCurrentAccessConfig = () => {
1895
- const currentConfig = api.runtime.config?.current?.() ?? api.config;
1879
+ const currentConfig = api.runtime.config.current();
1896
1880
  return {
1897
1881
  allowRemoteViewer: resolveDiffsPluginSecurity(resolveCurrentPluginConfig()).allowRemoteViewer,
1898
1882
  trustedProxies: currentConfig.gateway?.trustedProxies,
@@ -1923,7 +1907,7 @@ function registerDiffsPlugin(api) {
1923
1907
  api.on("before_prompt_build", async () => ({ prependSystemContext: DIFFS_AGENT_GUIDANCE }));
1924
1908
  }
1925
1909
  function resolveDiffsLanguagePackAvailability(api) {
1926
- const plugins = (api.runtime.config?.current?.() ?? api.config).plugins;
1910
+ const plugins = api.runtime.config.current().plugins;
1927
1911
  if (plugins?.enabled === false) return false;
1928
1912
  if (plugins?.deny?.includes(DIFFS_LANGUAGE_PACK_PLUGIN_ID)) return false;
1929
1913
  if (plugins?.allow && !plugins.allow.includes(DIFFS_LANGUAGE_PACK_PLUGIN_ID)) return false;
@@ -12,7 +12,7 @@ export function FromObject(context, type, value) {
12
12
  return value;
13
13
  const additionalProperties = GetAdditionalProperties(type);
14
14
  for (const key of Guard.Keys(value)) {
15
- if (Guard.HasPropertyKey(type.properties, key)) {
15
+ if (Guard.HasPropertyKey(type.properties, key) && IsSchema(type.properties[key])) {
16
16
  value[key] = FromType(context, type.properties[key], value[key]);
17
17
  continue;
18
18
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "typebox",
3
3
  "description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
4
- "version": "1.3.34",
4
+ "version": "1.3.35",
5
5
  "keywords": [
6
6
  "typescript",
7
7
  "jsonschema"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/diffs",
3
- "version": "2026.10.5-beta.4",
3
+ "version": "2026.10.10-beta.2",
4
4
  "description": "OpenClaw read-only diff viewer plugin and file renderer for agents.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -11,7 +11,7 @@
11
11
  "@pierre/diffs": "1.5.1",
12
12
  "@shikijs/langs": "4.5.0",
13
13
  "playwright-core": "1.63.0",
14
- "typebox": "1.3.34",
14
+ "typebox": "1.3.35",
15
15
  "zod": "4.6.5"
16
16
  },
17
17
  "openclaw": {
@@ -25,14 +25,14 @@
25
25
  "minHostVersion": ">=2026.4.30"
26
26
  },
27
27
  "compat": {
28
- "pluginApi": ">=2026.10.5-beta.4"
28
+ "pluginApi": ">=2026.10.10-beta.2"
29
29
  },
30
30
  "assetScripts": {
31
31
  "build": "node --import tsx ../../scripts/build-diffs-viewer-runtime.mts curated"
32
32
  },
33
33
  "build": {
34
34
  "bundledDist": false,
35
- "openclawVersion": "2026.10.5-beta.4",
35
+ "openclawVersion": "2026.10.10-beta.2",
36
36
  "staticAssets": [
37
37
  {
38
38
  "source": "./assets/viewer-runtime.js",
@@ -57,7 +57,7 @@
57
57
  "skills/**"
58
58
  ],
59
59
  "peerDependencies": {
60
- "openclaw": ">=2026.10.5-beta.4"
60
+ "openclaw": ">=2026.10.10-beta.2"
61
61
  },
62
62
  "peerDependenciesMeta": {
63
63
  "openclaw": {
@@ -10,7 +10,7 @@ The `diffs` tool accepts either `before` + `after` text, or a unified `patch` st
10
10
  Check `details.changed`: identical before/after input returns `false` without creating an artifact; rendered results return `true`.
11
11
 
12
12
  Use `mode=view` when you want an interactive gateway-hosted viewer. After the tool returns, present `details.viewerUrl` with an available surface-presentation tool.
13
- If the deployment uses a loopback trusted proxy (for example Tailscale Serve with `gateway.trustedProxies` including `127.0.0.1`), raw loopback viewer requests can fail closed without forwarded client-IP headers. In that topology, prefer `mode=file` / `mode=both`, or use a configured `viewerBaseUrl` / explicit proxy/public `baseUrl` when you need a shareable viewer URL.
13
+ If the deployment uses a loopback trusted proxy (for example Tailscale Serve with `gateway.trustedProxies` including `127.0.0.1`), raw loopback viewer requests can be rejected without forwarded client-IP headers. In that topology, prefer `mode=file` / `mode=both`, or use a configured `viewerBaseUrl` / explicit proxy/public `baseUrl` when you need a shareable viewer URL.
14
14
 
15
15
  Use `mode=file` when you need a rendered file artifact. Set `fileFormat=png` (default) or `fileFormat=pdf`. The tool result includes `details.filePath`.
16
16