























@@ -0,0 +1,126 @@
1+import { shellQuote } from "./host-command.ts";
2+import { providerIdFromModelId } from "./provider-auth.ts";
3+4+interface PluginIsolationOptions {
5+fallbackPluginId: string;
6+homeFallback?: string;
7+modelId: string;
8+nodeCommand?: string;
9+}
10+11+export function providerOnlyPluginId(modelId: string, fallbackPluginId: string): string {
12+return providerIdFromModelId(modelId) || fallbackPluginId;
13+}
14+15+export function posixProviderOnlyPluginIsolationScript(options: PluginIsolationOptions): string {
16+const nodeCommand = shellQuote(options.nodeCommand ?? "node");
17+const homeEnv = options.homeFallback
18+ ? `OPENCLAW_PARALLELS_HOME=${shellQuote(options.homeFallback)} `
19+ : "";
20+return `/usr/bin/env ${homeEnv}${nodeCommand} - <<'JS'
21+${providerOnlyPluginIsolationNodeScript(options)}
22+JS`;
23+}
24+25+export function windowsProviderOnlyPluginIsolationScript(options: PluginIsolationOptions): string {
26+const payloadJson = JSON.stringify({
27+modelId: options.modelId,
28+pluginId: providerOnlyPluginId(options.modelId, options.fallbackPluginId),
29+});
30+return `$env:OPENCLAW_PARALLELS_PLUGIN_ISOLATION = @'
31+${payloadJson}
32+'@
33+$isolationScriptPath = Join-Path ([System.IO.Path]::GetTempPath()) 'openclaw-parallels-plugin-isolation.cjs'
34+@'
35+${providerOnlyPluginIsolationNodeSource()}
36+'@ | Set-Content -Path $isolationScriptPath -Encoding UTF8
37+node.exe $isolationScriptPath
38+if ($LASTEXITCODE -ne 0) { throw "plugin isolation failed with exit code $LASTEXITCODE" }
39+Remove-Item $isolationScriptPath -Force -ErrorAction SilentlyContinue
40+Remove-Item Env:OPENCLAW_PARALLELS_PLUGIN_ISOLATION -Force -ErrorAction SilentlyContinue`;
41+}
42+43+function providerOnlyPluginIsolationNodeScript(options: PluginIsolationOptions): string {
44+const payloadJson = JSON.stringify({
45+homeFallback: options.homeFallback,
46+modelId: options.modelId,
47+pluginId: providerOnlyPluginId(options.modelId, options.fallbackPluginId),
48+});
49+return `process.env.OPENCLAW_PARALLELS_PLUGIN_ISOLATION = ${JSON.stringify(payloadJson)};
50+${providerOnlyPluginIsolationNodeSource()}`;
51+}
52+53+function providerOnlyPluginIsolationNodeSource(): string {
54+return String.raw`const fs = require("node:fs");
55+const path = require("node:path");
56+57+const payload = JSON.parse(process.env.OPENCLAW_PARALLELS_PLUGIN_ISOLATION || "{}");
58+const home =
59+ process.env.OPENCLAW_PARALLELS_HOME ||
60+ payload.homeFallback ||
61+ process.env.HOME ||
62+ process.env.USERPROFILE ||
63+ "/root";
64+const configPath = path.join(home, ".openclaw", "openclaw.json");
65+const stateDir = path.dirname(configPath);
66+const modelId = String(payload.modelId || "");
67+const allowedPluginId = String(payload.pluginId || "").trim();
68+if (!allowedPluginId || !modelId) {
69+ throw new Error("missing plugin isolation payload");
70+}
71+72+const readConfig = () => {
73+ if (!fs.existsSync(configPath)) {
74+ return {};
75+ }
76+ return JSON.parse(fs.readFileSync(configPath, "utf8"));
77+};
78+const objectRecord = (value) =>
79+ value && typeof value === "object" && !Array.isArray(value) ? value : {};
80+81+const config = readConfig();
82+config.plugins = objectRecord(config.plugins);
83+config.plugins.entries = { [allowedPluginId]: { enabled: true } };
84+config.plugins.allow = [allowedPluginId];
85+86+config.agents = objectRecord(config.agents);
87+config.agents.defaults = objectRecord(config.agents.defaults);
88+config.agents.defaults.model = {
89+ ...objectRecord(config.agents.defaults.model),
90+ primary: modelId,
91+};
92+config.agents.defaults.models = objectRecord(config.agents.defaults.models);
93+const selectedModelEntry = config.agents.defaults.models[modelId];
94+if (selectedModelEntry && typeof selectedModelEntry === "object" && !Array.isArray(selectedModelEntry)) {
95+ delete selectedModelEntry.agentRuntime;
96+}
97+98+const providerId = modelId.split("/", 1)[0] || "";
99+const providerModelId = modelId.slice(providerId.length + 1);
100+const providers = objectRecord(objectRecord(config.models).providers);
101+const providerEntry = providers[providerId];
102+if (providerEntry && typeof providerEntry === "object" && !Array.isArray(providerEntry)) {
103+ delete providerEntry.agentRuntime;
104+ if (Array.isArray(providerEntry.models)) {
105+ for (const model of providerEntry.models) {
106+ if (
107+ model &&
108+ typeof model === "object" &&
109+ (model.id === providerModelId ||
110+ model.id === modelId ||
111+ model.name === providerModelId ||
112+ model.name === modelId)
113+ ) {
114+ delete model.agentRuntime;
115+ }
116+ }
117+ }
118+}
119+120+fs.rmSync(path.join(stateDir, "npm", "node_modules", "@openclaw", "codex"), {
121+ recursive: true,
122+ force: true,
123+});
124+fs.mkdirSync(stateDir, { recursive: true });
125+fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");`;
126+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。