mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-26 09:12:13 +08:00
Compare commits
6 Commits
v2026.6.9
...
codex/doct
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebd3b19dc2 | ||
|
|
ce120c45c4 | ||
|
|
54d2021ec9 | ||
|
|
a7e2b5a7df | ||
|
|
50247c6dba | ||
|
|
3394bc03ee |
@@ -59,6 +59,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Plugins/QR: replace legacy `qrcode-terminal` QR rendering with bounded `qrcode-tui` helpers for plugin login/setup flows. (#65969) Thanks @vincentkoc.
|
||||
- Voice-call/realtime: wait for OpenAI session configuration before greeting or forwarding buffered audio, and reject non-allowlisted Twilio callers before stream setup. (#43501) Thanks @forrestblount.
|
||||
- ACPX/Codex: stop materializing `auth.json` bridge files for Codex ACP, Codex app-server, and Codex CLI runs; Codex-owned runtimes now use their normal `CODEX_HOME`/`~/.codex` auth path directly.
|
||||
|
||||
- Auto-reply/system events: route async exec-event completion replies through the persisted session delivery context, so long-running command results return to the originating channel instead of being dropped when live origin metadata is missing. (#70258) Thanks @wzfukui.
|
||||
- OpenAI/image generation: send reference-image edits as guarded multipart uploads instead of JSON data URLs, restoring complex multi-reference `gpt-image-2` edits. Fixes #70642. Thanks @dashhuang.
|
||||
- QA channel/security: reject non-HTTP(S) inbound attachment URLs before media fetch, and log rejected schemes so suspicious or misconfigured payloads are visible during debugging. (#70708) Thanks @vincentkoc.
|
||||
@@ -92,6 +93,8 @@ Docs: https://docs.openclaw.ai
|
||||
- Gateway/security: fail closed on agent-driven `gateway config.apply`/`config.patch` runtime edits by allowlisting a narrow set of agent-tunable prompt, model, and mention-gating paths (including Telegram topic-level `requireMention`) instead of relying on a hand-maintained denylist of protected subtrees that could miss new sensitive config keys. (#70726) Thanks @drobison00.
|
||||
- Webhooks/security: re-resolve `SecretRef`-backed webhook route secrets on each request so `openclaw secrets reload` revokes the previous secret immediately instead of waiting for a gateway restart. (#70727) Thanks @drobison00.
|
||||
- Memory/dreaming: decouple the managed dreaming cron from heartbeat by running it as an isolated lightweight agent turn, so dreaming runs even when heartbeat is disabled for the default agent and is no longer skipped by `heartbeat.activeHours`. `openclaw doctor --fix` migrates stale main-session dreaming jobs in persisted cron configs to the new shape. Fixes #69811, #67397, #68972. (#70737) Thanks @jalehman.
|
||||
- Doctor/Codex: enable the bundled Codex plugin from `openclaw doctor --fix` when the OpenAI plugin is explicitly enabled but Codex is still off, restoring `codex/*` model availability after plugin config drift. (#70767) Thanks @ngutman.
|
||||
|
||||
|
||||
## 2026.4.22
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
applyDoctorConfigMutation,
|
||||
type DoctorConfigMutationState,
|
||||
} from "./shared/config-mutation-state.js";
|
||||
import { maybeRepairConfiguredPluginAutoEnableBlockers } from "./shared/configured-plugin-auto-enable-blockers.js";
|
||||
import { scanEmptyAllowlistPolicyWarnings } from "./shared/empty-allowlist-scan.js";
|
||||
import { maybeRepairExecSafeBinProfiles } from "./shared/exec-safe-bins.js";
|
||||
import { maybeRepairLegacyToolsBySenderKeys } from "./shared/legacy-tools-by-sender.js";
|
||||
@@ -58,6 +59,12 @@ export async function runDoctorRepairSequence(params: {
|
||||
applyMutation(maybeRepairOpenPolicyAllowFrom(state.candidate));
|
||||
applyMutation(maybeRepairBundledPluginLoadPaths(state.candidate, env));
|
||||
applyMutation(maybeRepairStalePluginConfig(state.candidate, env));
|
||||
applyMutation(
|
||||
maybeRepairConfiguredPluginAutoEnableBlockers({
|
||||
cfg: state.candidate,
|
||||
env,
|
||||
}),
|
||||
);
|
||||
applyMutation(await maybeRepairAllowlistPolicyAllowFrom(state.candidate));
|
||||
|
||||
const emptyAllowlistWarnings = scanEmptyAllowlistPolicyWarnings(state.candidate, {
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
import { afterAll, describe, expect, it } from "vitest";
|
||||
import {
|
||||
makeIsolatedEnv,
|
||||
makeRegistry,
|
||||
resetPluginAutoEnableTestState,
|
||||
} from "../../../config/plugin-auto-enable.test-helpers.js";
|
||||
import type { OpenClawConfig } from "../../../config/types.openclaw.js";
|
||||
import {
|
||||
collectConfiguredPluginAutoEnableBlockerWarnings,
|
||||
maybeRepairConfiguredPluginAutoEnableBlockers,
|
||||
scanConfiguredPluginAutoEnableBlockers,
|
||||
} from "./configured-plugin-auto-enable-blockers.js";
|
||||
|
||||
const env = makeIsolatedEnv();
|
||||
function makeCodexRegistry(origin: "bundled" | "config" | "workspace" = "bundled") {
|
||||
const registry = makeRegistry([
|
||||
{
|
||||
id: "codex",
|
||||
channels: [],
|
||||
providers: ["codex"],
|
||||
activation: {
|
||||
onAgentHarnesses: ["codex"],
|
||||
},
|
||||
},
|
||||
]);
|
||||
registry.plugins[0].origin = origin;
|
||||
return registry;
|
||||
}
|
||||
|
||||
const registry = makeCodexRegistry();
|
||||
|
||||
afterAll(() => {
|
||||
resetPluginAutoEnableTestState();
|
||||
});
|
||||
|
||||
describe("configured plugin auto-enable blockers", () => {
|
||||
it("enables Codex when OpenAI is explicitly enabled and Codex is off", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
plugins: {
|
||||
entries: {
|
||||
openai: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const repaired = maybeRepairConfiguredPluginAutoEnableBlockers({
|
||||
cfg,
|
||||
env,
|
||||
manifestRegistry: registry,
|
||||
});
|
||||
|
||||
expect(repaired.config.plugins?.entries?.codex).toEqual({ enabled: true });
|
||||
expect(repaired.changes).toEqual([
|
||||
"plugins.entries.codex.enabled: enabled plugin because OpenAI plugin enabled.",
|
||||
]);
|
||||
expect(repaired.warnings).toEqual([]);
|
||||
});
|
||||
|
||||
it("adds Codex to a restrictive allowlist when OpenAI is explicitly allowlisted", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
plugins: {
|
||||
allow: ["openai"],
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const repaired = maybeRepairConfiguredPluginAutoEnableBlockers({
|
||||
cfg,
|
||||
env,
|
||||
manifestRegistry: registry,
|
||||
});
|
||||
|
||||
expect(repaired.config.plugins?.entries?.codex).toEqual({ enabled: true });
|
||||
expect(repaired.config.plugins?.allow).toEqual(["openai", "codex"]);
|
||||
expect(repaired.changes).toEqual([
|
||||
"plugins.entries.codex.enabled: enabled plugin because OpenAI plugin enabled.",
|
||||
'plugins.allow: added "codex" because OpenAI plugin enabled.',
|
||||
]);
|
||||
expect(repaired.warnings).toEqual([]);
|
||||
});
|
||||
|
||||
it("preserves existing Codex plugin config while enabling it", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
plugins: {
|
||||
entries: {
|
||||
openai: {
|
||||
enabled: true,
|
||||
},
|
||||
codex: {
|
||||
enabled: false,
|
||||
config: {
|
||||
appServer: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const repaired = maybeRepairConfiguredPluginAutoEnableBlockers({
|
||||
cfg,
|
||||
env,
|
||||
manifestRegistry: registry,
|
||||
});
|
||||
|
||||
expect(repaired.config.plugins?.entries?.codex).toEqual({
|
||||
enabled: true,
|
||||
config: {
|
||||
appServer: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("does not carry blocked keys while preserving existing Codex plugin config", () => {
|
||||
const blockedKey = ["__", "proto__"].join("");
|
||||
const codexEntry = Object.create(null) as Record<string, unknown>;
|
||||
codexEntry.enabled = false;
|
||||
codexEntry.config = {
|
||||
appServer: {
|
||||
enabled: true,
|
||||
},
|
||||
};
|
||||
codexEntry[blockedKey] = { polluted: true };
|
||||
const entries = Object.create(null) as Record<string, unknown>;
|
||||
entries.openai = { enabled: true };
|
||||
entries.codex = codexEntry;
|
||||
entries[blockedKey] = { enabled: true };
|
||||
const cfg: OpenClawConfig = {
|
||||
plugins: {
|
||||
entries,
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const repaired = maybeRepairConfiguredPluginAutoEnableBlockers({
|
||||
cfg,
|
||||
env,
|
||||
manifestRegistry: registry,
|
||||
});
|
||||
|
||||
expect(Object.prototype.hasOwnProperty.call(repaired.config.plugins?.entries, blockedKey)).toBe(
|
||||
false,
|
||||
);
|
||||
expect(
|
||||
Object.prototype.hasOwnProperty.call(repaired.config.plugins?.entries?.codex, blockedKey),
|
||||
).toBe(false);
|
||||
expect(repaired.config.plugins?.entries?.codex).toEqual({
|
||||
enabled: true,
|
||||
config: {
|
||||
appServer: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(Object.prototype).not.toHaveProperty("polluted");
|
||||
});
|
||||
|
||||
it("does not enable Codex when the plugin is unavailable", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
plugins: {
|
||||
entries: {
|
||||
openai: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const repaired = maybeRepairConfiguredPluginAutoEnableBlockers({
|
||||
cfg,
|
||||
env,
|
||||
manifestRegistry: makeRegistry([]),
|
||||
});
|
||||
|
||||
expect(repaired.config).toBe(cfg);
|
||||
expect(repaired.changes).toEqual([]);
|
||||
expect(repaired.warnings).toEqual([]);
|
||||
});
|
||||
|
||||
it("does not enable Codex just because OpenAI is enabled by default", () => {
|
||||
const repaired = maybeRepairConfiguredPluginAutoEnableBlockers({
|
||||
cfg: {},
|
||||
env,
|
||||
manifestRegistry: registry,
|
||||
});
|
||||
|
||||
expect(repaired.config).toEqual({});
|
||||
expect(repaired.changes).toEqual([]);
|
||||
expect(repaired.warnings).toEqual([]);
|
||||
});
|
||||
|
||||
it("does not inspect plugin manifests when OpenAI is not explicitly enabled", () => {
|
||||
const manifestRegistry = {
|
||||
get plugins(): never {
|
||||
throw new Error("manifest registry should not be inspected");
|
||||
},
|
||||
diagnostics: [],
|
||||
};
|
||||
|
||||
expect(
|
||||
scanConfiguredPluginAutoEnableBlockers({
|
||||
cfg: {},
|
||||
env,
|
||||
manifestRegistry,
|
||||
}),
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it("does not auto-enable non-bundled Codex manifests", () => {
|
||||
for (const origin of ["config", "workspace"] as const) {
|
||||
const cfg: OpenClawConfig = {
|
||||
plugins: {
|
||||
entries: {
|
||||
openai: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const repaired = maybeRepairConfiguredPluginAutoEnableBlockers({
|
||||
cfg,
|
||||
env,
|
||||
manifestRegistry: makeCodexRegistry(origin),
|
||||
});
|
||||
|
||||
expect(repaired.config).toBe(cfg);
|
||||
expect(repaired.changes).toEqual([]);
|
||||
expect(repaired.warnings).toEqual([]);
|
||||
}
|
||||
});
|
||||
|
||||
it("warns instead of removing a Codex denylist blocker", () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
plugins: {
|
||||
deny: ["codex"],
|
||||
entries: {
|
||||
openai: {
|
||||
enabled: true,
|
||||
},
|
||||
codex: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const repaired = maybeRepairConfiguredPluginAutoEnableBlockers({
|
||||
cfg,
|
||||
env,
|
||||
manifestRegistry: registry,
|
||||
});
|
||||
|
||||
expect(repaired.config).toBe(cfg);
|
||||
expect(repaired.changes).toEqual([]);
|
||||
expect(repaired.warnings).toEqual([
|
||||
'- plugins.deny: plugin "codex" is denied, but OpenAI plugin enabled. Remove it from plugins.deny before relying on that configuration.',
|
||||
]);
|
||||
});
|
||||
|
||||
it("reports preview warnings for OpenAI-enabled configs before repair", () => {
|
||||
const hits = scanConfiguredPluginAutoEnableBlockers({
|
||||
cfg: {
|
||||
plugins: {
|
||||
entries: {
|
||||
openai: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
env,
|
||||
manifestRegistry: registry,
|
||||
});
|
||||
|
||||
expect(hits).toEqual([
|
||||
{
|
||||
pluginId: "codex",
|
||||
reasons: ["OpenAI plugin enabled"],
|
||||
blocker: "not-enabled",
|
||||
},
|
||||
]);
|
||||
expect(
|
||||
collectConfiguredPluginAutoEnableBlockerWarnings({
|
||||
hits,
|
||||
doctorFixCommand: "openclaw doctor --fix",
|
||||
}),
|
||||
).toEqual([
|
||||
'- plugins.entries.codex.enabled: plugin is not enabled, but OpenAI plugin enabled. Run "openclaw doctor --fix" to enable it.',
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,191 @@
|
||||
import { ensurePluginAllowlisted } from "../../../config/plugins-allowlist.js";
|
||||
import { isBlockedObjectKey } from "../../../config/prototype-keys.js";
|
||||
import type { OpenClawConfig } from "../../../config/types.openclaw.js";
|
||||
import {
|
||||
loadPluginManifestRegistry,
|
||||
type PluginManifestRegistry,
|
||||
} from "../../../plugins/manifest-registry.js";
|
||||
|
||||
const CODEX_PLUGIN_ID = "codex";
|
||||
const OPENAI_PLUGIN_ID = "openai";
|
||||
const OPENAI_ENABLED_CODEX_REASON = "OpenAI plugin enabled";
|
||||
|
||||
export type ConfiguredPluginAutoEnableBlockerReason = "blocked-by-denylist" | "not-enabled";
|
||||
|
||||
export type ConfiguredPluginAutoEnableBlockerHit = {
|
||||
pluginId: typeof CODEX_PLUGIN_ID;
|
||||
reasons: [typeof OPENAI_ENABLED_CODEX_REASON];
|
||||
blocker: ConfiguredPluginAutoEnableBlockerReason;
|
||||
};
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
||||
}
|
||||
|
||||
function isPluginDenied(cfg: OpenClawConfig, pluginId: string): boolean {
|
||||
return Array.isArray(cfg.plugins?.deny) && cfg.plugins.deny.includes(pluginId);
|
||||
}
|
||||
|
||||
function isPluginEntryDisabled(cfg: OpenClawConfig, pluginId: string): boolean {
|
||||
return cfg.plugins?.entries?.[pluginId]?.enabled === false;
|
||||
}
|
||||
|
||||
function isPluginEntryEnabled(cfg: OpenClawConfig, pluginId: string): boolean {
|
||||
return cfg.plugins?.entries?.[pluginId]?.enabled === true;
|
||||
}
|
||||
|
||||
function isPluginAllowMissing(cfg: OpenClawConfig, pluginId: string): boolean {
|
||||
return Array.isArray(cfg.plugins?.allow) && !cfg.plugins.allow.includes(pluginId);
|
||||
}
|
||||
|
||||
function isOpenAiExplicitlyEnabled(cfg: OpenClawConfig): boolean {
|
||||
if (cfg.plugins?.enabled === false || isPluginDenied(cfg, OPENAI_PLUGIN_ID)) {
|
||||
return false;
|
||||
}
|
||||
if (isPluginEntryDisabled(cfg, OPENAI_PLUGIN_ID)) {
|
||||
return false;
|
||||
}
|
||||
if (isPluginAllowMissing(cfg, OPENAI_PLUGIN_ID)) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
isPluginEntryEnabled(cfg, OPENAI_PLUGIN_ID) ||
|
||||
cfg.plugins?.allow?.includes(OPENAI_PLUGIN_ID) === true
|
||||
);
|
||||
}
|
||||
|
||||
function isCodexEnabled(cfg: OpenClawConfig): boolean {
|
||||
if (isPluginDenied(cfg, CODEX_PLUGIN_ID)) {
|
||||
return false;
|
||||
}
|
||||
if (!isPluginEntryEnabled(cfg, CODEX_PLUGIN_ID)) {
|
||||
return false;
|
||||
}
|
||||
return !isPluginAllowMissing(cfg, CODEX_PLUGIN_ID);
|
||||
}
|
||||
|
||||
function resolveRegistry(params: {
|
||||
cfg: OpenClawConfig;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
manifestRegistry?: PluginManifestRegistry;
|
||||
}): PluginManifestRegistry {
|
||||
return (
|
||||
params.manifestRegistry ??
|
||||
loadPluginManifestRegistry({
|
||||
config: params.cfg,
|
||||
env: params.env,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function hasBundledCodexManifest(registry: PluginManifestRegistry): boolean {
|
||||
return registry.plugins.some(
|
||||
(plugin) => plugin.id === CODEX_PLUGIN_ID && plugin.origin === "bundled",
|
||||
);
|
||||
}
|
||||
|
||||
function shouldCheckCodexForOpenAi(cfg: OpenClawConfig): boolean {
|
||||
return isOpenAiExplicitlyEnabled(cfg) && !isCodexEnabled(cfg);
|
||||
}
|
||||
|
||||
function copyConfigRecord(value: unknown): Record<string, unknown> {
|
||||
if (!isRecord(value)) {
|
||||
return {};
|
||||
}
|
||||
const copy: Record<string, unknown> = {};
|
||||
for (const [key, entry] of Object.entries(value)) {
|
||||
if (!isBlockedObjectKey(key)) {
|
||||
copy[key] = entry;
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
function setCodexEntryEnabled(cfg: OpenClawConfig): OpenClawConfig {
|
||||
const entries = copyConfigRecord(cfg.plugins?.entries);
|
||||
const existingEntry = copyConfigRecord(entries[CODEX_PLUGIN_ID]);
|
||||
return {
|
||||
...cfg,
|
||||
plugins: {
|
||||
...cfg.plugins,
|
||||
entries: {
|
||||
...entries,
|
||||
[CODEX_PLUGIN_ID]: {
|
||||
...existingEntry,
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function scanConfiguredPluginAutoEnableBlockers(params: {
|
||||
cfg: OpenClawConfig;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
manifestRegistry?: PluginManifestRegistry;
|
||||
}): ConfiguredPluginAutoEnableBlockerHit[] {
|
||||
if (!shouldCheckCodexForOpenAi(params.cfg)) {
|
||||
return [];
|
||||
}
|
||||
const registry = resolveRegistry(params);
|
||||
if (!hasBundledCodexManifest(registry)) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
{
|
||||
pluginId: CODEX_PLUGIN_ID,
|
||||
reasons: [OPENAI_ENABLED_CODEX_REASON],
|
||||
blocker: isPluginDenied(params.cfg, CODEX_PLUGIN_ID) ? "blocked-by-denylist" : "not-enabled",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function collectConfiguredPluginAutoEnableBlockerWarnings(params: {
|
||||
hits: readonly ConfiguredPluginAutoEnableBlockerHit[];
|
||||
doctorFixCommand?: string;
|
||||
}): string[] {
|
||||
return params.hits.map((hit) => {
|
||||
if (hit.blocker === "blocked-by-denylist") {
|
||||
return `- plugins.deny: plugin "${hit.pluginId}" is denied, but ${hit.reasons[0]}. Remove it from plugins.deny before relying on that configuration.`;
|
||||
}
|
||||
const suffix = params.doctorFixCommand
|
||||
? ` Run "${params.doctorFixCommand}" to enable it.`
|
||||
: " Enable the plugin before relying on that configuration.";
|
||||
return `- plugins.entries.${hit.pluginId}.enabled: plugin is not enabled, but ${hit.reasons[0]}.${suffix}`;
|
||||
});
|
||||
}
|
||||
|
||||
export function maybeRepairConfiguredPluginAutoEnableBlockers(params: {
|
||||
cfg: OpenClawConfig;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
manifestRegistry?: PluginManifestRegistry;
|
||||
}): {
|
||||
config: OpenClawConfig;
|
||||
changes: string[];
|
||||
warnings: string[];
|
||||
} {
|
||||
const hits = scanConfiguredPluginAutoEnableBlockers(params);
|
||||
if (hits.length === 0) {
|
||||
return { config: params.cfg, changes: [], warnings: [] };
|
||||
}
|
||||
const hit = hits[0];
|
||||
if (hit.blocker === "blocked-by-denylist") {
|
||||
return {
|
||||
config: params.cfg,
|
||||
changes: [],
|
||||
warnings: collectConfiguredPluginAutoEnableBlockerWarnings({ hits }),
|
||||
};
|
||||
}
|
||||
|
||||
const hadAllowlistMissing = isPluginAllowMissing(params.cfg, CODEX_PLUGIN_ID);
|
||||
const config = ensurePluginAllowlisted(setCodexEntryEnabled(params.cfg), CODEX_PLUGIN_ID);
|
||||
const changes = [
|
||||
`plugins.entries.${CODEX_PLUGIN_ID}.enabled: enabled plugin because ${OPENAI_ENABLED_CODEX_REASON}.`,
|
||||
];
|
||||
if (hadAllowlistMissing) {
|
||||
changes.push(
|
||||
`plugins.allow: added "${CODEX_PLUGIN_ID}" because ${OPENAI_ENABLED_CODEX_REASON}.`,
|
||||
);
|
||||
}
|
||||
return { config, changes, warnings: [] };
|
||||
}
|
||||
@@ -124,6 +124,23 @@ export async function collectDoctorPreviewWarnings(params: {
|
||||
}
|
||||
|
||||
if (hasPluginConfig) {
|
||||
const {
|
||||
collectConfiguredPluginAutoEnableBlockerWarnings,
|
||||
scanConfiguredPluginAutoEnableBlockers,
|
||||
} = await import("./configured-plugin-auto-enable-blockers.js");
|
||||
const configuredPluginBlockerHits = scanConfiguredPluginAutoEnableBlockers({
|
||||
cfg: params.cfg,
|
||||
env,
|
||||
});
|
||||
if (configuredPluginBlockerHits.length > 0) {
|
||||
warnings.push(
|
||||
collectConfiguredPluginAutoEnableBlockerWarnings({
|
||||
hits: configuredPluginBlockerHits,
|
||||
doctorFixCommand: params.doctorFixCommand,
|
||||
}).join("\n"),
|
||||
);
|
||||
}
|
||||
|
||||
const {
|
||||
collectStalePluginConfigWarnings,
|
||||
isStalePluginAutoRepairBlocked,
|
||||
|
||||
Reference in New Issue
Block a user