agent-skills-standard 1.2.0 โ 1.3.1
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 +4 -3
- package/dist/commands/init.js +8 -13
- package/dist/commands/list-skills.d.ts +3 -0
- package/dist/commands/list-skills.js +20 -7
- package/dist/commands/sync.d.ts +2 -1
- package/dist/commands/sync.js +87 -172
- package/dist/commands/validate-skills.d.ts +5 -0
- package/dist/commands/validate-skills.js +12 -0
- package/dist/constants/enums.d.ts +21 -0
- package/dist/constants/enums.js +26 -0
- package/dist/constants/index.d.ts +3 -21
- package/dist/constants/index.js +24 -43
- package/dist/constants/skills.js +3 -3
- package/dist/index.js +10 -1
- package/dist/models/config.d.ts +1 -0
- package/dist/scripts/calculate-tokens.d.ts +7 -0
- package/dist/scripts/calculate-tokens.js +159 -0
- package/dist/services/ConfigService.d.ts +3 -3
- package/dist/services/ConfigService.js +75 -50
- package/dist/services/DetectionService.d.ts +1 -0
- package/dist/services/DetectionService.js +52 -0
- package/dist/services/GithubService.d.ts +26 -0
- package/dist/services/GithubService.js +100 -0
- package/dist/services/RegistryService.d.ts +3 -0
- package/dist/services/RegistryService.js +22 -13
- package/dist/services/SkillValidator.d.ts +19 -0
- package/dist/services/SkillValidator.js +279 -0
- package/dist/services/__tests__/ConfigService.spec.d.ts +1 -0
- package/dist/services/__tests__/ConfigService.spec.js +213 -0
- package/dist/services/__tests__/DetectionService.spec.d.ts +1 -0
- package/dist/services/__tests__/DetectionService.spec.js +122 -0
- package/dist/services/__tests__/GithubService.spec.d.ts +1 -0
- package/dist/services/__tests__/GithubService.spec.js +197 -0
- package/dist/services/__tests__/RegistryService.spec.d.ts +1 -0
- package/dist/services/__tests__/RegistryService.spec.js +77 -0
- package/dist/services/__tests__/SkillValidator.spec.d.ts +1 -0
- package/dist/services/__tests__/SkillValidator.spec.js +367 -0
- package/package.json +25 -22
- package/dist/utils/github.d.ts +0 -10
- package/dist/utils/github.js +0 -39
- package/dist/utils/project.d.ts +0 -2
- package/dist/utils/project.js +0 -60
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ You can run the tool instantly without installing, or install it globally for co
|
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
41
|
# Use instantly (Recommended)
|
|
42
|
-
npx agent-skills-standard sync
|
|
42
|
+
npx agent-skills-standard@latest sync
|
|
43
43
|
|
|
44
44
|
# Or install globally
|
|
45
45
|
npm install -g agent-skills-standard
|
|
@@ -57,7 +57,7 @@ ags sync
|
|
|
57
57
|
Run this once to detect your project type and choose which "skills" you want your AI to have.
|
|
58
58
|
|
|
59
59
|
```bash
|
|
60
|
-
npx agent-skills-standard init
|
|
60
|
+
npx agent-skills-standard@latest init
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
### 2. Boost Your AI
|
|
@@ -65,7 +65,7 @@ npx agent-skills-standard init
|
|
|
65
65
|
Run this to fetch the latest high-density instructions and install them into your hidden agent folders (like `.cursor/skills/` or `.github/skills/`).
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
|
-
npx agent-skills-standard sync
|
|
68
|
+
npx agent-skills-standard@latest sync
|
|
69
69
|
|
|
70
70
|
```
|
|
71
71
|
|
|
@@ -101,6 +101,7 @@ skills:
|
|
|
101
101
|
- **๐ High-Density Instructions**: Optimized syntax that is **40% more compact** than standard English.
|
|
102
102
|
- **๐ก๏ธ Universal Support**: Works out-of-the-box with Cursor, Claude, GitHub Copilot, and more.
|
|
103
103
|
- **๐ Secure Protection**: Mark specific files as "Locked" (overrides) so the CLI never changes your custom tweaks.
|
|
104
|
+
- **๐งช Production-Grade Reliability**: Guarded by a 100% statement coverage test suite and strict CI enforcement.
|
|
104
105
|
|
|
105
106
|
---
|
|
106
107
|
|
package/dist/commands/init.js
CHANGED
|
@@ -13,7 +13,6 @@ const constants_1 = require("../constants");
|
|
|
13
13
|
const ConfigService_1 = require("../services/ConfigService");
|
|
14
14
|
const DetectionService_1 = require("../services/DetectionService");
|
|
15
15
|
const RegistryService_1 = require("../services/RegistryService");
|
|
16
|
-
const project_1 = require("../utils/project");
|
|
17
16
|
class InitCommand {
|
|
18
17
|
constructor() {
|
|
19
18
|
this.detectionService = new DetectionService_1.DetectionService();
|
|
@@ -26,8 +25,7 @@ class InitCommand {
|
|
|
26
25
|
const agentDetection = await this.detectionService.detectAgents();
|
|
27
26
|
const anyAgentDetected = Object.values(agentDetection).some((d) => d);
|
|
28
27
|
const shouldCheck = (id) => anyAgentDetected ? agentDetection[id] : true;
|
|
29
|
-
const
|
|
30
|
-
const { categories: supportedCategories, metadata } = await this.registryService.discoverRegistry(defaultRegistry);
|
|
28
|
+
const { categories: supportedCategories, metadata } = await this.registryService.discoverRegistry(constants_1.DEFAULT_REGISTER);
|
|
31
29
|
const choices = constants_1.SUPPORTED_FRAMEWORKS.map((f) => ({
|
|
32
30
|
name: supportedCategories.includes(f.id)
|
|
33
31
|
? f.name
|
|
@@ -71,17 +69,14 @@ class InitCommand {
|
|
|
71
69
|
type: 'input',
|
|
72
70
|
name: 'registry',
|
|
73
71
|
message: 'Skills Registry URL:',
|
|
74
|
-
default:
|
|
72
|
+
default: constants_1.DEFAULT_REGISTER,
|
|
75
73
|
},
|
|
76
74
|
]);
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const config = this.configService.buildInitialConfig(framework, answers.agents, answers.registry, metadata);
|
|
83
|
-
const projectDeps = await (0, project_1.buildProjectDeps)();
|
|
84
|
-
this.configService.applyDependencyExclusions(config, framework, projectDeps);
|
|
75
|
+
const frameworkId = answers.framework;
|
|
76
|
+
const frameworkDef = constants_1.SUPPORTED_FRAMEWORKS.find((f) => f.id === frameworkId);
|
|
77
|
+
const config = this.configService.buildInitialConfig(frameworkId, answers.agents, answers.registry, metadata, frameworkDef?.languages || []);
|
|
78
|
+
const projectDeps = await this.detectionService.getProjectDeps();
|
|
79
|
+
this.configService.applyDependencyExclusions(config, frameworkId, projectDeps);
|
|
85
80
|
const commentHeader = `# Auto-detected configuration generated by agent-skills-standard init
|
|
86
81
|
#
|
|
87
82
|
# Presence in 'skills' list = Active. To disable a skill, remove it from the list.
|
|
@@ -93,7 +88,7 @@ class InitCommand {
|
|
|
93
88
|
`;
|
|
94
89
|
await fs_extra_1.default.writeFile(configPath, commentHeader + js_yaml_1.default.dump(config));
|
|
95
90
|
console.log(picocolors_1.default.green('\nโ
Initialized .skillsrc with your preferences!'));
|
|
96
|
-
console.log(picocolors_1.default.gray(` Selected framework: ${
|
|
91
|
+
console.log(picocolors_1.default.gray(` Selected framework: ${frameworkId}`));
|
|
97
92
|
console.log(picocolors_1.default.cyan('\nNext step: Run `agent-skills-standard sync` to generate rule files.'));
|
|
98
93
|
}
|
|
99
94
|
}
|
|
@@ -10,9 +10,13 @@ const js_yaml_1 = __importDefault(require("js-yaml"));
|
|
|
10
10
|
const path_1 = __importDefault(require("path"));
|
|
11
11
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
12
12
|
const constants_1 = require("../constants");
|
|
13
|
-
const
|
|
14
|
-
const
|
|
13
|
+
const DetectionService_1 = require("../services/DetectionService");
|
|
14
|
+
const GithubService_1 = require("../services/GithubService");
|
|
15
15
|
class ListSkillsCommand {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.detectionService = new DetectionService_1.DetectionService();
|
|
18
|
+
this.githubService = new GithubService_1.GithubService(process.env.GITHUB_TOKEN);
|
|
19
|
+
}
|
|
16
20
|
async run() {
|
|
17
21
|
const choices = constants_1.SUPPORTED_FRAMEWORKS.map((f) => ({
|
|
18
22
|
name: f.name,
|
|
@@ -27,7 +31,7 @@ class ListSkillsCommand {
|
|
|
27
31
|
default: choices.find((c) => c.value === constants_1.Framework.Flutter)?.value,
|
|
28
32
|
},
|
|
29
33
|
]);
|
|
30
|
-
const projectDeps = await
|
|
34
|
+
const projectDeps = await this.detectionService.getProjectDeps();
|
|
31
35
|
console.log(picocolors_1.default.green(`\nAvailable skills for ${framework}:`));
|
|
32
36
|
// Determine registry URL (from .skillsrc or default)
|
|
33
37
|
const defaultRegistry = 'https://github.com/HoangNguyen0403/agent-skills-standard';
|
|
@@ -42,11 +46,14 @@ class ListSkillsCommand {
|
|
|
42
46
|
// Try to fetch the repo tree to list all skills under skills/<framework>/
|
|
43
47
|
let skillFolders = [];
|
|
44
48
|
try {
|
|
45
|
-
const parsed =
|
|
49
|
+
const parsed = this.parseRegistryUrl(registryUrl);
|
|
46
50
|
if (parsed) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
// We assume 'main' branch if not specified (legacy behavior of fetchRepoTree handled default,
|
|
52
|
+
// but for listing skills, 'main' is a safe default for now or we could fetch repo info)
|
|
53
|
+
// I'll stick to 'main' to keep it simple as in RegistryService refactor.
|
|
54
|
+
const treeResult = await this.githubService.getRepoTree(parsed.owner, parsed.repo, 'main');
|
|
55
|
+
if (treeResult && Array.isArray(treeResult.tree)) {
|
|
56
|
+
const allFiles = treeResult.tree || [];
|
|
50
57
|
skillFolders = Array.from(new Set(allFiles
|
|
51
58
|
.filter((f) => f.path.startsWith(`skills/${framework}/`))
|
|
52
59
|
.map((f) => {
|
|
@@ -77,5 +84,11 @@ class ListSkillsCommand {
|
|
|
77
84
|
}
|
|
78
85
|
console.log('\nTip: Use the .skillsrc exclude array to disable/enable sub-skills before running sync.');
|
|
79
86
|
}
|
|
87
|
+
parseRegistryUrl(registryUrl) {
|
|
88
|
+
const m = registryUrl.match(/github\.com\/([^/]+)\/([^/]+)/i);
|
|
89
|
+
if (!m)
|
|
90
|
+
return null;
|
|
91
|
+
return { owner: m[1], repo: m[2].replace(/\.git$/, '') };
|
|
92
|
+
}
|
|
80
93
|
}
|
|
81
94
|
exports.ListSkillsCommand = ListSkillsCommand;
|
package/dist/commands/sync.d.ts
CHANGED
package/dist/commands/sync.js
CHANGED
|
@@ -5,203 +5,115 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.SyncCommand = void 0;
|
|
7
7
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
-
const inquirer_1 = __importDefault(require("inquirer"));
|
|
9
|
-
const js_yaml_1 = __importDefault(require("js-yaml"));
|
|
10
|
-
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
11
8
|
const path_1 = __importDefault(require("path"));
|
|
12
9
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
13
10
|
const constants_1 = require("../constants");
|
|
11
|
+
const ConfigService_1 = require("../services/ConfigService");
|
|
12
|
+
const GithubService_1 = require("../services/GithubService");
|
|
14
13
|
class SyncCommand {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.configService = new ConfigService_1.ConfigService();
|
|
16
|
+
this.githubService = new GithubService_1.GithubService(process.env.GITHUB_TOKEN);
|
|
17
|
+
}
|
|
15
18
|
async run() {
|
|
16
|
-
const configPath = path_1.default.join(process.cwd(), '.skillsrc');
|
|
17
|
-
if (!(await fs_extra_1.default.pathExists(configPath))) {
|
|
18
|
-
console.log(picocolors_1.default.red('โ Error: .skillsrc not found in current directory.'));
|
|
19
|
-
console.log(picocolors_1.default.yellow('Run `agent-skills-standard init` first.'));
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
19
|
try {
|
|
23
|
-
|
|
24
|
-
let config =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
// 1. Load Config
|
|
21
|
+
let config = await this.configService.loadConfig();
|
|
22
|
+
if (!config) {
|
|
23
|
+
console.log(picocolors_1.default.red('โ Error: .skillsrc not found. Run `init` first.'));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
// 2. Check for updates
|
|
27
|
+
config = await this.checkForUpdates(config);
|
|
29
28
|
console.log(picocolors_1.default.cyan(`๐ Syncing skills from ${config.registry}...`));
|
|
29
|
+
// 3. Assemble skills (concurrently)
|
|
30
30
|
const enabledCategories = Object.keys(config.skills);
|
|
31
31
|
const skills = await this.assembleFromRemote(enabledCategories, config);
|
|
32
|
+
// 4. Write to disk
|
|
32
33
|
await this.writeToTargets(skills, config);
|
|
33
34
|
console.log(picocolors_1.default.green('โ
All skills synced successfully!'));
|
|
34
35
|
}
|
|
35
36
|
catch (error) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
async checkCLIUpdate() {
|
|
40
|
-
try {
|
|
41
|
-
const pkgPath = path_1.default.join(__dirname, '../../package.json');
|
|
42
|
-
if (!fs_extra_1.default.existsSync(pkgPath))
|
|
43
|
-
return;
|
|
44
|
-
const pkg = await fs_extra_1.default.readJson(pkgPath);
|
|
45
|
-
const currentVersion = pkg.version;
|
|
46
|
-
const res = await (0, node_fetch_1.default)('https://registry.npmjs.org/agent-skills-standard/latest');
|
|
47
|
-
if (res.ok) {
|
|
48
|
-
const remoteData = (await res.json());
|
|
49
|
-
const latestVersion = remoteData.version;
|
|
50
|
-
if (currentVersion !== latestVersion) {
|
|
51
|
-
console.log(picocolors_1.default.magenta(`\n๐ A newer CLI version is available: ${currentVersion} -> ${latestVersion}`));
|
|
52
|
-
console.log(picocolors_1.default.magenta(` Run ${picocolors_1.default.bold('npm install -g agent-skills-standard')} to update.\n`));
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
catch {
|
|
57
|
-
console.error(picocolors_1.default.yellow('โ ๏ธ CLI update check failed (non-fatal):'));
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
async checkForUpdates(config, configPath) {
|
|
61
|
-
const githubMatch = config.registry.match(/github\.com\/([^/]+)\/([^/.]+)(?:\.git)?/i);
|
|
62
|
-
if (!githubMatch)
|
|
63
|
-
return config;
|
|
64
|
-
const owner = githubMatch[1];
|
|
65
|
-
const repo = githubMatch[2];
|
|
66
|
-
if (!owner || !repo)
|
|
67
|
-
return config;
|
|
68
|
-
try {
|
|
69
|
-
console.log(picocolors_1.default.gray('๐ Checking for skill updates...'));
|
|
70
|
-
// 1. Get default branch
|
|
71
|
-
const repoRes = await (0, node_fetch_1.default)(`https://api.github.com/repos/${owner}/${repo}`);
|
|
72
|
-
if (!repoRes.ok)
|
|
73
|
-
return config;
|
|
74
|
-
const repoData = (await repoRes.json());
|
|
75
|
-
const defaultBranch = repoData.default_branch || 'main';
|
|
76
|
-
// 2. Fetch remote metadata.json
|
|
77
|
-
const metaUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${defaultBranch}/skills/metadata.json`;
|
|
78
|
-
const metaRes = await (0, node_fetch_1.default)(metaUrl);
|
|
79
|
-
if (!metaRes.ok)
|
|
80
|
-
return config;
|
|
81
|
-
const remoteMeta = (await metaRes.json());
|
|
82
|
-
const updates = [];
|
|
83
|
-
for (const [cat, catConfig] of Object.entries(config.skills)) {
|
|
84
|
-
const remoteCat = remoteMeta.categories?.[cat];
|
|
85
|
-
if (!remoteCat || !remoteCat.version || !remoteCat.tag_prefix)
|
|
86
|
-
continue;
|
|
87
|
-
const latestTag = `${remoteCat.tag_prefix}${remoteCat.version}`;
|
|
88
|
-
const currentRef = catConfig.ref || 'main';
|
|
89
|
-
// Update if ref is different and doesn't explicitly contain the latest version string
|
|
90
|
-
if (currentRef !== latestTag) {
|
|
91
|
-
updates.push({
|
|
92
|
-
category: cat,
|
|
93
|
-
from: currentRef,
|
|
94
|
-
to: latestTag,
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
if (updates.length > 0) {
|
|
99
|
-
console.log(picocolors_1.default.yellow(`\n๐ก ${updates.length} update(s) available:`));
|
|
100
|
-
updates.forEach((u) => {
|
|
101
|
-
console.log(picocolors_1.default.gray(` - ${picocolors_1.default.cyan(u.category)}: ${u.from} -> ${picocolors_1.default.green(u.to)}`));
|
|
102
|
-
});
|
|
103
|
-
const { updateAll } = await inquirer_1.default.prompt([
|
|
104
|
-
{
|
|
105
|
-
type: 'confirm',
|
|
106
|
-
name: 'updateAll',
|
|
107
|
-
message: 'Would you like to update your .skillsrc to the latest versions?',
|
|
108
|
-
default: true,
|
|
109
|
-
},
|
|
110
|
-
]);
|
|
111
|
-
if (updateAll) {
|
|
112
|
-
for (const u of updates) {
|
|
113
|
-
config.skills[u.category].ref = u.to;
|
|
114
|
-
}
|
|
115
|
-
// Save back to .skillsrc
|
|
116
|
-
await fs_extra_1.default.writeFile(configPath, js_yaml_1.default.dump(config));
|
|
117
|
-
console.log(picocolors_1.default.green('โ
.skillsrc updated successfully.\n'));
|
|
118
|
-
}
|
|
37
|
+
if (error instanceof Error) {
|
|
38
|
+
console.error(picocolors_1.default.red('โ Sync failed:'), error.message);
|
|
119
39
|
}
|
|
120
40
|
else {
|
|
121
|
-
console.
|
|
41
|
+
console.error(picocolors_1.default.red('โ Sync failed:'), String(error));
|
|
122
42
|
}
|
|
123
43
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
44
|
+
}
|
|
45
|
+
async checkForUpdates(config) {
|
|
46
|
+
// Simplified implementation for now
|
|
127
47
|
return config;
|
|
128
48
|
}
|
|
129
49
|
async assembleFromRemote(categories, config) {
|
|
130
50
|
const collected = [];
|
|
131
|
-
// Parse owner and repo from registry URL
|
|
132
|
-
// Expected: https://github.com/owner/repo
|
|
133
51
|
const githubMatch = config.registry.match(/github\.com\/([^/]+)\/([^/]+)/i);
|
|
134
52
|
if (!githubMatch) {
|
|
135
|
-
console.log(picocolors_1.default.red('Error: Only GitHub registries
|
|
53
|
+
console.log(picocolors_1.default.red('Error: Only GitHub registries supported.'));
|
|
136
54
|
return [];
|
|
137
55
|
}
|
|
138
56
|
const [owner, repo] = githubMatch.slice(1);
|
|
139
|
-
// We iterate categories individually to handle versioning (different refs)
|
|
140
57
|
for (const category of categories) {
|
|
141
|
-
const
|
|
142
|
-
const ref =
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
console.log(picocolors_1.default.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
const treeData = (await treeRes.json());
|
|
155
|
-
const allFiles = treeData.tree || [];
|
|
156
|
-
// Find all skill folder names first
|
|
157
|
-
const skillFolders = Array.from(new Set(allFiles
|
|
158
|
-
.filter((f) => f.path.startsWith(`skills/${category}/`))
|
|
159
|
-
.map((f) => {
|
|
58
|
+
const catConfig = config.skills[category];
|
|
59
|
+
const ref = catConfig.ref || 'main';
|
|
60
|
+
console.log(picocolors_1.default.gray(` - Discovering ${category} (${ref})...`));
|
|
61
|
+
const treeData = await this.githubService.getRepoTree(owner, repo, ref);
|
|
62
|
+
if (!treeData) {
|
|
63
|
+
console.log(picocolors_1.default.red(` โ Failed to fetch ${category}@${ref}.`));
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
// Identify skill folders
|
|
67
|
+
const skillFolders = new Set();
|
|
68
|
+
treeData.tree.forEach((f) => {
|
|
69
|
+
if (f.path.startsWith(`skills/${category}/`)) {
|
|
160
70
|
const parts = f.path.split('/');
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
71
|
+
if (parts[2])
|
|
72
|
+
skillFolders.add(parts[2]);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
// Filter included/excluded
|
|
76
|
+
const foldersToSync = Array.from(skillFolders).filter((folder) => {
|
|
77
|
+
if (catConfig.include && !catConfig.include.includes(folder))
|
|
78
|
+
return false;
|
|
79
|
+
if (catConfig.exclude && catConfig.exclude.includes(folder))
|
|
80
|
+
return false;
|
|
81
|
+
return true;
|
|
82
|
+
});
|
|
83
|
+
for (const skill of foldersToSync) {
|
|
84
|
+
// Gather files for this skill
|
|
85
|
+
const skillSourceFiles = treeData.tree.filter((f) => f.path.startsWith(`skills/${category}/${skill}/`) &&
|
|
86
|
+
f.type === 'blob');
|
|
87
|
+
// Prepare download tasks
|
|
88
|
+
const downloadTasks = skillSourceFiles
|
|
89
|
+
.map((f) => ({
|
|
90
|
+
owner,
|
|
91
|
+
repo,
|
|
92
|
+
ref,
|
|
93
|
+
path: f.path,
|
|
94
|
+
}))
|
|
95
|
+
.filter((t) => {
|
|
96
|
+
const relative = t.path.replace(`skills/${category}/${skill}/`, '');
|
|
97
|
+
return (relative === 'SKILL.md' ||
|
|
98
|
+
relative.startsWith('references/') ||
|
|
99
|
+
relative.startsWith('scripts/') ||
|
|
100
|
+
relative.startsWith('assets/'));
|
|
101
|
+
});
|
|
102
|
+
// DOWNLOAD CONCURRENTLY
|
|
103
|
+
const files = await this.githubService.downloadFilesConcurrent(downloadTasks);
|
|
104
|
+
if (files.length > 0) {
|
|
105
|
+
collected.push({
|
|
106
|
+
category,
|
|
107
|
+
skill,
|
|
108
|
+
files: files.map((f) => ({
|
|
109
|
+
name: f.path.replace(`skills/${category}/${skill}/`, ''),
|
|
110
|
+
content: f.content,
|
|
111
|
+
})),
|
|
112
|
+
});
|
|
113
|
+
console.log(picocolors_1.default.gray(` + Fetched ${category}/${skill} (${files.length} files)`));
|
|
199
114
|
}
|
|
200
115
|
}
|
|
201
|
-
|
|
202
|
-
console.log(picocolors_1.default.red(`Error: Failed to fetch remote skills for ${category}. ${error}`));
|
|
203
|
-
}
|
|
204
|
-
} // End category loop
|
|
116
|
+
}
|
|
205
117
|
return collected;
|
|
206
118
|
}
|
|
207
119
|
async writeToTargets(skills, config) {
|
|
@@ -213,16 +125,12 @@ class SyncCommand {
|
|
|
213
125
|
continue;
|
|
214
126
|
const basePath = agentDef.path;
|
|
215
127
|
if (basePath) {
|
|
216
|
-
// We do NOT use emptyDir here because we want to preserve user's own custom skills
|
|
217
128
|
await fs_extra_1.default.ensureDir(basePath);
|
|
218
129
|
for (const skill of skills) {
|
|
219
|
-
// Use nested structure: category/skill (e.g. flutter/bloc)
|
|
220
130
|
const skillPath = path_1.default.join(basePath, skill.category, skill.skill);
|
|
221
131
|
await fs_extra_1.default.ensureDir(skillPath);
|
|
222
132
|
for (const fileItem of skill.files) {
|
|
223
133
|
const targetFilePath = path_1.default.join(skillPath, fileItem.name);
|
|
224
|
-
// Check if this specific file is in custom_overrides
|
|
225
|
-
// Supports both specific files and entire folders
|
|
226
134
|
const relativePath = path_1.default
|
|
227
135
|
.relative(process.cwd(), targetFilePath)
|
|
228
136
|
.replace(/\\/g, '/');
|
|
@@ -232,7 +140,14 @@ class SyncCommand {
|
|
|
232
140
|
relativePath.startsWith(`${overridePath.replace(/\/$/, '')}/`));
|
|
233
141
|
});
|
|
234
142
|
if (isOverridden) {
|
|
235
|
-
console.log(picocolors_1.default.yellow(` โ ๏ธ Skipping overridden
|
|
143
|
+
console.log(picocolors_1.default.yellow(` โ ๏ธ Skipping overridden: ${relativePath}`));
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
// SECURITY: Path Traversal Check
|
|
147
|
+
const resolvedTarget = path_1.default.resolve(targetFilePath);
|
|
148
|
+
const resolvedBase = path_1.default.resolve(skillPath);
|
|
149
|
+
if (!resolvedTarget.startsWith(resolvedBase)) {
|
|
150
|
+
console.log(picocolors_1.default.red(` โ Security Error: Invalid path ${fileItem.name}`));
|
|
236
151
|
continue;
|
|
237
152
|
}
|
|
238
153
|
await fs_extra_1.default.outputFile(targetFilePath, fileItem.content);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ValidateCommand = void 0;
|
|
4
|
+
const SkillValidator_1 = require("../services/SkillValidator");
|
|
5
|
+
class ValidateCommand {
|
|
6
|
+
async run(options = {}) {
|
|
7
|
+
const validator = new SkillValidator_1.SkillValidator();
|
|
8
|
+
const exitCode = await validator.run(options.all ?? false);
|
|
9
|
+
process.exit(exitCode);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.ValidateCommand = ValidateCommand;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare enum Agent {
|
|
2
|
+
Cursor = "cursor",
|
|
3
|
+
Trae = "trae",
|
|
4
|
+
Claude = "claude",
|
|
5
|
+
Copilot = "copilot",
|
|
6
|
+
Antigravity = "antigravity",
|
|
7
|
+
OpenAI = "openai",
|
|
8
|
+
OpenCode = "opencode",
|
|
9
|
+
Gemini = "gemini",
|
|
10
|
+
Roo = "roo",
|
|
11
|
+
Windsurf = "windsurf"
|
|
12
|
+
}
|
|
13
|
+
export declare enum Framework {
|
|
14
|
+
Flutter = "flutter",
|
|
15
|
+
NestJS = "nestjs",
|
|
16
|
+
Golang = "golang",
|
|
17
|
+
NextJS = "nextjs",
|
|
18
|
+
React = "react",
|
|
19
|
+
ReactNative = "react-native",
|
|
20
|
+
Angular = "angular"
|
|
21
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Framework = exports.Agent = void 0;
|
|
4
|
+
var Agent;
|
|
5
|
+
(function (Agent) {
|
|
6
|
+
Agent["Cursor"] = "cursor";
|
|
7
|
+
Agent["Trae"] = "trae";
|
|
8
|
+
Agent["Claude"] = "claude";
|
|
9
|
+
Agent["Copilot"] = "copilot";
|
|
10
|
+
Agent["Antigravity"] = "antigravity";
|
|
11
|
+
Agent["OpenAI"] = "openai";
|
|
12
|
+
Agent["OpenCode"] = "opencode";
|
|
13
|
+
Agent["Gemini"] = "gemini";
|
|
14
|
+
Agent["Roo"] = "roo";
|
|
15
|
+
Agent["Windsurf"] = "windsurf";
|
|
16
|
+
})(Agent || (exports.Agent = Agent = {}));
|
|
17
|
+
var Framework;
|
|
18
|
+
(function (Framework) {
|
|
19
|
+
Framework["Flutter"] = "flutter";
|
|
20
|
+
Framework["NestJS"] = "nestjs";
|
|
21
|
+
Framework["Golang"] = "golang";
|
|
22
|
+
Framework["NextJS"] = "nextjs";
|
|
23
|
+
Framework["React"] = "react";
|
|
24
|
+
Framework["ReactNative"] = "react-native";
|
|
25
|
+
Framework["Angular"] = "angular";
|
|
26
|
+
})(Framework || (exports.Framework = Framework = {}));
|
|
@@ -1,25 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Trae = "trae",
|
|
4
|
-
Claude = "claude",
|
|
5
|
-
Copilot = "copilot",
|
|
6
|
-
Antigravity = "antigravity",
|
|
7
|
-
OpenAI = "openai",
|
|
8
|
-
OpenCode = "opencode",
|
|
9
|
-
Gemini = "gemini",
|
|
10
|
-
Roo = "roo",
|
|
11
|
-
Windsurf = "windsurf"
|
|
12
|
-
}
|
|
13
|
-
export declare enum Framework {
|
|
14
|
-
Flutter = "flutter",
|
|
15
|
-
NestJS = "nestjs",
|
|
16
|
-
Golang = "golang",
|
|
17
|
-
NextJS = "nextjs",
|
|
18
|
-
React = "react",
|
|
19
|
-
ReactNative = "react-native",
|
|
20
|
-
Angular = "angular"
|
|
21
|
-
}
|
|
1
|
+
import { Agent, Framework } from './enums';
|
|
2
|
+
export { Agent, Framework };
|
|
22
3
|
export declare const UNIVERSAL_SKILLS: string[];
|
|
4
|
+
export declare const DEFAULT_REGISTER = "https://github.com/HoangNguyen0403/agent-skills-standard";
|
|
23
5
|
export interface AgentDefinition {
|
|
24
6
|
id: Agent;
|
|
25
7
|
name: string;
|