@openclaw/diffs 2026.8.2 → 2026.8.34
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.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as getServedViewerAsset, i as getServedLanguagePackViewerAsset, n as VIEWER_ASSET_PREFIX, t as LANGUAGE_PACK_VIEWER_ASSET_PREFIX } from "./viewer-assets-D3qrnaxI.
|
|
1
|
+
import { a as getServedViewerAsset, i as getServedLanguagePackViewerAsset, n as VIEWER_ASSET_PREFIX, t as LANGUAGE_PACK_VIEWER_ASSET_PREFIX } from "./viewer-assets-D3qrnaxI.mjs";
|
|
2
2
|
import { constants } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { definePluginEntry, resolvePreferredOpenClawTmpDir } from "./api.js";
|
|
2
2
|
import { resolveRequestClientIp } from "./runtime-api.js";
|
|
3
|
-
import { a as getServedViewerAsset, r as VIEWER_RUNTIME_PATH } from "
|
|
3
|
+
import { a as getServedViewerAsset, r as VIEWER_RUNTIME_PATH } from "./.setup/viewer-assets-D3qrnaxI.mjs";
|
|
4
4
|
import { buildPluginConfigSchema } from "openclaw/plugin-sdk/plugin-entry";
|
|
5
5
|
import { mapPluginConfigIssues } from "openclaw/plugin-sdk/extension-shared";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import { resolveGatewayPublicOrigin } from "openclaw/plugin-sdk/config-contracts";
|
|
8
|
-
import { resolveGatewayPort } from "openclaw/plugin-sdk/gateway-config-runtime";
|
|
9
8
|
import fs from "node:fs";
|
|
10
9
|
import path from "node:path";
|
|
11
10
|
import { resolveLivePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime";
|
|
@@ -25,6 +24,32 @@ import { Type } from "typebox";
|
|
|
25
24
|
import { parsePatchFiles, resolveLanguage } from "@pierre/diffs";
|
|
26
25
|
import { preloadDiffHTML } from "@pierre/diffs/ssr";
|
|
27
26
|
import { escapeHtml } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
27
|
+
//#region \0rolldown/runtime.js
|
|
28
|
+
var __defProp = Object.defineProperty;
|
|
29
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
30
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
31
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
32
|
+
var __exportAll = (all, no_symbols) => {
|
|
33
|
+
let target = {};
|
|
34
|
+
for (var name in all) __defProp(target, name, {
|
|
35
|
+
get: all[name],
|
|
36
|
+
enumerable: true
|
|
37
|
+
});
|
|
38
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
39
|
+
return target;
|
|
40
|
+
};
|
|
41
|
+
var __copyProps = (to, from, except, desc) => {
|
|
42
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
43
|
+
key = keys[i];
|
|
44
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
45
|
+
get: ((k) => from[k]).bind(null, key),
|
|
46
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return to;
|
|
50
|
+
};
|
|
51
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
52
|
+
//#endregion
|
|
28
53
|
//#region extensions/diffs/src/types.ts
|
|
29
54
|
const DIFF_LAYOUTS = ["unified", "split"];
|
|
30
55
|
const DIFF_MODES = [
|
|
@@ -48,6 +73,152 @@ const DIFF_OUTPUT_FORMATS = ["png", "pdf"];
|
|
|
48
73
|
const DIFF_ARTIFACT_ID_PATTERN = /^[0-9a-f]{20}$/;
|
|
49
74
|
const DIFF_ARTIFACT_TOKEN_PATTERN = /^[0-9a-f]{48}$/;
|
|
50
75
|
//#endregion
|
|
76
|
+
//#region src/gateway/gateway-http-route-contracts.ts
|
|
77
|
+
const GATEWAY_PROBE_ROUTES = /* @__PURE__ */ new Map([
|
|
78
|
+
["/health", "live"],
|
|
79
|
+
["/healthz", "live"],
|
|
80
|
+
["/ready", "ready"],
|
|
81
|
+
["/readyz", "ready"],
|
|
82
|
+
["/startup", "startup"],
|
|
83
|
+
["/startupz", "startup"]
|
|
84
|
+
]);
|
|
85
|
+
function classifyGatewayProbePath(pathname) {
|
|
86
|
+
for (const [root, status] of GATEWAY_PROBE_ROUTES) {
|
|
87
|
+
if (pathname === root) return status;
|
|
88
|
+
if (pathname.startsWith(`${root}/`)) return "namespace";
|
|
89
|
+
}
|
|
90
|
+
return "outside";
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region packages/normalization-core/src/string-coerce.ts
|
|
94
|
+
/** Trims string input and returns null for non-strings or empty strings. */
|
|
95
|
+
function normalizeNullableString(value) {
|
|
96
|
+
if (typeof value !== "string") return null;
|
|
97
|
+
const trimmed = value.trim();
|
|
98
|
+
return trimmed ? trimmed : null;
|
|
99
|
+
}
|
|
100
|
+
/** Trims string input and returns undefined for non-strings or empty strings. */
|
|
101
|
+
function normalizeOptionalString$1(value) {
|
|
102
|
+
return normalizeNullableString(value) ?? void 0;
|
|
103
|
+
}
|
|
104
|
+
/** Lowercases a normalized optional string. */
|
|
105
|
+
function normalizeOptionalLowercaseString(value) {
|
|
106
|
+
return normalizeOptionalString$1(value)?.toLowerCase();
|
|
107
|
+
}
|
|
108
|
+
/** Lowercases a normalized string or returns an empty string when absent. */
|
|
109
|
+
function normalizeLowercaseStringOrEmpty$1(value) {
|
|
110
|
+
return normalizeOptionalLowercaseString(value) ?? "";
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
113
|
+
//#region src/gateway/security-path.ts
|
|
114
|
+
const MAX_PATH_DECODE_PASSES = 32;
|
|
115
|
+
function normalizePathSeparators(pathname) {
|
|
116
|
+
const collapsed = pathname.replace(/\/{2,}/g, "/");
|
|
117
|
+
if (collapsed.length <= 1) return collapsed;
|
|
118
|
+
return collapsed.replace(/\/+$/, "");
|
|
119
|
+
}
|
|
120
|
+
function resolveDotSegments(pathname) {
|
|
121
|
+
try {
|
|
122
|
+
return new URL(pathname, "http://localhost").pathname;
|
|
123
|
+
} catch {
|
|
124
|
+
return pathname;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function normalizePathForSecurity(pathname) {
|
|
128
|
+
return normalizePathSeparators(normalizeLowercaseStringOrEmpty$1(resolveDotSegments(pathname))) || "/";
|
|
129
|
+
}
|
|
130
|
+
function pushNormalizedCandidate(candidates, seen, value) {
|
|
131
|
+
const normalized = normalizePathForSecurity(value);
|
|
132
|
+
if (seen.has(normalized)) return;
|
|
133
|
+
seen.add(normalized);
|
|
134
|
+
candidates.push(normalized);
|
|
135
|
+
}
|
|
136
|
+
function buildCanonicalPathCandidates(pathname, maxDecodePasses = MAX_PATH_DECODE_PASSES) {
|
|
137
|
+
const candidates = [];
|
|
138
|
+
const seen = /* @__PURE__ */ new Set();
|
|
139
|
+
pushNormalizedCandidate(candidates, seen, pathname);
|
|
140
|
+
let decoded = pathname;
|
|
141
|
+
let malformedEncoding = false;
|
|
142
|
+
let decodePasses = 0;
|
|
143
|
+
for (let pass = 0; pass < maxDecodePasses; pass++) {
|
|
144
|
+
let nextDecoded;
|
|
145
|
+
try {
|
|
146
|
+
nextDecoded = decodeURIComponent(decoded);
|
|
147
|
+
} catch {
|
|
148
|
+
malformedEncoding = true;
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
if (nextDecoded === decoded) break;
|
|
152
|
+
decodePasses += 1;
|
|
153
|
+
decoded = nextDecoded;
|
|
154
|
+
pushNormalizedCandidate(candidates, seen, decoded);
|
|
155
|
+
}
|
|
156
|
+
let decodePassLimitReached = false;
|
|
157
|
+
if (!malformedEncoding) try {
|
|
158
|
+
decodePassLimitReached = decodeURIComponent(decoded) !== decoded;
|
|
159
|
+
} catch {
|
|
160
|
+
malformedEncoding = true;
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
candidates,
|
|
164
|
+
decodePasses,
|
|
165
|
+
decodePassLimitReached,
|
|
166
|
+
malformedEncoding
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function canonicalizePathForSecurity(pathname) {
|
|
170
|
+
const { candidates, decodePasses, decodePassLimitReached, malformedEncoding } = buildCanonicalPathCandidates(pathname);
|
|
171
|
+
return {
|
|
172
|
+
canonicalPath: candidates[candidates.length - 1] ?? "/",
|
|
173
|
+
candidates,
|
|
174
|
+
decodePasses,
|
|
175
|
+
decodePassLimitReached,
|
|
176
|
+
malformedEncoding,
|
|
177
|
+
rawNormalizedPath: normalizePathSeparators(normalizeLowercaseStringOrEmpty$1(pathname)) || "/"
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
const PROTECTED_PLUGIN_ROUTE_PREFIXES = ["/api/channels"];
|
|
181
|
+
//#endregion
|
|
182
|
+
//#region src/gateway/server/plugins-http/path-context.ts
|
|
183
|
+
function normalizeProtectedPrefix(prefix) {
|
|
184
|
+
const collapsed = normalizeLowercaseStringOrEmpty$1(prefix).replace(/\/{2,}/g, "/");
|
|
185
|
+
if (collapsed.length <= 1) return collapsed || "/";
|
|
186
|
+
return collapsed.replace(/\/+$/, "");
|
|
187
|
+
}
|
|
188
|
+
/** Matches a normalized path against an exact protected prefix boundary. */
|
|
189
|
+
function prefixMatchPath(pathname, prefix) {
|
|
190
|
+
return pathname === prefix || pathname.startsWith(`${prefix}/`) || pathname.startsWith(`${prefix}%`);
|
|
191
|
+
}
|
|
192
|
+
const NORMALIZED_PROTECTED_PLUGIN_ROUTE_PREFIXES = PROTECTED_PLUGIN_ROUTE_PREFIXES.map(normalizeProtectedPrefix);
|
|
193
|
+
/** Returns true when any decoded path candidate targets a protected route. */
|
|
194
|
+
function isProtectedPluginRoutePathFromContext(context) {
|
|
195
|
+
if (context.candidates.some((candidate) => NORMALIZED_PROTECTED_PLUGIN_ROUTE_PREFIXES.some((prefix) => prefixMatchPath(candidate, prefix)))) return true;
|
|
196
|
+
if (context.decodePassLimitReached) return true;
|
|
197
|
+
if (!context.malformedEncoding) return false;
|
|
198
|
+
return NORMALIZED_PROTECTED_PLUGIN_ROUTE_PREFIXES.some((prefix) => prefixMatchPath(context.rawNormalizedPath, prefix));
|
|
199
|
+
}
|
|
200
|
+
/** Builds all security-relevant decoded path candidates for a request path. */
|
|
201
|
+
function resolvePluginRoutePathContext(pathname) {
|
|
202
|
+
const canonical = canonicalizePathForSecurity(pathname);
|
|
203
|
+
return {
|
|
204
|
+
pathname,
|
|
205
|
+
canonicalPath: canonical.canonicalPath,
|
|
206
|
+
candidates: canonical.candidates,
|
|
207
|
+
malformedEncoding: canonical.malformedEncoding,
|
|
208
|
+
decodePassLimitReached: canonical.decodePassLimitReached,
|
|
209
|
+
rawNormalizedPath: canonical.rawNormalizedPath
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
//#endregion
|
|
213
|
+
//#region \0openclaw:bundled-sdk:openclaw/plugin-sdk/gateway-config-runtime
|
|
214
|
+
var gateway_config_runtime_exports = /* @__PURE__ */ __exportAll({
|
|
215
|
+
classifyGatewayProbePath: () => classifyGatewayProbePath,
|
|
216
|
+
isProtectedPluginRoutePathFromContext: () => isProtectedPluginRoutePathFromContext,
|
|
217
|
+
resolvePluginRoutePathContext: () => resolvePluginRoutePathContext
|
|
218
|
+
});
|
|
219
|
+
import * as import_openclaw_plugin_sdk_gateway_config_runtime from "openclaw/plugin-sdk/gateway-config-runtime";
|
|
220
|
+
__reExport(gateway_config_runtime_exports, import_openclaw_plugin_sdk_gateway_config_runtime);
|
|
221
|
+
//#endregion
|
|
51
222
|
//#region extensions/diffs/src/url.ts
|
|
52
223
|
function buildViewerUrl(params) {
|
|
53
224
|
const normalizedBase = normalizeViewerBaseUrl(params.baseUrl?.trim() || params.viewerBaseUrl?.trim() || resolveGatewayPublicOrigin(params.config) || resolveGatewayBaseUrl(params.config));
|
|
@@ -74,7 +245,7 @@ function normalizeViewerBaseUrl(raw, fieldName = "baseUrl") {
|
|
|
74
245
|
}
|
|
75
246
|
function resolveGatewayBaseUrl(config) {
|
|
76
247
|
const scheme = config.gateway?.tls?.enabled ? "https" : "http";
|
|
77
|
-
const port = resolveGatewayPort(config);
|
|
248
|
+
const port = (0, gateway_config_runtime_exports.resolveGatewayPort)(config);
|
|
78
249
|
const customHost = config.gateway?.customBindHost?.trim();
|
|
79
250
|
if (config.gateway?.bind === "custom" && customHost) return `${scheme}://${customHost}:${port}`;
|
|
80
251
|
return `${scheme}://127.0.0.1:${port}`;
|
|
@@ -1602,7 +1773,7 @@ const MAX_TITLE_BYTES = 1024;
|
|
|
1602
1773
|
const MAX_PATH_BYTES = 2048;
|
|
1603
1774
|
const MAX_LANG_BYTES = 128;
|
|
1604
1775
|
const MAX_DIFF_ARTIFACT_TTL_SECONDS = 21600;
|
|
1605
|
-
const loadDiffsBrowserRuntime = createLazyRuntimeModule(() => import("
|
|
1776
|
+
const loadDiffsBrowserRuntime = createLazyRuntimeModule(() => import("./.setup/browser.runtime-VjaO3wrj.mjs"));
|
|
1606
1777
|
const DiffsToolSchema = Type.Object({
|
|
1607
1778
|
before: Type.Optional(Type.String({ description: "Original text content." })),
|
|
1608
1779
|
after: Type.Optional(Type.String({ description: "Updated text content." })),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/diffs",
|
|
3
|
-
"version": "2026.8.
|
|
3
|
+
"version": "2026.8.34",
|
|
4
4
|
"description": "OpenClaw read-only diff viewer plugin and file renderer for agents.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -25,14 +25,14 @@
|
|
|
25
25
|
"minHostVersion": ">=2026.4.30"
|
|
26
26
|
},
|
|
27
27
|
"compat": {
|
|
28
|
-
"pluginApi": ">=2026.8.
|
|
28
|
+
"pluginApi": ">=2026.8.34"
|
|
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.8.
|
|
35
|
+
"openclawVersion": "2026.8.34",
|
|
36
36
|
"staticAssets": [
|
|
37
37
|
{
|
|
38
38
|
"source": "./assets/viewer-runtime.js",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"skills/**"
|
|
56
56
|
],
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"openclaw": ">=2026.8.
|
|
58
|
+
"openclaw": ">=2026.8.34"
|
|
59
59
|
},
|
|
60
60
|
"peerDependenciesMeta": {
|
|
61
61
|
"openclaw": {
|
|
File without changes
|