aios-core 4.0.4 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.aios-core/cli/commands/migrate/analyze.js +6 -6
- package/.aios-core/cli/commands/migrate/backup.js +2 -2
- package/.aios-core/cli/commands/migrate/execute.js +4 -4
- package/.aios-core/cli/commands/migrate/index.js +5 -5
- package/.aios-core/cli/commands/migrate/rollback.js +6 -6
- package/.aios-core/cli/commands/migrate/update-imports.js +2 -2
- package/.aios-core/cli/commands/migrate/validate.js +2 -2
- package/.aios-core/cli/commands/pro/index.js +52 -0
- package/.aios-core/cli/index.js +1 -1
- package/.aios-core/core/ids/registry-updater.js +29 -3
- package/.aios-core/core/migration/migration-config.yaml +2 -2
- package/.aios-core/core/migration/module-mapping.yaml +2 -2
- package/.aios-core/core/registry/README.md +2 -2
- package/.aios-core/core/synapse/context/context-builder.js +34 -0
- package/.aios-core/core/synapse/diagnostics/collectors/consistency-collector.js +168 -0
- package/.aios-core/core/synapse/diagnostics/collectors/hook-collector.js +129 -0
- package/.aios-core/core/synapse/diagnostics/collectors/manifest-collector.js +82 -0
- package/.aios-core/core/synapse/diagnostics/collectors/output-analyzer.js +134 -0
- package/.aios-core/core/synapse/diagnostics/collectors/pipeline-collector.js +75 -0
- package/.aios-core/core/synapse/diagnostics/collectors/quality-collector.js +252 -0
- package/.aios-core/core/synapse/diagnostics/collectors/relevance-matrix.js +174 -0
- package/.aios-core/core/synapse/diagnostics/collectors/safe-read-json.js +31 -0
- package/.aios-core/core/synapse/diagnostics/collectors/session-collector.js +102 -0
- package/.aios-core/core/synapse/diagnostics/collectors/timing-collector.js +126 -0
- package/.aios-core/core/synapse/diagnostics/collectors/uap-collector.js +83 -0
- package/.aios-core/core/synapse/diagnostics/report-formatter.js +484 -0
- package/.aios-core/core/synapse/diagnostics/synapse-diagnostics.js +95 -0
- package/.aios-core/core/synapse/engine.js +73 -20
- package/.aios-core/core/synapse/runtime/hook-runtime.js +60 -0
- package/.aios-core/core-config.yaml +6 -0
- package/.aios-core/data/agent-config-requirements.yaml +2 -2
- package/.aios-core/data/aios-kb.md +4 -4
- package/.aios-core/data/entity-registry.yaml +210 -10
- package/.aios-core/data/registry-update-log.jsonl +52 -0
- package/.aios-core/development/agents/architect.md +10 -10
- package/.aios-core/development/agents/devops.md +93 -50
- package/.aios-core/development/agents/qa.md +94 -40
- package/.aios-core/development/agents/ux-design-expert.md +25 -25
- package/.aios-core/development/scripts/activation-runtime.js +63 -0
- package/.aios-core/development/scripts/generate-greeting.js +9 -8
- package/.aios-core/development/scripts/unified-activation-pipeline.js +102 -2
- package/.aios-core/development/tasks/{db-expansion-pack-integration.md → db-squad-integration.md} +5 -5
- package/.aios-core/development/tasks/{integrate-expansion-pack.md → integrate-squad.md} +2 -2
- package/.aios-core/development/tasks/next.md +3 -3
- package/.aios-core/development/tasks/pr-automation.md +2 -2
- package/.aios-core/development/tasks/publish-npm.md +257 -0
- package/.aios-core/development/tasks/release-management.md +4 -4
- package/.aios-core/development/tasks/setup-github.md +1 -1
- package/.aios-core/development/tasks/squad-creator-migrate.md +1 -1
- package/.aios-core/development/tasks/squad-creator-sync-ide-command.md +14 -14
- package/.aios-core/development/tasks/update-aios.md +1 -1
- package/.aios-core/development/tasks/validate-next-story.md +99 -2
- package/.aios-core/docs/standards/AIOS-COLOR-PALETTE-QUICK-REFERENCE.md +1 -1
- package/.aios-core/docs/standards/AIOS-COLOR-PALETTE-V2.1.md +5 -5
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-COMPLETE.md +21 -21
- package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.2-SUMMARY.md +25 -25
- package/.aios-core/docs/standards/OPEN-SOURCE-VS-SERVICE-DIFFERENCES.md +4 -4
- package/.aios-core/docs/standards/QUALITY-GATES-SPECIFICATION.md +3 -3
- package/.aios-core/docs/standards/STANDARDS-INDEX.md +13 -13
- package/.aios-core/docs/standards/STORY-TEMPLATE-V2-SPECIFICATION.md +1 -1
- package/.aios-core/framework-config.yaml +4 -0
- package/.aios-core/infrastructure/scripts/codex-skills-sync/index.js +182 -0
- package/.aios-core/infrastructure/scripts/codex-skills-sync/validate.js +172 -0
- package/.aios-core/infrastructure/scripts/ide-sync/README.md +14 -0
- package/.aios-core/infrastructure/scripts/ide-sync/index.js +6 -0
- package/.aios-core/infrastructure/scripts/tool-resolver.js +4 -4
- package/.aios-core/infrastructure/scripts/validate-paths.js +142 -0
- package/.aios-core/infrastructure/templates/aios-sync.yaml.template +11 -11
- package/.aios-core/infrastructure/templates/github-workflows/README.md +1 -1
- package/.aios-core/install-manifest.yaml +193 -109
- package/.aios-core/local-config.yaml.template +2 -0
- package/.aios-core/manifests/agents.csv +29 -1
- package/.aios-core/manifests/tasks.csv +80 -3
- package/.aios-core/product/README.md +2 -2
- package/.aios-core/product/data/integration-patterns.md +1 -1
- package/.aios-core/product/templates/ide-rules/cline-rules.md +1 -1
- package/.aios-core/product/templates/ide-rules/codex-rules.md +65 -0
- package/.aios-core/product/templates/ide-rules/copilot-rules.md +1 -1
- package/.aios-core/product/templates/ide-rules/roo-rules.md +1 -1
- package/.aios-core/user-guide.md +15 -14
- package/.aios-core/workflow-intelligence/engine/output-formatter.js +1 -1
- package/.claude/hooks/synapse-engine.js +9 -20
- package/README.md +14 -7
- package/bin/aios-init.js +255 -184
- package/bin/aios-minimal.js +2 -2
- package/bin/aios.js +4 -4
- package/package.json +6 -1
- package/packages/aios-pro-cli/bin/aios-pro.js +75 -2
- package/packages/aios-pro-cli/package.json +5 -1
- package/packages/aios-pro-cli/src/recover.js +100 -0
- package/packages/installer/src/__tests__/performance-benchmark.js +382 -0
- package/packages/installer/src/config/ide-configs.js +12 -1
- package/packages/installer/src/config/templates/core-config-template.js +2 -2
- package/packages/installer/src/installer/aios-core-installer.js +2 -2
- package/packages/installer/src/installer/file-hasher.js +97 -0
- package/packages/installer/src/installer/post-install-validator.js +41 -1
- package/packages/installer/src/pro/pro-scaffolder.js +335 -0
- package/packages/installer/src/utils/aios-colors.js +2 -2
- package/packages/installer/src/wizard/feedback.js +1 -1
- package/packages/installer/src/wizard/ide-config-generator.js +2 -2
- package/packages/installer/src/wizard/index.js +58 -19
- package/packages/installer/src/wizard/pro-setup.js +931 -0
- package/packages/installer/src/wizard/questions.js +20 -14
- package/packages/installer/src/wizard/validators.js +1 -1
- package/scripts/code-intel-health-check.js +343 -0
- package/scripts/package-synapse.js +323 -0
- package/scripts/validate-package-completeness.js +317 -0
|
@@ -123,6 +123,10 @@ ide_sync_system:
|
|
|
123
123
|
enabled: true
|
|
124
124
|
path: ".claude/commands/AIOS/agents"
|
|
125
125
|
format: "full-markdown-yaml"
|
|
126
|
+
codex:
|
|
127
|
+
enabled: true
|
|
128
|
+
path: ".codex/agents"
|
|
129
|
+
format: "full-markdown-yaml"
|
|
126
130
|
cursor:
|
|
127
131
|
enabled: true
|
|
128
132
|
path: ".cursor/rules/agents"
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs-extra');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
parseAllAgents,
|
|
10
|
+
normalizeCommands,
|
|
11
|
+
getVisibleCommands,
|
|
12
|
+
} = require('../ide-sync/agent-parser');
|
|
13
|
+
|
|
14
|
+
function getCodexHome() {
|
|
15
|
+
return process.env.CODEX_HOME || path.join(os.homedir(), '.codex');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getDefaultOptions() {
|
|
19
|
+
const projectRoot = process.cwd();
|
|
20
|
+
const envLocalDir = process.env.AIOS_CODEX_LOCAL_SKILLS_DIR;
|
|
21
|
+
const envGlobalDir = process.env.AIOS_CODEX_GLOBAL_SKILLS_DIR;
|
|
22
|
+
return {
|
|
23
|
+
projectRoot,
|
|
24
|
+
sourceDir: path.join(projectRoot, '.aios-core', 'development', 'agents'),
|
|
25
|
+
localSkillsDir: envLocalDir || path.join(projectRoot, '.codex', 'skills'),
|
|
26
|
+
globalSkillsDir: envGlobalDir || path.join(getCodexHome(), 'skills'),
|
|
27
|
+
global: false,
|
|
28
|
+
globalOnly: false,
|
|
29
|
+
dryRun: false,
|
|
30
|
+
quiet: false,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function trimText(text, max = 220) {
|
|
35
|
+
const normalized = String(text || '').replace(/\s+/g, ' ').trim();
|
|
36
|
+
if (normalized.length <= max) return normalized;
|
|
37
|
+
return `${normalized.slice(0, max - 3).trim()}...`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getSkillId(agentId) {
|
|
41
|
+
const id = String(agentId || '').trim();
|
|
42
|
+
if (id.startsWith('aios-')) return id;
|
|
43
|
+
return `aios-${id}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function buildSkillContent(agentData) {
|
|
47
|
+
const agent = agentData.agent || {};
|
|
48
|
+
const name = agent.name || agentData.id;
|
|
49
|
+
const title = agent.title || 'AIOS Agent';
|
|
50
|
+
const whenToUse = trimText(agent.whenToUse || `Use @${agentData.id} for specialized tasks.`);
|
|
51
|
+
|
|
52
|
+
const allCommands = normalizeCommands(agentData.commands || []);
|
|
53
|
+
const quick = getVisibleCommands(allCommands, 'quick');
|
|
54
|
+
const key = getVisibleCommands(allCommands, 'key');
|
|
55
|
+
const commands = [...quick, ...key.filter(k => !quick.some(q => q.name === k.name))]
|
|
56
|
+
.slice(0, 8)
|
|
57
|
+
.map(c => `- \`*${c.name}\` - ${c.description || 'No description'}`)
|
|
58
|
+
.join('\n');
|
|
59
|
+
|
|
60
|
+
const skillName = getSkillId(agentData.id);
|
|
61
|
+
const description = trimText(`${title} (${name}). ${whenToUse}`, 180);
|
|
62
|
+
|
|
63
|
+
return `---
|
|
64
|
+
name: ${skillName}
|
|
65
|
+
description: ${description}
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
# AIOS ${title} Activator
|
|
69
|
+
|
|
70
|
+
## When To Use
|
|
71
|
+
${whenToUse}
|
|
72
|
+
|
|
73
|
+
## Activation Protocol
|
|
74
|
+
1. Load \`.aios-core/development/agents/${agentData.filename}\` as source of truth (fallback: \`.codex/agents/${agentData.filename}\`).
|
|
75
|
+
2. Adopt this agent persona and command system.
|
|
76
|
+
3. Generate greeting via \`node .aios-core/development/scripts/generate-greeting.js ${agentData.id}\` and show it first.
|
|
77
|
+
4. Stay in this persona until the user asks to switch or exit.
|
|
78
|
+
|
|
79
|
+
## Starter Commands
|
|
80
|
+
${commands || '- `*help` - List available commands'}
|
|
81
|
+
|
|
82
|
+
## Non-Negotiables
|
|
83
|
+
- Follow \`.aios-core/constitution.md\`.
|
|
84
|
+
- Execute workflows/tasks only from declared dependencies.
|
|
85
|
+
- Do not invent requirements outside the project artifacts.
|
|
86
|
+
`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function buildSkillPlan(agents, skillsDir) {
|
|
90
|
+
return agents
|
|
91
|
+
.filter(a => !a.error || a.error === 'YAML parse failed, using fallback extraction')
|
|
92
|
+
.map(agentData => {
|
|
93
|
+
const skillId = getSkillId(agentData.id);
|
|
94
|
+
const targetDir = path.join(skillsDir, skillId);
|
|
95
|
+
const targetFile = path.join(targetDir, 'SKILL.md');
|
|
96
|
+
return {
|
|
97
|
+
agentId: agentData.id,
|
|
98
|
+
skillId,
|
|
99
|
+
targetDir,
|
|
100
|
+
targetFile,
|
|
101
|
+
content: buildSkillContent(agentData),
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function writeSkillPlan(plan, options) {
|
|
107
|
+
for (const item of plan) {
|
|
108
|
+
if (!options.dryRun) {
|
|
109
|
+
try {
|
|
110
|
+
fs.ensureDirSync(item.targetDir);
|
|
111
|
+
fs.writeFileSync(item.targetFile, item.content, 'utf8');
|
|
112
|
+
} catch (error) {
|
|
113
|
+
throw new Error(`Failed to write skill ${item.skillId} at ${item.targetFile}: ${error.message}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function syncSkills(options = {}) {
|
|
120
|
+
const resolved = { ...getDefaultOptions(), ...options };
|
|
121
|
+
if (resolved.globalOnly) {
|
|
122
|
+
resolved.global = true;
|
|
123
|
+
}
|
|
124
|
+
const agents = parseAllAgents(resolved.sourceDir);
|
|
125
|
+
const plan = buildSkillPlan(agents, resolved.localSkillsDir);
|
|
126
|
+
|
|
127
|
+
if (!resolved.globalOnly) {
|
|
128
|
+
writeSkillPlan(plan, resolved);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (resolved.global) {
|
|
132
|
+
const globalPlan = buildSkillPlan(agents, resolved.globalSkillsDir);
|
|
133
|
+
writeSkillPlan(globalPlan, resolved);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
generated: plan.length,
|
|
138
|
+
localSkillsDir: resolved.localSkillsDir,
|
|
139
|
+
globalSkillsDir: resolved.global || resolved.globalOnly ? resolved.globalSkillsDir : null,
|
|
140
|
+
dryRun: resolved.dryRun,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function parseArgs(argv = process.argv.slice(2)) {
|
|
145
|
+
const args = new Set(argv);
|
|
146
|
+
return {
|
|
147
|
+
global: args.has('--global'),
|
|
148
|
+
globalOnly: args.has('--global-only'),
|
|
149
|
+
dryRun: args.has('--dry-run'),
|
|
150
|
+
quiet: args.has('--quiet') || args.has('-q'),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function main() {
|
|
155
|
+
const options = parseArgs();
|
|
156
|
+
const result = syncSkills(options);
|
|
157
|
+
|
|
158
|
+
if (!options.quiet) {
|
|
159
|
+
if (!options.globalOnly) {
|
|
160
|
+
console.log(`✅ Generated ${result.generated} Codex skills in ${result.localSkillsDir}`);
|
|
161
|
+
}
|
|
162
|
+
if (result.globalSkillsDir) {
|
|
163
|
+
console.log(`✅ Installed ${result.generated} Codex skills in ${result.globalSkillsDir}`);
|
|
164
|
+
}
|
|
165
|
+
if (result.dryRun) {
|
|
166
|
+
console.log('ℹ️ Dry-run mode: no files written');
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (require.main === module) {
|
|
172
|
+
main();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
module.exports = {
|
|
176
|
+
buildSkillContent,
|
|
177
|
+
buildSkillPlan,
|
|
178
|
+
syncSkills,
|
|
179
|
+
parseArgs,
|
|
180
|
+
getCodexHome,
|
|
181
|
+
getSkillId,
|
|
182
|
+
};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const { parseAllAgents } = require('../ide-sync/agent-parser');
|
|
8
|
+
const { getSkillId } = require('./index');
|
|
9
|
+
|
|
10
|
+
function getDefaultOptions() {
|
|
11
|
+
const projectRoot = process.cwd();
|
|
12
|
+
return {
|
|
13
|
+
projectRoot,
|
|
14
|
+
sourceDir: path.join(projectRoot, '.aios-core', 'development', 'agents'),
|
|
15
|
+
skillsDir: path.join(projectRoot, '.codex', 'skills'),
|
|
16
|
+
strict: false,
|
|
17
|
+
quiet: false,
|
|
18
|
+
json: false,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function parseArgs(argv = process.argv.slice(2)) {
|
|
23
|
+
const args = new Set(argv);
|
|
24
|
+
return {
|
|
25
|
+
strict: args.has('--strict'),
|
|
26
|
+
quiet: args.has('--quiet') || args.has('-q'),
|
|
27
|
+
json: args.has('--json'),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function isParsableAgent(agent) {
|
|
32
|
+
return !agent.error || agent.error === 'YAML parse failed, using fallback extraction';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function validateSkillContent(content, expected) {
|
|
36
|
+
const issues = [];
|
|
37
|
+
const requiredChecks = [
|
|
38
|
+
{ ok: content.includes(`name: ${expected.skillId}`), reason: `missing frontmatter name "${expected.skillId}"` },
|
|
39
|
+
{
|
|
40
|
+
ok: content.includes(`.aios-core/development/agents/${expected.filename}`),
|
|
41
|
+
reason: `missing canonical agent path "${expected.filename}"`,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
ok: content.includes(`generate-greeting.js ${expected.agentId}`),
|
|
45
|
+
reason: `missing canonical greeting command for "${expected.agentId}"`,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
ok: content.includes('source of truth'),
|
|
49
|
+
reason: 'missing source-of-truth activation note',
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
for (const check of requiredChecks) {
|
|
54
|
+
if (!check.ok) {
|
|
55
|
+
issues.push(check.reason);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return issues;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function validateCodexSkills(options = {}) {
|
|
63
|
+
const resolved = { ...getDefaultOptions(), ...options };
|
|
64
|
+
const errors = [];
|
|
65
|
+
const warnings = [];
|
|
66
|
+
|
|
67
|
+
if (!fs.existsSync(resolved.skillsDir)) {
|
|
68
|
+
errors.push(`Skills directory not found: ${resolved.skillsDir}`);
|
|
69
|
+
return { ok: false, checked: 0, expected: 0, errors, warnings, missing: [], orphaned: [] };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const agents = parseAllAgents(resolved.sourceDir).filter(isParsableAgent);
|
|
73
|
+
const expected = agents.map(agent => ({
|
|
74
|
+
agentId: agent.id,
|
|
75
|
+
filename: agent.filename,
|
|
76
|
+
skillId: getSkillId(agent.id),
|
|
77
|
+
}));
|
|
78
|
+
|
|
79
|
+
const missing = [];
|
|
80
|
+
for (const item of expected) {
|
|
81
|
+
const skillPath = path.join(resolved.skillsDir, item.skillId, 'SKILL.md');
|
|
82
|
+
if (!fs.existsSync(skillPath)) {
|
|
83
|
+
missing.push(item.skillId);
|
|
84
|
+
errors.push(`Missing skill file: ${path.relative(resolved.projectRoot, skillPath)}`);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let content;
|
|
89
|
+
try {
|
|
90
|
+
content = fs.readFileSync(skillPath, 'utf8');
|
|
91
|
+
} catch (error) {
|
|
92
|
+
errors.push(`${item.skillId}: unable to read skill file (${error.message})`);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const issues = validateSkillContent(content, item);
|
|
96
|
+
for (const issue of issues) {
|
|
97
|
+
errors.push(`${item.skillId}: ${issue}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const expectedIds = new Set(expected.map(item => item.skillId));
|
|
102
|
+
const orphaned = [];
|
|
103
|
+
if (resolved.strict) {
|
|
104
|
+
const dirs = fs.readdirSync(resolved.skillsDir, { withFileTypes: true })
|
|
105
|
+
.filter(entry => entry.isDirectory() && entry.name.startsWith('aios-'))
|
|
106
|
+
.map(entry => entry.name);
|
|
107
|
+
for (const dir of dirs) {
|
|
108
|
+
if (!expectedIds.has(dir)) {
|
|
109
|
+
orphaned.push(dir);
|
|
110
|
+
errors.push(`Orphaned skill directory: ${path.join(path.relative(resolved.projectRoot, resolved.skillsDir), dir)}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (expected.length === 0) {
|
|
116
|
+
warnings.push('No parseable agents found in sourceDir');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
ok: errors.length === 0,
|
|
121
|
+
checked: expected.length,
|
|
122
|
+
expected: expected.length,
|
|
123
|
+
errors,
|
|
124
|
+
warnings,
|
|
125
|
+
missing,
|
|
126
|
+
orphaned,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function formatHumanReport(result) {
|
|
131
|
+
if (result.ok) {
|
|
132
|
+
return `✅ Codex skills validation passed (${result.checked} skills checked)`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const lines = [
|
|
136
|
+
`❌ Codex skills validation failed (${result.errors.length} issue(s))`,
|
|
137
|
+
...result.errors.map(error => `- ${error}`),
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
if (result.warnings.length > 0) {
|
|
141
|
+
lines.push(...result.warnings.map(warning => `⚠️ ${warning}`));
|
|
142
|
+
}
|
|
143
|
+
return lines.join('\n');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function main() {
|
|
147
|
+
const args = parseArgs();
|
|
148
|
+
const result = validateCodexSkills(args);
|
|
149
|
+
|
|
150
|
+
if (!args.quiet) {
|
|
151
|
+
if (args.json) {
|
|
152
|
+
console.log(JSON.stringify(result, null, 2));
|
|
153
|
+
} else {
|
|
154
|
+
console.log(formatHumanReport(result));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!result.ok) {
|
|
159
|
+
process.exitCode = 1;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (require.main === module) {
|
|
164
|
+
main();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = {
|
|
168
|
+
validateCodexSkills,
|
|
169
|
+
validateSkillContent,
|
|
170
|
+
parseArgs,
|
|
171
|
+
getDefaultOptions,
|
|
172
|
+
};
|
|
@@ -10,10 +10,18 @@ Automatically synchronizes AIOS agent definitions to IDE command files.
|
|
|
10
10
|
IDE Sync keeps agent definitions in `.aios-core/development/agents/` synchronized with IDE-specific command files in:
|
|
11
11
|
|
|
12
12
|
- `.claude/commands/AIOS/agents/` (Claude Code)
|
|
13
|
+
- `.codex/agents/` (Codex CLI support files)
|
|
13
14
|
- `.cursor/rules/agents/` (Cursor)
|
|
14
15
|
- `.windsurf/rules/agents/` (Windsurf)
|
|
15
16
|
- `.antigravity/rules/agents/` (Antigravity)
|
|
16
17
|
|
|
18
|
+
For Codex `/skills` activators, use the dedicated skills sync:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm run sync:skills:codex
|
|
22
|
+
npm run sync:skills:codex:global
|
|
23
|
+
```
|
|
24
|
+
|
|
17
25
|
## Pre-commit Integration (Story TD-4)
|
|
18
26
|
|
|
19
27
|
The pre-commit hook automatically:
|
|
@@ -48,6 +56,7 @@ Sync specific IDE only:
|
|
|
48
56
|
|
|
49
57
|
```bash
|
|
50
58
|
npm run sync:ide:cursor
|
|
59
|
+
npm run sync:ide:codex
|
|
51
60
|
npm run sync:ide:windsurf
|
|
52
61
|
```
|
|
53
62
|
|
|
@@ -92,6 +101,10 @@ ideSync:
|
|
|
92
101
|
enabled: true
|
|
93
102
|
path: .claude/commands/AIOS/agents
|
|
94
103
|
format: full-markdown-yaml
|
|
104
|
+
codex:
|
|
105
|
+
enabled: true
|
|
106
|
+
path: .codex/agents
|
|
107
|
+
format: full-markdown-yaml
|
|
95
108
|
cursor:
|
|
96
109
|
enabled: true
|
|
97
110
|
path: .cursor/rules/agents
|
|
@@ -109,6 +122,7 @@ Each IDE has a specific format for agent files:
|
|
|
109
122
|
| IDE | Format | Extension |
|
|
110
123
|
| ----------- | ----------------------- | --------- |
|
|
111
124
|
| Claude Code | Full markdown with YAML | `.md` |
|
|
125
|
+
| Codex CLI | Condensed rules | `.md` |
|
|
112
126
|
| Cursor | Condensed rules | `.md` |
|
|
113
127
|
| Windsurf | XML-tagged markdown | `.md` |
|
|
114
128
|
| Antigravity | Cursor-style | `.md` |
|
|
@@ -61,6 +61,11 @@ function loadConfig(projectRoot) {
|
|
|
61
61
|
path: '.claude/commands/AIOS/agents',
|
|
62
62
|
format: 'full-markdown-yaml',
|
|
63
63
|
},
|
|
64
|
+
codex: {
|
|
65
|
+
enabled: true,
|
|
66
|
+
path: '.codex/agents',
|
|
67
|
+
format: 'full-markdown-yaml',
|
|
68
|
+
},
|
|
64
69
|
cursor: {
|
|
65
70
|
enabled: true,
|
|
66
71
|
path: '.cursor/rules/agents',
|
|
@@ -444,6 +449,7 @@ ${colors.bright}Options:${colors.reset}
|
|
|
444
449
|
|
|
445
450
|
${colors.bright}Examples:${colors.reset}
|
|
446
451
|
node ide-sync/index.js sync
|
|
452
|
+
node ide-sync/index.js sync --ide codex
|
|
447
453
|
node ide-sync/index.js sync --ide cursor
|
|
448
454
|
node ide-sync/index.js validate --strict
|
|
449
455
|
node ide-sync/index.js sync --dry-run --verbose
|
|
@@ -8,7 +8,7 @@ const glob = require('glob');
|
|
|
8
8
|
*
|
|
9
9
|
* Features:
|
|
10
10
|
* - Map-based caching for performance (<5ms cached lookups)
|
|
11
|
-
* - Search path priority:
|
|
11
|
+
* - Search path priority: squad → common → core
|
|
12
12
|
* - Glob-based file resolution
|
|
13
13
|
* - Schema validation
|
|
14
14
|
* - Health checking (tool_call, command, http methods)
|
|
@@ -25,7 +25,7 @@ class ToolResolver {
|
|
|
25
25
|
this.basePaths = [
|
|
26
26
|
'aios-core/tools',
|
|
27
27
|
'common/tools',
|
|
28
|
-
//
|
|
28
|
+
// Squad paths added dynamically during resolution
|
|
29
29
|
];
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -34,7 +34,7 @@ class ToolResolver {
|
|
|
34
34
|
*
|
|
35
35
|
* @param {string} toolName - Tool identifier (e.g., 'clickup', 'github-cli')
|
|
36
36
|
* @param {object} context - Resolution context (optional)
|
|
37
|
-
* @param {string} context.expansionPack - Specific
|
|
37
|
+
* @param {string} context.expansionPack - Specific squad to search
|
|
38
38
|
* @returns {object} Tool definition with schema_version detected
|
|
39
39
|
* @throws {Error} If tool not found or validation fails
|
|
40
40
|
*/
|
|
@@ -45,7 +45,7 @@ class ToolResolver {
|
|
|
45
45
|
return this.cache.get(cacheKey);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
// 2. Build search paths (
|
|
48
|
+
// 2. Build search paths (squad → core priority)
|
|
49
49
|
const searchPaths = [];
|
|
50
50
|
if (context.expansionPack) {
|
|
51
51
|
searchPaths.push(`expansion-packs/${context.expansionPack}/tools`);
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const FORBIDDEN_ABSOLUTE_PATTERNS = [
|
|
8
|
+
/\/Users\/[^\s/'"]+/g,
|
|
9
|
+
/\/home\/[^\s/'"]+/g,
|
|
10
|
+
/[A-Za-z]:\\Users\\[^\s\\'"]+/g,
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
function getDefaultOptions() {
|
|
14
|
+
const projectRoot = process.cwd();
|
|
15
|
+
return {
|
|
16
|
+
projectRoot,
|
|
17
|
+
skillsDir: path.join(projectRoot, '.codex', 'skills'),
|
|
18
|
+
requiredFiles: [
|
|
19
|
+
path.join(projectRoot, 'AGENTS.md'),
|
|
20
|
+
path.join(projectRoot, '.aios-core', 'product', 'templates', 'ide-rules', 'codex-rules.md'),
|
|
21
|
+
],
|
|
22
|
+
quiet: false,
|
|
23
|
+
json: false,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function parseArgs(argv = process.argv.slice(2)) {
|
|
28
|
+
const args = new Set(argv);
|
|
29
|
+
return {
|
|
30
|
+
quiet: args.has('--quiet') || args.has('-q'),
|
|
31
|
+
json: args.has('--json'),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function listSkillFiles(skillsDir) {
|
|
36
|
+
if (!fs.existsSync(skillsDir)) return [];
|
|
37
|
+
return fs.readdirSync(skillsDir, { withFileTypes: true })
|
|
38
|
+
.filter(entry => entry.isDirectory() && entry.name.startsWith('aios-'))
|
|
39
|
+
.map(entry => path.join(skillsDir, entry.name, 'SKILL.md'))
|
|
40
|
+
.filter(file => fs.existsSync(file));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function collectAbsolutePathViolations(content, filePath) {
|
|
44
|
+
const errors = [];
|
|
45
|
+
const lines = content.split('\n');
|
|
46
|
+
lines.forEach((line, index) => {
|
|
47
|
+
for (const pattern of FORBIDDEN_ABSOLUTE_PATTERNS) {
|
|
48
|
+
const matches = line.match(pattern) || [];
|
|
49
|
+
for (const match of matches) {
|
|
50
|
+
errors.push(`${filePath}:${index + 1} forbidden absolute path "${match}"`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
return errors;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function validateSkillPathConventions(content, filePath) {
|
|
58
|
+
const errors = [];
|
|
59
|
+
if (!content.includes('.aios-core/development/agents/')) {
|
|
60
|
+
errors.push(`${filePath} missing canonical source path ".aios-core/development/agents/"`);
|
|
61
|
+
}
|
|
62
|
+
if (!content.includes('.aios-core/development/scripts/generate-greeting.js')) {
|
|
63
|
+
errors.push(`${filePath} missing canonical greeting script path`);
|
|
64
|
+
}
|
|
65
|
+
return errors;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function validatePaths(options = {}) {
|
|
69
|
+
const resolved = { ...getDefaultOptions(), ...options };
|
|
70
|
+
const errors = [];
|
|
71
|
+
const checkedFiles = [];
|
|
72
|
+
|
|
73
|
+
const skillFiles = listSkillFiles(resolved.skillsDir);
|
|
74
|
+
const filesToCheck = [...resolved.requiredFiles, ...skillFiles];
|
|
75
|
+
|
|
76
|
+
for (const file of filesToCheck) {
|
|
77
|
+
if (!fs.existsSync(file)) {
|
|
78
|
+
errors.push(`Missing required file: ${path.relative(resolved.projectRoot, file)}`);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let content;
|
|
83
|
+
try {
|
|
84
|
+
content = fs.readFileSync(file, 'utf8');
|
|
85
|
+
} catch (error) {
|
|
86
|
+
errors.push(`Unable to read file: ${path.relative(resolved.projectRoot, file)} (${error.message})`);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
checkedFiles.push(file);
|
|
90
|
+
errors.push(...collectAbsolutePathViolations(content, path.relative(resolved.projectRoot, file)));
|
|
91
|
+
|
|
92
|
+
if (file.endsWith('SKILL.md')) {
|
|
93
|
+
errors.push(...validateSkillPathConventions(content, path.relative(resolved.projectRoot, file)));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
ok: errors.length === 0,
|
|
99
|
+
checked: checkedFiles.length,
|
|
100
|
+
errors,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function formatHumanReport(result) {
|
|
105
|
+
if (result.ok) {
|
|
106
|
+
return `✅ Path validation passed (${result.checked} files checked)`;
|
|
107
|
+
}
|
|
108
|
+
return [
|
|
109
|
+
`❌ Path validation failed (${result.errors.length} issue(s))`,
|
|
110
|
+
...result.errors.map(error => `- ${error}`),
|
|
111
|
+
].join('\n');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function main() {
|
|
115
|
+
const args = parseArgs();
|
|
116
|
+
const result = validatePaths(args);
|
|
117
|
+
|
|
118
|
+
if (!args.quiet) {
|
|
119
|
+
if (args.json) {
|
|
120
|
+
console.log(JSON.stringify(result, null, 2));
|
|
121
|
+
} else {
|
|
122
|
+
console.log(formatHumanReport(result));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (!result.ok) {
|
|
127
|
+
process.exitCode = 1;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (require.main === module) {
|
|
132
|
+
main();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
module.exports = {
|
|
136
|
+
validatePaths,
|
|
137
|
+
parseArgs,
|
|
138
|
+
getDefaultOptions,
|
|
139
|
+
listSkillFiles,
|
|
140
|
+
collectAbsolutePathViolations,
|
|
141
|
+
validateSkillPathConventions,
|
|
142
|
+
};
|