Skip to content

Commit 6a4069d

Browse files
authored
fix: share plugin runtime helpers
Consolidate shared plugin runtime MIME/schema helpers, preserve canonical runtime behavior, and guard QQBot STT fetches.
1 parent f3c9203 commit 6a4069d

127 files changed

Lines changed: 789 additions & 829 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ Docs: https://docs.openclaw.ai
169169
- Skills: cap skills watcher directory traversal at the same depth used by skill discovery so large non-skill trees under configured skill roots do not exhaust file descriptors on startup. Fixes #75501. Thanks @wzq-xzwj.
170170
- Docs/Docker: document a local Compose override for Docker Desktop DNS failures in the shared-network `openclaw-cli` sidecar, keeping the default compose setup hardened while unblocking `openclaw plugins install` when users opt in. Fixes #79018. Thanks @Jason-Vaughan.
171171
- Installer: when npm installs `openclaw` outside the parent shell PATH, print follow-up commands with the resolved binary path instead of telling users to run `openclaw` from a shell that will report `command not found`. Fixes #72382. Thanks @jbob762.
172+
- Plugins/runtime: share MIME and JSON Schema helpers across bundled plugins while preserving canonical media MIME inference, browser URL wildcard semantics, migration home-path resolution, QA request-limit responses, and extensionless text file previews.
172173
- Compute plugin callback authorization dynamically [AI]. (#78866) Thanks @pgondhi987.
173174
- fix(active-memory): require admin scope for global toggles [AI]. (#78863) Thanks @pgondhi987.
174175
- Honor owner enforcement for native commands [AI]. (#78864) Thanks @pgondhi987.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
28e280d21693216c99cfa8da553589b41741d37c0ada956e316ee01d3d6c202c plugin-sdk-api-baseline.json
2-
633dae33da97f6a073c5561709c57d5c0b7ff67af0512d0261f05455c24b38de plugin-sdk-api-baseline.jsonl
1+
973ce3342740726100f6f09d18c6802474f5f7eab255253cf6ea3e8d66c9a383 plugin-sdk-api-baseline.json
2+
f4cbbaaa129733216e1a566865d86b0832f5f35bc3db6c9ead1e2f937564dc68 plugin-sdk-api-baseline.jsonl

docs/plugins/sdk-subpaths.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ For the plugin authoring guide, see [Plugin SDK overview](/plugins/sdk-overview)
4646
| --- | --- |
4747
| `plugin-sdk/channel-core` | `defineChannelPluginEntry`, `defineSetupPluginEntry`, `createChatChannelPlugin`, `createChannelPluginBase` |
4848
| `plugin-sdk/config-schema` | Root `openclaw.json` Zod schema export (`OpenClawSchema`) |
49+
| `plugin-sdk/json-schema-runtime` | Cached JSON Schema validation helper for plugin-owned schemas |
4950
| `plugin-sdk/channel-setup` | `createOptionalChannelSetupSurface`, `createOptionalChannelSetupAdapter`, `createOptionalChannelSetupWizard`, plus `DEFAULT_ACCOUNT_ID`, `createTopLevelChannelDmPolicy`, `setSetupChannelEnabled`, `splitSetupEntries` |
5051
| `plugin-sdk/setup` | Shared setup wizard helpers, allowlist prompts, setup status builders |
5152
| `plugin-sdk/setup-runtime` | `createPatchedAccountSetupAdapter`, `createEnvPatchedAccountSetupAdapter`, `createSetupInputPresenceValidator`, `noteChannelLookupFailure`, `noteChannelLookupSummary`, `promptResolvedAllowFrom`, `splitSetupEntries`, `createAllowlistSetupWizardProxy`, `createDelegatedSetupWizardProxy` |
@@ -264,6 +265,7 @@ For the plugin authoring guide, see [Plugin SDK overview](/plugins/sdk-overview)
264265
| Subpath | Key exports |
265266
| --- | --- |
266267
| `plugin-sdk/media-runtime` | Shared media fetch/transform/store helpers, ffprobe-backed video dimension probing, and media payload builders |
268+
| `plugin-sdk/media-mime` | Narrow MIME normalization, file-extension mapping, MIME detection, and media-kind helpers |
267269
| `plugin-sdk/media-store` | Narrow media store helpers such as `saveMediaBuffer` |
268270
| `plugin-sdk/media-generation-runtime` | Shared media-generation failover helpers, candidate selection, and missing-model messaging |
269271
| `plugin-sdk/media-understanding` | Media understanding provider types plus provider-facing image/audio helper exports |

extensions/browser/src/browser/request-policy.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,32 @@ describe("browser url pattern matching", () => {
3838
});
3939

4040
it("matches glob patterns", () => {
41+
expect(matchBrowserUrlPattern("*", "https://example.com/app/dash")).toBe(true);
4142
expect(matchBrowserUrlPattern("**/dash", "https://example.com/app/dash")).toBe(true);
4243
expect(matchBrowserUrlPattern("https://example.com/*", "https://example.com/a")).toBe(true);
4344
expect(matchBrowserUrlPattern("https://example.com/*", "https://other.com/a")).toBe(false);
45+
expect(matchBrowserUrlPattern("https://example.com/*", "https://example.com/app/dash")).toBe(
46+
false,
47+
);
48+
expect(matchBrowserUrlPattern("https://example.com/**", "https://example.com/app/dash")).toBe(
49+
true,
50+
);
51+
});
52+
53+
it("treats URL punctuation as literal in wildcard patterns", () => {
54+
expect(
55+
matchBrowserUrlPattern(
56+
"https://example.com/download?file=*",
57+
"https://example.com/download?file=report.pdf",
58+
),
59+
).toBe(true);
60+
expect(
61+
matchBrowserUrlPattern(
62+
"https://example.com/download?file=*",
63+
"https://example.com/downloadXfile=report.pdf",
64+
),
65+
).toBe(false);
66+
expect(matchBrowserUrlPattern("http://[::1]:*/**", "http://[::1]:9222/json/list")).toBe(true);
4467
});
4568

4669
it("rejects empty patterns", () => {
Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
function wildcardPatternToRegExp(pattern: string): RegExp {
2+
let source = "^";
3+
for (let index = 0; index < pattern.length; index += 1) {
4+
const char = pattern[index] ?? "";
5+
if (char === "*") {
6+
if (pattern[index + 1] === "*") {
7+
source += ".*";
8+
index += 1;
9+
} else {
10+
source += "[^/]*";
11+
}
12+
continue;
13+
}
14+
source += char.replace(/[\\^$+?.()|[\]{}]/gu, "\\$&");
15+
}
16+
source += "$";
17+
return new RegExp(source, "u");
18+
}
19+
120
export function matchBrowserUrlPattern(pattern: string, url: string): boolean {
221
const trimmedPattern = pattern.trim();
322
if (!trimmedPattern) {
@@ -6,10 +25,11 @@ export function matchBrowserUrlPattern(pattern: string, url: string): boolean {
625
if (trimmedPattern === url) {
726
return true;
827
}
28+
if (trimmedPattern === "*") {
29+
return true;
30+
}
931
if (trimmedPattern.includes("*")) {
10-
const escaped = trimmedPattern.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
11-
const regex = new RegExp(`^${escaped.replace(/\*\*/g, ".*").replace(/\*/g, ".*")}$`);
12-
return regex.test(url);
32+
return wildcardPatternToRegExp(trimmedPattern).test(url);
1333
}
1434
return url.includes(trimmedPattern);
1535
}

extensions/byteplus/video-generation-provider.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ function mockSuccessfulBytePlusTask(params?: { model?: string }) {
3636
}),
3737
})
3838
.mockResolvedValueOnce({
39-
headers: new Headers({ "content-type": "video/mp4" }),
40-
arrayBuffer: async () => Buffer.from("mp4-bytes"),
39+
headers: new Headers({ "content-type": "video/webm" }),
40+
arrayBuffer: async () => Buffer.from("webm-bytes"),
4141
});
4242
}
4343

@@ -63,6 +63,7 @@ describe("byteplus video generation provider", () => {
6363
}),
6464
);
6565
expect(result.videos).toHaveLength(1);
66+
expect(result.videos[0]?.fileName).toBe("video-1.webm");
6667
expect(result.metadata).toEqual(
6768
expect.objectContaining({
6869
taskId: "task_123",

extensions/byteplus/video-generation-provider.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { extensionForMime } from "openclaw/plugin-sdk/media-mime";
12
import { isProviderApiKeyConfigured } from "openclaw/plugin-sdk/provider-auth";
23
import { resolveApiKeyForProvider } from "openclaw/plugin-sdk/provider-auth-runtime";
34
import {
@@ -127,7 +128,7 @@ async function downloadBytePlusVideo(params: {
127128
return {
128129
buffer: Buffer.from(arrayBuffer),
129130
mimeType,
130-
fileName: `video-1.${mimeType.includes("webm") ? "webm" : "mp4"}`,
131+
fileName: `video-1.${extensionForMime(mimeType)?.slice(1) ?? "mp4"}`,
131132
};
132133
}
133134

extensions/canvas/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"@lit/context": "^1.1.6",
1313
"chokidar": "^5.0.0",
1414
"lit": "^3.3.2",
15-
"typebox": "^1.0.58",
15+
"typebox": "1.1.37",
1616
"ws": "^8.20.0"
1717
},
1818
"openclaw": {

extensions/codex/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@
1111
"@mariozechner/pi-coding-agent": "0.73.0",
1212
"@openai/codex": "0.128.0",
1313
"ajv": "^8.20.0",
14-
"ws": "^8.20.0",
15-
"zod": "^4.4.3"
14+
"ws": "^8.20.0"
1615
},
1716
"devDependencies": {
1817
"@openclaw/plugin-sdk": "workspace:*"

extensions/codex/src/app-server/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createHmac, randomBytes } from "node:crypto";
2-
import { z } from "zod";
2+
import { z } from "openclaw/plugin-sdk/zod";
33
import type { CodexSandboxPolicy, CodexServiceTier } from "./protocol.js";
44

55
const START_OPTIONS_KEY_SECRET = randomBytes(32);

0 commit comments

Comments
 (0)