aios-core 4.0.2 → 4.1.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 +5 -5
- 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/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 +190 -106
- package/.aios-core/local-config.yaml.template +2 -0
- 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/enforce-architecture-first.py +196 -0
- package/.claude/hooks/install-hooks.sh +41 -0
- package/.claude/hooks/mind-clone-governance.py +192 -0
- package/.claude/hooks/pre-commit-mmos-guard.sh +99 -0
- package/.claude/hooks/pre-commit-version-check.sh +156 -0
- package/.claude/hooks/read-protection.py +151 -0
- package/.claude/hooks/slug-validation.py +176 -0
- package/.claude/hooks/sql-governance.py +182 -0
- package/.claude/hooks/synapse-engine.js +9 -20
- package/.claude/hooks/write-path-validation.py +194 -0
- package/README.md +44 -14
- package/bin/aios-init.js +255 -184
- package/bin/aios-minimal.js +2 -2
- package/bin/aios.js +19 -19
- package/package.json +7 -4
- 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 +547 -0
- package/packages/installer/src/wizard/questions.js +20 -14
- package/packages/installer/src/wizard/validators.js +1 -1
- package/scripts/package-synapse.js +323 -0
- package/scripts/validate-package-completeness.js +317 -0
|
@@ -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
|
+
};
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# Usage:
|
|
5
5
|
# 1. Copy this file to your project root as .aios-sync.yaml
|
|
6
6
|
# 2. Configure active_ides for your setup
|
|
7
|
-
# 3. Add
|
|
7
|
+
# 3. Add squad_aliases for your squads
|
|
8
8
|
# 4. Run *command to sync components
|
|
9
9
|
#
|
|
10
10
|
# Documentation: https://synkra.dev/docs/ide-sync
|
|
@@ -24,11 +24,11 @@ active_ides:
|
|
|
24
24
|
# - cline # Cline (.cline/)
|
|
25
25
|
|
|
26
26
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
27
|
-
#
|
|
27
|
+
# SQUAD ALIASES
|
|
28
28
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
29
29
|
# Maps directory name → command prefix
|
|
30
30
|
# Example: squads/legal/ → .claude/commands/Legal/
|
|
31
|
-
|
|
31
|
+
squad_aliases:
|
|
32
32
|
# Add your squads here:
|
|
33
33
|
# squad-name: CommandPrefix
|
|
34
34
|
# legal: Legal
|
|
@@ -39,7 +39,7 @@ pack_aliases:
|
|
|
39
39
|
# SYNC MAPPINGS
|
|
40
40
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
41
41
|
# Source → destination patterns
|
|
42
|
-
# Use {
|
|
42
|
+
# Use {squad_alias} placeholder for dynamic squad alias substitution
|
|
43
43
|
sync_mappings:
|
|
44
44
|
|
|
45
45
|
# Agents - sync to all IDEs
|
|
@@ -47,7 +47,7 @@ sync_mappings:
|
|
|
47
47
|
source: "squads/*/agents/"
|
|
48
48
|
destinations:
|
|
49
49
|
claude:
|
|
50
|
-
- path: ".claude/commands/{
|
|
50
|
+
- path: ".claude/commands/{squad_alias}/agents/"
|
|
51
51
|
format: "md"
|
|
52
52
|
wrapper: "none"
|
|
53
53
|
cursor:
|
|
@@ -55,7 +55,7 @@ sync_mappings:
|
|
|
55
55
|
format: "mdc"
|
|
56
56
|
wrapper: "cursor-rule"
|
|
57
57
|
windsurf:
|
|
58
|
-
- path: ".windsurf/{
|
|
58
|
+
- path: ".windsurf/{squad_alias}/agents/"
|
|
59
59
|
format: "md"
|
|
60
60
|
wrapper: "none"
|
|
61
61
|
gemini:
|
|
@@ -63,7 +63,7 @@ sync_mappings:
|
|
|
63
63
|
format: "md"
|
|
64
64
|
wrapper: "none"
|
|
65
65
|
trae:
|
|
66
|
-
- path: ".trae/{
|
|
66
|
+
- path: ".trae/{squad_alias}/agents/"
|
|
67
67
|
format: "md"
|
|
68
68
|
wrapper: "none"
|
|
69
69
|
|
|
@@ -72,7 +72,7 @@ sync_mappings:
|
|
|
72
72
|
source: "squads/*/tasks/"
|
|
73
73
|
destinations:
|
|
74
74
|
claude:
|
|
75
|
-
- path: ".claude/commands/{
|
|
75
|
+
- path: ".claude/commands/{squad_alias}/tasks/"
|
|
76
76
|
format: "md"
|
|
77
77
|
wrapper: "none"
|
|
78
78
|
|
|
@@ -81,7 +81,7 @@ sync_mappings:
|
|
|
81
81
|
source: "squads/*/workflows/"
|
|
82
82
|
destinations:
|
|
83
83
|
claude:
|
|
84
|
-
- path: ".claude/commands/{
|
|
84
|
+
- path: ".claude/commands/{squad_alias}/workflows/"
|
|
85
85
|
format: "md"
|
|
86
86
|
wrapper: "none"
|
|
87
87
|
cursor:
|
|
@@ -94,7 +94,7 @@ sync_mappings:
|
|
|
94
94
|
source: "squads/*/checklists/"
|
|
95
95
|
destinations:
|
|
96
96
|
claude:
|
|
97
|
-
- path: ".claude/commands/{
|
|
97
|
+
- path: ".claude/commands/{squad_alias}/checklists/"
|
|
98
98
|
format: "md"
|
|
99
99
|
wrapper: "none"
|
|
100
100
|
|
|
@@ -103,7 +103,7 @@ sync_mappings:
|
|
|
103
103
|
source: "squads/*/data/"
|
|
104
104
|
destinations:
|
|
105
105
|
claude:
|
|
106
|
-
- path: ".claude/commands/{
|
|
106
|
+
- path: ".claude/commands/{squad_alias}/data/"
|
|
107
107
|
format: "md"
|
|
108
108
|
wrapper: "none"
|
|
109
109
|
|
|
@@ -104,6 +104,6 @@ For Go projects, use `setup-go@v5`:
|
|
|
104
104
|
|
|
105
105
|
## Related
|
|
106
106
|
|
|
107
|
-
- [Story 5.10 - GitHub DevOps Setup](../../../docs/stories/
|
|
107
|
+
- [Story 5.10 - GitHub DevOps Setup](../../../docs/stories/v4.0.4/sprint-5/story-5.10-github-devops-user-projects.md)
|
|
108
108
|
- [setup-github task](../../development/tasks/setup-github.md)
|
|
109
109
|
- [GitHub Actions Documentation](https://docs.github.com/en/actions)
|