agent-skills-standard 1.1.0 → 1.1.2
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 +5 -2
- package/dist/commands/init.js +67 -33
- package/dist/commands/list-skills.d.ts +3 -0
- package/dist/commands/list-skills.js +81 -0
- package/dist/constants/index.d.ts +25 -2
- package/dist/constants/index.js +153 -93
- package/dist/constants/skills.d.ts +13 -0
- package/dist/constants/skills.js +57 -0
- package/dist/index.js +9 -1
- package/dist/utils/github.d.ts +10 -0
- package/dist/utils/github.js +39 -0
- package/dist/utils/project.d.ts +2 -0
- package/dist/utils/project.js +60 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
**The engine behind High-Density AI coding. Command your AI assistants with professional standards.**
|
|
7
7
|
|
|
8
|
-
The `agent-skills-standard` CLI is the official command-line tool to manage, sync, and version-control engineering standards across all major AI agents (**Cursor, Claude Code, GitHub Copilot,
|
|
8
|
+
The `agent-skills-standard` CLI is the official command-line tool to manage, sync, and version-control engineering standards across all major AI agents (**Cursor, Claude Code, GitHub Copilot, Gemini, Roo Code, OpenCode, and more**).
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -86,7 +86,10 @@ The CLI connects to the [Official Skills Registry](https://github.com/HoangNguye
|
|
|
86
86
|
|
|
87
87
|
- **Flutter**: Clean Architecture, BLoC, AutoRoute, Performance, Security.
|
|
88
88
|
- **Dart**: Idiomatic Patterns, Advanced Tooling.
|
|
89
|
-
- **
|
|
89
|
+
- **TypeScript/JavaScript**: Best practices, Security, Tooling.
|
|
90
|
+
- **React**: Hooks, Patterns, Performance.
|
|
91
|
+
- **NestJS**: Architecture, Microservices, Security.
|
|
92
|
+
- **Next.js**: App Router, RSC, FSD Architecture.
|
|
90
93
|
- **Golang**: (Coming Soon)
|
|
91
94
|
|
|
92
95
|
---
|
package/dist/commands/init.js
CHANGED
|
@@ -11,10 +11,12 @@ const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
|
11
11
|
const path_1 = __importDefault(require("path"));
|
|
12
12
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
13
13
|
const constants_1 = require("../constants");
|
|
14
|
+
const github_1 = require("../utils/github");
|
|
15
|
+
const project_1 = require("../utils/project");
|
|
14
16
|
class InitCommand {
|
|
15
17
|
async run() {
|
|
16
18
|
const configPath = path_1.default.join(process.cwd(), '.skillsrc');
|
|
17
|
-
// Load package.json for dependency checks
|
|
19
|
+
// Load package.json for dependency checks (for framework detection)
|
|
18
20
|
const packageJsonPath = path_1.default.join(process.cwd(), 'package.json');
|
|
19
21
|
let packageDeps = {};
|
|
20
22
|
if (await fs_extra_1.default.pathExists(packageJsonPath)) {
|
|
@@ -64,33 +66,30 @@ class InitCommand {
|
|
|
64
66
|
// Default to a sane list if registry is unreachable
|
|
65
67
|
let supportedCategories = ['flutter', 'dart'];
|
|
66
68
|
let metadata = {};
|
|
67
|
-
|
|
68
|
-
const metadataUrl = 'https://raw.githubusercontent.com/HoangNguyen0403/agent-skills-standard/main/skills/metadata.json';
|
|
69
|
+
// Attempt to discover available categories and registry metadata from the canonical registry
|
|
69
70
|
try {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
// Extract top-level folders in skills/
|
|
83
|
-
const categories = new Set();
|
|
84
|
-
allFiles.forEach((f) => {
|
|
85
|
-
if (f.path.startsWith('skills/') && f.type === 'tree') {
|
|
86
|
-
const parts = f.path.split('/');
|
|
87
|
-
if (parts.length === 2) {
|
|
88
|
-
categories.add(parts[1]);
|
|
71
|
+
const defaultRegistry = 'https://github.com/HoangNguyen0403/agent-skills-standard';
|
|
72
|
+
const parsed = (0, github_1.parseRegistryUrl)(defaultRegistry);
|
|
73
|
+
if (parsed) {
|
|
74
|
+
const treeResult = await (0, github_1.fetchRepoTree)(parsed.owner, parsed.repo);
|
|
75
|
+
if (treeResult && Array.isArray(treeResult.data.tree)) {
|
|
76
|
+
const allFiles = treeResult.data.tree || [];
|
|
77
|
+
const categories = new Set();
|
|
78
|
+
allFiles.forEach((f) => {
|
|
79
|
+
if (f.path.startsWith('skills/') && f.type === 'tree') {
|
|
80
|
+
const parts = f.path.split('/');
|
|
81
|
+
if (parts.length === 2)
|
|
82
|
+
categories.add(parts[1]);
|
|
89
83
|
}
|
|
84
|
+
});
|
|
85
|
+
if (categories.size > 0)
|
|
86
|
+
supportedCategories = Array.from(categories);
|
|
87
|
+
// Try to fetch metadata.json at the resolved branch
|
|
88
|
+
const metaUrl = `https://raw.githubusercontent.com/${parsed.owner}/${parsed.repo}/${treeResult.branch}/skills/metadata.json`;
|
|
89
|
+
const metaRes = await (0, node_fetch_1.default)(metaUrl);
|
|
90
|
+
if (metaRes.ok) {
|
|
91
|
+
metadata = (await metaRes.json());
|
|
90
92
|
}
|
|
91
|
-
});
|
|
92
|
-
if (categories.size > 0) {
|
|
93
|
-
supportedCategories = Array.from(categories);
|
|
94
93
|
}
|
|
95
94
|
}
|
|
96
95
|
}
|
|
@@ -145,18 +144,25 @@ class InitCommand {
|
|
|
145
144
|
default: 'https://github.com/HoangNguyen0403/agent-skills-standard',
|
|
146
145
|
},
|
|
147
146
|
]);
|
|
148
|
-
const
|
|
149
|
-
const selectedFramework = constants_1.SUPPORTED_FRAMEWORKS.find((f) => f.id ===
|
|
150
|
-
const isSupported = supportedCategories.includes(
|
|
147
|
+
const framework = answers.framework;
|
|
148
|
+
const selectedFramework = constants_1.SUPPORTED_FRAMEWORKS.find((f) => f.id === framework);
|
|
149
|
+
const isSupported = supportedCategories.includes(framework);
|
|
151
150
|
if (!isSupported) {
|
|
152
|
-
console.log(picocolors_1.default.yellow(`\nNotice: Skills for ${
|
|
151
|
+
console.log(picocolors_1.default.yellow(`\nNotice: Skills for ${framework} are not yet strictly defined and will be added soon.`));
|
|
153
152
|
console.log(picocolors_1.default.gray('The CLI will still generate rule files with global standards.\n'));
|
|
154
153
|
}
|
|
155
154
|
const neededSkills = new Set();
|
|
156
|
-
neededSkills.add(
|
|
155
|
+
neededSkills.add(framework);
|
|
157
156
|
if (selectedFramework) {
|
|
158
157
|
selectedFramework.languages.forEach((l) => neededSkills.add(l));
|
|
159
158
|
}
|
|
159
|
+
// Special case: Next.js and React Native imply React
|
|
160
|
+
if (framework === constants_1.Framework.NextJS || framework === constants_1.Framework.ReactNative) {
|
|
161
|
+
neededSkills.add(constants_1.Framework.React);
|
|
162
|
+
}
|
|
163
|
+
// Add framework-specific skills from the registry to potential skills
|
|
164
|
+
const frameworkSkills = constants_1.SKILL_DETECTION_REGISTRY[framework] || [];
|
|
165
|
+
frameworkSkills.forEach((s) => neededSkills.add(s.id));
|
|
160
166
|
const config = {
|
|
161
167
|
registry: answers.registry,
|
|
162
168
|
agents: answers.agents,
|
|
@@ -168,6 +174,7 @@ class InitCommand {
|
|
|
168
174
|
const allKnownCategories = [
|
|
169
175
|
...constants_1.SUPPORTED_FRAMEWORKS.map((f) => f.id),
|
|
170
176
|
...constants_1.SUPPORTED_FRAMEWORKS.flatMap((f) => f.languages),
|
|
177
|
+
...Object.values(constants_1.SKILL_DETECTION_REGISTRY).flatMap((skills) => skills.map((s) => s.id)),
|
|
171
178
|
];
|
|
172
179
|
for (const skill of [...new Set(allKnownCategories)]) {
|
|
173
180
|
if (neededSkills.has(skill)) {
|
|
@@ -182,11 +189,38 @@ class InitCommand {
|
|
|
182
189
|
};
|
|
183
190
|
}
|
|
184
191
|
}
|
|
185
|
-
|
|
192
|
+
// Detect common framework skills and disable them if not used
|
|
193
|
+
const projectDeps = await (0, project_1.buildProjectDeps)();
|
|
194
|
+
for (const skill of frameworkSkills) {
|
|
195
|
+
const entry = config.skills[skill.id];
|
|
196
|
+
if (!entry)
|
|
197
|
+
continue;
|
|
198
|
+
// Only rely on declared dependencies for detection.
|
|
199
|
+
const used = skill.packages.some((p) => projectDeps.has(p));
|
|
200
|
+
// If not used, add to parent framework's exclude list so users
|
|
201
|
+
// see which sub-skills were disabled by detection and can opt-in.
|
|
202
|
+
if (!used) {
|
|
203
|
+
const parent = config.skills[framework] || { enabled: true };
|
|
204
|
+
const excludes = parent.exclude ? [...parent.exclude] : [];
|
|
205
|
+
if (!excludes.includes(skill.id))
|
|
206
|
+
excludes.push(skill.id);
|
|
207
|
+
parent.exclude = excludes;
|
|
208
|
+
config.skills[framework] = parent;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const commentHeader = `# Auto-detected configuration generated by agent-skills-standard init
|
|
212
|
+
#
|
|
213
|
+
# 'exclude': IDs of sub-skills to skip during sync (auto-populated with undetected skills).
|
|
214
|
+
# 'custom_overrides': IDs of skills to PROTECT. Use this if you have modified a standard
|
|
215
|
+
# skill locally and don't want the CLI to overwrite it.
|
|
216
|
+
#
|
|
217
|
+
# Run 'ags list-skills' to view all available skills.
|
|
218
|
+
`;
|
|
219
|
+
await fs_extra_1.default.writeFile(configPath, commentHeader + js_yaml_1.default.dump(config));
|
|
186
220
|
console.log(picocolors_1.default.green('\n✅ Initialized .skillsrc with your preferences!'));
|
|
187
|
-
console.log(picocolors_1.default.gray(` Selected framework: ${
|
|
221
|
+
console.log(picocolors_1.default.gray(` Selected framework: ${framework}`));
|
|
188
222
|
console.log(picocolors_1.default.gray(` Auto-enabled languages: ${Array.from(neededSkills)
|
|
189
|
-
.filter((s) => s !==
|
|
223
|
+
.filter((s) => s !== framework)
|
|
190
224
|
.join(', ') || 'none'}`));
|
|
191
225
|
console.log(picocolors_1.default.cyan('\nNext step: Run `agent-skills-standard sync` to generate rule files.'));
|
|
192
226
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ListSkillsCommand = void 0;
|
|
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 path_1 = __importDefault(require("path"));
|
|
11
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
12
|
+
const constants_1 = require("../constants");
|
|
13
|
+
const github_1 = require("../utils/github");
|
|
14
|
+
const project_1 = require("../utils/project");
|
|
15
|
+
class ListSkillsCommand {
|
|
16
|
+
async run() {
|
|
17
|
+
const choices = constants_1.SUPPORTED_FRAMEWORKS.map((f) => ({
|
|
18
|
+
name: f.name,
|
|
19
|
+
value: f.id,
|
|
20
|
+
}));
|
|
21
|
+
const { framework } = await inquirer_1.default.prompt([
|
|
22
|
+
{
|
|
23
|
+
type: 'list',
|
|
24
|
+
name: 'framework',
|
|
25
|
+
message: 'Select framework to list available skills for:',
|
|
26
|
+
choices,
|
|
27
|
+
default: choices.find((c) => c.value === constants_1.Framework.Flutter)?.value,
|
|
28
|
+
},
|
|
29
|
+
]);
|
|
30
|
+
const projectDeps = await (0, project_1.buildProjectDeps)();
|
|
31
|
+
console.log(picocolors_1.default.green(`\nAvailable skills for ${framework}:`));
|
|
32
|
+
// Determine registry URL (from .skillsrc or default)
|
|
33
|
+
const defaultRegistry = 'https://github.com/HoangNguyen0403/agent-skills-standard';
|
|
34
|
+
let registryUrl = defaultRegistry;
|
|
35
|
+
const configPath = path_1.default.join(process.cwd(), '.skillsrc');
|
|
36
|
+
if (await fs_extra_1.default.pathExists(configPath)) {
|
|
37
|
+
const raw = await fs_extra_1.default.readFile(configPath, 'utf8');
|
|
38
|
+
const conf = js_yaml_1.default.load(raw);
|
|
39
|
+
if (conf && conf.registry)
|
|
40
|
+
registryUrl = conf.registry;
|
|
41
|
+
}
|
|
42
|
+
// Try to fetch the repo tree to list all skills under skills/<framework>/
|
|
43
|
+
let skillFolders = [];
|
|
44
|
+
try {
|
|
45
|
+
const parsed = (0, github_1.parseRegistryUrl)(registryUrl);
|
|
46
|
+
if (parsed) {
|
|
47
|
+
const treeResult = await (0, github_1.fetchRepoTree)(parsed.owner, parsed.repo);
|
|
48
|
+
if (treeResult && Array.isArray(treeResult.data.tree)) {
|
|
49
|
+
const allFiles = treeResult.data.tree || [];
|
|
50
|
+
skillFolders = Array.from(new Set(allFiles
|
|
51
|
+
.filter((f) => f.path.startsWith(`skills/${framework}/`))
|
|
52
|
+
.map((f) => {
|
|
53
|
+
const parts = f.path.split('/');
|
|
54
|
+
return parts[2];
|
|
55
|
+
})
|
|
56
|
+
.filter(Boolean)));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// ignore network errors and fall back to detection registry
|
|
62
|
+
}
|
|
63
|
+
// Fallback: use detection registry skill ids if we couldn't fetch tree
|
|
64
|
+
const detectSkills = constants_1.SKILL_DETECTION_REGISTRY[framework] || [];
|
|
65
|
+
if (!skillFolders || skillFolders.length === 0) {
|
|
66
|
+
skillFolders = detectSkills.map((s) => s.id);
|
|
67
|
+
}
|
|
68
|
+
// For each discovered skill, show whether it would be detected (if we have rules)
|
|
69
|
+
for (const skillName of skillFolders.sort()) {
|
|
70
|
+
const detectRule = detectSkills.find((x) => x.id === skillName);
|
|
71
|
+
let mark = picocolors_1.default.yellow('no-rule');
|
|
72
|
+
if (detectRule) {
|
|
73
|
+
const present = detectRule.packages.some((p) => projectDeps.has(p));
|
|
74
|
+
mark = present ? picocolors_1.default.green('detected') : picocolors_1.default.gray('not-detected');
|
|
75
|
+
}
|
|
76
|
+
console.log(`- ${skillName} (${mark})`);
|
|
77
|
+
}
|
|
78
|
+
console.log('\nTip: Use the .skillsrc exclude array to disable/enable sub-skills before running sync.');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.ListSkillsCommand = ListSkillsCommand;
|
|
@@ -1,15 +1,38 @@
|
|
|
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
|
+
}
|
|
12
|
+
export declare enum Framework {
|
|
13
|
+
Flutter = "flutter",
|
|
14
|
+
NestJS = "nestjs",
|
|
15
|
+
Golang = "golang",
|
|
16
|
+
NextJS = "nextjs",
|
|
17
|
+
React = "react",
|
|
18
|
+
ReactNative = "react-native",
|
|
19
|
+
Angular = "angular"
|
|
20
|
+
}
|
|
1
21
|
export interface AgentDefinition {
|
|
2
|
-
id:
|
|
22
|
+
id: Agent;
|
|
3
23
|
name: string;
|
|
4
24
|
path: string;
|
|
5
25
|
detectionFiles: string[];
|
|
6
26
|
}
|
|
7
27
|
export interface FrameworkDefinition {
|
|
8
|
-
id:
|
|
28
|
+
id: Framework;
|
|
9
29
|
name: string;
|
|
10
30
|
languages: string[];
|
|
11
31
|
detectionFiles: string[];
|
|
12
32
|
detectionDependencies?: string[];
|
|
13
33
|
}
|
|
34
|
+
export declare const getAgentDefinition: (id: Agent) => AgentDefinition;
|
|
35
|
+
export declare const getFrameworkDefinition: (id: Framework) => FrameworkDefinition;
|
|
14
36
|
export declare const SUPPORTED_AGENTS: AgentDefinition[];
|
|
15
37
|
export declare const SUPPORTED_FRAMEWORKS: FrameworkDefinition[];
|
|
38
|
+
export { SKILL_DETECTION_REGISTRY, SkillDetection } from './skills';
|
package/dist/constants/index.js
CHANGED
|
@@ -1,95 +1,155 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SUPPORTED_FRAMEWORKS = exports.SUPPORTED_AGENTS = void 0;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
]
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
3
|
+
exports.SKILL_DETECTION_REGISTRY = exports.SUPPORTED_FRAMEWORKS = exports.SUPPORTED_AGENTS = exports.getFrameworkDefinition = exports.getAgentDefinition = 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 || (exports.Agent = Agent = {}));
|
|
16
|
+
var Framework;
|
|
17
|
+
(function (Framework) {
|
|
18
|
+
Framework["Flutter"] = "flutter";
|
|
19
|
+
Framework["NestJS"] = "nestjs";
|
|
20
|
+
Framework["Golang"] = "golang";
|
|
21
|
+
Framework["NextJS"] = "nextjs";
|
|
22
|
+
Framework["React"] = "react";
|
|
23
|
+
Framework["ReactNative"] = "react-native";
|
|
24
|
+
Framework["Angular"] = "angular";
|
|
25
|
+
})(Framework || (exports.Framework = Framework = {}));
|
|
26
|
+
const getAgentDefinition = (id) => {
|
|
27
|
+
switch (id) {
|
|
28
|
+
case Agent.Cursor:
|
|
29
|
+
return {
|
|
30
|
+
id,
|
|
31
|
+
name: 'Cursor',
|
|
32
|
+
path: '.cursor/skills',
|
|
33
|
+
detectionFiles: ['.cursor', '.cursorrules'],
|
|
34
|
+
};
|
|
35
|
+
case Agent.Trae:
|
|
36
|
+
return {
|
|
37
|
+
id,
|
|
38
|
+
name: 'Trae',
|
|
39
|
+
path: '.trae/skills',
|
|
40
|
+
detectionFiles: ['.trae'],
|
|
41
|
+
};
|
|
42
|
+
case Agent.Claude:
|
|
43
|
+
return {
|
|
44
|
+
id,
|
|
45
|
+
name: 'Claude Code',
|
|
46
|
+
path: '.claude/skills',
|
|
47
|
+
detectionFiles: ['.claude', 'CLAUDE.md'],
|
|
48
|
+
};
|
|
49
|
+
case Agent.Copilot:
|
|
50
|
+
return {
|
|
51
|
+
id,
|
|
52
|
+
name: 'GitHub Copilot',
|
|
53
|
+
path: '.github/skills',
|
|
54
|
+
detectionFiles: ['.github'],
|
|
55
|
+
};
|
|
56
|
+
case Agent.Antigravity:
|
|
57
|
+
return {
|
|
58
|
+
id,
|
|
59
|
+
name: 'Antigravity',
|
|
60
|
+
path: '.agent/skills',
|
|
61
|
+
detectionFiles: ['.agent'],
|
|
62
|
+
};
|
|
63
|
+
case Agent.OpenAI:
|
|
64
|
+
return {
|
|
65
|
+
id,
|
|
66
|
+
name: 'OpenAI',
|
|
67
|
+
path: '.codex/skills',
|
|
68
|
+
detectionFiles: ['.codex'],
|
|
69
|
+
};
|
|
70
|
+
case Agent.OpenCode:
|
|
71
|
+
return {
|
|
72
|
+
id,
|
|
73
|
+
name: 'OpenCode',
|
|
74
|
+
path: '.opencode/skills',
|
|
75
|
+
detectionFiles: ['.opencode'],
|
|
76
|
+
};
|
|
77
|
+
case Agent.Gemini:
|
|
78
|
+
return {
|
|
79
|
+
id,
|
|
80
|
+
name: 'Gemini',
|
|
81
|
+
path: '.gemini/skills',
|
|
82
|
+
detectionFiles: ['.gemini'],
|
|
83
|
+
};
|
|
84
|
+
case Agent.Roo:
|
|
85
|
+
return {
|
|
86
|
+
id,
|
|
87
|
+
name: 'Roo Code',
|
|
88
|
+
path: '.roo/skills',
|
|
89
|
+
detectionFiles: ['.roo'],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
exports.getAgentDefinition = getAgentDefinition;
|
|
94
|
+
const getFrameworkDefinition = (id) => {
|
|
95
|
+
switch (id) {
|
|
96
|
+
case Framework.Flutter:
|
|
97
|
+
return {
|
|
98
|
+
id,
|
|
99
|
+
name: 'Flutter',
|
|
100
|
+
languages: ['dart'],
|
|
101
|
+
detectionFiles: ['pubspec.yaml'],
|
|
102
|
+
};
|
|
103
|
+
case Framework.NestJS:
|
|
104
|
+
return {
|
|
105
|
+
id,
|
|
106
|
+
name: 'NestJS',
|
|
107
|
+
languages: ['typescript', 'javascript'],
|
|
108
|
+
detectionFiles: ['nest-cli.json'],
|
|
109
|
+
detectionDependencies: ['@nestjs/core'],
|
|
110
|
+
};
|
|
111
|
+
case Framework.Golang:
|
|
112
|
+
return {
|
|
113
|
+
id,
|
|
114
|
+
name: 'Go (Golang)',
|
|
115
|
+
languages: ['go'],
|
|
116
|
+
detectionFiles: ['go.mod'],
|
|
117
|
+
};
|
|
118
|
+
case Framework.NextJS:
|
|
119
|
+
return {
|
|
120
|
+
id,
|
|
121
|
+
name: 'Next.js',
|
|
122
|
+
languages: ['typescript', 'javascript'],
|
|
123
|
+
detectionFiles: ['next.config.js', 'next.config.mjs'],
|
|
124
|
+
detectionDependencies: ['next'],
|
|
125
|
+
};
|
|
126
|
+
case Framework.React:
|
|
127
|
+
return {
|
|
128
|
+
id,
|
|
129
|
+
name: 'React',
|
|
130
|
+
languages: ['typescript', 'javascript'],
|
|
131
|
+
detectionFiles: [],
|
|
132
|
+
detectionDependencies: ['react', 'react-dom'],
|
|
133
|
+
};
|
|
134
|
+
case Framework.ReactNative:
|
|
135
|
+
return {
|
|
136
|
+
id,
|
|
137
|
+
name: 'React Native',
|
|
138
|
+
languages: ['typescript', 'javascript'],
|
|
139
|
+
detectionFiles: ['metro.config.js'],
|
|
140
|
+
detectionDependencies: ['react-native'],
|
|
141
|
+
};
|
|
142
|
+
case Framework.Angular:
|
|
143
|
+
return {
|
|
144
|
+
id,
|
|
145
|
+
name: 'Angular',
|
|
146
|
+
languages: ['typescript'],
|
|
147
|
+
detectionFiles: ['angular.json'],
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
exports.getFrameworkDefinition = getFrameworkDefinition;
|
|
152
|
+
exports.SUPPORTED_AGENTS = Object.values(Agent).map(exports.getAgentDefinition);
|
|
153
|
+
exports.SUPPORTED_FRAMEWORKS = Object.values(Framework).map(exports.getFrameworkDefinition);
|
|
154
|
+
var skills_1 = require("./skills");
|
|
155
|
+
Object.defineProperty(exports, "SKILL_DETECTION_REGISTRY", { enumerable: true, get: function () { return skills_1.SKILL_DETECTION_REGISTRY; } });
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SkillDetection defines how to automatically enable a skill based on project dependencies.
|
|
3
|
+
*/
|
|
4
|
+
export interface SkillDetection {
|
|
5
|
+
/** The skill ID as defined in the registry (e.g., 'riverpod-state-management') */
|
|
6
|
+
id: string;
|
|
7
|
+
/** List of npm or pub packages that indicate this skill is used */
|
|
8
|
+
packages: string[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Registry of automatic skill detection rules grouped by framework.
|
|
12
|
+
*/
|
|
13
|
+
export declare const SKILL_DETECTION_REGISTRY: Record<string, SkillDetection[]>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SKILL_DETECTION_REGISTRY = void 0;
|
|
4
|
+
const index_1 = require("./index");
|
|
5
|
+
/**
|
|
6
|
+
* Registry of automatic skill detection rules grouped by framework.
|
|
7
|
+
*/
|
|
8
|
+
exports.SKILL_DETECTION_REGISTRY = {
|
|
9
|
+
[index_1.Framework.Flutter]: [
|
|
10
|
+
{
|
|
11
|
+
id: 'riverpod-state-management',
|
|
12
|
+
packages: ['flutter_riverpod', 'riverpod'],
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: 'bloc-state-management',
|
|
16
|
+
packages: ['flutter_bloc', 'bloc'],
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: 'auto-route-navigation',
|
|
20
|
+
packages: ['auto_route'],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: 'go-router-navigation',
|
|
24
|
+
packages: ['go_router'],
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 'getx-navigation',
|
|
28
|
+
packages: ['get'],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 'getx-state-management',
|
|
32
|
+
packages: ['get'],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 'localization',
|
|
36
|
+
packages: ['easy_localization'],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: 'retrofit-networking',
|
|
40
|
+
packages: ['retrofit'],
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
[index_1.Framework.NestJS]: [
|
|
44
|
+
{
|
|
45
|
+
id: 'caching',
|
|
46
|
+
packages: ['@nestjs/cache-manager', 'cache-manager'],
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: 'database',
|
|
50
|
+
packages: ['@nestjs/typeorm', '@nestjs/prisma', '@nestjs/mongoose'],
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: 'security',
|
|
54
|
+
packages: ['@nestjs/passport', 'passport', 'helmet'],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const commander_1 = require("commander");
|
|
5
5
|
const init_1 = require("./commands/init");
|
|
6
|
+
const list_skills_1 = require("./commands/list-skills");
|
|
6
7
|
const sync_1 = require("./commands/sync");
|
|
7
8
|
const program = new commander_1.Command();
|
|
8
9
|
program
|
|
9
10
|
.name('agent-skills-standard')
|
|
10
11
|
.description('A CLI to manage and sync AI agent skills for Cursor, Claude, Copilot, and more.')
|
|
11
|
-
.version('1.1.
|
|
12
|
+
.version('1.1.2');
|
|
12
13
|
program
|
|
13
14
|
.command('init')
|
|
14
15
|
.description('Initialize a .skillsrc configuration file interactively')
|
|
@@ -23,4 +24,11 @@ program
|
|
|
23
24
|
const sync = new sync_1.SyncCommand();
|
|
24
25
|
await sync.run();
|
|
25
26
|
});
|
|
27
|
+
program
|
|
28
|
+
.command('list-skills')
|
|
29
|
+
.description('List available framework skills and detection status')
|
|
30
|
+
.action(async () => {
|
|
31
|
+
const cmd = new list_skills_1.ListSkillsCommand();
|
|
32
|
+
await cmd.run();
|
|
33
|
+
});
|
|
26
34
|
program.parse();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { GitHubTreeResponse } from '../models/types';
|
|
2
|
+
export declare function parseRegistryUrl(registryUrl: string): {
|
|
3
|
+
owner: string;
|
|
4
|
+
repo: string;
|
|
5
|
+
} | null;
|
|
6
|
+
export declare function fetchRepoTree(owner: string, repo: string, ref?: string): Promise<{
|
|
7
|
+
data: GitHubTreeResponse;
|
|
8
|
+
branch: string;
|
|
9
|
+
} | null>;
|
|
10
|
+
export default fetchRepoTree;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parseRegistryUrl = parseRegistryUrl;
|
|
7
|
+
exports.fetchRepoTree = fetchRepoTree;
|
|
8
|
+
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
9
|
+
function parseRegistryUrl(registryUrl) {
|
|
10
|
+
const m = registryUrl.match(/github\.com\/([^/]+)\/([^/]+)/i);
|
|
11
|
+
if (!m)
|
|
12
|
+
return null;
|
|
13
|
+
return { owner: m[1], repo: m[2].replace(/\.git$/, '') };
|
|
14
|
+
}
|
|
15
|
+
async function fetchRepoTree(owner, repo, ref) {
|
|
16
|
+
try {
|
|
17
|
+
let branch = ref;
|
|
18
|
+
if (!branch) {
|
|
19
|
+
// Resolve default branch
|
|
20
|
+
const repoRes = await (0, node_fetch_1.default)(`https://api.github.com/repos/${owner}/${repo}`);
|
|
21
|
+
if (!repoRes.ok)
|
|
22
|
+
return null;
|
|
23
|
+
const repoData = (await repoRes.json());
|
|
24
|
+
branch = repoData.default_branch || 'main';
|
|
25
|
+
}
|
|
26
|
+
const treeUrl = `https://api.github.com/repos/${owner}/${repo}/git/trees/${branch}?recursive=1`;
|
|
27
|
+
const res = await (0, node_fetch_1.default)(treeUrl, {
|
|
28
|
+
headers: { Accept: 'application/vnd.github.v3+json' },
|
|
29
|
+
});
|
|
30
|
+
if (!res.ok)
|
|
31
|
+
return null;
|
|
32
|
+
const data = (await res.json());
|
|
33
|
+
return { data, branch };
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.default = fetchRepoTree;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.buildProjectDeps = buildProjectDeps;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
async function buildProjectDeps() {
|
|
10
|
+
const set = new Set();
|
|
11
|
+
const packageJsonPath = path_1.default.join(process.cwd(), 'package.json');
|
|
12
|
+
if (await fs_extra_1.default.pathExists(packageJsonPath)) {
|
|
13
|
+
try {
|
|
14
|
+
const pkg = await fs_extra_1.default.readJson(packageJsonPath);
|
|
15
|
+
const deps = {
|
|
16
|
+
...(pkg.dependencies || {}),
|
|
17
|
+
...(pkg.devDependencies || {}),
|
|
18
|
+
};
|
|
19
|
+
for (const k of Object.keys(deps))
|
|
20
|
+
set.add(k);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// ignore
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const pubspecPath = path_1.default.join(process.cwd(), 'pubspec.yaml');
|
|
27
|
+
if (await fs_extra_1.default.pathExists(pubspecPath)) {
|
|
28
|
+
try {
|
|
29
|
+
const loaded = await fs_extra_1.default.readFile(pubspecPath, 'utf8');
|
|
30
|
+
// simple parse: only collect keys inside dependencies/dev_dependencies sections
|
|
31
|
+
const lines = loaded.split(/\r?\n/);
|
|
32
|
+
let currentSection = null;
|
|
33
|
+
let sectionIndent = null;
|
|
34
|
+
for (const line of lines) {
|
|
35
|
+
const sectionMatch = line.match(/^(\s*)(dependencies|dev_dependencies)\s*:/);
|
|
36
|
+
if (sectionMatch) {
|
|
37
|
+
currentSection = sectionMatch[2];
|
|
38
|
+
sectionIndent = sectionMatch[1].length;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (!currentSection || sectionIndent === null)
|
|
42
|
+
continue;
|
|
43
|
+
const entryMatch = line.match(/^(\s*)([a-zA-Z0-9_\-@\\/]+)\s*:/);
|
|
44
|
+
if (!entryMatch)
|
|
45
|
+
continue;
|
|
46
|
+
const indent = entryMatch[1].length;
|
|
47
|
+
const key = entryMatch[2];
|
|
48
|
+
// only include keys that are nested under the current section and are not known non-packages
|
|
49
|
+
if (indent > sectionIndent && key !== 'sdk' && key !== 'flutter') {
|
|
50
|
+
set.add(key);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// ignore
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return set;
|
|
59
|
+
}
|
|
60
|
+
exports.default = buildProjectDeps;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-skills-standard",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "A CLI to manage and sync AI agent skills standard for Cursor, Claude, Copilot, and more.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"commander": "^11.1.0",
|
|
26
26
|
"fs-extra": "^11.2.0",
|
|
27
|
-
"inquirer": "^
|
|
27
|
+
"inquirer": "^8.2.5",
|
|
28
28
|
"js-yaml": "^4.1.0",
|
|
29
29
|
"node-fetch": "^2.7.0",
|
|
30
30
|
"picocolors": "^1.0.0"
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@eslint/js": "^9.39.2",
|
|
34
34
|
"@types/fs-extra": "^11.0.4",
|
|
35
|
-
"@types/inquirer": "^
|
|
35
|
+
"@types/inquirer": "^8.2.5",
|
|
36
36
|
"@types/js-yaml": "^4.0.9",
|
|
37
37
|
"@types/node": "^20.10.5",
|
|
38
38
|
"@types/node-fetch": "^2.6.9",
|