skiller 0.7.10 → 0.7.11
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/README.md +71 -51
- package/dist/agents/AmpAgent.js +40 -0
- package/dist/agents/CodexCliAgent.js +6 -0
- package/dist/agents/CopilotAgent.js +40 -0
- package/dist/agents/CursorAgent.js +3 -0
- package/dist/agents/GeminiCliAgent.js +6 -0
- package/dist/agents/GooseAgent.js +6 -0
- package/dist/agents/KiloCodeAgent.js +6 -0
- package/dist/agents/OpenCodeAgent.js +6 -0
- package/dist/agents/RooCodeAgent.js +6 -0
- package/dist/cli/commands.js +7 -7
- package/dist/cli/index.js +4 -1
- package/dist/core/SkillsProcessor.js +97 -19
- package/dist/lib.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -46,6 +46,14 @@ A Claude-centric fork of [ruler](https://github.com/intellectronica/ruler) with
|
|
|
46
46
|
|
|
47
47
|
- `[backup].enabled = false` disables `.bak` files
|
|
48
48
|
|
|
49
|
+
## 8. Multi-Agent Skills Propagation
|
|
50
|
+
|
|
51
|
+
- `.claude/skills/` is the source of truth — skills are automatically copied to agent-specific directories on `skiller apply`
|
|
52
|
+
- Supported agent paths: `.codex/skills`, `.cursor/skills`, `.opencode/skill`, `.roo/skills`, `.gemini/skills`, `.agents/skills`
|
|
53
|
+
- Shared paths are deduplicated (Claude/Copilot/Kilo share `.claude/skills`, Goose/Amp share `.agents/skills`)
|
|
54
|
+
- Agent skills directories are auto-added to `.gitignore` (excluding `.claude/skills`)
|
|
55
|
+
- Validates skill structure — warns on missing `SKILL.md`
|
|
56
|
+
|
|
49
57
|
---
|
|
50
58
|
|
|
51
59
|
# Skiller: Centralise Your AI Coding Assistant Instructions
|
|
@@ -79,35 +87,35 @@ Skiller solves this by providing a **single source of truth** for all your AI ag
|
|
|
79
87
|
|
|
80
88
|
## Supported AI Agents
|
|
81
89
|
|
|
82
|
-
| Agent | Rules File(s) | MCP Configuration / Notes |
|
|
83
|
-
| ---------------- | -------------------------------------------------- | ------------------------------------------------ |
|
|
84
|
-
| AGENTS.md | `AGENTS.md` | (pseudo-agent ensuring root `AGENTS.md` exists) |
|
|
85
|
-
| GitHub Copilot | `AGENTS.md` | `.vscode/mcp.json` |
|
|
86
|
-
| Claude Code | `CLAUDE.md` (@filename references) | `.mcp.json` |
|
|
87
|
-
| OpenAI Codex CLI | `AGENTS.md` | `.codex/config.toml` |
|
|
88
|
-
| Jules | `AGENTS.md` | - |
|
|
89
|
-
| Cursor | `AGENTS.md` | `.cursor/mcp.json` |
|
|
90
|
-
| Windsurf | `AGENTS.md` | `.windsurf/mcp_config.json` |
|
|
91
|
-
| Cline | `.clinerules` | - |
|
|
92
|
-
| Crush | `CRUSH.md` | `.crush.json` |
|
|
93
|
-
| Amp | `AGENTS.md` | - |
|
|
94
|
-
| Amazon Q CLI | `.amazonq/rules/skiller_q_rules.md` | `.amazonq/mcp.json` |
|
|
95
|
-
| Aider | `AGENTS.md`, `.aider.conf.yml` | `.mcp.json` |
|
|
96
|
-
| Firebase Studio | `.idx/airules.md` | `.idx/mcp.json` |
|
|
97
|
-
| Open Hands | `.openhands/microagents/repo.md` | `config.toml` |
|
|
98
|
-
| Gemini CLI | `AGENTS.md` | `.gemini/settings.json` |
|
|
99
|
-
| Junie | `.junie/guidelines.md` | - |
|
|
100
|
-
| AugmentCode | `.augment/rules/skiller_augment_instructions.md` | - |
|
|
101
|
-
| Kilo Code | `.kilocode/rules/skiller_kilocode_instructions.md` | `.kilocode/mcp.json` |
|
|
102
|
-
| OpenCode | `AGENTS.md` | `opencode.json` |
|
|
103
|
-
| Goose | `.goosehints` | - |
|
|
104
|
-
| Qwen Code | `AGENTS.md` | `.qwen/settings.json` |
|
|
105
|
-
| RooCode | `AGENTS.md` | `.roo/mcp.json` |
|
|
106
|
-
| Zed | `AGENTS.md` | `.zed/settings.json` (project root, never $HOME) |
|
|
107
|
-
| Trae AI | `.trae/rules/project_rules.md` | - |
|
|
108
|
-
| Warp | `WARP.md` | - |
|
|
109
|
-
| Kiro | `.kiro/steering/skiller_kiro_instructions.md` | - |
|
|
110
|
-
| Firebender | `firebender.json` | `firebender.json` (rules and MCP in same file) |
|
|
90
|
+
| Agent | Rules File(s) | MCP Configuration / Notes | Skills Location |
|
|
91
|
+
| ---------------- | -------------------------------------------------- | ------------------------------------------------ | ------------------ |
|
|
92
|
+
| AGENTS.md | `AGENTS.md` | (pseudo-agent ensuring root `AGENTS.md` exists) | - |
|
|
93
|
+
| GitHub Copilot | `AGENTS.md` | `.vscode/mcp.json` | `.claude/skills/` |
|
|
94
|
+
| Claude Code | `CLAUDE.md` (@filename references) | `.mcp.json` | `.claude/skills/` |
|
|
95
|
+
| OpenAI Codex CLI | `AGENTS.md` | `.codex/config.toml` | `.codex/skills/` |
|
|
96
|
+
| Jules | `AGENTS.md` | - | - |
|
|
97
|
+
| Cursor | `AGENTS.md` | `.cursor/mcp.json` | `.cursor/skills/` |
|
|
98
|
+
| Windsurf | `AGENTS.md` | `.windsurf/mcp_config.json` | - |
|
|
99
|
+
| Cline | `.clinerules` | - | - |
|
|
100
|
+
| Crush | `CRUSH.md` | `.crush.json` | - |
|
|
101
|
+
| Amp | `AGENTS.md` | - | `.agents/skills/` |
|
|
102
|
+
| Amazon Q CLI | `.amazonq/rules/skiller_q_rules.md` | `.amazonq/mcp.json` | - |
|
|
103
|
+
| Aider | `AGENTS.md`, `.aider.conf.yml` | `.mcp.json` | - |
|
|
104
|
+
| Firebase Studio | `.idx/airules.md` | `.idx/mcp.json` | - |
|
|
105
|
+
| Open Hands | `.openhands/microagents/repo.md` | `config.toml` | - |
|
|
106
|
+
| Gemini CLI | `AGENTS.md` | `.gemini/settings.json` | `.gemini/skills/` |
|
|
107
|
+
| Junie | `.junie/guidelines.md` | - | - |
|
|
108
|
+
| AugmentCode | `.augment/rules/skiller_augment_instructions.md` | - | - |
|
|
109
|
+
| Kilo Code | `.kilocode/rules/skiller_kilocode_instructions.md` | `.kilocode/mcp.json` | `.claude/skills/` |
|
|
110
|
+
| OpenCode | `AGENTS.md` | `opencode.json` | `.opencode/skill/` |
|
|
111
|
+
| Goose | `.goosehints` | - | `.agents/skills/` |
|
|
112
|
+
| Qwen Code | `AGENTS.md` | `.qwen/settings.json` | - |
|
|
113
|
+
| RooCode | `AGENTS.md` | `.roo/mcp.json` | `.roo/skills/` |
|
|
114
|
+
| Zed | `AGENTS.md` | `.zed/settings.json` (project root, never $HOME) | - |
|
|
115
|
+
| Trae AI | `.trae/rules/project_rules.md` | - | - |
|
|
116
|
+
| Warp | `WARP.md` | - | - |
|
|
117
|
+
| Kiro | `.kiro/steering/skiller_kiro_instructions.md` | - | - |
|
|
118
|
+
| Firebender | `firebender.json` | `firebender.json` (rules and MCP in same file) | - |
|
|
111
119
|
|
|
112
120
|
## Getting Started
|
|
113
121
|
|
|
@@ -555,11 +563,21 @@ export CODEX_HOME="$(pwd)/.codex"
|
|
|
555
563
|
|
|
556
564
|
## Skills Support
|
|
557
565
|
|
|
558
|
-
Skiller can manage and propagate
|
|
566
|
+
Skiller can manage and propagate skills to supported AI agents. Skills are stored in `.claude/skills/` as the **committed source of truth** and automatically copied to agent-specific directories on `skiller apply`.
|
|
559
567
|
|
|
560
568
|
### How It Works
|
|
561
569
|
|
|
562
|
-
Skills are specialized knowledge packages that extend AI agent capabilities
|
|
570
|
+
Skills are specialized knowledge packages that extend AI agent capabilities. Skiller discovers skills in your `.claude/skills/` directory, keeps them in sync via bidirectional `.mdc`/`SKILL.md` sync, and propagates them to all agents with native skills support:
|
|
571
|
+
|
|
572
|
+
- **Claude Code, GitHub Copilot, Kilo Code**: `.claude/skills/` (shared, source of truth)
|
|
573
|
+
- **OpenAI Codex CLI**: `.codex/skills/`
|
|
574
|
+
- **Cursor**: `.cursor/skills/`
|
|
575
|
+
- **OpenCode**: `.opencode/skill/`
|
|
576
|
+
- **Goose, Amp**: `.agents/skills/` (shared)
|
|
577
|
+
- **Roo Code**: `.roo/skills/`
|
|
578
|
+
- **Gemini CLI**: `.gemini/skills/`
|
|
579
|
+
|
|
580
|
+
Shared paths are deduplicated — agents sharing the same directory only trigger one copy operation.
|
|
563
581
|
|
|
564
582
|
### Skills Directory Structure
|
|
565
583
|
|
|
@@ -586,11 +604,11 @@ Each skill can be defined in two ways:
|
|
|
586
604
|
|
|
587
605
|
Skiller provides bidirectional sync between `.mdc` files and `SKILL.md` folders:
|
|
588
606
|
|
|
589
|
-
| Scenario
|
|
590
|
-
|
|
591
|
-
| `.mdc` exists, no `SKILL.md`
|
|
592
|
-
| `SKILL.md` body is `@reference` | .mdc is source of truth (frontmatter in SKILL.md)
|
|
593
|
-
| `SKILL.md` has full content
|
|
607
|
+
| Scenario | Sync Direction |
|
|
608
|
+
| ------------------------------- | ---------------------------------------------------------- |
|
|
609
|
+
| `.mdc` exists, no `SKILL.md` | → Generate `SKILL.md` with `@reference` to .mdc |
|
|
610
|
+
| `SKILL.md` body is `@reference` | .mdc is source of truth (frontmatter in SKILL.md) |
|
|
611
|
+
| `SKILL.md` has full content | → Generate .mdc from body, update SKILL.md to `@reference` |
|
|
594
612
|
|
|
595
613
|
The `@reference` body pattern indicates that the `.mdc` file contains the skill content:
|
|
596
614
|
|
|
@@ -656,6 +674,12 @@ Skiller validates discovered skills and issues warnings for:
|
|
|
656
674
|
|
|
657
675
|
Warnings don't prevent propagation but help identify potential issues.
|
|
658
676
|
|
|
677
|
+
### `.gitignore` Integration
|
|
678
|
+
|
|
679
|
+
When skills propagation is enabled, agent skills directories are automatically added to `.gitignore` (excluding `.claude/skills/` which is the committed source of truth):
|
|
680
|
+
|
|
681
|
+
- `.codex/skills/`, `.cursor/skills/`, `.opencode/skill/`, `.agents/skills/`, `.roo/skills/`, `.gemini/skills/`
|
|
682
|
+
|
|
659
683
|
### Dry-Run Mode
|
|
660
684
|
|
|
661
685
|
Test skills propagation without making changes:
|
|
@@ -664,23 +688,12 @@ Test skills propagation without making changes:
|
|
|
664
688
|
skiller apply --dry-run
|
|
665
689
|
```
|
|
666
690
|
|
|
667
|
-
This shows which skills would be synced and
|
|
691
|
+
This shows which skills would be synced, validated, and copied to each agent directory.
|
|
668
692
|
|
|
669
693
|
### Example Workflow
|
|
670
694
|
|
|
671
695
|
```bash
|
|
672
|
-
#
|
|
673
|
-
cat > .claude/skills/my-skill.mdc << 'EOF'
|
|
674
|
-
---
|
|
675
|
-
description: My custom skill
|
|
676
|
-
---
|
|
677
|
-
|
|
678
|
-
# My Custom Skill
|
|
679
|
-
|
|
680
|
-
This skill provides specialized knowledge for...
|
|
681
|
-
EOF
|
|
682
|
-
|
|
683
|
-
# Option 2: Create a skill folder directly
|
|
696
|
+
# 1. Create a skill folder
|
|
684
697
|
mkdir -p .claude/skills/my-skill
|
|
685
698
|
cat > .claude/skills/my-skill/SKILL.md << 'EOF'
|
|
686
699
|
---
|
|
@@ -693,10 +706,17 @@ description: My custom skill
|
|
|
693
706
|
This skill provides specialized knowledge for...
|
|
694
707
|
EOF
|
|
695
708
|
|
|
696
|
-
# Apply to sync
|
|
709
|
+
# 2. Apply to sync and propagate skills
|
|
697
710
|
skiller apply
|
|
698
711
|
|
|
699
|
-
# Skills are now available to
|
|
712
|
+
# 3. Skills are now available to all compatible agents:
|
|
713
|
+
# - Claude Code, Copilot, Kilo Code: .claude/skills/my-skill/
|
|
714
|
+
# - Codex CLI: .codex/skills/my-skill/
|
|
715
|
+
# - Cursor: .cursor/skills/my-skill/
|
|
716
|
+
# - OpenCode: .opencode/skill/my-skill/
|
|
717
|
+
# - Goose, Amp: .agents/skills/my-skill/
|
|
718
|
+
# - Roo Code: .roo/skills/my-skill/
|
|
719
|
+
# - Gemini CLI: .gemini/skills/my-skill/
|
|
700
720
|
```
|
|
701
721
|
|
|
702
722
|
## `.gitignore` Integration
|
package/dist/agents/AmpAgent.js
CHANGED
|
@@ -1,6 +1,40 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.AmpAgent = void 0;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
4
38
|
const AgentsMdAgent_1 = require("./AgentsMdAgent");
|
|
5
39
|
class AmpAgent extends AgentsMdAgent_1.AgentsMdAgent {
|
|
6
40
|
getIdentifier() {
|
|
@@ -9,5 +43,11 @@ class AmpAgent extends AgentsMdAgent_1.AgentsMdAgent {
|
|
|
9
43
|
getName() {
|
|
10
44
|
return 'Amp';
|
|
11
45
|
}
|
|
46
|
+
supportsNativeSkills() {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
getSkillsPath(projectRoot) {
|
|
50
|
+
return path.join(projectRoot, '.agents/skills');
|
|
51
|
+
}
|
|
12
52
|
}
|
|
13
53
|
exports.AmpAgent = AmpAgent;
|
|
@@ -139,5 +139,11 @@ class CodexCliAgent {
|
|
|
139
139
|
supportsMcpRemote() {
|
|
140
140
|
return false; // Codex CLI only supports STDIO based on PR description
|
|
141
141
|
}
|
|
142
|
+
supportsNativeSkills() {
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
getSkillsPath(projectRoot) {
|
|
146
|
+
return path.join(projectRoot, '.codex/skills');
|
|
147
|
+
}
|
|
142
148
|
}
|
|
143
149
|
exports.CodexCliAgent = CodexCliAgent;
|
|
@@ -1,6 +1,40 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.CopilotAgent = void 0;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
4
38
|
const AgentsMdAgent_1 = require("./AgentsMdAgent");
|
|
5
39
|
/**
|
|
6
40
|
* GitHub Copilot agent adapter.
|
|
@@ -39,5 +73,11 @@ class CopilotAgent {
|
|
|
39
73
|
supportsMcpRemote() {
|
|
40
74
|
return true;
|
|
41
75
|
}
|
|
76
|
+
supportsNativeSkills() {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
getSkillsPath(projectRoot) {
|
|
80
|
+
return path.join(projectRoot, '.claude/skills');
|
|
81
|
+
}
|
|
42
82
|
}
|
|
43
83
|
exports.CopilotAgent = CopilotAgent;
|
|
@@ -89,5 +89,8 @@ class CursorAgent extends AgentsMdAgent_1.AgentsMdAgent {
|
|
|
89
89
|
// Cursor has native support for rules via .cursor/rules/
|
|
90
90
|
return true;
|
|
91
91
|
}
|
|
92
|
+
getSkillsPath(projectRoot) {
|
|
93
|
+
return path.join(projectRoot, '.cursor/skills');
|
|
94
|
+
}
|
|
92
95
|
}
|
|
93
96
|
exports.CursorAgent = CursorAgent;
|
|
@@ -95,5 +95,11 @@ class GeminiCliAgent extends AgentsMdAgent_1.AgentsMdAgent {
|
|
|
95
95
|
supportsMcpRemote() {
|
|
96
96
|
return true;
|
|
97
97
|
}
|
|
98
|
+
supportsNativeSkills() {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
getSkillsPath(projectRoot) {
|
|
102
|
+
return path.join(projectRoot, '.gemini/skills');
|
|
103
|
+
}
|
|
98
104
|
}
|
|
99
105
|
exports.GeminiCliAgent = GeminiCliAgent;
|
|
@@ -54,5 +54,11 @@ class GooseAgent extends AbstractAgent_1.AbstractAgent {
|
|
|
54
54
|
// Goose doesn't support MCP configuration via local config files
|
|
55
55
|
return '';
|
|
56
56
|
}
|
|
57
|
+
supportsNativeSkills() {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
getSkillsPath(projectRoot) {
|
|
61
|
+
return path.join(projectRoot, '.agents/skills');
|
|
62
|
+
}
|
|
57
63
|
}
|
|
58
64
|
exports.GooseAgent = GooseAgent;
|
|
@@ -59,5 +59,11 @@ class KiloCodeAgent extends AbstractAgent_1.AbstractAgent {
|
|
|
59
59
|
supportsMcpRemote() {
|
|
60
60
|
return true;
|
|
61
61
|
}
|
|
62
|
+
supportsNativeSkills() {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
getSkillsPath(projectRoot) {
|
|
66
|
+
return path.join(projectRoot, '.claude/skills');
|
|
67
|
+
}
|
|
62
68
|
}
|
|
63
69
|
exports.KiloCodeAgent = KiloCodeAgent;
|
|
@@ -95,5 +95,11 @@ class OpenCodeAgent {
|
|
|
95
95
|
supportsMcpRemote() {
|
|
96
96
|
return true;
|
|
97
97
|
}
|
|
98
|
+
supportsNativeSkills() {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
getSkillsPath(projectRoot) {
|
|
102
|
+
return path.join(projectRoot, '.opencode/skill');
|
|
103
|
+
}
|
|
98
104
|
}
|
|
99
105
|
exports.OpenCodeAgent = OpenCodeAgent;
|
|
@@ -135,5 +135,11 @@ class RooCodeAgent {
|
|
|
135
135
|
getMcpServerKey() {
|
|
136
136
|
return 'mcpServers';
|
|
137
137
|
}
|
|
138
|
+
supportsNativeSkills() {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
getSkillsPath(projectRoot) {
|
|
142
|
+
return path.join(projectRoot, '.roo/skills');
|
|
143
|
+
}
|
|
138
144
|
}
|
|
139
145
|
exports.RooCodeAgent = RooCodeAgent;
|
package/dist/cli/commands.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.run = run;
|
|
7
|
-
const yargs_1 = __importDefault(require("yargs"));
|
|
8
|
-
const helpers_1 = require("yargs/helpers");
|
|
9
4
|
const handlers_1 = require("./handlers");
|
|
10
5
|
const index_1 = require("../agents/index");
|
|
11
6
|
/**
|
|
12
7
|
* Sets up and parses CLI commands.
|
|
13
8
|
*/
|
|
14
|
-
function run() {
|
|
15
|
-
|
|
9
|
+
async function run() {
|
|
10
|
+
const dynamicImport = new Function('modulePath', 'return import(modulePath);');
|
|
11
|
+
const [{ default: yargs }, { hideBin }] = await Promise.all([
|
|
12
|
+
dynamicImport('yargs'),
|
|
13
|
+
dynamicImport('yargs/helpers'),
|
|
14
|
+
]);
|
|
15
|
+
yargs(hideBin(process.argv))
|
|
16
16
|
.scriptName('skiller')
|
|
17
17
|
.usage('$0 <command> [options]')
|
|
18
18
|
.command('apply', 'Apply skiller configurations to supported AI agents', (y) => {
|
package/dist/cli/index.js
CHANGED
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.isReferenceBody = isReferenceBody;
|
|
37
37
|
exports.syncMdcToSkillMd = syncMdcToSkillMd;
|
|
38
38
|
exports.discoverSkills = discoverSkills;
|
|
39
|
+
exports.copySkillsToAgent = copySkillsToAgent;
|
|
39
40
|
exports.getSkillsGitignorePaths = getSkillsGitignorePaths;
|
|
40
41
|
exports.propagateSkills = propagateSkills;
|
|
41
42
|
exports.migrateRulesToSkills = migrateRulesToSkills;
|
|
@@ -237,21 +238,25 @@ ${yaml.dump(skillFrontmatter || { name: skillName }, { lineWidth: -1, noRefs: tr
|
|
|
237
238
|
else {
|
|
238
239
|
referencedPath = path.resolve(skillFolderPath, refCheck.referencePath);
|
|
239
240
|
}
|
|
240
|
-
// One-time migration: for old @.claude/rules/ references,
|
|
241
|
-
//
|
|
242
|
-
|
|
243
|
-
let actualPath = referencedPath;
|
|
241
|
+
// One-time migration: for old @.claude/rules/ references, prefer the
|
|
242
|
+
// original rules path if it exists, then fall back to migrated skills.
|
|
243
|
+
const candidatePaths = [referencedPath];
|
|
244
244
|
if (refCheck.referencePath?.includes('/rules/')) {
|
|
245
245
|
const refFileName = path.basename(refCheck.referencePath);
|
|
246
246
|
const refBaseName = path.basename(refFileName, '.mdc');
|
|
247
|
-
|
|
247
|
+
candidatePaths.push(path.join(skillsDir, refBaseName, refFileName));
|
|
248
248
|
}
|
|
249
249
|
let referencedContent = null;
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
250
|
+
let actualPath = referencedPath;
|
|
251
|
+
for (const candidatePath of candidatePaths) {
|
|
252
|
+
try {
|
|
253
|
+
referencedContent = await fs.readFile(candidatePath, 'utf8');
|
|
254
|
+
actualPath = candidatePath;
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
// Try next candidate
|
|
259
|
+
}
|
|
255
260
|
}
|
|
256
261
|
if (referencedContent === null) {
|
|
257
262
|
warnings.push(`Cannot migrate ${skillName}: referenced file not found at ${actualPath}`);
|
|
@@ -364,24 +369,76 @@ async function discoverSkills(projectRoot, skillerDir) {
|
|
|
364
369
|
// Walk the skills tree
|
|
365
370
|
return await (0, SkillsUtils_1.walkSkillsTree)(skillsPath);
|
|
366
371
|
}
|
|
372
|
+
/**
|
|
373
|
+
* Copies skills from source directory to target agent's skills directory.
|
|
374
|
+
* Validates skill structure and returns copy count and warnings.
|
|
375
|
+
*/
|
|
376
|
+
async function copySkillsToAgent(sourceSkillsDir, targetSkillsDir, verbose, dryRun) {
|
|
377
|
+
const warnings = [];
|
|
378
|
+
let copied = 0;
|
|
379
|
+
try {
|
|
380
|
+
await fs.access(sourceSkillsDir);
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
// Source directory doesn't exist
|
|
384
|
+
return { copied: 0, warnings: [] };
|
|
385
|
+
}
|
|
386
|
+
// Use walkSkillsTree to discover skills
|
|
387
|
+
const skillsTree = await (0, SkillsUtils_1.walkSkillsTree)(sourceSkillsDir);
|
|
388
|
+
// Validate and copy each skill
|
|
389
|
+
for (const skill of skillsTree.skills) {
|
|
390
|
+
// skill.path is absolute, use it directly
|
|
391
|
+
const skillPath = skill.path;
|
|
392
|
+
const skillMdPath = path.join(skillPath, constants_1.SKILL_MD_FILENAME);
|
|
393
|
+
// Validate: skill must have SKILL.md
|
|
394
|
+
try {
|
|
395
|
+
await fs.access(skillMdPath);
|
|
396
|
+
}
|
|
397
|
+
catch {
|
|
398
|
+
warnings.push(`Skill '${skill.name}' missing required SKILL.md file, skipping`);
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
// Copy skill directory to target using relative path
|
|
402
|
+
const relativeSkillPath = path.relative(sourceSkillsDir, skill.path);
|
|
403
|
+
const targetSkillPath = path.join(targetSkillsDir, relativeSkillPath);
|
|
404
|
+
if (!dryRun) {
|
|
405
|
+
await (0, SkillsUtils_1.copySkillsDirectory)(skillPath, targetSkillPath);
|
|
406
|
+
}
|
|
407
|
+
(0, constants_1.logVerboseInfo)(dryRun
|
|
408
|
+
? `DRY RUN: Would copy skill '${skill.name}' to ${targetSkillsDir}`
|
|
409
|
+
: `Copied skill '${skill.name}' to ${targetSkillsDir}`, verbose, dryRun);
|
|
410
|
+
copied++;
|
|
411
|
+
}
|
|
412
|
+
return { copied, warnings };
|
|
413
|
+
}
|
|
367
414
|
/**
|
|
368
415
|
* Gets the paths that skills will generate, for gitignore purposes.
|
|
369
|
-
*
|
|
370
|
-
* This function now returns an empty array as skills are committed.
|
|
416
|
+
* Collects paths from all agents with native skills support, excluding the source (.claude/skills).
|
|
371
417
|
*/
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
418
|
+
function getSkillsGitignorePaths(projectRoot, agents) {
|
|
419
|
+
const paths = [];
|
|
420
|
+
const sourceSkillsPath = path.join(projectRoot, constants_1.CLAUDE_SKILLS_PATH);
|
|
421
|
+
for (const agent of agents) {
|
|
422
|
+
if (agent.supportsNativeSkills?.() && agent.getSkillsPath) {
|
|
423
|
+
const skillsPath = agent.getSkillsPath(projectRoot);
|
|
424
|
+
if (skillsPath && skillsPath !== sourceSkillsPath) {
|
|
425
|
+
// Convert to relative path for gitignore
|
|
426
|
+
const relativePath = path.relative(projectRoot, skillsPath);
|
|
427
|
+
// Deduplicate paths
|
|
428
|
+
if (!paths.includes(relativePath)) {
|
|
429
|
+
paths.push(relativePath);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return paths;
|
|
378
435
|
}
|
|
379
436
|
/**
|
|
380
437
|
* Propagates skills for agents that need them.
|
|
381
438
|
* In the new architecture, skills are committed to .claude/skills and discovered by agents natively.
|
|
382
439
|
* This function now only discovers and validates skills.
|
|
383
440
|
*/
|
|
384
|
-
async function propagateSkills(projectRoot,
|
|
441
|
+
async function propagateSkills(projectRoot, agents, skillsEnabled, verbose, dryRun, skillerDir) {
|
|
385
442
|
if (!skillsEnabled) {
|
|
386
443
|
(0, constants_1.logVerboseInfo)('Skills support disabled', verbose, dryRun);
|
|
387
444
|
return;
|
|
@@ -422,6 +479,27 @@ async function propagateSkills(projectRoot, _agents, skillsEnabled, verbose, dry
|
|
|
422
479
|
return;
|
|
423
480
|
}
|
|
424
481
|
(0, constants_1.logVerboseInfo)(`Discovered ${skills.length} skill(s)`, verbose, dryRun);
|
|
482
|
+
// Copy skills to all agents with native skills support
|
|
483
|
+
const destinationPaths = new Set();
|
|
484
|
+
for (const agent of agents) {
|
|
485
|
+
if (agent.supportsNativeSkills?.() && agent.getSkillsPath) {
|
|
486
|
+
const targetPath = agent.getSkillsPath(projectRoot);
|
|
487
|
+
if (targetPath && targetPath !== skillsDir) {
|
|
488
|
+
// Deduplicate shared paths
|
|
489
|
+
destinationPaths.add(targetPath);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
// Copy skills to each unique destination
|
|
494
|
+
for (const targetPath of destinationPaths) {
|
|
495
|
+
const result = await copySkillsToAgent(skillsDir, targetPath, verbose, dryRun);
|
|
496
|
+
if (result.copied > 0) {
|
|
497
|
+
(0, constants_1.logVerboseInfo)(`Copied ${result.copied} skill(s) to ${targetPath}`, verbose, dryRun);
|
|
498
|
+
}
|
|
499
|
+
for (const warning of result.warnings) {
|
|
500
|
+
(0, constants_1.logWarn)(warning, dryRun);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
425
503
|
}
|
|
426
504
|
/**
|
|
427
505
|
* Recursively finds all folders containing SKILL.md in a directory.
|
package/dist/lib.js
CHANGED
|
@@ -147,7 +147,7 @@ async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cli
|
|
|
147
147
|
if (skillsEnabledForGitignore) {
|
|
148
148
|
// Skills enabled by default or explicitly
|
|
149
149
|
const { getSkillsGitignorePaths } = await Promise.resolve().then(() => __importStar(require('./core/SkillsProcessor')));
|
|
150
|
-
const skillsPaths =
|
|
150
|
+
const skillsPaths = getSkillsGitignorePaths(projectRoot, selectedAgents);
|
|
151
151
|
allGeneratedPaths = [...generatedPaths, ...skillsPaths];
|
|
152
152
|
}
|
|
153
153
|
await (0, apply_engine_1.updateGitignore)(projectRoot, allGeneratedPaths, loadedConfig, cliGitignoreEnabled, dryRun);
|