Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .aios-core/core/synapse/layers/layer-processor.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class LayerProcessor {
* @param {object[]} context.previousLayers - Results from previous layers
* @returns {{ rules: string[], metadata: object } | null} Rules and metadata, or null to skip
*/
process(context) {
process(_context) {
throw new Error(`${this.name}: process() must be implemented by subclass`);
}

Expand Down Expand Up @@ -80,3 +80,5 @@ class LayerProcessor {
}

module.exports = LayerProcessor;


105 changes: 105 additions & 0 deletions .aios-core/infrastructure/scripts/validate-claude-integration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env node
'use strict';

const fs = require('fs');
const path = require('path');
const { loadConfig } = require('./ide-sync/index');

function parseArgs(argv = process.argv.slice(2)) {
const args = new Set(argv);
return {
quiet: args.has('--quiet') || args.has('-q'),
json: args.has('--json'),
};
}

function countMarkdownFiles(dirPath) {
if (!fs.existsSync(dirPath)) return 0;
return fs.readdirSync(dirPath).filter((f) => f.endsWith('.md')).length;
}

function validateClaudeIntegration(options = {}) {
const projectRoot = options.projectRoot || process.cwd();
const rulesFile = options.rulesFile || path.join(projectRoot, '.claude', 'CLAUDE.md');
const agentsDir = options.agentsDir || path.join(projectRoot, '.claude', 'commands', 'AIOS', 'agents');
const hooksDir = options.hooksDir || path.join(projectRoot, '.claude', 'hooks');
const sourceAgentsDir =
options.sourceAgentsDir || path.join(projectRoot, '.aios-core', 'development', 'agents');

const errors = [];
const warnings = [];

if (!fs.existsSync(agentsDir)) {
errors.push(`Missing Claude agents dir: ${path.relative(projectRoot, agentsDir)}`);
}
if (!fs.existsSync(rulesFile)) {
warnings.push(`Claude rules file not found yet: ${path.relative(projectRoot, rulesFile)}`);
}
if (!fs.existsSync(hooksDir)) {
warnings.push(`Claude hooks dir not found yet: ${path.relative(projectRoot, hooksDir)}`);
}

const sourceCount = countMarkdownFiles(sourceAgentsDir);
const claudeCount = countMarkdownFiles(agentsDir);
const redirectCount = Object.keys((loadConfig(projectRoot).redirects || {})).length;
const expectedCount = sourceCount > 0 ? sourceCount + redirectCount : sourceCount;
if (expectedCount > 0 && claudeCount !== expectedCount) {
warnings.push(`Claude agent count differs from expected (${claudeCount}/${expectedCount})`);
}

return {
ok: errors.length === 0,
errors,
warnings,
metrics: {
sourceAgents: sourceCount,
claudeAgents: claudeCount,
expectedAgents: expectedCount,
},
};
}

function formatHumanReport(result) {
if (result.ok) {
const lines = [`✅ Claude integration validation passed (agents: ${result.metrics.claudeAgents})`];
if (result.warnings.length > 0) {
lines.push(...result.warnings.map((w) => `⚠️ ${w}`));
}
return lines.join('\n');
}
const lines = [
`❌ Claude integration validation failed (${result.errors.length} issue(s))`,
...result.errors.map((e) => `- ${e}`),
];
if (result.warnings.length > 0) {
lines.push(...result.warnings.map((w) => `⚠️ ${w}`));
}
return lines.join('\n');
}

function main() {
const args = parseArgs();
const result = validateClaudeIntegration(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 = {
validateClaudeIntegration,
parseArgs,
countMarkdownFiles,
};
145 changes: 145 additions & 0 deletions .aios-core/infrastructure/scripts/validate-codex-integration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#!/usr/bin/env node
'use strict';

const fs = require('fs');
const path = require('path');
const { loadConfig } = require('./ide-sync/index');

function getDefaultOptions() {
const projectRoot = process.cwd();
return {
projectRoot,
instructionsFile: path.join(projectRoot, 'AGENTS.md'),
agentsDir: path.join(projectRoot, '.codex', 'agents'),
skillsDir: path.join(projectRoot, '.codex', 'skills'),
sourceAgentsDir: path.join(projectRoot, '.aios-core', 'development', 'agents'),
quiet: false,
json: false,
};
}

function parseArgs(argv = process.argv.slice(2)) {
const args = new Set(argv);
return {
quiet: args.has('--quiet') || args.has('-q'),
json: args.has('--json'),
};
}

function countMarkdownFiles(dirPath) {
if (!fs.existsSync(dirPath)) return 0;
return fs.readdirSync(dirPath).filter((f) => f.endsWith('.md')).length;
}

function countSkillFiles(skillsDir) {
if (!fs.existsSync(skillsDir)) return 0;
const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
return entries
.filter((entry) => entry.isDirectory() && entry.name.startsWith('aios-'))
.filter((entry) => fs.existsSync(path.join(skillsDir, entry.name, 'SKILL.md')))
.length;
}

function validateCodexIntegration(options = {}) {
const projectRoot = options.projectRoot || process.cwd();
const resolved = {
...getDefaultOptions(),
...options,
projectRoot,
instructionsFile: options.instructionsFile || path.join(projectRoot, 'AGENTS.md'),
agentsDir: options.agentsDir || path.join(projectRoot, '.codex', 'agents'),
skillsDir: options.skillsDir || path.join(projectRoot, '.codex', 'skills'),
sourceAgentsDir: options.sourceAgentsDir || path.join(projectRoot, '.aios-core', 'development', 'agents'),
};
const errors = [];
const warnings = [];

if (!fs.existsSync(resolved.instructionsFile)) {
warnings.push(
`Codex instructions file not found yet: ${path.relative(resolved.projectRoot, resolved.instructionsFile)}`,
);
}

if (!fs.existsSync(resolved.agentsDir)) {
errors.push(`Missing Codex agents dir: ${path.relative(resolved.projectRoot, resolved.agentsDir)}`);
}

if (!fs.existsSync(resolved.skillsDir)) {
errors.push(`Missing Codex skills dir: ${path.relative(resolved.projectRoot, resolved.skillsDir)}`);
}

const sourceCount = countMarkdownFiles(resolved.sourceAgentsDir);
const codexAgentsCount = countMarkdownFiles(resolved.agentsDir);
const codexSkillsCount = countSkillFiles(resolved.skillsDir);
const redirectCount = Object.keys((loadConfig(projectRoot).redirects || {})).length;
const expectedAgents = sourceCount > 0 ? sourceCount + redirectCount : sourceCount;

if (expectedAgents > 0 && codexAgentsCount !== expectedAgents) {
warnings.push(`Codex agent count differs from expected (${codexAgentsCount}/${expectedAgents})`);
}

if (sourceCount > 0 && codexSkillsCount !== sourceCount) {
warnings.push(`Codex skill count differs from source (${codexSkillsCount}/${sourceCount})`);
}

return {
ok: errors.length === 0,
errors,
warnings,
metrics: {
sourceAgents: sourceCount,
expectedAgents,
codexAgents: codexAgentsCount,
codexSkills: codexSkillsCount,
},
};
}

function formatHumanReport(result) {
if (result.ok) {
const lines = [
`✅ Codex integration validation passed (agents: ${result.metrics.codexAgents}, skills: ${result.metrics.codexSkills})`,
];
if (result.warnings.length > 0) {
lines.push(...result.warnings.map((w) => `⚠️ ${w}`));
}
return lines.join('\n');
}
const lines = [
`❌ Codex integration validation failed (${result.errors.length} issue(s))`,
...result.errors.map((e) => `- ${e}`),
];
if (result.warnings.length > 0) {
lines.push(...result.warnings.map((w) => `⚠️ ${w}`));
}
return lines.join('\n');
}

function main() {
const args = parseArgs();
const result = validateCodexIntegration(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 = {
validateCodexIntegration,
parseArgs,
getDefaultOptions,
countMarkdownFiles,
countSkillFiles,
};
Loading