


























11#!/usr/bin/env node
223+import fs from "node:fs/promises";
34import path from "node:path";
45import ts from "typescript";
56import {
@@ -48,6 +49,28 @@ const legacyLifecycleCleanupNames = new Set([
4849"archiveRemovedSessionTranscripts",
4950"cleanupArchivedSessionTranscripts",
5051]);
52+const sessionStoreRuntimeFileBackedCompatNames = new Set([
53+"loadSessionStore",
54+"readSessionEntries",
55+"readSessionEntry",
56+"readLatestAssistantTextFromSessionTranscript",
57+"readSessionStoreReadOnly",
58+"resolveAndPersistSessionFile",
59+"resolveSessionFilePath",
60+"resolveSessionStoreEntry",
61+"saveSessionStore",
62+"updateSessionStore",
63+]);
64+65+export const allowedSessionStoreRuntimeFileBackedCompatExports = new Set([
66+"loadSessionStore",
67+"readLatestAssistantTextFromSessionTranscript",
68+"resolveAndPersistSessionFile",
69+"resolveSessionFilePath",
70+"resolveSessionStoreEntry",
71+"saveSessionStore",
72+"updateSessionStore",
73+]);
51745275export const migratedSessionAccessorFiles = new Set([
5376"src/agents/embedded-agent-runner/compaction-successor-transcript.ts",
@@ -252,6 +275,74 @@ function findNamedSessionStoreViolations(content, fileName, legacyNames, legacyK
252275);
253276}
254277278+export function collectSessionStoreRuntimeFileBackedCompatExports(content, fileName = "source.ts") {
279+const sourceFile = ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, true);
280+const exports = new Map();
281+282+const rememberExport = (node, exportedName, sourceName = exportedName) => {
283+if (!sessionStoreRuntimeFileBackedCompatNames.has(sourceName)) {
284+return;
285+}
286+exports.set(exportedName, {
287+line: toLine(sourceFile, node),
288+ sourceName,
289+});
290+};
291+292+for (const statement of sourceFile.statements) {
293+const isExported = statement.modifiers?.some(
294+(modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword,
295+);
296+if (isExported && ts.isVariableStatement(statement)) {
297+for (const declaration of statement.declarationList.declarations) {
298+if (ts.isIdentifier(declaration.name)) {
299+rememberExport(declaration.name, declaration.name.text);
300+}
301+}
302+continue;
303+}
304+if (isExported && ts.isFunctionDeclaration(statement) && statement.name) {
305+rememberExport(statement.name, statement.name.text);
306+continue;
307+}
308+if (
309+ts.isExportDeclaration(statement) &&
310+statement.exportClause &&
311+ts.isNamedExports(statement.exportClause)
312+) {
313+for (const specifier of statement.exportClause.elements) {
314+rememberExport(
315+specifier,
316+specifier.name.text,
317+specifier.propertyName?.text ?? specifier.name.text,
318+);
319+}
320+}
321+}
322+323+return exports;
324+}
325+326+export function findSessionStoreRuntimeFileBackedCompatExportViolations(
327+content,
328+fileName = "source.ts",
329+) {
330+const exports = collectSessionStoreRuntimeFileBackedCompatExports(content, fileName);
331+const violations = [];
332+for (const [exportedName, exported] of exports) {
333+if (
334+exportedName !== exported.sourceName ||
335+!allowedSessionStoreRuntimeFileBackedCompatExports.has(exportedName)
336+) {
337+violations.push({
338+line: exported.line,
339+reason: `exports unratcheted file-backed SDK session helper "${exported.sourceName}"`,
340+});
341+}
342+}
343+return violations;
344+}
345+255346export function findSessionAccessorBoundaryViolations(content, fileName = "source.ts") {
256347const legacyNames = legacyNamesForFile(fileName);
257348const legacyKind = legacyNames === legacyWholeStoreAccessNames ? "access" : "reader";
@@ -405,13 +496,22 @@ export async function main() {
405496),
406497findViolations: findSessionLifecycleCleanupBoundaryViolations,
407498});
499+const sessionStoreRuntimePath = path.join(repoRoot, "src/plugin-sdk/session-store-runtime.ts");
500+const sessionStoreRuntimeCompatViolations =
501+findSessionStoreRuntimeFileBackedCompatExportViolations(
502+await fs.readFile(sessionStoreRuntimePath, "utf8"),
503+sessionStoreRuntimePath,
504+).map((violation) =>
505+Object.assign({ path: "src/plugin-sdk/session-store-runtime.ts" }, violation),
506+);
408507const violations = [
409508 ...readViolations,
410509 ...writeViolations,
411510 ...transcriptWriterViolations,
412511 ...sessionCreateLifecycleViolations,
413512 ...manualCompactTrimViolations,
414513 ...lifecycleCleanupViolations,
514+ ...sessionStoreRuntimeCompatViolations,
415515];
416516417517if (violations.length === 0) {
@@ -424,7 +524,7 @@ export async function main() {
424524console.error(`- ${violation.path}:${violation.line}: ${violation.reason}`);
425525}
426526console.error(
427-"Use src/config/sessions/session-accessor.ts helpers for migrated read/write and transcript-writer paths. Expand this ratchet only after a slice migrates more files.",
527+"Use src/config/sessions/session-accessor.ts helpers for migrated read/write and transcript-writer paths. Expand file-backed SDK compatibility only as an explicit pre-SQLite migration decision.",
428528);
429529process.exit(1);
430530}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。