aios-core
Version:
Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework
356 lines (319 loc) • 12.7 kB
JavaScript
;
const fs = require('fs');
const path = require('path');
const yaml = require('js-yaml');
const { spawnSync } = require('child_process');
const { validateClaudeIntegration } = require('./validate-claude-integration');
const { validateCodexIntegration } = require('./validate-codex-integration');
const { validateGeminiIntegration } = require('./validate-gemini-integration');
const { validateCodexSkills } = require('./codex-skills-sync/validate');
const { validatePaths } = require('./validate-paths');
function parseArgs(argv = process.argv.slice(2)) {
const args = new Set(
argv.filter((arg) => !arg.startsWith('--contract=') && !arg.startsWith('--diff=')),
);
const contractArg = argv.find((arg) => arg.startsWith('--contract='));
const diffArg = argv.find((arg) => arg.startsWith('--diff='));
return {
quiet: args.has('--quiet') || args.has('-q'),
json: args.has('--json'),
contractPath: contractArg ? contractArg.slice('--contract='.length) : null,
diffPath: diffArg ? diffArg.slice('--diff='.length) : null,
};
}
function runSyncValidate(ide, projectRoot) {
const script = path.join('.aios-core', 'infrastructure', 'scripts', 'ide-sync', 'index.js');
const result = spawnSync('node', [script, 'validate', '--ide', ide, '--strict'], {
cwd: projectRoot,
encoding: 'utf8',
});
return {
ok: result.status === 0,
errors: result.status === 0 ? [] : [`Sync validation failed for ${ide}`],
warnings: [],
raw: result.stdout || result.stderr || '',
};
}
function getDefaultContractPath(projectRoot = process.cwd()) {
return path.join(
projectRoot,
'.aios-core',
'infrastructure',
'contracts',
'compatibility',
'aios-4.0.4.yaml',
);
}
function loadCompatibilityContract(contractPath) {
if (!contractPath || !fs.existsSync(contractPath)) {
return null;
}
const raw = fs.readFileSync(contractPath, 'utf8');
return yaml.load(raw);
}
function normalizeResult(input) {
if (!input || typeof input !== 'object') {
return { ok: false, errors: ['Validator returned invalid result'], warnings: [] };
}
return {
ok: Boolean(input.ok),
errors: Array.isArray(input.errors) ? input.errors : [],
warnings: Array.isArray(input.warnings) ? input.warnings : [],
metrics: input.metrics || {},
};
}
function escapeRegex(value) {
return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function validateCompatibilityContract(contract, resultById, options = {}) {
const violations = [];
if (!contract || typeof contract !== 'object') {
return ['Compatibility contract is missing or invalid'];
}
const matrix = Array.isArray(contract.ide_matrix) ? contract.ide_matrix : [];
if (matrix.length === 0) {
return ['Compatibility contract ide_matrix is empty'];
}
const docsPath = options.docsPath;
if (!docsPath || !fs.existsSync(docsPath)) {
violations.push(`Compatibility matrix document not found: ${docsPath || 'undefined'}`);
return violations;
}
const docsContent = fs.readFileSync(docsPath, 'utf8');
for (const ide of matrix) {
const ideName = ide.ide || 'unknown';
const displayName = ide.display_name || ideName;
const requiredChecks = Array.isArray(ide.required_checks) ? ide.required_checks : [];
const expectedStatus = ide.expected_status;
if (!expectedStatus) {
violations.push(`Contract missing expected_status for IDE "${ideName}"`);
}
const rowRegex = new RegExp(
`\\|\\s*${escapeRegex(displayName)}\\s*\\|\\s*${escapeRegex(expectedStatus || '')}\\s*\\|`,
'i',
);
if (!rowRegex.test(docsContent)) {
violations.push(
`Docs matrix mismatch for "${displayName}": expected status "${expectedStatus}" in ${options.docsPathRelative}`,
);
}
for (const checkId of requiredChecks) {
const checkResult = resultById[checkId];
if (!checkResult) {
violations.push(`Contract requires unknown check "${checkId}" for IDE "${ideName}"`);
continue;
}
if (!checkResult.ok) {
violations.push(`Contract violation for "${ideName}": required check "${checkId}" failed`);
}
}
}
const globalRequiredChecks = Array.isArray(contract.global_required_checks)
? contract.global_required_checks
: [];
for (const checkId of globalRequiredChecks) {
const checkResult = resultById[checkId];
if (!checkResult) {
violations.push(`Contract requires unknown global check "${checkId}"`);
continue;
}
if (!checkResult.ok) {
violations.push(`Contract violation: global required check "${checkId}" failed`);
}
}
return violations;
}
function sortUnique(values = []) {
return [...new Set(values)].sort();
}
function diffCompatibilityContracts(currentContract, previousContract) {
if (!currentContract || !previousContract) {
return null;
}
const currentRelease = currentContract.release || null;
const previousRelease = previousContract.release || null;
const releaseChanged = currentRelease !== previousRelease;
const currentGlobalChecks = sortUnique(currentContract.global_required_checks || []);
const previousGlobalChecks = sortUnique(previousContract.global_required_checks || []);
const globalChecksAdded = currentGlobalChecks.filter((item) => !previousGlobalChecks.includes(item));
const globalChecksRemoved = previousGlobalChecks.filter((item) => !currentGlobalChecks.includes(item));
const currentByIde = Object.fromEntries((currentContract.ide_matrix || []).map((item) => [item.ide, item]));
const previousByIde = Object.fromEntries((previousContract.ide_matrix || []).map((item) => [item.ide, item]));
const ideKeys = sortUnique([...Object.keys(currentByIde), ...Object.keys(previousByIde)]);
const ideChanges = [];
for (const ide of ideKeys) {
const current = currentByIde[ide];
const previous = previousByIde[ide];
if (!previous && current) {
ideChanges.push({ ide, type: 'added', current });
continue;
}
if (previous && !current) {
ideChanges.push({ ide, type: 'removed', previous });
continue;
}
const currentStatus = current.expected_status || null;
const previousStatus = previous.expected_status || null;
const statusChanged = currentStatus !== previousStatus;
const currentChecks = sortUnique(current.required_checks || []);
const previousChecks = sortUnique(previous.required_checks || []);
const checksAdded = currentChecks.filter((item) => !previousChecks.includes(item));
const checksRemoved = previousChecks.filter((item) => !currentChecks.includes(item));
if (statusChanged || checksAdded.length > 0 || checksRemoved.length > 0) {
ideChanges.push({
ide,
type: 'changed',
status: { previous: previousStatus, current: currentStatus },
required_checks: {
added: checksAdded,
removed: checksRemoved,
},
});
}
}
return {
from_release: previousRelease,
to_release: currentRelease,
release_changed: releaseChanged,
global_required_checks: {
added: globalChecksAdded,
removed: globalChecksRemoved,
},
ide_changes: ideChanges,
has_changes:
releaseChanged
|| globalChecksAdded.length > 0
|| globalChecksRemoved.length > 0
|| ideChanges.length > 0,
};
}
function runParityValidation(options = {}, deps = {}) {
const projectRoot = options.projectRoot || process.cwd();
const runSync = deps.runSyncValidate || runSyncValidate;
const runClaudeIntegration = deps.validateClaudeIntegration || validateClaudeIntegration;
const runCodexIntegration = deps.validateCodexIntegration || validateCodexIntegration;
const runGeminiIntegration = deps.validateGeminiIntegration || validateGeminiIntegration;
const runCodexSkills = deps.validateCodexSkills || validateCodexSkills;
const runPaths = deps.validatePaths || validatePaths;
const resolvedContractPath = options.contractPath
? path.resolve(projectRoot, options.contractPath)
: getDefaultContractPath(projectRoot);
const loadContract = deps.loadCompatibilityContract || loadCompatibilityContract;
const contract = loadContract(resolvedContractPath);
const resolvedDiffPath = options.diffPath ? path.resolve(projectRoot, options.diffPath) : null;
const previousContract = resolvedDiffPath ? loadContract(resolvedDiffPath) : null;
const docsPath = path.join(projectRoot, 'docs', 'ide-integration.md');
const docsPathRelative = path.relative(projectRoot, docsPath);
const checks = [
{ id: 'claude-sync', exec: () => runSync('claude-code', projectRoot) },
{ id: 'claude-integration', exec: () => runClaudeIntegration({ projectRoot }) },
{ id: 'codex-sync', exec: () => runSync('codex', projectRoot) },
{ id: 'codex-integration', exec: () => runCodexIntegration({ projectRoot }) },
{ id: 'gemini-sync', exec: () => runSync('gemini', projectRoot) },
{ id: 'gemini-integration', exec: () => runGeminiIntegration({ projectRoot }) },
{ id: 'cursor-sync', exec: () => runSync('cursor', projectRoot) },
{ id: 'github-copilot-sync', exec: () => runSync('github-copilot', projectRoot) },
{ id: 'antigravity-sync', exec: () => runSync('antigravity', projectRoot) },
{ id: 'codex-skills', exec: () => runCodexSkills({ projectRoot, strict: true, quiet: true }) },
{ id: 'paths', exec: () => runPaths({ projectRoot }) },
];
const results = checks.map((check) => {
const normalized = normalizeResult(check.exec());
return { id: check.id, ...normalized };
});
const resultById = Object.fromEntries(results.map((r) => [r.id, r]));
const contractViolations = validateCompatibilityContract(contract, resultById, {
docsPath,
docsPathRelative,
});
const contractSummary = contract
? {
release: contract.release || null,
path: path.relative(projectRoot, resolvedContractPath),
}
: {
release: null,
path: path.relative(projectRoot, resolvedContractPath),
};
return {
ok: results.every((r) => r.ok) && contractViolations.length === 0,
checks: results,
contract: contractSummary,
contractDiff: diffCompatibilityContracts(contract, previousContract),
contractViolations,
};
}
function formatHumanReport(result) {
const lines = [];
if (result.contract && result.contract.release) {
lines.push(`Compatibility Contract: ${result.contract.release} (${result.contract.path})`);
lines.push('');
}
if (result.contractDiff) {
lines.push(
`Contract Diff: ${result.contractDiff.from_release || 'unknown'} -> ${result.contractDiff.to_release || 'unknown'}`,
);
if (!result.contractDiff.has_changes) {
lines.push('- no changes');
} else {
if (result.contractDiff.release_changed) {
lines.push('- release changed');
}
const globalAdded = result.contractDiff.global_required_checks.added || [];
const globalRemoved = result.contractDiff.global_required_checks.removed || [];
if (globalAdded.length > 0) {
lines.push(`- global checks added: ${globalAdded.join(', ')}`);
}
if (globalRemoved.length > 0) {
lines.push(`- global checks removed: ${globalRemoved.join(', ')}`);
}
for (const ideChange of result.contractDiff.ide_changes || []) {
lines.push(`- ${ideChange.ide}: ${ideChange.type}`);
}
}
lines.push('');
}
for (const check of result.checks) {
lines.push(`${check.ok ? '✅' : '❌'} ${check.id}`);
if (check.errors.length > 0) {
lines.push(...check.errors.map((e) => `- ${e}`));
}
if (check.warnings.length > 0) {
lines.push(...check.warnings.map((w) => `⚠️ ${w}`));
}
}
if (Array.isArray(result.contractViolations) && result.contractViolations.length > 0) {
lines.push('');
lines.push('❌ Compatibility Contract Violations');
lines.push(...result.contractViolations.map((v) => `- ${v}`));
}
lines.push('');
lines.push(result.ok ? '✅ Parity validation passed' : '❌ Parity validation failed');
return lines.join('\n');
}
function main() {
const args = parseArgs();
const result = runParityValidation(args);
if (!args.quiet) {
if (args.json) {
console.log(JSON.stringify(result, null, 2));
} else {
console.log(formatHumanReport(result));
}
}
if (!result.ok) {
process.exitCode = 1;
}
}
if (require.main === module) {
main();
}
module.exports = {
parseArgs,
runSyncValidate,
runParityValidation,
normalizeResult,
formatHumanReport,
diffCompatibilityContracts,
};