

























@@ -0,0 +1,118 @@
1+import path from "node:path";
2+import { z } from "zod";
3+import { resolveStateDir } from "../config/paths.js";
4+import { readJsonFile, writeJsonAtomic } from "../infra/json-files.js";
5+import { safeParseWithSchema } from "../utils/zod-parse.js";
6+import {
7+INSTALLED_PLUGIN_INDEX_VERSION,
8+refreshInstalledPluginIndex,
9+type InstalledPluginIndex,
10+type RefreshInstalledPluginIndexParams,
11+} from "./installed-plugin-index.js";
12+13+const INSTALLED_PLUGIN_INDEX_STORE_PATH = path.join("plugins", "installed-index.json");
14+15+export type InstalledPluginIndexStoreOptions = {
16+env?: NodeJS.ProcessEnv;
17+stateDir?: string;
18+filePath?: string;
19+};
20+21+const ContributionArraySchema = z.array(z.string());
22+23+const InstalledPluginIndexContributionsSchema = z
24+.object({
25+providers: ContributionArraySchema,
26+channels: ContributionArraySchema,
27+channelConfigs: ContributionArraySchema,
28+setupProviders: ContributionArraySchema,
29+cliBackends: ContributionArraySchema,
30+modelCatalogProviders: ContributionArraySchema,
31+commandAliases: ContributionArraySchema,
32+contracts: ContributionArraySchema,
33+})
34+.passthrough();
35+36+const InstalledPluginIndexRecordSchema = z
37+.object({
38+pluginId: z.string(),
39+packageName: z.string().optional(),
40+packageVersion: z.string().optional(),
41+installRecord: z.record(z.string(), z.unknown()).optional(),
42+installRecordHash: z.string().optional(),
43+packageInstall: z.unknown().optional(),
44+manifestPath: z.string(),
45+manifestHash: z.string(),
46+packageJsonPath: z.string().optional(),
47+packageJsonHash: z.string().optional(),
48+rootDir: z.string(),
49+origin: z.string(),
50+enabled: z.boolean(),
51+contributions: InstalledPluginIndexContributionsSchema,
52+compat: z.array(z.string()),
53+})
54+.passthrough();
55+56+const PluginDiagnosticSchema = z
57+.object({
58+level: z.union([z.literal("warn"), z.literal("error")]),
59+message: z.string(),
60+pluginId: z.string().optional(),
61+source: z.string().optional(),
62+})
63+.passthrough();
64+65+const InstalledPluginIndexSchema = z
66+.object({
67+version: z.literal(INSTALLED_PLUGIN_INDEX_VERSION),
68+hostContractVersion: z.string(),
69+compatRegistryVersion: z.string(),
70+generatedAt: z.string(),
71+refreshReason: z.string().optional(),
72+plugins: z.array(InstalledPluginIndexRecordSchema),
73+diagnostics: z.array(PluginDiagnosticSchema),
74+})
75+.passthrough();
76+77+function parseInstalledPluginIndex(value: unknown): InstalledPluginIndex | null {
78+return safeParseWithSchema(InstalledPluginIndexSchema, value) as InstalledPluginIndex | null;
79+}
80+81+export function resolveInstalledPluginIndexStorePath(
82+options: InstalledPluginIndexStoreOptions = {},
83+): string {
84+if (options.filePath) {
85+return options.filePath;
86+}
87+const env = options.env ?? process.env;
88+const stateDir = options.stateDir ?? resolveStateDir(env);
89+return path.join(stateDir, INSTALLED_PLUGIN_INDEX_STORE_PATH);
90+}
91+92+export async function readPersistedInstalledPluginIndex(
93+options: InstalledPluginIndexStoreOptions = {},
94+): Promise<InstalledPluginIndex | null> {
95+const parsed = await readJsonFile<unknown>(resolveInstalledPluginIndexStorePath(options));
96+return parseInstalledPluginIndex(parsed);
97+}
98+99+export async function writePersistedInstalledPluginIndex(
100+index: InstalledPluginIndex,
101+options: InstalledPluginIndexStoreOptions = {},
102+): Promise<string> {
103+const filePath = resolveInstalledPluginIndexStorePath(options);
104+await writeJsonAtomic(filePath, index, {
105+trailingNewline: true,
106+ensureDirMode: 0o700,
107+mode: 0o600,
108+});
109+return filePath;
110+}
111+112+export async function refreshPersistedInstalledPluginIndex(
113+params: RefreshInstalledPluginIndexParams & InstalledPluginIndexStoreOptions,
114+): Promise<InstalledPluginIndex> {
115+const index = refreshInstalledPluginIndex(params);
116+await writePersistedInstalledPluginIndex(index, params);
117+return index;
118+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。