aios-core
Version:
Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework
183 lines (156 loc) • 5.25 kB
JavaScript
;
const fs = require('fs-extra');
const path = require('path');
const os = require('os');
const {
parseAllAgents,
normalizeCommands,
getVisibleCommands,
} = require('../ide-sync/agent-parser');
function getCodexHome() {
return process.env.CODEX_HOME || path.join(os.homedir(), '.codex');
}
function getDefaultOptions() {
const projectRoot = process.cwd();
const envLocalDir = process.env.AIOS_CODEX_LOCAL_SKILLS_DIR;
const envGlobalDir = process.env.AIOS_CODEX_GLOBAL_SKILLS_DIR;
return {
projectRoot,
sourceDir: path.join(projectRoot, '.aios-core', 'development', 'agents'),
localSkillsDir: envLocalDir || path.join(projectRoot, '.codex', 'skills'),
globalSkillsDir: envGlobalDir || path.join(getCodexHome(), 'skills'),
global: false,
globalOnly: false,
dryRun: false,
quiet: false,
};
}
function trimText(text, max = 220) {
const normalized = String(text || '').replace(/\s+/g, ' ').trim();
if (normalized.length <= max) return normalized;
return `${normalized.slice(0, max - 3).trim()}...`;
}
function getSkillId(agentId) {
const id = String(agentId || '').trim();
if (id.startsWith('aios-')) return id;
return `aios-${id}`;
}
function buildSkillContent(agentData) {
const agent = agentData.agent || {};
const name = agent.name || agentData.id;
const title = agent.title || 'AIOS Agent';
const whenToUse = trimText(agent.whenToUse || `Use @${agentData.id} for specialized tasks.`);
const allCommands = normalizeCommands(agentData.commands || []);
const quick = getVisibleCommands(allCommands, 'quick');
const key = getVisibleCommands(allCommands, 'key');
const commands = [...quick, ...key.filter(k => !quick.some(q => q.name === k.name))]
.slice(0, 8)
.map(c => `- \`*${c.name}\` - ${c.description || 'No description'}`)
.join('\n');
const skillName = getSkillId(agentData.id);
const description = trimText(`${title} (${name}). ${whenToUse}`, 180);
return `---
name: ${skillName}
description: ${description}
---
# AIOS ${title} Activator
## When To Use
${whenToUse}
## Activation Protocol
1. Load \`.aios-core/development/agents/${agentData.filename}\` as source of truth (fallback: \`.codex/agents/${agentData.filename}\`).
2. Adopt this agent persona and command system.
3. Generate greeting via \`node .aios-core/development/scripts/generate-greeting.js ${agentData.id}\` and show it first.
4. Stay in this persona until the user asks to switch or exit.
## Starter Commands
${commands || '- `*help` - List available commands'}
## Non-Negotiables
- Follow \`.aios-core/constitution.md\`.
- Execute workflows/tasks only from declared dependencies.
- Do not invent requirements outside the project artifacts.
`;
}
function buildSkillPlan(agents, skillsDir) {
return agents
.filter(a => !a.error || a.error === 'YAML parse failed, using fallback extraction')
.map(agentData => {
const skillId = getSkillId(agentData.id);
const targetDir = path.join(skillsDir, skillId);
const targetFile = path.join(targetDir, 'SKILL.md');
return {
agentId: agentData.id,
skillId,
targetDir,
targetFile,
content: buildSkillContent(agentData),
};
});
}
function writeSkillPlan(plan, options) {
for (const item of plan) {
if (!options.dryRun) {
try {
fs.ensureDirSync(item.targetDir);
fs.writeFileSync(item.targetFile, item.content, 'utf8');
} catch (error) {
throw new Error(`Failed to write skill ${item.skillId} at ${item.targetFile}: ${error.message}`);
}
}
}
}
function syncSkills(options = {}) {
const resolved = { ...getDefaultOptions(), ...options };
if (resolved.globalOnly) {
resolved.global = true;
}
const agents = parseAllAgents(resolved.sourceDir);
const plan = buildSkillPlan(agents, resolved.localSkillsDir);
if (!resolved.globalOnly) {
writeSkillPlan(plan, resolved);
}
if (resolved.global) {
const globalPlan = buildSkillPlan(agents, resolved.globalSkillsDir);
writeSkillPlan(globalPlan, resolved);
}
return {
generated: plan.length,
localSkillsDir: resolved.localSkillsDir,
globalSkillsDir: resolved.global || resolved.globalOnly ? resolved.globalSkillsDir : null,
dryRun: resolved.dryRun,
};
}
function parseArgs(argv = process.argv.slice(2)) {
const args = new Set(argv);
return {
global: args.has('--global'),
globalOnly: args.has('--global-only'),
dryRun: args.has('--dry-run'),
quiet: args.has('--quiet') || args.has('-q'),
};
}
function main() {
const options = parseArgs();
const result = syncSkills(options);
if (!options.quiet) {
if (!options.globalOnly) {
console.log(`✅ Generated ${result.generated} Codex skills in ${result.localSkillsDir}`);
}
if (result.globalSkillsDir) {
console.log(`✅ Installed ${result.generated} Codex skills in ${result.globalSkillsDir}`);
}
if (result.dryRun) {
console.log('ℹ️ Dry-run mode: no files written');
}
}
}
if (require.main === module) {
main();
}
module.exports = {
buildSkillContent,
buildSkillPlan,
syncSkills,
parseArgs,
getCodexHome,
getSkillId,
};