/** * Manifest — 清单文件读写 * * 存储在 control-ui/clawlink-manifest.json, * 记录当前已加载的扩展点及其版本,用于 reconciliation。 */ import { readFileSync, writeFileSync, unlinkSync, existsSync } from 'node:fs'; import { join } from 'node:path'; import { logger } from '../../util/logger.js'; const MANIFEST_FILENAME = 'clawlink-manifest.json'; export interface ManifestData { bundleHash: string; /** 当前使用的注入策略。 */ strategy?: 'regex'; extensions: Record; } /** * 读取清单文件。不存在或解析失败返回 null。 */ export function readManifest(controlUiDir: string): ManifestData | null { const filepath = join(controlUiDir, MANIFEST_FILENAME); if (!existsSync(filepath)) { return null; } try { const raw = readFileSync(filepath, 'utf-8'); return JSON.parse(raw) as ManifestData; } catch (err) { logger.warn(`[ui-ext] Failed to parse manifest: ${(err as Error).message}`); return null; } } /** * 写入清单文件。 */ export function writeManifest(controlUiDir: string, data: ManifestData): void { const filepath = join(controlUiDir, MANIFEST_FILENAME); writeFileSync(filepath, JSON.stringify(data, null, 2), 'utf-8'); logger.debug('[ui-ext] Manifest written'); } /** * 删除清单文件。 */ export function removeManifest(controlUiDir: string): void { const filepath = join(controlUiDir, MANIFEST_FILENAME); if (existsSync(filepath)) { unlinkSync(filepath); logger.debug('[ui-ext] Manifest removed'); } }