mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-30 13:43:26 +08:00
* feat: add SQLite state store and ECC status CLI * fix: replace better-sqlite3 with sql.js to eliminate native module CI failures better-sqlite3 requires native C++ compilation (node-gyp, prebuild-install) which fails in CI across npm/pnpm on all platforms: - npm ci: lock file out of sync with native transitive deps - pnpm: native bindings not found at runtime - Windows: native compilation fails entirely sql.js is a pure JavaScript/WASM SQLite implementation with zero native dependencies. The adapter in index.js wraps the sql.js API to match the better-sqlite3 interface used by migrations.js and queries.js. Key implementation detail: sql.js db.export() implicitly ends active transactions, so the adapter defers disk writes (saveToDisk) until after transaction commit via an inTransaction guard flag. createStateStore is now async (sql.js requires async WASM init). Updated status.js, sessions-cli.js, and tests accordingly.
93 lines
2.1 KiB
JavaScript
93 lines
2.1 KiB
JavaScript
'use strict';
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const Ajv = require('ajv');
|
|
|
|
const SCHEMA_PATH = path.join(__dirname, '..', '..', '..', 'schemas', 'state-store.schema.json');
|
|
|
|
const ENTITY_DEFINITIONS = {
|
|
session: 'session',
|
|
skillRun: 'skillRun',
|
|
skillVersion: 'skillVersion',
|
|
decision: 'decision',
|
|
installState: 'installState',
|
|
governanceEvent: 'governanceEvent',
|
|
};
|
|
|
|
let cachedSchema = null;
|
|
let cachedAjv = null;
|
|
const cachedValidators = new Map();
|
|
|
|
function readSchema() {
|
|
if (cachedSchema) {
|
|
return cachedSchema;
|
|
}
|
|
|
|
cachedSchema = JSON.parse(fs.readFileSync(SCHEMA_PATH, 'utf8'));
|
|
return cachedSchema;
|
|
}
|
|
|
|
function getAjv() {
|
|
if (cachedAjv) {
|
|
return cachedAjv;
|
|
}
|
|
|
|
cachedAjv = new Ajv({
|
|
allErrors: true,
|
|
strict: false,
|
|
});
|
|
return cachedAjv;
|
|
}
|
|
|
|
function getEntityValidator(entityName) {
|
|
if (cachedValidators.has(entityName)) {
|
|
return cachedValidators.get(entityName);
|
|
}
|
|
|
|
const schema = readSchema();
|
|
const definitionName = ENTITY_DEFINITIONS[entityName];
|
|
|
|
if (!definitionName || !schema.$defs || !schema.$defs[definitionName]) {
|
|
throw new Error(`Unknown state-store schema entity: ${entityName}`);
|
|
}
|
|
|
|
const validatorSchema = {
|
|
$schema: schema.$schema,
|
|
...schema.$defs[definitionName],
|
|
$defs: schema.$defs,
|
|
};
|
|
const validator = getAjv().compile(validatorSchema);
|
|
cachedValidators.set(entityName, validator);
|
|
return validator;
|
|
}
|
|
|
|
function formatValidationErrors(errors = []) {
|
|
return errors
|
|
.map(error => `${error.instancePath || '/'} ${error.message}`)
|
|
.join('; ');
|
|
}
|
|
|
|
function validateEntity(entityName, payload) {
|
|
const validator = getEntityValidator(entityName);
|
|
const valid = validator(payload);
|
|
return {
|
|
valid,
|
|
errors: validator.errors || [],
|
|
};
|
|
}
|
|
|
|
function assertValidEntity(entityName, payload, label) {
|
|
const result = validateEntity(entityName, payload);
|
|
if (!result.valid) {
|
|
throw new Error(`Invalid ${entityName}${label ? ` (${label})` : ''}: ${formatValidationErrors(result.errors)}`);
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
assertValidEntity,
|
|
formatValidationErrors,
|
|
readSchema,
|
|
validateEntity,
|
|
};
|