























@@ -5,8 +5,13 @@ import path from "node:path";
55import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
66import type { OpenClawConfig } from "../config/config.js";
77import { resolveChannelAllowFromPath } from "../pairing/pairing-store.js";
8-import { openOpenClawStateDatabase } from "../state/openclaw-state-db.js";
8+import type { DB as OpenClawStateKyselyDatabase } from "../state/openclaw-state-db.generated.js";
9+import {
10+closeOpenClawStateDatabaseForTest,
11+openOpenClawStateDatabase,
12+} from "../state/openclaw-state-db.js";
913import { createTrackedTempDirs } from "../test-utils/tracked-temp-dirs.js";
14+import { executeSqliteQueryTakeFirstSync, getNodeSqliteKysely } from "./kysely-sync.js";
1015import {
1116autoMigrateLegacyState,
1217detectLegacyStateMigrations,
@@ -87,6 +92,8 @@ vi.mock("../channels/plugins/bundled.js", () => {
87928893const tempDirs = createTrackedTempDirs();
899495+type UpdateCheckStateDatabase = Pick<OpenClawStateKyselyDatabase, "update_check_state">;
96+9097async function expectMissingPath(targetPath: string): Promise<void> {
9198let statError: NodeJS.ErrnoException | undefined;
9299try {
@@ -101,6 +108,30 @@ async function expectMissingPath(targetPath: string): Promise<void> {
101108}
102109const createTempDir = () => tempDirs.make("openclaw-state-migrations-test-");
103110111+function readUpdateCheckState(env: NodeJS.ProcessEnv):
112+| {
113+last_checked_at: string | null;
114+last_available_version: string | null;
115+last_available_tag: string | null;
116+auto_install_id: string | null;
117+}
118+| undefined {
119+const { db } = openOpenClawStateDatabase({ env });
120+const stateDb = getNodeSqliteKysely<UpdateCheckStateDatabase>(db);
121+return executeSqliteQueryTakeFirstSync(
122+db,
123+stateDb
124+.selectFrom("update_check_state")
125+.select([
126+"last_checked_at",
127+"last_available_version",
128+"last_available_tag",
129+"auto_install_id",
130+])
131+.where("state_key", "=", "default"),
132+);
133+}
134+104135function createConfig(): OpenClawConfig {
105136return {
106137agents: {
@@ -179,6 +210,7 @@ async function createLegacyStateFixture(params?: { includePreKey?: boolean }) {
179210180211afterEach(async () => {
181212vi.useRealTimers();
213+closeOpenClawStateDatabaseForTest();
182214await tempDirs.cleanup();
183215});
184216@@ -518,6 +550,44 @@ describe("state migrations", () => {
518550await expectMissingPath(path.join(settingsDir, "voicewake.json"));
519551});
520552553+it("migrates legacy update-check JSON into shared SQLite state", async () => {
554+const root = await createTempDir();
555+const stateDir = path.join(root, ".openclaw");
556+const env = createEnv(stateDir);
557+const cfg = createConfig();
558+const sourcePath = path.join(stateDir, "update-check.json");
559+await fs.mkdir(stateDir, { recursive: true });
560+await fs.writeFile(
561+sourcePath,
562+JSON.stringify({
563+lastCheckedAt: "2026-01-17T09:30:00.000Z",
564+lastAvailableVersion: "2.0.0",
565+lastAvailableTag: "latest",
566+autoInstallId: "install-1",
567+}),
568+"utf8",
569+);
570+571+const detected = await detectLegacyStateMigrations({ cfg, env, homedir: () => root });
572+expect(detected.updateCheck.hasLegacy).toBe(true);
573+expect(detected.preview).toContain(
574+"- Update-check state: legacy JSON file → shared SQLite state",
575+);
576+577+const result = await runLegacyStateMigrations({ detected, config: cfg });
578+579+expect(result.warnings).toStrictEqual([]);
580+expect(result.changes).toContain("Migrated update-check state → shared SQLite state");
581+expect(readUpdateCheckState(env)).toMatchObject({
582+last_checked_at: "2026-01-17T09:30:00.000Z",
583+last_available_version: "2.0.0",
584+last_available_tag: "latest",
585+auto_install_id: "install-1",
586+});
587+await expectMissingPath(sourcePath);
588+await expect(fs.readFile(`${sourcePath}.migrated`, "utf8")).resolves.toContain("2.0.0");
589+});
590+521591it("keeps legacy delivery queue files when shared SQLite already has a conflicting row", async () => {
522592const root = await createTempDir();
523593const stateDir = path.join(root, ".openclaw");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。