🎉 init: 小龙的工作空间
This commit is contained in:
@@ -0,0 +1,472 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* PR-C Deprecation Check Script
|
||||
* Scans OpenClaw config and plugin state for deprecated modules.
|
||||
*
|
||||
* Run: node scripts/check-deprecations.mjs
|
||||
*
|
||||
* Checks:
|
||||
* 1. Active Memory blocking mode
|
||||
* 2. Dreaming REM phase enabled
|
||||
* 3. Dream Diary generation
|
||||
* 4. QMD search mode / QMD engine references
|
||||
* 5. Honcho memory plugin enabled
|
||||
* 6. LanceDB memory plugin enabled
|
||||
* 7. memory-wiki plugin loaded
|
||||
* 8. Commitments auto-infer
|
||||
* 9. Grounded Backfill / REM Backfill CLI usage
|
||||
*/
|
||||
|
||||
import { readFileSync, existsSync, readdirSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { homedir } from "node:os";
|
||||
import { warnOnce, warnMany } from "./lib/deprecation-warning.mjs";
|
||||
|
||||
const AGENTS_HOME = join(homedir(), ".openclaw");
|
||||
const CONFIG_PATH = join(AGENTS_HOME, "openclaw.json");
|
||||
const OPENCLAW_HOME = process.env.OPENCLAW_HOME || "/opt/homebrew/lib/node_modules/openclaw";
|
||||
const EXTENSIONS_DIR = join(OPENCLAW_HOME, "dist", "extensions");
|
||||
|
||||
// Load user config
|
||||
function loadConfig() {
|
||||
if (!existsSync(CONFIG_PATH)) return null;
|
||||
try {
|
||||
return JSON.parse(readFileSync(CONFIG_PATH, "utf8"));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Load plugin entry for a given extension id
|
||||
function loadPlugin(id) {
|
||||
const pluginJsonPath = join(EXTENSIONS_DIR, id, "openclaw.plugin.json");
|
||||
if (!existsSync(pluginJsonPath)) return null;
|
||||
try {
|
||||
return JSON.parse(readFileSync(pluginJsonPath, "utf8"));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a plugin is enabled in user config
|
||||
function isPluginEnabled(config, pluginId) {
|
||||
const entries = config?.plugins?.entries;
|
||||
if (!entries) return false;
|
||||
const entry = entries[pluginId];
|
||||
if (!entry) return false;
|
||||
return entry.enabled !== false;
|
||||
}
|
||||
|
||||
// ─── Check Functions ────────────────────────────────
|
||||
|
||||
function checkActiveMemoryBlocking(config) {
|
||||
const warnings = [];
|
||||
const entry = config?.plugins?.entries?.["active-memory"];
|
||||
if (!entry) return warnings;
|
||||
|
||||
const mode = entry.config?.mode;
|
||||
if (mode === "blocking") {
|
||||
warnings.push({
|
||||
key: "active-memory.blocking",
|
||||
message: "active-memory blocking mode is deprecated. Set mode to 'precompute' instead."
|
||||
});
|
||||
}
|
||||
return warnings;
|
||||
}
|
||||
|
||||
function checkDreamingRemPhase(config) {
|
||||
const warnings = [];
|
||||
const entry = config?.plugins?.entries?.["memory-core"];
|
||||
if (!entry) return warnings;
|
||||
|
||||
const dreaming = entry.config?.dreaming;
|
||||
if (!dreaming) return warnings;
|
||||
|
||||
// Check REM phase enabled
|
||||
const remEnabled = dreaming?.phases?.rem?.enabled;
|
||||
if (remEnabled === true) {
|
||||
warnings.push({
|
||||
key: "dreaming.rem-phase",
|
||||
message: "Dreaming REM phase is deprecated. It will be replaced by Collect/Promote."
|
||||
});
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
function checkDreamDiary(config) {
|
||||
const warnings = [];
|
||||
const entry = config?.plugins?.entries?.["memory-core"];
|
||||
if (!entry) return warnings;
|
||||
|
||||
const dreaming = entry.config?.dreaming;
|
||||
if (!dreaming) return warnings;
|
||||
|
||||
// Dream Diary is implied by REM phase or certain storage modes
|
||||
const storage = dreaming?.storage;
|
||||
const hasDiaryMode = storage?.mode === "separate" || storage?.mode === "both";
|
||||
const separateReports = storage?.separateReports === true;
|
||||
|
||||
if (hasDiaryMode || separateReports) {
|
||||
warnings.push({
|
||||
key: "dreaming.dream-diary",
|
||||
message: "Dream Diary generation is deprecated and will be removed."
|
||||
});
|
||||
}
|
||||
|
||||
// Also check if dreaming has a configured model (used for diary)
|
||||
if (dreaming?.model) {
|
||||
warnings.push({
|
||||
key: "dreaming.diary-model",
|
||||
message: "Dreaming diary model override is deprecated."
|
||||
});
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
function checkQmdReference(config) {
|
||||
const warnings = [];
|
||||
|
||||
// Check memory search config for QMD
|
||||
const memorySearch = config?.agents?.defaults?.memorySearch;
|
||||
if (memorySearch?.provider === "qmd" || memorySearch?.backend === "qmd") {
|
||||
warnings.push({
|
||||
key: "qmd.memory-search",
|
||||
message: "QMD memory engine is legacy. Migrate to Builtin MemoryCore."
|
||||
});
|
||||
}
|
||||
|
||||
// Check active-memory QMD reference
|
||||
const activeCfg = config?.plugins?.entries?.["active-memory"]?.config;
|
||||
if (activeCfg?.qmd?.searchMode) {
|
||||
warnings.push({
|
||||
key: "qmd.active-memory",
|
||||
message: "QMD search mode in active-memory is legacy. Remove qmd config."
|
||||
});
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
function checkHonchoLanceDB(config) {
|
||||
const warnings = [];
|
||||
|
||||
// Check if honcho or lancedb plugins are loaded
|
||||
const pluginEntries = config?.plugins?.entries || {};
|
||||
|
||||
if (pluginEntries["memory-honcho"]?.enabled !== false && isPluginInExtensions("honcho")) {
|
||||
warnings.push({
|
||||
key: "honcho.plugin",
|
||||
message: "Honcho memory plugin is legacy. Existing data readable during migration."
|
||||
});
|
||||
}
|
||||
|
||||
if (pluginEntries["memory-lancedb"]?.enabled !== false && isPluginInExtensions("lancedb")) {
|
||||
warnings.push({
|
||||
key: "lancedb.plugin",
|
||||
message: "LanceDB memory plugin is legacy. Existing data readable during migration."
|
||||
});
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
function checkMemoryWiki(config) {
|
||||
const warnings = [];
|
||||
const entry = config?.plugins?.entries?.["memory-wiki"];
|
||||
|
||||
if (entry?.enabled !== false) {
|
||||
// Check if memory-wiki extension exists and isn't disabled
|
||||
const wikiPlugin = loadPlugin("memory-wiki");
|
||||
if (wikiPlugin) {
|
||||
warnings.push({
|
||||
key: "memory-wiki.plugin",
|
||||
message: "memory-wiki plugin is legacy. wiki_search/wiki_get/wiki_apply/wiki_lint/wiki_status remain available during migration."
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
function checkCommitmentsAutoInfer(config) {
|
||||
const warnings = [];
|
||||
|
||||
// Commitments auto-infer is part of the session-memory bundled module
|
||||
const commitments = config?.commitments;
|
||||
if (commitments?.autoInfer === true) {
|
||||
warnings.push({
|
||||
key: "commitments.auto-infer",
|
||||
message: "Commitments auto-infer is deprecated. Use explicit cron tasks instead."
|
||||
});
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
function checkGroundedBackfill(config) {
|
||||
const warnings = [];
|
||||
|
||||
// Grounded Backfill is a CLI feature — we check if related config exists
|
||||
const dreaming = config?.plugins?.entries?.["memory-core"]?.config?.dreaming;
|
||||
if (!dreaming) return warnings;
|
||||
|
||||
// If dreaming has unusual storage paths that suggest backfill usage
|
||||
const storage = dreaming?.storage;
|
||||
if (storage?.mode === "separate") {
|
||||
warnings.push({
|
||||
key: "backfill.storage-mode",
|
||||
message: "Grounded Backfill / REM Backfill is deprecated and will not evolve further."
|
||||
});
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
// ─── Helpers ────────────────────────────────────────
|
||||
|
||||
function isPluginInExtensions(name) {
|
||||
try {
|
||||
const dirs = readdirSync(EXTENSIONS_DIR, { withFileTypes: true })
|
||||
.filter(d => d.isDirectory());
|
||||
|
||||
for (const d of dirs) {
|
||||
if (d.name.includes(name)) return true;
|
||||
// Check plugin.json
|
||||
const pluginPath = join(EXTENSIONS_DIR, d.name, "openclaw.plugin.json");
|
||||
if (existsSync(pluginPath)) {
|
||||
const plugin = JSON.parse(readFileSync(pluginPath, "utf8"));
|
||||
if (plugin.id?.includes(name)) return true;
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ─── Legacy Registry (PR-1 Freeze) ───────────────────
|
||||
// Maps deprecation keys to replacement info and migration window.
|
||||
// Used to enhance check-deprecations output.
|
||||
|
||||
const LEGACY_REGISTRY = {
|
||||
"active-memory.blocking": {
|
||||
module: "active-memory blocking mode",
|
||||
status: "Active. Deprecated.",
|
||||
replacement: 'Set mode to "precompute" in active-memory config',
|
||||
migrationWindow: "90 days from 2026-06-04",
|
||||
removalTarget: "2026-09-04",
|
||||
},
|
||||
"dreaming.rem-phase": {
|
||||
module: "Dreaming REM phase",
|
||||
status: "Active. Deprecated.",
|
||||
replacement: "Collect/Promote two-phase dreaming (PR-5)",
|
||||
migrationWindow: "90 days from 2026-06-04",
|
||||
removalTarget: "2026-09-04",
|
||||
},
|
||||
"dreaming.dream-diary": {
|
||||
module: "Dream Diary",
|
||||
status: "Active. Deprecated.",
|
||||
replacement: "Inline dreaming output (no separate diary storage)",
|
||||
migrationWindow: "90 days from 2026-06-04",
|
||||
removalTarget: "2026-09-04",
|
||||
},
|
||||
"dreaming.diary-model": {
|
||||
module: "Dream Diary model override",
|
||||
status: "Active. Deprecated.",
|
||||
replacement: "Use default dreaming model",
|
||||
migrationWindow: "90 days from 2026-06-04",
|
||||
removalTarget: "2026-09-04",
|
||||
},
|
||||
"qmd.memory-search": {
|
||||
module: "QMD memory search engine",
|
||||
status: "Active. Deprecated.",
|
||||
replacement: "Builtin MemoryCore FTS5 + BM25",
|
||||
migrationWindow: "90 days from 2026-06-04",
|
||||
removalTarget: "2026-09-04",
|
||||
},
|
||||
"qmd.active-memory": {
|
||||
module: "QMD active-memory search mode",
|
||||
status: "Active. Deprecated.",
|
||||
replacement: "Remove qmd config block from active-memory",
|
||||
migrationWindow: "90 days from 2026-06-04",
|
||||
removalTarget: "2026-09-04",
|
||||
},
|
||||
"honcho.plugin": {
|
||||
module: "Honcho memory plugin",
|
||||
status: "Legacy. Data readable during migration.",
|
||||
replacement: "memory-core (FTS5 + BM25)",
|
||||
migrationWindow: "60 days from 2026-06-04",
|
||||
removalTarget: "2026-08-04",
|
||||
},
|
||||
"lancedb.plugin": {
|
||||
module: "LanceDB memory plugin",
|
||||
status: "Legacy. Data readable during migration.",
|
||||
replacement: "memory-core (FTS5 + BM25)",
|
||||
migrationWindow: "60 days from 2026-06-04",
|
||||
removalTarget: "2026-08-04",
|
||||
},
|
||||
"memory-wiki.plugin": {
|
||||
module: "memory-wiki plugin",
|
||||
status: "Active. Deprecated.",
|
||||
replacement: "memory-core wiki compilation",
|
||||
migrationWindow: "90 days from 2026-06-04",
|
||||
removalTarget: "2026-09-04",
|
||||
},
|
||||
"commitments.auto-infer": {
|
||||
module: "Commitments auto-infer",
|
||||
status: "Active. Deprecated.",
|
||||
replacement: "Explicit cron tasks (use cron tool)",
|
||||
migrationWindow: "90 days from 2026-06-04",
|
||||
removalTarget: "2026-09-04",
|
||||
},
|
||||
"backfill.storage-mode": {
|
||||
module: "Grounded Backfill / REM Backfill CLI",
|
||||
status: "Active. Deprecated.",
|
||||
replacement: "No replacement. Stop using immediately.",
|
||||
migrationWindow: "Immediate — effective 2026-06-04",
|
||||
removalTarget: "2026-06-04",
|
||||
},
|
||||
};
|
||||
|
||||
function getLegacyInfo(key) {
|
||||
return LEGACY_REGISTRY[key] || null;
|
||||
}
|
||||
|
||||
function formatLegacyTable(warnings) {
|
||||
// Group warnings by their legacy info
|
||||
const seen = new Set();
|
||||
const rows = [];
|
||||
for (const w of warnings) {
|
||||
if (seen.has(w.key)) continue;
|
||||
seen.add(w.key);
|
||||
const info = LEGACY_REGISTRY[w.key] || {
|
||||
module: w.key,
|
||||
status: "Unknown",
|
||||
replacement: "N/A",
|
||||
migrationWindow: "N/A",
|
||||
removalTarget: "N/A",
|
||||
};
|
||||
rows.push(info);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
// ─── Main ────────────────────────────────────────────
|
||||
|
||||
function runAllChecks() {
|
||||
const config = loadConfig();
|
||||
const allWarnings = [];
|
||||
const checkResults = [];
|
||||
|
||||
if (!config) {
|
||||
console.warn("[DEPRECATED][OpenClaw v2] config: Could not load openclaw.json");
|
||||
return { warnings: [], results: [{ name: "config", error: "Could not load config" }] };
|
||||
}
|
||||
|
||||
const checks = [
|
||||
{ name: "active-memory blocking mode", fn: () => checkActiveMemoryBlocking(config) },
|
||||
{ name: "dreaming REM phase", fn: () => checkDreamingRemPhase(config) },
|
||||
{ name: "dream diary", fn: () => checkDreamDiary(config) },
|
||||
{ name: "QMD reference", fn: () => checkQmdReference(config) },
|
||||
{ name: "Honcho / LanceDB", fn: () => checkHonchoLanceDB(config) },
|
||||
{ name: "memory-wiki", fn: () => checkMemoryWiki(config) },
|
||||
{ name: "commitments auto-infer", fn: () => checkCommitmentsAutoInfer(config) },
|
||||
{ name: "grounded backfill", fn: () => checkGroundedBackfill(config) },
|
||||
];
|
||||
|
||||
console.log("");
|
||||
console.log("═══════════════════════════════════════");
|
||||
console.log(" PR-C: Deprecation Warning Check");
|
||||
console.log(` Architecture Freeze: 2026-06-04`);
|
||||
console.log(` ${new Date().toISOString()}`);
|
||||
console.log("═══════════════════════════════════════");
|
||||
console.log("");
|
||||
|
||||
for (const check of checks) {
|
||||
try {
|
||||
const warnings = check.fn();
|
||||
checkResults.push({ name: check.name, warnings, passed: warnings.length === 0 });
|
||||
allWarnings.push(...warnings);
|
||||
} catch (e) {
|
||||
checkResults.push({ name: check.name, warnings: [], passed: false, error: e.message });
|
||||
}
|
||||
}
|
||||
|
||||
// Emit warnings (deduplicated)
|
||||
if (allWarnings.length > 0) {
|
||||
console.log(" ⚠ Deprecation warnings found:\n");
|
||||
for (const w of allWarnings) {
|
||||
warnOnce(w.key, w.message);
|
||||
}
|
||||
} else {
|
||||
console.log(" ✓ No deprecation warnings found.");
|
||||
}
|
||||
|
||||
// Summary
|
||||
console.log("");
|
||||
const checksWithWarnings = checkResults.filter(c => c.warnings.length > 0);
|
||||
const checksFailed = checkResults.filter(c => c.error);
|
||||
|
||||
console.log(` Checks run: ${checks.length}`);
|
||||
console.log(` With warnings: ${checksWithWarnings.length}`);
|
||||
console.log(` Total warnings: ${allWarnings.length}`);
|
||||
|
||||
if (checksFailed.length > 0) {
|
||||
console.log(` Check errors: ${checksFailed.length}`);
|
||||
for (const c of checksFailed) {
|
||||
console.log(` ⚠ ${c.name}: ${c.error}`);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── PR-1 Enhanced Output: Legacy Table ─────────────
|
||||
if (allWarnings.length > 0) {
|
||||
const legacyRows = formatLegacyTable(allWarnings);
|
||||
|
||||
console.log("");
|
||||
console.log(" ─────────────────────────────────────────────");
|
||||
console.log(" Deprecated Modules (PR-1 Legacy Inventory):");
|
||||
console.log(" ─────────────────────────────────────────────");
|
||||
console.log("");
|
||||
|
||||
for (const row of legacyRows) {
|
||||
console.log(` Module: ${row.module}`);
|
||||
console.log(` Status: ${row.status}`);
|
||||
console.log(` Replacement: ${row.replacement}`);
|
||||
console.log(` Migration Window: ${row.migrationWindow}`);
|
||||
console.log(` Removal Target: ${row.removalTarget}`);
|
||||
console.log("");
|
||||
}
|
||||
|
||||
// Migration timeline
|
||||
console.log(" ─────────────────────────────────────────────");
|
||||
console.log(" Migration Timeline:");
|
||||
console.log("");
|
||||
console.log(" Day 0 2026-06-04 Freeze active");
|
||||
console.log(" Day 30 2026-07-04 Legacy warnings active");
|
||||
console.log(" Day 60 2026-08-04 Honcho/LanceDB read-only cutoff");
|
||||
console.log(" Day 90 2026-09-04 All legacy modules removed");
|
||||
console.log("");
|
||||
|
||||
// Per-module key list for scripting
|
||||
console.log(" Deprecated keys:");
|
||||
for (const w of allWarnings) {
|
||||
const info = LEGACY_REGISTRY[w.key];
|
||||
const target = info ? info.removalTarget : "N/A";
|
||||
console.log(` • ${w.key} (removal: ${target})`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("");
|
||||
return { warnings: allWarnings, results: checkResults };
|
||||
}
|
||||
|
||||
// Run if called as main
|
||||
if (process.argv[1]?.includes("check-deprecations")) {
|
||||
const result = runAllChecks();
|
||||
process.exit(0); // Never fail on deprecation warnings
|
||||
}
|
||||
|
||||
export { runAllChecks, loadConfig, LEGACY_REGISTRY, getLegacyInfo, formatLegacyTable,
|
||||
checkActiveMemoryBlocking, checkDreamingRemPhase, checkDreamDiary,
|
||||
checkQmdReference, checkHonchoLanceDB, checkMemoryWiki,
|
||||
checkCommitmentsAutoInfer, checkGroundedBackfill };
|
||||
Reference in New Issue
Block a user