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.
Files changed (107) hide show
  1. package/.aios-core/cli/commands/migrate/analyze.js +6 -6
  2. package/.aios-core/cli/commands/migrate/backup.js +2 -2
  3. package/.aios-core/cli/commands/migrate/execute.js +4 -4
  4. package/.aios-core/cli/commands/migrate/index.js +5 -5
  5. package/.aios-core/cli/commands/migrate/rollback.js +6 -6
  6. package/.aios-core/cli/commands/migrate/update-imports.js +2 -2
  7. package/.aios-core/cli/commands/migrate/validate.js +2 -2
  8. package/.aios-core/cli/commands/pro/index.js +52 -0
  9. package/.aios-core/cli/index.js +1 -1
  10. package/.aios-core/core/ids/registry-updater.js +29 -3
  11. package/.aios-core/core/migration/migration-config.yaml +2 -2
  12. package/.aios-core/core/migration/module-mapping.yaml +2 -2
  13. package/.aios-core/core/registry/README.md +2 -2
  14. package/.aios-core/core/synapse/context/context-builder.js +34 -0
  15. package/.aios-core/core/synapse/diagnostics/collectors/consistency-collector.js +168 -0
  16. package/.aios-core/core/synapse/diagnostics/collectors/hook-collector.js +129 -0
  17. package/.aios-core/core/synapse/diagnostics/collectors/manifest-collector.js +82 -0
  18. package/.aios-core/core/synapse/diagnostics/collectors/output-analyzer.js +134 -0
  19. package/.aios-core/core/synapse/diagnostics/collectors/pipeline-collector.js +75 -0
  20. package/.aios-core/core/synapse/diagnostics/collectors/quality-collector.js +252 -0
  21. package/.aios-core/core/synapse/diagnostics/collectors/relevance-matrix.js +174 -0
  22. package/.aios-core/core/synapse/diagnostics/collectors/safe-read-json.js +31 -0
  23. package/.aios-core/core/synapse/diagnostics/collectors/session-collector.js +102 -0
  24. package/.aios-core/core/synapse/diagnostics/collectors/timing-collector.js +126 -0
  25. package/.aios-core/core/synapse/diagnostics/collectors/uap-collector.js +83 -0
  26. package/.aios-core/core/synapse/diagnostics/report-formatter.js +484 -0
  27. package/.aios-core/core/synapse/diagnostics/synapse-diagnostics.js +95 -0
  28. package/.aios-core/core/synapse/engine.js +73 -20
  29. package/.aios-core/core/synapse/runtime/hook-runtime.js +60 -0
  30. package/.aios-core/core-config.yaml +6 -0
  31. package/.aios-core/data/agent-config-requirements.yaml +2 -2
  32. package/.aios-core/data/aios-kb.md +4 -4
  33. package/.aios-core/data/entity-registry.yaml +210 -10
  34. package/.aios-core/data/registry-update-log.jsonl +52 -0
  35. package/.aios-core/development/agents/architect.md +10 -10
  36. package/.aios-core/development/agents/devops.md +93 -50
  37. package/.aios-core/development/agents/qa.md +94 -40
  38. package/.aios-core/development/agents/ux-design-expert.md +25 -25
  39. package/.aios-core/development/scripts/activation-runtime.js +63 -0
  40. package/.aios-core/development/scripts/generate-greeting.js +9 -8
  41. package/.aios-core/development/scripts/unified-activation-pipeline.js +102 -2
  42. package/.aios-core/development/tasks/{db-expansion-pack-integration.md → db-squad-integration.md} +5 -5
  43. package/.aios-core/development/tasks/{integrate-expansion-pack.md → integrate-squad.md} +2 -2
  44. package/.aios-core/development/tasks/next.md +3 -3
  45. package/.aios-core/development/tasks/pr-automation.md +2 -2
  46. package/.aios-core/development/tasks/publish-npm.md +257 -0
  47. package/.aios-core/development/tasks/release-management.md +4 -4
  48. package/.aios-core/development/tasks/setup-github.md +1 -1
  49. package/.aios-core/development/tasks/squad-creator-migrate.md +1 -1
  50. package/.aios-core/development/tasks/squad-creator-sync-ide-command.md +14 -14
  51. package/.aios-core/development/tasks/update-aios.md +1 -1
  52. package/.aios-core/development/tasks/validate-next-story.md +99 -2
  53. package/.aios-core/docs/standards/AIOS-COLOR-PALETTE-QUICK-REFERENCE.md +1 -1
  54. package/.aios-core/docs/standards/AIOS-COLOR-PALETTE-V2.1.md +5 -5
  55. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-COMPLETE.md +21 -21
  56. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.2-SUMMARY.md +25 -25
  57. package/.aios-core/docs/standards/OPEN-SOURCE-VS-SERVICE-DIFFERENCES.md +4 -4
  58. package/.aios-core/docs/standards/QUALITY-GATES-SPECIFICATION.md +3 -3
  59. package/.aios-core/docs/standards/STANDARDS-INDEX.md +13 -13
  60. package/.aios-core/docs/standards/STORY-TEMPLATE-V2-SPECIFICATION.md +1 -1
  61. package/.aios-core/framework-config.yaml +4 -0
  62. package/.aios-core/infrastructure/scripts/codex-skills-sync/index.js +182 -0
  63. package/.aios-core/infrastructure/scripts/codex-skills-sync/validate.js +172 -0
  64. package/.aios-core/infrastructure/scripts/ide-sync/README.md +14 -0
  65. package/.aios-core/infrastructure/scripts/ide-sync/index.js +6 -0
  66. package/.aios-core/infrastructure/scripts/tool-resolver.js +4 -4
  67. package/.aios-core/infrastructure/scripts/validate-paths.js +142 -0
  68. package/.aios-core/infrastructure/templates/aios-sync.yaml.template +11 -11
  69. package/.aios-core/infrastructure/templates/github-workflows/README.md +1 -1
  70. package/.aios-core/install-manifest.yaml +193 -109
  71. package/.aios-core/local-config.yaml.template +2 -0
  72. package/.aios-core/manifests/agents.csv +29 -1
  73. package/.aios-core/manifests/tasks.csv +80 -3
  74. package/.aios-core/product/README.md +2 -2
  75. package/.aios-core/product/data/integration-patterns.md +1 -1
  76. package/.aios-core/product/templates/ide-rules/cline-rules.md +1 -1
  77. package/.aios-core/product/templates/ide-rules/codex-rules.md +65 -0
  78. package/.aios-core/product/templates/ide-rules/copilot-rules.md +1 -1
  79. package/.aios-core/product/templates/ide-rules/roo-rules.md +1 -1
  80. package/.aios-core/user-guide.md +15 -14
  81. package/.aios-core/workflow-intelligence/engine/output-formatter.js +1 -1
  82. package/.claude/hooks/synapse-engine.js +9 -20
  83. package/README.md +14 -7
  84. package/bin/aios-init.js +255 -184
  85. package/bin/aios-minimal.js +2 -2
  86. package/bin/aios.js +4 -4
  87. package/package.json +6 -1
  88. package/packages/aios-pro-cli/bin/aios-pro.js +75 -2
  89. package/packages/aios-pro-cli/package.json +5 -1
  90. package/packages/aios-pro-cli/src/recover.js +100 -0
  91. package/packages/installer/src/__tests__/performance-benchmark.js +382 -0
  92. package/packages/installer/src/config/ide-configs.js +12 -1
  93. package/packages/installer/src/config/templates/core-config-template.js +2 -2
  94. package/packages/installer/src/installer/aios-core-installer.js +2 -2
  95. package/packages/installer/src/installer/file-hasher.js +97 -0
  96. package/packages/installer/src/installer/post-install-validator.js +41 -1
  97. package/packages/installer/src/pro/pro-scaffolder.js +335 -0
  98. package/packages/installer/src/utils/aios-colors.js +2 -2
  99. package/packages/installer/src/wizard/feedback.js +1 -1
  100. package/packages/installer/src/wizard/ide-config-generator.js +2 -2
  101. package/packages/installer/src/wizard/index.js +58 -19
  102. package/packages/installer/src/wizard/pro-setup.js +931 -0
  103. package/packages/installer/src/wizard/questions.js +20 -14
  104. package/packages/installer/src/wizard/validators.js +1 -1
  105. package/scripts/code-intel-health-check.js +343 -0
  106. package/scripts/package-synapse.js +323 -0
  107. package/scripts/validate-package-completeness.js +317 -0
@@ -476,7 +476,7 @@ Use this checklist when creating or reviewing stories:
476
476
  #### Terminology
477
477
  - [ ] Uses "Squad" not "Expansion Pack"
478
478
  - [ ] Uses "@aios/" npm scope
479
- - [ ] References v2.1 architecture
479
+ - [ ] References v4.0.4 architecture
480
480
 
481
481
  ---
482
482
 
@@ -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: expansion pack → common → core
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
- // Expansion pack paths added dynamically during resolution
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 expansion pack to search
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 (expansion pack → core priority)
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
+ };