Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .aiox-core/core-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,12 @@ ideSync:
enabled: true
path: .antigravity/rules/agents
format: cursor-style
kimi:
enabled: true
path: .kimi/skills
format: kimi-skill
fallbackSources:
- .codex/agents
redirects: {}
validation:
strictMode: true
Expand Down
10 changes: 9 additions & 1 deletion .aiox-core/core/config/schemas/framework-config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,15 @@
"enabled": { "type": "boolean" },
"path": { "type": "string" },
"skillsPath": { "type": "string" },
"format": { "type": "string", "enum": ["full-markdown-yaml", "condensed-rules", "cursor-style"] }
"fallbackSources": {
"type": "array",
"items": { "type": "string" },
"description": "Fallback source directories used when the primary IDE sync source has no matching definitions"
},
"format": {
"type": "string",
"enum": ["full-markdown-yaml", "condensed-rules", "cursor-style", "kimi-skill"]
}
},
"additionalProperties": false
}
Expand Down
6 changes: 6 additions & 0 deletions .aiox-core/framework-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ ide_sync_system:
enabled: true
path: ".antigravity/rules/agents"
format: "cursor-style"
kimi:
enabled: true
path: ".kimi/skills"
format: "kimi-skill"
fallbackSources:
- ".codex/agents"
redirects: {}
validation:
strict_mode: true
Expand Down
5 changes: 4 additions & 1 deletion .aiox-core/infrastructure/scripts/ide-sync/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ Each IDE has a specific format for agent files:
| GitHub Copilot | Full markdown with YAML | `.md` |
| Cursor | Condensed MDC rules | `.mdc` |
| Antigravity | Cursor-style | `.md` |
| Kimi | Skill directory | `SKILL.md` |

Platform-specific checks:

Expand Down Expand Up @@ -181,7 +182,9 @@ alwaysApply: false
└── transformers/
├── claude-code.js # Claude Code format
├── cursor.js # Cursor format
└── antigravity.js # Antigravity format
├── antigravity.js # Antigravity format
├── github-copilot.js # GitHub Copilot format
└── kimi.js # Kimi skill format
```

## Performance
Expand Down
42 changes: 40 additions & 2 deletions .aiox-core/infrastructure/scripts/ide-sync/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const claudeCodeTransformer = require('./transformers/claude-code');
const cursorTransformer = require('./transformers/cursor');
const antigravityTransformer = require('./transformers/antigravity');
const githubCopilotTransformer = require('./transformers/github-copilot');
const kimiTransformer = require(path.resolve(__dirname, 'transformers', 'kimi'));

// ANSI colors for output
const colors = {
Expand Down Expand Up @@ -88,6 +89,12 @@ function loadConfig(projectRoot) {
path: '.antigravity/rules/agents',
format: 'cursor-style',
},
kimi: {
enabled: true,
path: '.kimi/skills',
format: 'kimi-skill',
fallbackSources: ['.codex/agents'],
},
},
redirects: {
'aiox-developer': 'aiox-master',
Expand Down Expand Up @@ -129,6 +136,7 @@ function getTransformer(format) {
'condensed-rules': cursorTransformer,
'cursor-style': antigravityTransformer,
'github-copilot': githubCopilotTransformer,
'kimi-skill': kimiTransformer,
};

return transformers[format] || claudeCodeTransformer;
Expand All @@ -142,6 +150,14 @@ function transformPrimaryContent(transformer, agent, ideName) {
return transformer.transform(agent);
}

function isPathInside(rootDir, candidatePath) {
const relativePath = path.relative(rootDir, candidatePath);
return relativePath !== '' &&
relativePath !== '..' &&
!relativePath.startsWith(`..${path.sep}`) &&
!path.isAbsolute(relativePath);
}

/**
* Sync agents to a specific IDE
* @param {object[]} agents - Parsed agent data
Expand Down Expand Up @@ -194,7 +210,25 @@ function syncIde(agents, ideConfig, ideName, projectRoot, options) {
try {
const content = transformPrimaryContent(transformer, agent, ideName);
const filename = transformer.getFilename(agent);
const targetPath = path.join(result.targetDir, filename);

// Kimi format uses subdirectories per skill: <skill-id>/SKILL.md
let targetPath;
if (ideConfig.format === 'kimi-skill' && transformer.getDirname) {
const targetRoot = path.resolve(result.targetDir);
const dirname = transformer.getDirname(agent);
const skillDir = path.resolve(targetRoot, dirname);
targetPath = path.resolve(skillDir, filename);

if (!isPathInside(targetRoot, skillDir) || !isPathInside(targetRoot, targetPath)) {
throw new Error(`Unsafe Kimi output path for agent '${agent.id}'`);
}

if (!options.dryRun) {
fs.ensureDirSync(skillDir);
}
} else {
targetPath = path.join(result.targetDir, filename);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

if (!options.dryRun) {
fs.writeFileSync(targetPath, content, 'utf8');
Expand Down Expand Up @@ -409,7 +443,11 @@ async function commandValidate(options) {
try {
const content = transformPrimaryContent(transformer, agent, ideName);
const filename = transformer.getFilename(agent);
expectedFiles.push({ filename, content });
// Kimi format stores each skill in <skill-id>/SKILL.md — record nested path
const relPath = ideConfig.format === 'kimi-skill' && transformer.getDirname
? path.join(transformer.getDirname(agent), filename)
: filename;
expectedFiles.push({ filename: relPath, content });
} catch (error) {
// Skip agents that fail to transform
}
Expand Down
Loading
Loading