refactor: remove stale file-backed shims

This commit is contained in:
Peter Steinberger
2026-05-08 22:29:28 +01:00
parent a8a834fb6b
commit cf2dc1a472
29 changed files with 39 additions and 326 deletions

View File

@@ -41,7 +41,6 @@ import {
} from "openclaw/plugin-sdk/agent-harness-runtime";
import { resolveAgentDir } from "openclaw/plugin-sdk/agent-runtime";
import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
import { pathExists } from "openclaw/plugin-sdk/security-runtime";
import {
buildCodexAppInventoryCacheKey,
defaultCodexAppInventoryCache,

View File

@@ -2348,6 +2348,8 @@ export function createDiagnosticsOtelService(): OpenClawPluginService {
case "webhook.error":
recordWebhookError(evt);
return;
case "sqlite.wal.checkpoint.error":
return;
case "message.queued":
recordMessageQueued(evt);
return;

View File

@@ -1 +0,0 @@
export { createPersistentDedupe } from "openclaw/plugin-sdk/persistent-dedupe";

View File

@@ -1 +0,0 @@
export { maybeCreateMatrixMigrationSnapshot } from "../../migration-snapshot-backup.js";

View File

@@ -2389,8 +2389,8 @@ describe("memory-core dreaming phases", () => {
});
const phaseSignalStore = await readPhaseSignalStoreForTest(workspaceDir, nowMs);
expect(phaseSignalStore.entries[liveKey!]).toMatchObject({ remHits: 1 });
expect(phaseSignalStore.entries[staleKey!]).toBeUndefined();
expect(phaseSignalStore.entries[liveKey]).toMatchObject({ remHits: 1 });
expect(phaseSignalStore.entries[staleKey]).toBeUndefined();
const remOutput = await fs.readFile(
path.join(workspaceDir, "memory", `${DREAMING_TEST_DAY}.md`),

View File

@@ -801,7 +801,7 @@ describe("short-term promotion", () => {
expect(ranked[0].score).toBeGreaterThan(ranked[1].score);
const phaseStore = await readPhaseSignalStore(workspaceDir);
expect(phaseStore.entries[boostedKey!]).toMatchObject({
expect(phaseStore.entries[boostedKey]).toMatchObject({
lightHits: 1,
remHits: 1,
});

View File

@@ -49,15 +49,19 @@ describe("memory wiki source sync migration", () => {
await fs.writeFile(path.join(locksDir, "stale.lock"), "stale", "utf8");
const provider = createMemoryWikiSourceSyncMigrationProvider(createConfig(vaultRoot));
await expect(provider.detect()).resolves.toMatchObject({
const ctx = {} as MigrationProviderContext;
if (!provider.detect) {
throw new Error("Expected memory wiki migration provider to expose detect");
}
await expect(provider.detect(ctx)).resolves.toMatchObject({
found: true,
confidence: "high",
});
const plan = await provider.plan({} as MigrationProviderContext);
const plan = await provider.plan(ctx);
expect(plan.items.map((item) => item.id)).toContain("memory-wiki-vault-metadata-json");
const result = await provider.apply({} as MigrationProviderContext, plan);
const result = await provider.apply(ctx, plan);
const item = result.items.find((item) => item.id === "memory-wiki-vault-metadata-json");
expect(item).toMatchObject({

View File

@@ -1,25 +0,0 @@
import path from "node:path";
import { getMSTeamsRuntime } from "./runtime.js";
type MSTeamsCredentialPathOptions = {
env?: NodeJS.ProcessEnv;
homedir?: () => string;
stateDir?: string;
pathOverride?: string;
filename: string;
};
export function resolveMSTeamsCredentialFilePath(params: MSTeamsCredentialPathOptions): string {
if (params.pathOverride) {
return params.pathOverride;
}
if (params.stateDir) {
return path.join(params.stateDir, params.filename);
}
const env = params.env ?? process.env;
const stateDir = params.homedir
? getMSTeamsRuntime().state.resolveStateDir(env, params.homedir)
: getMSTeamsRuntime().state.resolveStateDir(env);
return path.join(stateDir, params.filename);
}

View File

@@ -980,7 +980,7 @@ describe("slack prepareSlackMessage inbound contract", () => {
);
history.mockClear();
seedExistingSession(prepared!.ctxPayload.SessionKey!);
seedExistingSession(prepared.ctxPayload.SessionKey!);
const existing = await prepareMessageWith(
slackCtx,
account,

View File

@@ -0,0 +1 @@
export { detectTelegramLegacyStateMigrations } from "./src/state-migrations.js";

View File

@@ -11,6 +11,7 @@ export const KNIP_UNUSED_FILE_ALLOWLIST = [
"extensions/diffs/src/viewer-payload.ts",
"extensions/matrix/src/plugin-entry.runtime.js",
"extensions/memory-core/src/memory-tool-manager-mock.ts",
"extensions/skill-workshop/src/state-migrations.ts",
"src/agents/subagent-registry.runtime.ts",
"src/auto-reply/inbound.group-require-mention-test-plugins.ts",
"src/auto-reply/reply/get-reply.test-loader.ts",

View File

@@ -162,9 +162,9 @@ async function main() {
);
const auditEntries = (await listCrestodianAuditEntriesForTests()).map((entry) => entry.value);
const auditOperations = auditEntries.map((entry) => entry.operation);
const auditOperations = new Set(auditEntries.map((entry) => entry.operation));
for (const operation of spec.auditOperations) {
assert(auditOperations.includes(operation), `${operation} audit entry missing`);
assert(auditOperations.has(operation), `${operation} audit entry missing`);
}
console.log("Crestodian first-run Docker E2E passed");

View File

@@ -1,3 +1,5 @@
import { streamSimpleOpenAICodexResponses } from "@mariozechner/pi-ai/openai-codex-responses";
import { streamSimpleOpenAIResponses } from "@mariozechner/pi-ai/openai-responses";
import { Agent, type StreamFn } from "openclaw/plugin-sdk/agent-core";
import { describe, expect, it } from "vitest";
import {
@@ -7,8 +9,6 @@ import {
type Model,
type SimpleStreamOptions,
} from "./pi-ai-contract.js";
import { streamSimpleOpenAICodexResponses } from "./pi-ai-openai-codex-responses-contract.js";
import { streamSimpleOpenAIResponses } from "./pi-ai-openai-responses-contract.js";
type ResponsesModel = Model<"openai-responses"> | Model<"openai-codex-responses">;

View File

@@ -1 +0,0 @@
export { streamSimpleOpenAICodexResponses } from "@mariozechner/pi-ai/openai-codex-responses";

View File

@@ -1 +0,0 @@
export { streamSimpleOpenAIResponses } from "@mariozechner/pi-ai/openai-responses";

View File

@@ -209,6 +209,7 @@ describe("maybeRepairLegacyCronStore", () => {
name: "Stateful job",
enabled: true,
createdAtMs: Date.parse("2026-02-01T00:00:00.000Z"),
updatedAtMs: Date.parse("2026-02-01T00:00:00.000Z"),
schedule: { kind: "every", everyMs: 60_000 },
sessionTarget: "main",
wakeMode: "next-heartbeat",
@@ -304,6 +305,7 @@ describe("maybeRepairLegacyCronStore", () => {
name: "Stateful job",
enabled: true,
createdAtMs: Date.parse("2026-02-01T00:00:00.000Z"),
updatedAtMs: Date.parse("2026-02-01T00:00:00.000Z"),
schedule: { kind: "every", everyMs: 60_000 },
sessionTarget: "main",
wakeMode: "next-heartbeat",

View File

@@ -1,4 +1,3 @@
import path from "node:path";
import { resolveModelAgentRuntimeMetadata } from "../agents/agent-runtime-metadata.js";
import { DEFAULT_CONTEXT_TOKENS } from "../agents/defaults.js";
import { getRuntimeConfig } from "../config/config.js";

View File

@@ -1,50 +0,0 @@
import { describe, expect, it } from "vitest";
import { createExpiringMapCache, resolveCacheTtlMs } from "./cache-utils.js";
describe("resolveCacheTtlMs", () => {
it("accepts exact non-negative integers", () => {
expect(resolveCacheTtlMs({ envValue: "0", defaultTtlMs: 60_000 })).toBe(0);
expect(resolveCacheTtlMs({ envValue: "120000", defaultTtlMs: 60_000 })).toBe(120_000);
});
it("rejects malformed env values and falls back to the default", () => {
expect(resolveCacheTtlMs({ envValue: "0abc", defaultTtlMs: 60_000 })).toBe(60_000);
expect(resolveCacheTtlMs({ envValue: "15ms", defaultTtlMs: 60_000 })).toBe(60_000);
});
});
describe("createExpiringMapCache", () => {
it("expires entries on read after the TTL", () => {
let now = 1_000;
const cache = createExpiringMapCache<string, string>({
ttlMs: 5_000,
clock: () => now,
});
cache.set("alpha", "a");
expect(cache.get("alpha")).toBe("a");
now = 6_001;
expect(cache.get("alpha")).toBeUndefined();
expect(cache.size()).toBe(0);
});
it("supports dynamic TTLs and opportunistic pruning", () => {
let now = 1_000;
let ttlMs = 5_000;
const cache = createExpiringMapCache<string, string>({
ttlMs: () => ttlMs,
pruneIntervalMs: 1_000,
clock: () => now,
});
cache.set("stale", "old");
now = 7_000;
ttlMs = 2_000;
cache.set("fresh", "new");
expect(cache.get("stale")).toBeUndefined();
expect(cache.keys()).toEqual(["fresh"]);
});
});

View File

@@ -1,159 +0,0 @@
import fs from "node:fs";
import { parseStrictNonNegativeInteger } from "../infra/parse-finite-number.js";
export function resolveCacheTtlMs(params: {
envValue: string | undefined;
defaultTtlMs: number;
}): number {
const { envValue, defaultTtlMs } = params;
if (envValue) {
const parsed = parseStrictNonNegativeInteger(envValue);
if (parsed !== undefined) {
return parsed;
}
}
return defaultTtlMs;
}
export function isCacheEnabled(ttlMs: number): boolean {
return ttlMs > 0;
}
type CacheTtlResolver = number | (() => number);
type CachePruneIntervalResolver = number | ((ttlMs: number) => number);
type ExpiringMapCacheEntry<TValue> = {
storedAt: number;
value: TValue;
};
type ExpiringMapCache<TKey, TValue> = {
get: (key: TKey) => TValue | undefined;
set: (key: TKey, value: TValue) => void;
delete: (key: TKey) => void;
clear: () => void;
keys: () => TKey[];
size: () => number;
pruneExpired: () => void;
};
function resolveCacheNumeric(value: CacheTtlResolver): number {
return typeof value === "function" ? value() : value;
}
function resolvePruneIntervalMs(
ttlMs: number,
pruneIntervalMs: CachePruneIntervalResolver | undefined,
): number {
if (typeof pruneIntervalMs === "function") {
return Math.max(0, Math.floor(pruneIntervalMs(ttlMs)));
}
if (typeof pruneIntervalMs === "number") {
return Math.max(0, Math.floor(pruneIntervalMs));
}
return ttlMs;
}
function isCacheEntryExpired(storedAt: number, now: number, ttlMs: number): boolean {
return now - storedAt > ttlMs;
}
export function createExpiringMapCache<TKey, TValue>(options: {
ttlMs: CacheTtlResolver;
pruneIntervalMs?: CachePruneIntervalResolver;
clock?: () => number;
}): ExpiringMapCache<TKey, TValue> {
const cache = new Map<TKey, ExpiringMapCacheEntry<TValue>>();
const now = options.clock ?? Date.now;
let lastPruneAt = 0;
function getTtlMs(): number {
return Math.max(0, Math.floor(resolveCacheNumeric(options.ttlMs)));
}
function maybePruneExpiredEntries(nowMs: number, ttlMs: number): void {
if (!isCacheEnabled(ttlMs)) {
return;
}
if (nowMs - lastPruneAt < resolvePruneIntervalMs(ttlMs, options.pruneIntervalMs)) {
return;
}
for (const [key, entry] of cache.entries()) {
if (isCacheEntryExpired(entry.storedAt, nowMs, ttlMs)) {
cache.delete(key);
}
}
lastPruneAt = nowMs;
}
return {
get: (key) => {
const ttlMs = getTtlMs();
if (!isCacheEnabled(ttlMs)) {
return undefined;
}
const nowMs = now();
maybePruneExpiredEntries(nowMs, ttlMs);
const entry = cache.get(key);
if (!entry) {
return undefined;
}
if (isCacheEntryExpired(entry.storedAt, nowMs, ttlMs)) {
cache.delete(key);
return undefined;
}
return entry.value;
},
set: (key, value) => {
const ttlMs = getTtlMs();
if (!isCacheEnabled(ttlMs)) {
return;
}
const nowMs = now();
maybePruneExpiredEntries(nowMs, ttlMs);
cache.set(key, {
storedAt: nowMs,
value,
});
},
delete: (key) => {
cache.delete(key);
},
clear: () => {
cache.clear();
lastPruneAt = 0;
},
keys: () => [...cache.keys()],
size: () => cache.size,
pruneExpired: () => {
const ttlMs = getTtlMs();
if (!isCacheEnabled(ttlMs)) {
return;
}
const nowMs = now();
for (const [key, entry] of cache.entries()) {
if (isCacheEntryExpired(entry.storedAt, nowMs, ttlMs)) {
cache.delete(key);
}
}
lastPruneAt = nowMs;
},
};
}
type FileStatSnapshot = {
mtimeMs: number;
sizeBytes: number;
};
export function getFileStatSnapshot(filePath: string): FileStatSnapshot | undefined {
try {
const stats = fs.statSync(filePath);
return {
mtimeMs: stats.mtimeMs,
sizeBytes: stats.size,
};
} catch {
return undefined;
}
}

View File

@@ -1,33 +0,0 @@
import type { SessionEntry } from "./types.js";
export function applySessionStoreMigrations(store: Record<string, SessionEntry>): boolean {
let changed = false;
// Best-effort migration: message provider → channel naming.
for (const entry of Object.values(store)) {
if (!entry || typeof entry !== "object") {
continue;
}
const rec = entry as unknown as Record<string, unknown>;
if (typeof rec.channel !== "string" && typeof rec.provider === "string") {
rec.channel = rec.provider;
delete rec.provider;
changed = true;
}
if (typeof rec.lastChannel !== "string" && typeof rec.lastProvider === "string") {
rec.lastChannel = rec.lastProvider;
delete rec.lastProvider;
changed = true;
}
// Best-effort migration: legacy `room` field → `groupChannel` (keep value, prune old key).
if (typeof rec.groupChannel !== "string" && typeof rec.room === "string") {
rec.groupChannel = rec.room;
delete rec.room;
changed = true;
} else if ("room" in rec) {
delete rec.room;
changed = true;
}
}
return changed;
}

View File

@@ -31,7 +31,7 @@ afterEach(() => {
});
describe("appendAssistantMessageToSessionTranscript", () => {
const fixture = useTempSessionsFixture("transcript-test-");
useTempSessionsFixture("transcript-test-");
const sessionId = "test-session-id";
const sessionKey = "test-session";
type ExactAssistantMessage = Parameters<

View File

@@ -14,14 +14,6 @@ import {
type TestConfig = Record<string, unknown>;
function parseLastJsonLine(raw: string): unknown {
const lastLine = raw.trim().split("\n").at(-1);
if (!lastLine) {
throw new Error("Expected audit log to contain at least one JSON line");
}
return JSON.parse(lastLine) as unknown;
}
const mockConfig = vi.hoisted(() => {
const initial = {};
const state = {

View File

@@ -123,12 +123,13 @@ async function createFixture(
return { attachmentId, sessionKey, originalPath };
}
function readManagedImageRecordFromSqlite<
T extends Record<string, unknown> = Record<string, unknown>,
>(stateDir: string, attachmentId: string): T {
function readManagedImageRecordFromSqlite(
stateDir: string,
attachmentId: string,
): Record<string, unknown> {
const value = readOpenClawStateKvJson("managed_outgoing_image_records", attachmentId, {
env: { ...process.env, OPENCLAW_STATE_DIR: stateDir },
}) as T | undefined;
}) as Record<string, unknown> | undefined;
if (!value) {
throw new Error(`Expected managed image record ${attachmentId}`);
}
@@ -291,6 +292,7 @@ describe("handleManagedOutgoingImageHttpRequest", () => {
const { result } = await requestManagedImage({
stateDir,
pathName,
authResponse: { authMethod: "token" },
headers: { "x-openclaw-requester-session-key": "agent:main:main" },
});
@@ -526,9 +528,9 @@ describe("createManagedOutgoingImageBlocks", () => {
expect(JSON.stringify(blocks[0])).not.toContain(sourcePath);
const attachmentId = requireAttachmentIdFromUrl(blocks[0]?.url);
const record = readManagedImageRecordFromSqlite<{
const record = readManagedImageRecordFromSqlite(stateDir, attachmentId) as {
original: { filename: string; path: string };
}>(stateDir, attachmentId);
};
expect(record.original.filename).toMatch(/\.png$/);
expect(record.original.path).not.toBe(sourcePath);
expect(record.original.path).toContain(expectedManagedOriginalsDir());
@@ -582,10 +584,9 @@ describe("createManagedOutgoingImageBlocks", () => {
expect(JSON.stringify(blocks[0])).not.toContain("sig=secret");
const attachmentId = requireAttachmentIdFromUrl(blocks[0]?.url);
const record = readManagedImageRecordFromSqlite<{ original: { path: string } }>(
stateDir,
attachmentId,
);
const record = readManagedImageRecordFromSqlite(stateDir, attachmentId) as {
original: { path: string };
};
expect(record.original.path).toContain(expectedManagedOriginalsDir());
expect(JSON.stringify(record)).not.toContain("127.0.0.1");
expect(JSON.stringify(record)).not.toContain("sig=secret");
@@ -623,7 +624,7 @@ describe("createManagedOutgoingImageBlocks", () => {
const attachmentId = requireAttachmentIdFromUrl(blocks[0]?.url);
const record = readManagedImageRecordFromSqlite(stateDir, String(attachmentId)) as {
const record = readManagedImageRecordFromSqlite(stateDir, attachmentId) as {
original: { path: string };
};

View File

@@ -49,10 +49,7 @@ test("sessions.create stores dashboard session model and parent linkage, and cre
expect(created.payload?.entry?.providerOverride).toBe("openai");
expect(created.payload?.entry?.modelOverride).toBe("gpt-test-a");
expect(created.payload?.entry?.parentSessionKey).toBe("agent:main:main");
const sessionFile = requireNonEmptyString(
created.payload?.entry?.sessionFile,
"created session file",
);
requireNonEmptyString(created.payload?.entry?.sessionFile, "created session file");
expect(created.payload?.sessionId).toMatch(
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,
);

View File

@@ -1,7 +0,0 @@
import "./fs-safe-defaults.js";
export {
createFileLockManager,
type FileLockHeldEntry,
type FileLockManager,
} from "@openclaw/fs-safe/file-lock";

View File

@@ -1,8 +0,0 @@
import "./fs-safe-defaults.js";
export {
fileStore,
type FileStore,
type FileStoreOptions,
type FileStorePruneOptions,
type FileStoreWriteOptions,
} from "@openclaw/fs-safe/store";

View File

@@ -203,6 +203,10 @@ function sanitizeDiagnosticEvent(event: DiagnosticEventPayload): DiagnosticStabi
case "webhook.error":
record.channel = event.channel;
break;
case "sqlite.wal.checkpoint.error":
record.source = event.databaseLabel;
assignReasonCode(record, event.error);
break;
case "message.queued":
record.channel = event.channel;
record.source = event.source;

View File

@@ -28,10 +28,8 @@ const piPackageStringPattern = /["'](@mariozechner\/pi-[^"']+)["']/g;
const allowedPiPackageImportFiles = new Set([
"src/agents/agent-core-contract.ts",
"src/agents/pi-ai-contract.ts",
"src/agents/pi-ai-openai-codex-responses-contract.ts",
"src/agents/pi-ai-oauth-contract.ts",
"src/agents/pi-ai-openai-completions-contract.ts",
"src/agents/pi-ai-openai-responses-contract.ts",
"src/agents/pi-coding-agent-contract.ts",
"src/agents/pi-tui-contract.ts",
"src/types/pi-agent-core.d.ts",

View File

@@ -1,5 +1,4 @@
import { z } from "zod";
import { tryReadJsonSync } from "../infra/json-files.js";
import { isBlockedObjectKey } from "../infra/prototype-keys.js";
import { readOpenClawStateKvJson } from "../state/openclaw-state-kv.js";
import { safeParseWithSchema } from "../utils/zod-parse.js";