@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/README.md +1 -1
- package/dist/.setup/{browser.runtime-BfvyJ76b.mjs → browser.runtime-DP8xInXM.mjs} +12 -45
- package/dist/.setup/{viewer-assets-C646cpoV.mjs → viewer-assets-D_VrsDqE.mjs} +4 -9
- package/dist/assets/viewer-runtime.js +30 -30
- package/dist/index.js +24 -40
- package/node_modules/typebox/build/value/clean/from_object.mjs +1 -1
- package/node_modules/typebox/package.json +1 -1
- package/package.json +5 -5
- package/skills/diffs/SKILL.md +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as getServedViewerAsset, r as VIEWER_RUNTIME_PATH } from "./.setup/viewer-assets-
|
|
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
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
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
|
-
|
|
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
|
-
|
|
741
|
-
|
|
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-
|
|
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(
|
|
1877
|
+
const resolveCurrentPluginConfig = () => resolveLivePluginConfigObject(() => api.runtime.config.current(), "diffs", api.pluginConfig) ?? {};
|
|
1894
1878
|
const resolveCurrentAccessConfig = () => {
|
|
1895
|
-
const currentConfig = api.runtime.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 =
|
|
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
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/diffs",
|
|
3
|
-
"version": "2026.10.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
60
|
+
"openclaw": ">=2026.10.10-beta.2"
|
|
61
61
|
},
|
|
62
62
|
"peerDependenciesMeta": {
|
|
63
63
|
"openclaw": {
|
package/skills/diffs/SKILL.md
CHANGED
|
@@ -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
|
|
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
|
|