惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Y
Y Combinator Blog
腾讯CDC
Recent Announcements
Recent Announcements
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Hugging Face - Blog
Hugging Face - Blog
H
Help Net Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
博客园_首页
D
DataBreaches.Net
P
Proofpoint News Feed
云风的 BLOG
云风的 BLOG
V
Visual Studio Blog
月光博客
月光博客
Jina AI
Jina AI
Stack Overflow Blog
Stack Overflow Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 【当耐特】
Vercel News
Vercel News
WordPress大学
WordPress大学
J
Java Code Geeks
博客园 - 聂微东
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
U
Unit 42

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
fix(doctor): reset stale plugin slots · openclaw/openclaw...
vincentkoc · 2026-05-04 · via Recent Commits to openclaw:main

@@ -4,17 +4,19 @@ import type { OpenClawConfig } from "../../../config/types.openclaw.js";

44

import { normalizePluginId } from "../../../plugins/config-state.js";

55

import { loadInstalledPluginIndexInstallRecordsSync } from "../../../plugins/installed-plugin-index-records.js";

66

import { loadManifestMetadataSnapshot } from "../../../plugins/manifest-contract-eligibility.js";

7+

import { defaultSlotIdForKey, type PluginSlotKey } from "../../../plugins/slots.js";

78

import { sanitizeForLog } from "../../../terminal/ansi.js";

89

import { asObjectRecord } from "./object.js";

9101011

const CHANNEL_CONFIG_META_KEYS = new Set(["defaults", "modelByChannel"]);

111212-

type StalePluginSurface = "allow" | "entries" | "channel" | "heartbeat" | "modelByChannel";

13+

type StalePluginSurface = "allow" | "entries" | "slot" | "channel" | "heartbeat" | "modelByChannel";

13141415

type StalePluginConfigHit = {

1516

pluginId: string;

1617

pathLabel: string;

1718

surface: StalePluginSurface;

19+

slotKey?: PluginSlotKey;

1820

};

19212022

type StalePluginRegistryState = {

@@ -131,6 +133,32 @@ function scanStalePluginConfigWithState(

131133

}

132134

}

133135136+

const slots = asObjectRecord(plugins?.slots);

137+

if (slots) {

138+

for (const slotKey of ["memory", "contextEngine"] as const satisfies readonly PluginSlotKey[]) {

139+

const rawPluginId = slots[slotKey];

140+

if (typeof rawPluginId !== "string") {

141+

continue;

142+

}

143+

const pluginId = normalizePluginId(rawPluginId);

144+

const defaultSlotId = defaultSlotIdForKey(slotKey);

145+

if (

146+

!pluginId ||

147+

rawPluginId.trim().toLowerCase() === "none" ||

148+

pluginId === normalizePluginId(defaultSlotId) ||

149+

knownIds.has(pluginId)

150+

) {

151+

continue;

152+

}

153+

hits.push({

154+

pluginId: rawPluginId,

155+

pathLabel: `plugins.slots.${slotKey}`,

156+

surface: "slot",

157+

slotKey,

158+

});

159+

}

160+

}

161+134162

const staleChannelIds = collectDanglingChannelIds({

135163

cfg,

136164

registryState,

@@ -236,6 +264,9 @@ function formatStalePluginHitWarning(hit: StalePluginConfigHit): string {

236264

if (hit.surface === "allow" || hit.surface === "entries") {

237265

return `- ${hit.pathLabel}: stale plugin reference "${hit.pluginId}" was found.`;

238266

}

267+

if (hit.surface === "slot") {

268+

return `- ${hit.pathLabel}: slot references missing plugin "${hit.pluginId}".`;

269+

}

239270

if (hit.surface === "channel") {

240271

return `- ${hit.pathLabel}: dangling channel config for missing plugin "${hit.pluginId}" was found.`;

241272

}

@@ -310,6 +341,19 @@ export function maybeRepairStalePluginConfig(

310341

}

311342

}

312343344+

const slotHits = hits.filter(

345+

(hit): hit is StalePluginConfigHit & { slotKey: PluginSlotKey } =>

346+

hit.surface === "slot" && hit.slotKey !== undefined,

347+

);

348+

if (slotHits.length > 0) {

349+

const slots = asObjectRecord(nextPlugins?.slots);

350+

if (slots) {

351+

for (const hit of slotHits) {

352+

slots[hit.slotKey] = defaultSlotIdForKey(hit.slotKey);

353+

}

354+

}

355+

}

356+313357

const channelIds = hits.filter((hit) => hit.surface === "channel").map((hit) => hit.pluginId);

314358

if (channelIds.length > 0) {

315359

removeDanglingChannelReferences(next, channelIds);

@@ -326,6 +370,11 @@ export function maybeRepairStalePluginConfig(

326370

`- plugins.entries: removed ${entryIds.length} stale plugin entr${entryIds.length === 1 ? "y" : "ies"} (${entryIds.join(", ")})`,

327371

);

328372

}

373+

if (slotHits.length > 0) {

374+

changes.push(

375+

`- plugins.slots: reset ${slotHits.length} stale plugin slot${slotHits.length === 1 ? "" : "s"} (${slotHits.map((hit) => `${hit.slotKey}: ${hit.pluginId} -> ${defaultSlotIdForKey(hit.slotKey)}`).join(", ")})`,

376+

);

377+

}

329378

if (channelIds.length > 0) {

330379

changes.push(

331380

`- channels: removed ${channelIds.length} stale channel config${channelIds.length === 1 ? "" : "s"} (${channelIds.join(", ")})`,