mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-30 21:53:28 +08:00
121 lines
3.5 KiB
JavaScript
121 lines
3.5 KiB
JavaScript
const fs = require('fs');
|
|
const path = require('path');
|
|
const Ajv = require('ajv');
|
|
|
|
const SCHEMA_PATH = path.join(__dirname, '..', '..', 'schemas', 'install-state.schema.json');
|
|
|
|
let cachedValidator = null;
|
|
|
|
function readJson(filePath, label) {
|
|
try {
|
|
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
} catch (error) {
|
|
throw new Error(`Failed to read ${label}: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
function getValidator() {
|
|
if (cachedValidator) {
|
|
return cachedValidator;
|
|
}
|
|
|
|
const schema = readJson(SCHEMA_PATH, 'install-state schema');
|
|
const ajv = new Ajv({ allErrors: true });
|
|
cachedValidator = ajv.compile(schema);
|
|
return cachedValidator;
|
|
}
|
|
|
|
function formatValidationErrors(errors = []) {
|
|
return errors
|
|
.map(error => `${error.instancePath || '/'} ${error.message}`)
|
|
.join('; ');
|
|
}
|
|
|
|
function validateInstallState(state) {
|
|
const validator = getValidator();
|
|
const valid = validator(state);
|
|
return {
|
|
valid,
|
|
errors: validator.errors || [],
|
|
};
|
|
}
|
|
|
|
function assertValidInstallState(state, label) {
|
|
const result = validateInstallState(state);
|
|
if (!result.valid) {
|
|
throw new Error(`Invalid install-state${label ? ` (${label})` : ''}: ${formatValidationErrors(result.errors)}`);
|
|
}
|
|
}
|
|
|
|
function createInstallState(options) {
|
|
const installedAt = options.installedAt || new Date().toISOString();
|
|
const state = {
|
|
schemaVersion: 'ecc.install.v1',
|
|
installedAt,
|
|
target: {
|
|
id: options.adapter.id,
|
|
target: options.adapter.target || undefined,
|
|
kind: options.adapter.kind || undefined,
|
|
root: options.targetRoot,
|
|
installStatePath: options.installStatePath,
|
|
},
|
|
request: {
|
|
profile: options.request.profile || null,
|
|
modules: Array.isArray(options.request.modules) ? [...options.request.modules] : [],
|
|
includeComponents: Array.isArray(options.request.includeComponents)
|
|
? [...options.request.includeComponents]
|
|
: [],
|
|
excludeComponents: Array.isArray(options.request.excludeComponents)
|
|
? [...options.request.excludeComponents]
|
|
: [],
|
|
legacyLanguages: Array.isArray(options.request.legacyLanguages)
|
|
? [...options.request.legacyLanguages]
|
|
: [],
|
|
legacyMode: Boolean(options.request.legacyMode),
|
|
},
|
|
resolution: {
|
|
selectedModules: Array.isArray(options.resolution.selectedModules)
|
|
? [...options.resolution.selectedModules]
|
|
: [],
|
|
skippedModules: Array.isArray(options.resolution.skippedModules)
|
|
? [...options.resolution.skippedModules]
|
|
: [],
|
|
},
|
|
source: {
|
|
repoVersion: options.source.repoVersion || null,
|
|
repoCommit: options.source.repoCommit || null,
|
|
manifestVersion: options.source.manifestVersion,
|
|
},
|
|
operations: Array.isArray(options.operations)
|
|
? options.operations.map(operation => ({ ...operation }))
|
|
: [],
|
|
};
|
|
|
|
if (options.lastValidatedAt) {
|
|
state.lastValidatedAt = options.lastValidatedAt;
|
|
}
|
|
|
|
assertValidInstallState(state, 'create');
|
|
return state;
|
|
}
|
|
|
|
function readInstallState(filePath) {
|
|
const state = readJson(filePath, 'install-state');
|
|
assertValidInstallState(state, filePath);
|
|
return state;
|
|
}
|
|
|
|
function writeInstallState(filePath, state) {
|
|
assertValidInstallState(state, filePath);
|
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
fs.writeFileSync(filePath, `${JSON.stringify(state, null, 2)}\n`);
|
|
return state;
|
|
}
|
|
|
|
module.exports = {
|
|
createInstallState,
|
|
readInstallState,
|
|
validateInstallState,
|
|
writeInstallState,
|
|
};
|