mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-14 08:04:17 +00:00
refactor: neutralize sqlite snapshot helpers
This commit is contained in:
@@ -134,8 +134,8 @@ The branch already has a real shared SQLite base:
|
||||
input only; runtime no longer reads or writes TTS prefs JSON files, and the
|
||||
legacy path resolver lives in the doctor migration module.
|
||||
- Subagent run recovery and OpenRouter model capability cache runtime modules
|
||||
now keep SQLite readers/writers separate from doctor-only legacy JSON import
|
||||
helpers.
|
||||
now keep SQLite snapshot readers/writers separate from doctor-only legacy JSON
|
||||
import helpers.
|
||||
- `src/agents/filesystem/virtual-agent-fs.sqlite.ts` implements a SQLite VFS
|
||||
over the agent database `vfs_entries` table.
|
||||
- `src/agents/runtime-worker.entry.ts` creates per-run SQLite VFS, tool artifact,
|
||||
@@ -147,13 +147,14 @@ The branch already has a real shared SQLite base:
|
||||
Doctor imports legacy `~/.openclaw/exec-approvals.json`; runtime writes no
|
||||
longer create or rewrite that file.
|
||||
- Device identity, device auth, and bootstrap runtime modules now keep their
|
||||
SQLite readers/writers separate from doctor-only legacy JSON import helpers.
|
||||
- Web push, APNs, Voice Wake, and Voice Wake routing runtime modules now keep
|
||||
their SQLite readers/writers separate from doctor-only legacy JSON import
|
||||
SQLite snapshot readers/writers separate from doctor-only legacy JSON import
|
||||
helpers.
|
||||
- Web push, APNs, Voice Wake, and Voice Wake routing runtime modules now keep
|
||||
their SQLite snapshot readers/writers separate from doctor-only legacy JSON
|
||||
import helpers.
|
||||
- Pairing state, plugin binding approvals, and cron job state now follow the
|
||||
same split: runtime modules expose SQLite-backed operations and narrow
|
||||
migration writers, while doctor imports/removes the old JSON files through
|
||||
same split: runtime modules expose SQLite-backed operations and neutral
|
||||
snapshot helpers, while doctor imports/removes the old JSON files through
|
||||
`src/commands/doctor/legacy/*` modules.
|
||||
- Core pairing and cron runtime modules no longer export legacy JSON path
|
||||
builders. Doctor-owned legacy modules construct `pending.json`, `paired.json`,
|
||||
|
||||
@@ -164,7 +164,7 @@ function readPersistentCache(): Map<string, OpenRouterModelCapabilities> | undef
|
||||
return readSqliteCache();
|
||||
}
|
||||
|
||||
export function writeOpenRouterModelCapabilitiesCacheForMigration(
|
||||
export function writeOpenRouterModelCapabilitiesCacheSnapshot(
|
||||
map: Map<string, OpenRouterModelCapabilities>,
|
||||
env?: NodeJS.ProcessEnv,
|
||||
): void {
|
||||
|
||||
@@ -110,7 +110,7 @@ function normalizePersistedRunRecords(params: {
|
||||
return out;
|
||||
}
|
||||
|
||||
export function normalizeSubagentRunRecordsForMigration(params: {
|
||||
export function normalizeSubagentRunRecordsSnapshot(params: {
|
||||
runsRaw: Record<string, unknown>;
|
||||
isLegacy: boolean;
|
||||
}): Map<string, SubagentRunRecord> {
|
||||
@@ -372,7 +372,7 @@ function writeSubagentRegistryRunsToSqlite(
|
||||
}, subagentRegistryDbOptions(env));
|
||||
}
|
||||
|
||||
export function writeSubagentRegistryRunsForMigration(
|
||||
export function writeSubagentRegistryRunsSnapshot(
|
||||
runs: Map<string, SubagentRunRecord>,
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): void {
|
||||
|
||||
@@ -2,8 +2,8 @@ import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { resolveStateDir } from "../../../config/paths.js";
|
||||
import {
|
||||
parseDeviceAuthStoreForMigration,
|
||||
writeDeviceAuthStoreForMigration,
|
||||
parseDeviceAuthStoreSnapshot,
|
||||
writeDeviceAuthStoreSnapshot,
|
||||
} from "../../../infra/device-auth-store.js";
|
||||
|
||||
function resolveDeviceAuthPath(env: NodeJS.ProcessEnv = process.env): string {
|
||||
@@ -32,11 +32,11 @@ export function importLegacyDeviceAuthFileToSqlite(env: NodeJS.ProcessEnv = proc
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
const store = parseDeviceAuthStoreForMigration(parsed);
|
||||
const store = parseDeviceAuthStoreSnapshot(parsed);
|
||||
if (!store) {
|
||||
return { imported: false, tokens: 0 };
|
||||
}
|
||||
writeDeviceAuthStoreForMigration(env, store);
|
||||
writeDeviceAuthStoreSnapshot(env, store);
|
||||
try {
|
||||
fs.rmSync(filePath, { force: true });
|
||||
} catch {
|
||||
|
||||
@@ -2,8 +2,8 @@ import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { resolveStateDir } from "../../../config/paths.js";
|
||||
import {
|
||||
parseStoredDeviceIdentityForMigration,
|
||||
writeStoredDeviceIdentityForMigration,
|
||||
parseStoredDeviceIdentitySnapshot,
|
||||
writeStoredDeviceIdentitySnapshot,
|
||||
} from "../../../infra/device-identity.js";
|
||||
|
||||
function resolveIdentityPathForEnv(env: NodeJS.ProcessEnv = process.env): string {
|
||||
@@ -31,11 +31,11 @@ export function importLegacyDeviceIdentityFileToSqlite(env: NodeJS.ProcessEnv =
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
const stored = parseStoredDeviceIdentityForMigration(parsed);
|
||||
const stored = parseStoredDeviceIdentitySnapshot(parsed);
|
||||
if (!stored) {
|
||||
return { imported: false };
|
||||
}
|
||||
writeStoredDeviceIdentityForMigration(filePath, stored);
|
||||
writeStoredDeviceIdentitySnapshot(filePath, stored);
|
||||
try {
|
||||
fs.rmSync(filePath, { force: true });
|
||||
} catch {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, unlinkSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import {
|
||||
parseOpenRouterModelCapabilitiesCachePayload,
|
||||
writeOpenRouterModelCapabilitiesCacheForMigration,
|
||||
writeOpenRouterModelCapabilitiesCacheSnapshot,
|
||||
type OpenRouterModelCapabilities,
|
||||
} from "../../../agents/pi-embedded-runner/openrouter-model-capabilities.js";
|
||||
import { resolveStateDir } from "../../../config/paths.js";
|
||||
@@ -47,7 +47,7 @@ export function importLegacyOpenRouterModelCapabilitiesCacheToSqlite(
|
||||
}
|
||||
const legacyJsonCache = readLegacyJsonCache(env);
|
||||
if (legacyJsonCache) {
|
||||
writeOpenRouterModelCapabilitiesCacheForMigration(legacyJsonCache, env);
|
||||
writeOpenRouterModelCapabilitiesCacheSnapshot(legacyJsonCache, env);
|
||||
}
|
||||
try {
|
||||
unlinkSync(resolveLegacyJsonCachePath(env));
|
||||
|
||||
@@ -3,8 +3,8 @@ import path from "node:path";
|
||||
import { resolveStateDir } from "../../../config/paths.js";
|
||||
import { expandHomePrefix } from "../../../infra/home-dir.js";
|
||||
import {
|
||||
normalizePluginBindingApprovalsForMigration,
|
||||
writePluginBindingApprovalsForMigration,
|
||||
normalizePluginBindingApprovalsSnapshot,
|
||||
writePluginBindingApprovalsSnapshot,
|
||||
} from "../../../plugins/conversation-binding.js";
|
||||
|
||||
const LEGACY_APPROVALS_PATH = "~/.openclaw/plugin-binding-approvals.json";
|
||||
@@ -35,10 +35,10 @@ export function importLegacyPluginBindingApprovalFileToSqlite(): {
|
||||
if (!legacyPluginBindingApprovalFileExists()) {
|
||||
return { imported: false, approvals: 0 };
|
||||
}
|
||||
const file = normalizePluginBindingApprovalsForMigration(
|
||||
const file = normalizePluginBindingApprovalsSnapshot(
|
||||
JSON.parse(fs.readFileSync(filePath, "utf8")) as unknown,
|
||||
);
|
||||
writePluginBindingApprovalsForMigration(file);
|
||||
writePluginBindingApprovalsSnapshot(file);
|
||||
try {
|
||||
fs.unlinkSync(filePath);
|
||||
} catch {
|
||||
|
||||
@@ -2,8 +2,8 @@ import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { resolveStateDir } from "../../../config/paths.js";
|
||||
import {
|
||||
normalizeApnsRegistrationStateForMigration,
|
||||
writeApnsRegistrationStateForMigration,
|
||||
normalizeApnsRegistrationStateSnapshot,
|
||||
writeApnsRegistrationStateSnapshot,
|
||||
} from "../../../infra/push-apns.js";
|
||||
|
||||
const LEGACY_APNS_STATE_FILENAME = "push/apns-registrations.json";
|
||||
@@ -33,11 +33,11 @@ export async function importLegacyApnsRegistrationFileToSqlite(baseDir?: string)
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
const normalized = normalizeApnsRegistrationStateForMigration(parsed);
|
||||
const normalized = normalizeApnsRegistrationStateSnapshot(parsed);
|
||||
if (!normalized) {
|
||||
return { imported: false, registrations: 0 };
|
||||
}
|
||||
await writeApnsRegistrationStateForMigration(normalized, baseDir);
|
||||
await writeApnsRegistrationStateSnapshot(normalized, baseDir);
|
||||
await fs.rm(filePath, { force: true }).catch(() => undefined);
|
||||
return { imported: true, registrations: Object.keys(normalized.registrationsByNodeId).length };
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { resolveStateDir } from "../../../config/paths.js";
|
||||
import {
|
||||
writeWebPushRegistrationStateForMigration,
|
||||
writeWebPushVapidKeysForMigration,
|
||||
writeWebPushRegistrationStateSnapshot,
|
||||
writeWebPushVapidKeysSnapshot,
|
||||
type VapidKeyPair,
|
||||
type WebPushRegistrationState,
|
||||
} from "../../../infra/push-web.js";
|
||||
@@ -45,7 +45,7 @@ export async function importLegacyWebPushFilesToSqlite(baseDir?: string): Promis
|
||||
try {
|
||||
const state = JSON.parse(await fs.readFile(statePath, "utf8")) as WebPushRegistrationState;
|
||||
if (state && typeof state === "object") {
|
||||
await writeWebPushRegistrationStateForMigration(state, baseDir);
|
||||
await writeWebPushRegistrationStateSnapshot(state, baseDir);
|
||||
subscriptions = Object.keys(state.subscriptionsByEndpointHash ?? {}).length;
|
||||
await fs.rm(statePath, { force: true }).catch(() => undefined);
|
||||
files += 1;
|
||||
@@ -60,7 +60,7 @@ export async function importLegacyWebPushFilesToSqlite(baseDir?: string): Promis
|
||||
try {
|
||||
const keys = JSON.parse(await fs.readFile(vapidPath, "utf8")) as VapidKeyPair;
|
||||
if (keys?.publicKey && keys.privateKey) {
|
||||
writeWebPushVapidKeysForMigration(keys, baseDir);
|
||||
writeWebPushVapidKeysSnapshot(keys, baseDir);
|
||||
await fs.rm(vapidPath, { force: true }).catch(() => undefined);
|
||||
importedVapidKeys = true;
|
||||
files += 1;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import {
|
||||
normalizeSubagentRunRecordsForMigration,
|
||||
normalizeSubagentRunRecordsSnapshot,
|
||||
resolveSubagentStateDir,
|
||||
writeSubagentRegistryRunsForMigration,
|
||||
writeSubagentRegistryRunsSnapshot,
|
||||
} from "../../../agents/subagent-registry.store.js";
|
||||
import type { SubagentRunRecord } from "../../../agents/subagent-registry.types.js";
|
||||
import { loadJsonFile } from "../../../infra/json-file.js";
|
||||
@@ -44,7 +44,7 @@ function loadLegacySubagentRegistryFile(pathname: string): Map<string, SubagentR
|
||||
if (!runsRaw || typeof runsRaw !== "object") {
|
||||
return new Map();
|
||||
}
|
||||
return normalizeSubagentRunRecordsForMigration({
|
||||
return normalizeSubagentRunRecordsSnapshot({
|
||||
runsRaw: runsRaw as Record<string, unknown>,
|
||||
isLegacy: record.version === 1,
|
||||
});
|
||||
@@ -70,7 +70,7 @@ export function importLegacySubagentRegistryFileToSqlite(env: NodeJS.ProcessEnv
|
||||
return { imported: false, runs: 0 };
|
||||
}
|
||||
const runs = loadLegacySubagentRegistryFile(pathname);
|
||||
writeSubagentRegistryRunsForMigration(runs, env);
|
||||
writeSubagentRegistryRunsSnapshot(runs, env);
|
||||
try {
|
||||
fs.unlinkSync(pathname);
|
||||
} catch {
|
||||
|
||||
@@ -3,7 +3,7 @@ import path from "node:path";
|
||||
import { resolveStateDir } from "../../../config/paths.js";
|
||||
import {
|
||||
normalizeVoiceWakeRoutingConfig,
|
||||
writeVoiceWakeRoutingConfigForMigration,
|
||||
writeVoiceWakeRoutingConfigSnapshot,
|
||||
} from "../../../infra/voicewake-routing.js";
|
||||
|
||||
function resolveLegacyPath(baseDir?: string) {
|
||||
@@ -38,7 +38,7 @@ export async function importLegacyVoiceWakeRoutingConfigFileToSqlite(baseDir?: s
|
||||
throw error;
|
||||
}
|
||||
const normalized = normalizeVoiceWakeRoutingConfig(raw);
|
||||
writeVoiceWakeRoutingConfigForMigration(normalized, baseDir);
|
||||
writeVoiceWakeRoutingConfigSnapshot(normalized, baseDir);
|
||||
await fs.rm(filePath, { force: true }).catch(() => undefined);
|
||||
return { imported: true, routes: normalized.routes.length };
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { resolveStateDir } from "../../../config/paths.js";
|
||||
import {
|
||||
normalizeVoiceWakeConfigForMigration,
|
||||
writeVoiceWakeConfigForMigration,
|
||||
normalizeVoiceWakeConfigSnapshot,
|
||||
writeVoiceWakeConfigSnapshot,
|
||||
} from "../../../infra/voicewake.js";
|
||||
|
||||
function resolveLegacyPath(baseDir?: string) {
|
||||
@@ -37,8 +37,8 @@ export async function importLegacyVoiceWakeConfigFileToSqlite(baseDir?: string):
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
const normalized = normalizeVoiceWakeConfigForMigration(raw);
|
||||
writeVoiceWakeConfigForMigration(normalized, baseDir);
|
||||
const normalized = normalizeVoiceWakeConfigSnapshot(raw);
|
||||
writeVoiceWakeConfigSnapshot(normalized, baseDir);
|
||||
await fs.rm(filePath, { force: true }).catch(() => undefined);
|
||||
return { imported: true, triggers: normalized.triggers.length };
|
||||
}
|
||||
|
||||
@@ -58,12 +58,12 @@ export function storeDeviceAuthStore(params: {
|
||||
return params.store;
|
||||
}
|
||||
|
||||
export function parseDeviceAuthStoreForMigration(raw: unknown): DeviceAuthStore | null {
|
||||
export function parseDeviceAuthStoreSnapshot(raw: unknown): DeviceAuthStore | null {
|
||||
const store = DeviceAuthStoreSchema.safeParse(raw);
|
||||
return store.success ? store.data : null;
|
||||
}
|
||||
|
||||
export function writeDeviceAuthStoreForMigration(
|
||||
export function writeDeviceAuthStoreSnapshot(
|
||||
env: NodeJS.ProcessEnv | undefined,
|
||||
store: DeviceAuthStore,
|
||||
): void {
|
||||
|
||||
@@ -226,11 +226,11 @@ export function loadDeviceIdentityIfPresentForEnv(
|
||||
}
|
||||
}
|
||||
|
||||
export function parseStoredDeviceIdentityForMigration(value: unknown): StoredDeviceIdentity | null {
|
||||
export function parseStoredDeviceIdentitySnapshot(value: unknown): StoredDeviceIdentity | null {
|
||||
return parseStoredIdentity(value);
|
||||
}
|
||||
|
||||
export function writeStoredDeviceIdentityForMigration(
|
||||
export function writeStoredDeviceIdentitySnapshot(
|
||||
filePath: string,
|
||||
stored: StoredDeviceIdentity,
|
||||
): void {
|
||||
|
||||
@@ -396,7 +396,7 @@ async function persistRegistrationsState(
|
||||
);
|
||||
}
|
||||
|
||||
export function normalizeApnsRegistrationStateForMigration(
|
||||
export function normalizeApnsRegistrationStateSnapshot(
|
||||
parsed: unknown,
|
||||
): ApnsRegistrationState | null {
|
||||
if (!parsed || typeof parsed !== "object") {
|
||||
@@ -419,7 +419,7 @@ export function normalizeApnsRegistrationStateForMigration(
|
||||
return { registrationsByNodeId: normalized };
|
||||
}
|
||||
|
||||
export async function writeApnsRegistrationStateForMigration(
|
||||
export async function writeApnsRegistrationStateSnapshot(
|
||||
state: ApnsRegistrationState,
|
||||
baseDir?: string,
|
||||
): Promise<void> {
|
||||
|
||||
@@ -103,14 +103,14 @@ async function persistState(state: WebPushRegistrationState, baseDir?: string):
|
||||
);
|
||||
}
|
||||
|
||||
export async function writeWebPushRegistrationStateForMigration(
|
||||
export async function writeWebPushRegistrationStateSnapshot(
|
||||
state: WebPushRegistrationState,
|
||||
baseDir?: string,
|
||||
): Promise<void> {
|
||||
await persistState(state, baseDir);
|
||||
}
|
||||
|
||||
export function writeWebPushVapidKeysForMigration(keys: VapidKeyPair, baseDir?: string): void {
|
||||
export function writeWebPushVapidKeysSnapshot(keys: VapidKeyPair, baseDir?: string): void {
|
||||
writeOpenClawStateKvJson<OpenClawStateJsonValue>(
|
||||
WEB_PUSH_SCOPE,
|
||||
WEB_PUSH_VAPID_KEY,
|
||||
|
||||
@@ -295,7 +295,7 @@ export async function setVoiceWakeRoutingConfig(
|
||||
return next;
|
||||
}
|
||||
|
||||
export function writeVoiceWakeRoutingConfigForMigration(
|
||||
export function writeVoiceWakeRoutingConfigSnapshot(
|
||||
config: VoiceWakeRoutingConfig,
|
||||
baseDir?: string,
|
||||
): void {
|
||||
|
||||
@@ -66,7 +66,7 @@ export async function setVoiceWakeTriggers(
|
||||
return next;
|
||||
}
|
||||
|
||||
export function normalizeVoiceWakeConfigForMigration(raw: unknown): VoiceWakeConfig {
|
||||
export function normalizeVoiceWakeConfigSnapshot(raw: unknown): VoiceWakeConfig {
|
||||
const updatedAtMs = (raw as Partial<VoiceWakeConfig> | undefined)?.updatedAtMs;
|
||||
return {
|
||||
triggers: sanitizeTriggers((raw as Partial<VoiceWakeConfig> | undefined)?.triggers),
|
||||
@@ -74,7 +74,7 @@ export function normalizeVoiceWakeConfigForMigration(raw: unknown): VoiceWakeCon
|
||||
};
|
||||
}
|
||||
|
||||
export function writeVoiceWakeConfigForMigration(config: VoiceWakeConfig, baseDir?: string): void {
|
||||
export function writeVoiceWakeConfigSnapshot(config: VoiceWakeConfig, baseDir?: string): void {
|
||||
writeOpenClawStateKvJson<OpenClawStateJsonValue>(
|
||||
VOICEWAKE_SCOPE,
|
||||
VOICEWAKE_CONFIG_KEY,
|
||||
|
||||
@@ -342,7 +342,7 @@ function createApprovalRequestId(): string {
|
||||
return crypto.randomBytes(9).toString("base64url");
|
||||
}
|
||||
|
||||
export function normalizePluginBindingApprovalsForMigration(
|
||||
export function normalizePluginBindingApprovalsSnapshot(
|
||||
value: unknown,
|
||||
): PluginBindingApprovalsFile {
|
||||
const parsed = value as Partial<PluginBindingApprovalsFile> | undefined;
|
||||
@@ -372,7 +372,7 @@ export function normalizePluginBindingApprovalsForMigration(
|
||||
|
||||
function loadApprovalsFromSqlite(): PluginBindingApprovalsFile {
|
||||
try {
|
||||
return normalizePluginBindingApprovalsForMigration(
|
||||
return normalizePluginBindingApprovalsSnapshot(
|
||||
readOpenClawStateKvJson(
|
||||
APPROVALS_KV_SCOPE,
|
||||
APPROVALS_KV_KEY,
|
||||
@@ -385,7 +385,7 @@ function loadApprovalsFromSqlite(): PluginBindingApprovalsFile {
|
||||
}
|
||||
}
|
||||
|
||||
export function writePluginBindingApprovalsForMigration(file: PluginBindingApprovalsFile): void {
|
||||
export function writePluginBindingApprovalsSnapshot(file: PluginBindingApprovalsFile): void {
|
||||
writeOpenClawStateKvJson<OpenClawStateJsonValue>(
|
||||
APPROVALS_KV_SCOPE,
|
||||
APPROVALS_KV_KEY,
|
||||
@@ -398,7 +398,7 @@ export function writePluginBindingApprovalsForMigration(file: PluginBindingAppro
|
||||
}
|
||||
|
||||
async function saveApprovals(file: PluginBindingApprovalsFile): Promise<void> {
|
||||
writePluginBindingApprovalsForMigration(file);
|
||||
writePluginBindingApprovalsSnapshot(file);
|
||||
}
|
||||
|
||||
function getApprovals(): PluginBindingApprovalsFile {
|
||||
|
||||
Reference in New Issue
Block a user