aiox-core 5.0.7 → 5.0.8
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/.aiox-core/cli/commands/pro/buyer.js +379 -0
- package/.aiox-core/cli/commands/pro/index.js +191 -52
- package/.aiox-core/cli/commands/validate/index.js +2 -0
- package/.aiox-core/core/code-intel/helpers/dev-helper.js +1 -1
- package/.aiox-core/core/code-intel/helpers/devops-helper.js +0 -1
- package/.aiox-core/core/code-intel/helpers/planning-helper.js +1 -1
- package/.aiox-core/core/code-intel/helpers/qa-helper.js +2 -2
- package/.aiox-core/core/config/schemas/framework-config.schema.json +1 -0
- package/.aiox-core/core/config/template-overrides.js +1 -1
- package/.aiox-core/core/doctor/checks/ide-sync.js +81 -25
- package/.aiox-core/core/doctor/checks/rules-files.js +0 -1
- package/.aiox-core/core/doctor/checks/skills-count.js +83 -15
- package/.aiox-core/core/graph-dashboard/cli.js +1 -2
- package/.aiox-core/core/graph-dashboard/data-sources/code-intel-source.js +1 -1
- package/.aiox-core/core/ids/layer-classifier.js +1 -1
- package/.aiox-core/core/pro/pro-updater.js +578 -0
- package/.aiox-core/core/synapse/context/context-tracker.js +107 -9
- package/.aiox-core/core/synapse/layers/layer-processor.js +1 -1
- package/.aiox-core/core-config.yaml +15 -1
- package/.aiox-core/data/capability-detection.js +15 -15
- package/.aiox-core/data/entity-registry.yaml +18 -2
- package/.aiox-core/data/registry-update-log.jsonl +5 -0
- package/.aiox-core/data/tok3-token-comparison.js +0 -4
- package/.aiox-core/data/tool-search-validation.js +1 -1
- package/.aiox-core/development/agents/aiox-master.md +44 -6
- package/.aiox-core/development/agents/data-engineer.md +4 -4
- package/.aiox-core/development/agents/devops.md +52 -2
- package/.aiox-core/development/agents/po.md +1 -1
- package/.aiox-core/development/agents/qa.md +5 -11
- package/.aiox-core/development/agents/sm.md +3 -3
- package/.aiox-core/development/agents/ux-design-expert.md +1 -1
- package/.aiox-core/development/scripts/unified-activation-pipeline.js +29 -3
- package/.aiox-core/development/tasks/dev-develop-story.md +46 -7
- package/.aiox-core/development/tasks/devops-pro-access-grant.md +93 -0
- package/.aiox-core/development/tasks/devops-pro-activate.md +42 -0
- package/.aiox-core/development/tasks/devops-pro-check-access.md +34 -0
- package/.aiox-core/development/tasks/devops-pro-request-reset.md +34 -0
- package/.aiox-core/development/tasks/devops-pro-resend-verification.md +32 -0
- package/.aiox-core/development/tasks/devops-pro-reset-password.md +36 -0
- package/.aiox-core/development/tasks/devops-pro-validate-login.md +36 -0
- package/.aiox-core/development/tasks/devops-pro-verify-status.md +33 -0
- package/.aiox-core/development/tasks/qa-gate.md +54 -4
- package/.aiox-core/development/tasks/validate-next-story.md +39 -2
- package/.aiox-core/framework-config.yaml +1 -0
- package/.aiox-core/infrastructure/scripts/codex-skills-sync/README.md +69 -0
- package/.aiox-core/infrastructure/scripts/codex-skills-sync/bootstrap.js +727 -0
- package/.aiox-core/infrastructure/scripts/codex-skills-sync/index.js +10 -0
- package/.aiox-core/infrastructure/scripts/codex-skills-sync/validate.js +65 -4
- package/.aiox-core/infrastructure/scripts/generate-settings-json.js +29 -4
- package/.aiox-core/infrastructure/scripts/ide-sync/agent-parser.js +4 -0
- package/.aiox-core/infrastructure/scripts/ide-sync/index.js +67 -7
- package/.aiox-core/infrastructure/scripts/ide-sync/transformers/claude-code.js +145 -3
- package/.aiox-core/infrastructure/scripts/repair-agent-references.js +263 -0
- package/.aiox-core/infrastructure/scripts/validate-claude-integration.js +60 -8
- package/.aiox-core/infrastructure/scripts/validate-paths.js +13 -0
- package/.aiox-core/install-manifest.yaml +134 -82
- package/.aiox-core/utils/filters/index.js +2 -1
- package/.claude/commands/AIOX/agents/aiox-master.md +21 -0
- package/.claude/commands/AIOX/agents/analyst.md +21 -0
- package/.claude/commands/AIOX/agents/architect.md +21 -0
- package/.claude/commands/AIOX/agents/data-engineer.md +21 -0
- package/.claude/commands/AIOX/agents/dev.md +21 -0
- package/.claude/commands/AIOX/agents/devops.md +21 -0
- package/.claude/commands/AIOX/agents/pm.md +21 -0
- package/.claude/commands/AIOX/agents/po.md +21 -0
- package/.claude/commands/AIOX/agents/qa.md +21 -0
- package/.claude/commands/AIOX/agents/sm.md +21 -0
- package/.claude/commands/AIOX/agents/squad-creator.md +21 -0
- package/.claude/commands/AIOX/agents/ux-design-expert.md +21 -0
- package/.claude/commands/AIOX/scripts/agent-config-loader.js +624 -0
- package/.claude/commands/AIOX/scripts/generate-greeting.js +160 -0
- package/.claude/commands/AIOX/scripts/greeting-builder.js +866 -0
- package/.claude/commands/AIOX/scripts/session-context-loader.js +286 -0
- package/.claude/commands/AIOX/stories/story-6.1.4.md +1404 -0
- package/.claude/commands/cohort-squad/agents/cohort-manager.md +156 -0
- package/.claude/commands/design-system/agents/brad-frost.md +1097 -0
- package/.claude/commands/design-system/agents/dan-mall.md +857 -0
- package/.claude/commands/design-system/agents/dave-malouf.md +2272 -0
- package/.claude/commands/design-system/agents/design-chief.md +102 -0
- package/.claude/commands/design-system/agents/nano-banana-generator.md +162 -0
- package/.claude/commands/greet.md +101 -0
- package/.claude/commands/synapse/manager.md +75 -0
- package/.claude/commands/synapse/tasks/add-rule.md +94 -0
- package/.claude/commands/synapse/tasks/create-command.md +109 -0
- package/.claude/commands/synapse/tasks/create-domain.md +127 -0
- package/.claude/commands/synapse/tasks/diagnose-synapse.md +245 -0
- package/.claude/commands/synapse/tasks/edit-rule.md +109 -0
- package/.claude/commands/synapse/tasks/suggest-domain.md +116 -0
- package/.claude/commands/synapse/tasks/toggle-domain.md +83 -0
- package/.claude/commands/synapse/templates/domain-template +8 -0
- package/.claude/commands/synapse/templates/manifest-entry-template +4 -0
- package/.claude/commands/synapse/utils/manifest-parser-reference.md +134 -0
- package/.claude/hooks/precompact-session-digest.cjs +2 -2
- package/.claude/skills/AIOX/agents/aiox-master/SKILL.md +511 -0
- package/.claude/skills/AIOX/agents/analyst/SKILL.md +281 -0
- package/.claude/skills/AIOX/agents/architect/SKILL.md +482 -0
- package/.claude/skills/AIOX/agents/data-engineer/SKILL.md +503 -0
- package/.claude/skills/AIOX/agents/dev/SKILL.md +568 -0
- package/.claude/skills/AIOX/agents/devops/SKILL.md +597 -0
- package/.claude/skills/AIOX/agents/pm/SKILL.md +385 -0
- package/.claude/skills/AIOX/agents/po/SKILL.md +343 -0
- package/.claude/skills/AIOX/agents/qa/SKILL.md +451 -0
- package/.claude/skills/AIOX/agents/sm/SKILL.md +295 -0
- package/.claude/skills/AIOX/agents/squad-creator/SKILL.md +352 -0
- package/.claude/skills/AIOX/agents/ux-design-expert/SKILL.md +503 -0
- package/.claude/skills/architect-first/SKILL.md +275 -0
- package/.claude/skills/architect-first/assets/architecture-template.md +505 -0
- package/.claude/skills/architect-first/assets/config-template.yaml +351 -0
- package/.claude/skills/architect-first/references/architecture-checklist.md +216 -0
- package/.claude/skills/architect-first/references/pre-implementation-checklist.md +119 -0
- package/.claude/skills/architect-first/references/stop-rules-guide.md +291 -0
- package/.claude/skills/architect-first/references/testing-strategy-guide.md +477 -0
- package/.claude/skills/architect-first/scripts/architecture_validator.py +490 -0
- package/.claude/skills/architect-first/scripts/check_coupling.py +306 -0
- package/.claude/skills/architect-first/scripts/validate_risk_mitigation.py +382 -0
- package/.claude/skills/checklist-runner/SKILL.md +113 -0
- package/.claude/skills/clone-mind.md +329 -0
- package/.claude/skills/coderabbit-review/SKILL.md +106 -0
- package/.claude/skills/course-generation-workflow.md +76 -0
- package/.claude/skills/enhance-workflow.md +466 -0
- package/.claude/skills/mcp-builder/LICENSE.txt +202 -0
- package/.claude/skills/mcp-builder/SKILL.md +328 -0
- package/.claude/skills/mcp-builder/reference/evaluation.md +602 -0
- package/.claude/skills/mcp-builder/reference/mcp_best_practices.md +915 -0
- package/.claude/skills/mcp-builder/reference/node_mcp_server.md +916 -0
- package/.claude/skills/mcp-builder/reference/python_mcp_server.md +752 -0
- package/.claude/skills/mcp-builder/scripts/connections.py +151 -0
- package/.claude/skills/mcp-builder/scripts/evaluation.py +373 -0
- package/.claude/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
- package/.claude/skills/mcp-builder/scripts/requirements.txt +2 -0
- package/.claude/skills/ralph.md +181 -0
- package/.claude/skills/skill-creator/LICENSE.txt +202 -0
- package/.claude/skills/skill-creator/SKILL.md +209 -0
- package/.claude/skills/skill-creator/scripts/init_skill.py +303 -0
- package/.claude/skills/skill-creator/scripts/package_skill.py +110 -0
- package/.claude/skills/skill-creator/scripts/quick_validate.py +65 -0
- package/.claude/skills/squad.md +301 -0
- package/.claude/skills/synapse/SKILL.md +132 -0
- package/.claude/skills/synapse/assets/README.md +50 -0
- package/.claude/skills/synapse/references/brackets.md +100 -0
- package/.claude/skills/synapse/references/commands.md +118 -0
- package/.claude/skills/synapse/references/domains.md +126 -0
- package/.claude/skills/synapse/references/layers.md +186 -0
- package/.claude/skills/synapse/references/manifest.md +142 -0
- package/.claude/skills/tech-search/SKILL.md +431 -0
- package/.claude/skills/tech-search/prompts/page-extract.md +133 -0
- package/README.en.md +2 -2
- package/README.md +8 -2
- package/bin/aiox.js +55 -4
- package/bin/utils/framework-guard.js +4 -2
- package/bin/utils/pro-detector.js +119 -28
- package/bin/utils/validate-publish.js +6 -6
- package/docs/aiox-agent-flows/devops-system.md +18 -0
- package/docs/aiox-workflows/README.md +1 -0
- package/docs/aiox-workflows/pro-access-grant-workflow.md +218 -0
- package/docs/guides/pro/access-grant-ops-playbook.md +370 -0
- package/docs/guides/pro/install-gate-setup.md +12 -6
- package/docs/guides/pro/squad-creator-handoff-pro-access-ops.md +134 -0
- package/docs/guides/supabase-ops-handoff.md +768 -0
- package/package.json +12 -1
- package/packages/aiox-pro-cli/bin/aiox-pro.js +33 -12
- package/packages/installer/src/config/configure-environment.js +118 -50
- package/packages/installer/src/installer/aiox-core-installer.js +124 -27
- package/packages/installer/src/installer/brownfield-upgrader.js +66 -9
- package/packages/installer/src/installer/dependency-installer.js +4 -0
- package/packages/installer/src/pro/pro-scaffolder.js +5 -5
- package/packages/installer/src/updater/index.js +151 -10
- package/packages/installer/src/wizard/ide-config-generator.js +73 -7
- package/packages/installer/src/wizard/index.js +119 -31
- package/packages/installer/src/wizard/pro-setup.js +118 -47
- package/packages/installer/src/wizard/validation/validators/dependency-validator.js +32 -25
- package/packages/installer/src/wizard/validation/validators/file-structure-validator.js +26 -0
- package/packages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js +84 -1
- package/packages/installer/tests/unit/claude-md-template-v5/claude-md-template-v5.test.js +1 -1
- package/packages/installer/tests/unit/doctor/doctor-checks.test.js +85 -19
- package/packages/installer/tests/unit/entity-registry-bootstrap.test.js +4 -4
- package/packages/installer/tests/unit/generate-settings-json/generate-settings-json.test.js +5 -5
- package/packages/installer/tests/unit/ide-sync-integration/ide-sync-integration.test.js +4 -4
- package/packages/installer/tests/unit/merger/yaml-merger.test.js +11 -11
- package/pro/README.md +12 -1
- package/pro/license/index.js +3 -11
- package/pro/license/license-api.js +25 -0
- package/pro/license/license-cache.js +135 -31
- package/pro/license/license-crypto.js +59 -3
- package/pro/package.json +5 -4
- package/pro/squads/README.md +16 -16
- package/pro/squads/index.js +1 -1
- package/scripts/e2e/installed-skills-smoke.js +264 -0
- package/scripts/package-synapse.js +3 -3
- package/scripts/validate-package-completeness.js +8 -11
- package/.aiox-core/lib/build.json +0 -1
|
@@ -5,6 +5,8 @@ const fs = require('fs-extra');
|
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const os = require('os');
|
|
7
7
|
|
|
8
|
+
// summary: Sync local Codex skills for core AIOX agents.
|
|
9
|
+
|
|
8
10
|
const {
|
|
9
11
|
parseAllAgents,
|
|
10
12
|
normalizeCommands,
|
|
@@ -43,6 +45,13 @@ function getSkillId(agentId) {
|
|
|
43
45
|
return `aiox-${id}`;
|
|
44
46
|
}
|
|
45
47
|
|
|
48
|
+
function getLegacySkillId(agentId) {
|
|
49
|
+
const id = String(agentId || '').trim();
|
|
50
|
+
if (!id) return 'aios-unknown';
|
|
51
|
+
if (id.startsWith('aiox-')) return id.replace(/^aiox-/, 'aios-');
|
|
52
|
+
return `aios-${id}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
46
55
|
function buildSkillContent(agentData) {
|
|
47
56
|
const agent = agentData.agent || {};
|
|
48
57
|
const name = agent.name || agentData.id;
|
|
@@ -179,4 +188,5 @@ module.exports = {
|
|
|
179
188
|
parseArgs,
|
|
180
189
|
getCodexHome,
|
|
181
190
|
getSkillId,
|
|
191
|
+
getLegacySkillId,
|
|
182
192
|
};
|
|
@@ -5,7 +5,9 @@ const fs = require('fs');
|
|
|
5
5
|
const path = require('path');
|
|
6
6
|
|
|
7
7
|
const { parseAllAgents } = require('../ide-sync/agent-parser');
|
|
8
|
-
const { getSkillId } = require('./index');
|
|
8
|
+
const { getSkillId, getLegacySkillId } = require('./index');
|
|
9
|
+
|
|
10
|
+
const GENERATED_MARKER = '<!-- AIOX-CODEX-LOCAL-SKILLS: generated -->';
|
|
9
11
|
|
|
10
12
|
function getDefaultOptions() {
|
|
11
13
|
const projectRoot = process.cwd();
|
|
@@ -14,6 +16,7 @@ function getDefaultOptions() {
|
|
|
14
16
|
sourceDir: path.join(projectRoot, '.aiox-core', 'development', 'agents'),
|
|
15
17
|
skillsDir: path.join(projectRoot, '.codex', 'skills'),
|
|
16
18
|
strict: false,
|
|
19
|
+
allowOrphaned: false,
|
|
17
20
|
quiet: false,
|
|
18
21
|
json: false,
|
|
19
22
|
};
|
|
@@ -59,6 +62,35 @@ function validateSkillContent(content, expected) {
|
|
|
59
62
|
return issues;
|
|
60
63
|
}
|
|
61
64
|
|
|
65
|
+
function extractGeneratedSquadSource(content) {
|
|
66
|
+
const value = String(content || '');
|
|
67
|
+
const patterns = [
|
|
68
|
+
/`(squads\/[^`]+\/agents\/[^`]+\.md)`/,
|
|
69
|
+
/<!--\s*Source:\s*(squads\/[^>\s]+\/agents\/[^>\s]+\.md)\s*-->/,
|
|
70
|
+
/<!--\s*(squads\/[^>\s]+\/agents\/[^>\s]+\.md)\s*-->/,
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
for (const pattern of patterns) {
|
|
74
|
+
const match = value.match(pattern);
|
|
75
|
+
if (match) return match[1];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return '';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function isGeneratedSquadSkill(content, projectRoot) {
|
|
82
|
+
if (!String(content || '').includes(GENERATED_MARKER)) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const sourcePath = extractGeneratedSquadSource(content);
|
|
87
|
+
if (!sourcePath) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return fs.existsSync(path.join(projectRoot, sourcePath));
|
|
92
|
+
}
|
|
93
|
+
|
|
62
94
|
function validateCodexSkills(options = {}) {
|
|
63
95
|
const resolved = { ...getDefaultOptions(), ...options };
|
|
64
96
|
const errors = [];
|
|
@@ -66,7 +98,7 @@ function validateCodexSkills(options = {}) {
|
|
|
66
98
|
|
|
67
99
|
if (!fs.existsSync(resolved.skillsDir)) {
|
|
68
100
|
errors.push(`Skills directory not found: ${resolved.skillsDir}`);
|
|
69
|
-
return { ok: false, checked: 0, expected: 0, errors, warnings, missing: [], orphaned: [] };
|
|
101
|
+
return { ok: false, checked: 0, expected: 0, errors, warnings, missing: [], orphaned: [], ignored: [] };
|
|
70
102
|
}
|
|
71
103
|
|
|
72
104
|
const agents = parseAllAgents(resolved.sourceDir).filter(isParsableAgent);
|
|
@@ -74,6 +106,7 @@ function validateCodexSkills(options = {}) {
|
|
|
74
106
|
agentId: agent.id,
|
|
75
107
|
filename: agent.filename,
|
|
76
108
|
skillId: getSkillId(agent.id),
|
|
109
|
+
legacySkillId: getLegacySkillId(agent.id),
|
|
77
110
|
}));
|
|
78
111
|
|
|
79
112
|
const missing = [];
|
|
@@ -99,13 +132,37 @@ function validateCodexSkills(options = {}) {
|
|
|
99
132
|
}
|
|
100
133
|
|
|
101
134
|
const expectedIds = new Set(expected.map(item => item.skillId));
|
|
135
|
+
const legacyIds = new Set(expected.map(item => item.legacySkillId));
|
|
102
136
|
const orphaned = [];
|
|
137
|
+
const legacy = [];
|
|
138
|
+
const ignored = [];
|
|
103
139
|
if (resolved.strict) {
|
|
104
140
|
const dirs = fs.readdirSync(resolved.skillsDir, { withFileTypes: true })
|
|
105
|
-
.filter(entry => entry.isDirectory() && entry.name.startsWith('aiox-'))
|
|
141
|
+
.filter(entry => entry.isDirectory() && (entry.name.startsWith('aiox-') || entry.name.startsWith('aios-')))
|
|
106
142
|
.map(entry => entry.name);
|
|
107
143
|
for (const dir of dirs) {
|
|
108
|
-
if (
|
|
144
|
+
if (legacyIds.has(dir)) {
|
|
145
|
+
legacy.push(dir);
|
|
146
|
+
errors.push(`Legacy skill alias directory: ${path.join(path.relative(resolved.projectRoot, resolved.skillsDir), dir)}`);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (dir.startsWith('aiox-') && !expectedIds.has(dir)) {
|
|
150
|
+
if (resolved.allowOrphaned) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const skillPath = path.join(resolved.skillsDir, dir, 'SKILL.md');
|
|
154
|
+
let content = '';
|
|
155
|
+
try {
|
|
156
|
+
content = fs.readFileSync(skillPath, 'utf8');
|
|
157
|
+
} catch (_error) {
|
|
158
|
+
content = '';
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (isGeneratedSquadSkill(content, resolved.projectRoot)) {
|
|
162
|
+
ignored.push(dir);
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
|
|
109
166
|
orphaned.push(dir);
|
|
110
167
|
errors.push(`Orphaned skill directory: ${path.join(path.relative(resolved.projectRoot, resolved.skillsDir), dir)}`);
|
|
111
168
|
}
|
|
@@ -124,6 +181,8 @@ function validateCodexSkills(options = {}) {
|
|
|
124
181
|
warnings,
|
|
125
182
|
missing,
|
|
126
183
|
orphaned,
|
|
184
|
+
legacy,
|
|
185
|
+
ignored,
|
|
127
186
|
};
|
|
128
187
|
}
|
|
129
188
|
|
|
@@ -167,6 +226,8 @@ if (require.main === module) {
|
|
|
167
226
|
module.exports = {
|
|
168
227
|
validateCodexSkills,
|
|
169
228
|
validateSkillContent,
|
|
229
|
+
extractGeneratedSquadSource,
|
|
230
|
+
isGeneratedSquadSkill,
|
|
170
231
|
parseArgs,
|
|
171
232
|
getDefaultOptions,
|
|
172
233
|
};
|
|
@@ -243,11 +243,36 @@ function writeSettingsJson(projectRoot, permissions) {
|
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
const updated = { ...existing };
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
246
|
+
const existingPermissions =
|
|
247
|
+
existing && existing.permissions && typeof existing.permissions === 'object'
|
|
248
|
+
? existing.permissions
|
|
249
|
+
: {};
|
|
250
|
+
const generatedPermissionsEmpty =
|
|
251
|
+
permissions.allow.length === 0 && permissions.deny.length === 0;
|
|
252
|
+
|
|
253
|
+
if (generatedPermissionsEmpty) {
|
|
254
|
+
if (Object.keys(existingPermissions).length > 0) {
|
|
255
|
+
updated.permissions = existingPermissions;
|
|
256
|
+
} else {
|
|
257
|
+
delete updated.permissions;
|
|
258
|
+
}
|
|
249
259
|
} else {
|
|
250
|
-
|
|
260
|
+
const mergedAllow = Array.from(
|
|
261
|
+
new Set([...(Array.isArray(existingPermissions.allow) ? existingPermissions.allow : []), ...permissions.allow]),
|
|
262
|
+
);
|
|
263
|
+
const mergedDeny = Array.from(
|
|
264
|
+
new Set([...(Array.isArray(existingPermissions.deny) ? existingPermissions.deny : []), ...permissions.deny]),
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
if (mergedDeny.length > 0 || mergedAllow.length > 0) {
|
|
268
|
+
updated.permissions = {
|
|
269
|
+
...existingPermissions,
|
|
270
|
+
allow: mergedAllow,
|
|
271
|
+
deny: mergedDeny,
|
|
272
|
+
};
|
|
273
|
+
} else {
|
|
274
|
+
delete updated.permissions;
|
|
275
|
+
}
|
|
251
276
|
}
|
|
252
277
|
|
|
253
278
|
const newContent = JSON.stringify(updated, null, 2) + '\n';
|
|
@@ -119,8 +119,12 @@ function extractAgentInfoFallback(content) {
|
|
|
119
119
|
* @returns {object} - Parsed agent data
|
|
120
120
|
*/
|
|
121
121
|
function parseAgentFile(filePath) {
|
|
122
|
+
const relativeSourcePath = path.relative(process.cwd(), filePath);
|
|
122
123
|
const result = {
|
|
123
124
|
path: filePath,
|
|
125
|
+
sourcePath: relativeSourcePath && !relativeSourcePath.startsWith('..') && !path.isAbsolute(relativeSourcePath)
|
|
126
|
+
? relativeSourcePath.split(path.sep).join('/')
|
|
127
|
+
: null,
|
|
124
128
|
filename: path.basename(filePath),
|
|
125
129
|
id: path.basename(filePath, '.md'),
|
|
126
130
|
raw: null,
|
|
@@ -60,6 +60,7 @@ function loadConfig(projectRoot) {
|
|
|
60
60
|
'claude-code': {
|
|
61
61
|
enabled: true,
|
|
62
62
|
path: '.claude/commands/AIOX/agents',
|
|
63
|
+
skillsPath: '.claude/skills',
|
|
63
64
|
format: 'full-markdown-yaml',
|
|
64
65
|
},
|
|
65
66
|
codex: {
|
|
@@ -133,6 +134,14 @@ function getTransformer(format) {
|
|
|
133
134
|
return transformers[format] || claudeCodeTransformer;
|
|
134
135
|
}
|
|
135
136
|
|
|
137
|
+
function transformPrimaryContent(transformer, agent, ideName) {
|
|
138
|
+
if (ideName === 'claude-code' && typeof transformer.transformCommand === 'function') {
|
|
139
|
+
return transformer.transformCommand(agent);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return transformer.transform(agent);
|
|
143
|
+
}
|
|
144
|
+
|
|
136
145
|
/**
|
|
137
146
|
* Sync agents to a specific IDE
|
|
138
147
|
* @param {object[]} agents - Parsed agent data
|
|
@@ -146,7 +155,9 @@ function syncIde(agents, ideConfig, ideName, projectRoot, options) {
|
|
|
146
155
|
const result = {
|
|
147
156
|
ide: ideName,
|
|
148
157
|
targetDir: path.join(projectRoot, ideConfig.path),
|
|
158
|
+
skillRootDir: ideConfig.skillsPath ? path.join(projectRoot, ideConfig.skillsPath) : null,
|
|
149
159
|
files: [],
|
|
160
|
+
skillFiles: [],
|
|
150
161
|
errors: [],
|
|
151
162
|
};
|
|
152
163
|
|
|
@@ -181,7 +192,7 @@ function syncIde(agents, ideConfig, ideName, projectRoot, options) {
|
|
|
181
192
|
}
|
|
182
193
|
|
|
183
194
|
try {
|
|
184
|
-
const content = transformer
|
|
195
|
+
const content = transformPrimaryContent(transformer, agent, ideName);
|
|
185
196
|
const filename = transformer.getFilename(agent);
|
|
186
197
|
const targetPath = path.join(result.targetDir, filename);
|
|
187
198
|
|
|
@@ -195,6 +206,25 @@ function syncIde(agents, ideConfig, ideName, projectRoot, options) {
|
|
|
195
206
|
path: targetPath,
|
|
196
207
|
content,
|
|
197
208
|
});
|
|
209
|
+
|
|
210
|
+
if (ideName === 'claude-code' && typeof transformer.transformSkill === 'function') {
|
|
211
|
+
const skillContent = transformer.transformSkill(agent);
|
|
212
|
+
const skillRelativePath = transformer.getSkillRelativePath(agent);
|
|
213
|
+
const skillRootDir = result.skillRootDir || path.join(projectRoot, '.claude', 'skills');
|
|
214
|
+
const skillPath = path.join(skillRootDir, skillRelativePath);
|
|
215
|
+
|
|
216
|
+
if (!options.dryRun) {
|
|
217
|
+
fs.ensureDirSync(path.dirname(skillPath));
|
|
218
|
+
fs.writeFileSync(skillPath, skillContent, 'utf8');
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
result.skillFiles.push({
|
|
222
|
+
agent: agent.id,
|
|
223
|
+
filename: skillRelativePath,
|
|
224
|
+
path: skillPath,
|
|
225
|
+
content: skillContent,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
198
228
|
} catch (error) {
|
|
199
229
|
result.errors.push({
|
|
200
230
|
agent: agent.id,
|
|
@@ -211,7 +241,7 @@ function syncIde(agents, ideConfig, ideName, projectRoot, options) {
|
|
|
211
241
|
* @param {object} options - Command options
|
|
212
242
|
*/
|
|
213
243
|
async function commandSync(options) {
|
|
214
|
-
const projectRoot = process.cwd();
|
|
244
|
+
const projectRoot = options.projectRoot || process.cwd();
|
|
215
245
|
const config = loadConfig(projectRoot);
|
|
216
246
|
|
|
217
247
|
if (!config.enabled) {
|
|
@@ -284,6 +314,7 @@ async function commandSync(options) {
|
|
|
284
314
|
}
|
|
285
315
|
|
|
286
316
|
const agentCount = result.files.length;
|
|
317
|
+
const skillCount = (result.skillFiles || []).length;
|
|
287
318
|
const commandCount = (result.commandFiles || []).length;
|
|
288
319
|
const redirectCount = redirectResult.written.length;
|
|
289
320
|
const errorCount = result.errors.length;
|
|
@@ -295,7 +326,7 @@ async function commandSync(options) {
|
|
|
295
326
|
}
|
|
296
327
|
|
|
297
328
|
console.log(
|
|
298
|
-
` ${status} ${agentCount} agents${commandCount > 0 ? `, ${commandCount} commands` : ''}, ${redirectCount} redirects${errorCount > 0 ? `, ${errorCount} errors` : ''}`
|
|
329
|
+
` ${status} ${agentCount} agents${skillCount > 0 ? `, ${skillCount} skills` : ''}${commandCount > 0 ? `, ${commandCount} commands` : ''}, ${redirectCount} redirects${errorCount > 0 ? `, ${errorCount} errors` : ''}`
|
|
299
330
|
);
|
|
300
331
|
|
|
301
332
|
if (options.verbose && result.errors.length > 0) {
|
|
@@ -307,7 +338,10 @@ async function commandSync(options) {
|
|
|
307
338
|
}
|
|
308
339
|
|
|
309
340
|
// Summary
|
|
310
|
-
const totalFiles = results.reduce(
|
|
341
|
+
const totalFiles = results.reduce(
|
|
342
|
+
(sum, r) => sum + r.files.length + (r.skillFiles || []).length + (r.commandFiles || []).length,
|
|
343
|
+
0
|
|
344
|
+
);
|
|
311
345
|
const totalRedirects =
|
|
312
346
|
Object.keys(config.redirects).length * targetIdes.filter(([, c]) => c.enabled).length;
|
|
313
347
|
const totalErrors = results.reduce((sum, r) => sum + r.errors.length, 0);
|
|
@@ -317,11 +351,11 @@ async function commandSync(options) {
|
|
|
317
351
|
|
|
318
352
|
if (options.dryRun) {
|
|
319
353
|
console.log(
|
|
320
|
-
`${colors.yellow}Dry run: ${totalFiles}
|
|
354
|
+
`${colors.yellow}Dry run: ${totalFiles} files + ${totalRedirects} redirects would be written${colors.reset}`
|
|
321
355
|
);
|
|
322
356
|
} else {
|
|
323
357
|
console.log(
|
|
324
|
-
`${colors.green}✅ Sync complete: ${totalFiles}
|
|
358
|
+
`${colors.green}✅ Sync complete: ${totalFiles} files + ${totalRedirects} redirects${colors.reset}`
|
|
325
359
|
);
|
|
326
360
|
}
|
|
327
361
|
|
|
@@ -373,7 +407,7 @@ async function commandValidate(options) {
|
|
|
373
407
|
if (agent.error) continue;
|
|
374
408
|
|
|
375
409
|
try {
|
|
376
|
-
const content = transformer
|
|
410
|
+
const content = transformPrimaryContent(transformer, agent, ideName);
|
|
377
411
|
const filename = transformer.getFilename(agent);
|
|
378
412
|
expectedFiles.push({ filename, content });
|
|
379
413
|
} catch (error) {
|
|
@@ -411,6 +445,31 @@ async function commandValidate(options) {
|
|
|
411
445
|
targetDir: path.join(projectRoot, '.gemini', 'commands'),
|
|
412
446
|
};
|
|
413
447
|
}
|
|
448
|
+
|
|
449
|
+
if (ideName === 'claude-code' && typeof transformer.transformSkill === 'function') {
|
|
450
|
+
const skillNamespace = path.posix.join('AIOX', 'agents') + '/';
|
|
451
|
+
const expectedSkillFiles = [];
|
|
452
|
+
|
|
453
|
+
for (const agent of agents) {
|
|
454
|
+
if (agent.error) continue;
|
|
455
|
+
|
|
456
|
+
try {
|
|
457
|
+
const skillContent = transformer.transformSkill(agent);
|
|
458
|
+
const skillRelativePath = transformer.getSkillRelativePath(agent);
|
|
459
|
+
const filename = skillRelativePath.startsWith(skillNamespace)
|
|
460
|
+
? skillRelativePath.slice(skillNamespace.length)
|
|
461
|
+
: skillRelativePath;
|
|
462
|
+
expectedSkillFiles.push({ filename, content: skillContent });
|
|
463
|
+
} catch (error) {
|
|
464
|
+
// Skip agents that fail to transform
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
ideConfigs['claude-code-skills'] = {
|
|
469
|
+
expectedFiles: expectedSkillFiles,
|
|
470
|
+
targetDir: path.join(projectRoot, ideConfig.skillsPath || '.claude/skills', 'AIOX', 'agents'),
|
|
471
|
+
};
|
|
472
|
+
}
|
|
414
473
|
}
|
|
415
474
|
|
|
416
475
|
// Validate
|
|
@@ -534,6 +593,7 @@ if (require.main === module) {
|
|
|
534
593
|
module.exports = {
|
|
535
594
|
loadConfig,
|
|
536
595
|
getTransformer,
|
|
596
|
+
transformPrimaryContent,
|
|
537
597
|
syncIde,
|
|
538
598
|
commandSync,
|
|
539
599
|
commandValidate,
|
|
@@ -6,6 +6,27 @@
|
|
|
6
6
|
* Target: .claude/commands/AIOX/agents/*.md
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
function normalizePath(value) {
|
|
12
|
+
return String(value || '').split(path.sep).join('/');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getSourcePath(agentData) {
|
|
16
|
+
if (agentData.sourcePath) {
|
|
17
|
+
return normalizePath(agentData.sourcePath);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (agentData.path) {
|
|
21
|
+
const relative = path.relative(process.cwd(), agentData.path);
|
|
22
|
+
if (relative && !relative.startsWith('..') && !path.isAbsolute(relative)) {
|
|
23
|
+
return normalizePath(relative);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return `.aiox-core/development/agents/${agentData.filename}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
9
30
|
/**
|
|
10
31
|
* Transform agent data to Claude Code format
|
|
11
32
|
* For Claude Code, we use the full original file (identity transform)
|
|
@@ -13,12 +34,13 @@
|
|
|
13
34
|
* @returns {string} - Transformed content
|
|
14
35
|
*/
|
|
15
36
|
function transform(agentData) {
|
|
37
|
+
const sourcePath = getSourcePath(agentData);
|
|
16
38
|
// Claude Code uses the full original file
|
|
17
39
|
if (agentData.raw) {
|
|
18
40
|
// Add sync footer if not present
|
|
19
|
-
const syncFooter = `\n---\n*AIOX Agent - Synced from
|
|
41
|
+
const syncFooter = `\n---\n*AIOX Agent - Synced from ${sourcePath}*\n`;
|
|
20
42
|
|
|
21
|
-
if (!agentData.raw.includes(
|
|
43
|
+
if (!agentData.raw.includes(`Synced from ${sourcePath}`)) {
|
|
22
44
|
return agentData.raw.trimEnd() + syncFooter;
|
|
23
45
|
}
|
|
24
46
|
return agentData.raw;
|
|
@@ -28,6 +50,47 @@ function transform(agentData) {
|
|
|
28
50
|
return generateMinimalContent(agentData);
|
|
29
51
|
}
|
|
30
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Transform agent data to a Claude Code legacy command shim.
|
|
55
|
+
* The full activation payload lives in the Claude Skill sidecar.
|
|
56
|
+
* @param {object} agentData - Parsed agent data from agent-parser
|
|
57
|
+
* @returns {string} - Legacy command shim content
|
|
58
|
+
*/
|
|
59
|
+
function transformCommand(agentData) {
|
|
60
|
+
const agent = agentData.agent || {};
|
|
61
|
+
const sourcePath = getSourcePath(agentData);
|
|
62
|
+
const skillPath = `.claude/skills/${getSkillRelativePath(agentData)}`;
|
|
63
|
+
const name = agent.name || agentData.id;
|
|
64
|
+
const title = agent.title || 'AIOX Agent';
|
|
65
|
+
const whenToUse = normalizeInlineText(
|
|
66
|
+
agent.whenToUse || 'Use this AIOX agent when the task matches its responsibility.',
|
|
67
|
+
360
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
return `# ${agentData.id}
|
|
71
|
+
|
|
72
|
+
<!-- ACORE-CLAUDE-AGENT-COMMAND: legacy-shim -->
|
|
73
|
+
<!-- Canonical Skill: ${skillPath} -->
|
|
74
|
+
<!-- Source: ${sourcePath} -->
|
|
75
|
+
|
|
76
|
+
**${name}** - ${title}
|
|
77
|
+
|
|
78
|
+
> ${whenToUse}
|
|
79
|
+
|
|
80
|
+
## Compatibility Activation
|
|
81
|
+
|
|
82
|
+
This command is a legacy compatibility shim. The canonical Claude activation payload is:
|
|
83
|
+
|
|
84
|
+
\`${skillPath}\`
|
|
85
|
+
|
|
86
|
+
When this command is invoked:
|
|
87
|
+
|
|
88
|
+
1. Read \`${skillPath}\` in full.
|
|
89
|
+
2. Follow the activation instructions from that skill.
|
|
90
|
+
3. If the skill file is unavailable, read \`${sourcePath}\` as fallback.
|
|
91
|
+
`;
|
|
92
|
+
}
|
|
93
|
+
|
|
31
94
|
/**
|
|
32
95
|
* Generate minimal content if raw file is unavailable
|
|
33
96
|
* @param {object} agentData - Parsed agent data
|
|
@@ -36,6 +99,7 @@ function transform(agentData) {
|
|
|
36
99
|
function generateMinimalContent(agentData) {
|
|
37
100
|
const agent = agentData.agent || {};
|
|
38
101
|
const persona = agentData.persona_profile || {};
|
|
102
|
+
const sourcePath = getSourcePath(agentData);
|
|
39
103
|
|
|
40
104
|
const icon = agent.icon || '🤖';
|
|
41
105
|
const name = agent.name || agentData.id;
|
|
@@ -62,12 +126,86 @@ ${icon} **${name}** - ${title}
|
|
|
62
126
|
|
|
63
127
|
content += `
|
|
64
128
|
---
|
|
65
|
-
*AIOX Agent - Synced from
|
|
129
|
+
*AIOX Agent - Synced from ${sourcePath}*
|
|
66
130
|
`;
|
|
67
131
|
|
|
68
132
|
return content;
|
|
69
133
|
}
|
|
70
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Normalize free text for YAML frontmatter.
|
|
137
|
+
* @param {string} text - Raw text
|
|
138
|
+
* @param {number} maxLength - Maximum length
|
|
139
|
+
* @returns {string} - Normalized text
|
|
140
|
+
*/
|
|
141
|
+
function normalizeInlineText(text, maxLength = 240) {
|
|
142
|
+
const value = String(text || '').replace(/\s+/g, ' ').trim();
|
|
143
|
+
|
|
144
|
+
if (value.length <= maxLength) {
|
|
145
|
+
return value;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return `${value.slice(0, maxLength - 3).trimEnd()}...`;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Quote a value for one-line YAML frontmatter.
|
|
153
|
+
* @param {string} value - Raw value
|
|
154
|
+
* @returns {string} - YAML-safe quoted value
|
|
155
|
+
*/
|
|
156
|
+
function quoteYamlString(value) {
|
|
157
|
+
return JSON.stringify(normalizeInlineText(value));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Build a Claude skill description from the parsed agent metadata.
|
|
162
|
+
* @param {object} agentData - Parsed agent data
|
|
163
|
+
* @returns {string} - Skill description
|
|
164
|
+
*/
|
|
165
|
+
function buildSkillDescription(agentData) {
|
|
166
|
+
const agent = agentData.agent || {};
|
|
167
|
+
const name = agent.name || agentData.id;
|
|
168
|
+
const title = agent.title || 'AIOX Agent';
|
|
169
|
+
const whenToUse = agent.whenToUse || 'Use this AIOX agent when the task matches its responsibility.';
|
|
170
|
+
|
|
171
|
+
return `Activate ${name} (${agentData.id}) for ${title}. ${whenToUse}`;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Get the relative Claude skill path for this agent under .claude/skills.
|
|
176
|
+
* @param {object} agentData - Parsed agent data
|
|
177
|
+
* @returns {string} - Relative skill path
|
|
178
|
+
*/
|
|
179
|
+
function getSkillRelativePath(agentData) {
|
|
180
|
+
return path.posix.join('AIOX', 'agents', agentData.id, 'SKILL.md');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Transform agent data to a Claude Skill sidecar.
|
|
185
|
+
* The command file remains the compatibility surface; the skill is the new canonical Claude surface.
|
|
186
|
+
* @param {object} agentData - Parsed agent data from agent-parser
|
|
187
|
+
* @returns {string} - Skill content
|
|
188
|
+
*/
|
|
189
|
+
function transformSkill(agentData) {
|
|
190
|
+
const sourcePath = getSourcePath(agentData);
|
|
191
|
+
const name = `aiox-${agentData.id}`;
|
|
192
|
+
const description = buildSkillDescription(agentData);
|
|
193
|
+
const sourceContent = agentData.raw ? agentData.raw.trimEnd() : generateMinimalContent(agentData).trimEnd();
|
|
194
|
+
|
|
195
|
+
return `---
|
|
196
|
+
name: ${name}
|
|
197
|
+
description: ${quoteYamlString(description)}
|
|
198
|
+
user-invocable: true
|
|
199
|
+
activation_type: pipeline
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
<!-- ACORE-CLAUDE-AGENT-SKILL: generated -->
|
|
203
|
+
<!-- Source: ${sourcePath} -->
|
|
204
|
+
|
|
205
|
+
${sourceContent}
|
|
206
|
+
`;
|
|
207
|
+
}
|
|
208
|
+
|
|
71
209
|
/**
|
|
72
210
|
* Get the target filename for this agent
|
|
73
211
|
* @param {object} agentData - Parsed agent data
|
|
@@ -79,6 +217,10 @@ function getFilename(agentData) {
|
|
|
79
217
|
|
|
80
218
|
module.exports = {
|
|
81
219
|
transform,
|
|
220
|
+
transformCommand,
|
|
221
|
+
transformSkill,
|
|
82
222
|
getFilename,
|
|
223
|
+
getSkillRelativePath,
|
|
224
|
+
getSourcePath,
|
|
83
225
|
format: 'full-markdown-yaml',
|
|
84
226
|
};
|