agent-skills-standard 1.0.4
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/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.js +175 -0
- package/dist/commands/sync.d.ts +5 -0
- package/dist/commands/sync.js +153 -0
- package/dist/constants/index.d.ts +14 -0
- package/dist/constants/index.js +79 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +26 -0
- package/dist/models/config.d.ts +13 -0
- package/dist/models/config.js +2 -0
- package/dist/models/types.d.ts +28 -0
- package/dist/models/types.js +2 -0
- package/package.json +60 -0
|
@@ -0,0 +1,175 @@
|
|
|
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.InitCommand = 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 node_fetch_1 = __importDefault(require("node-fetch"));
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
13
|
+
const constants_1 = require("../constants");
|
|
14
|
+
class InitCommand {
|
|
15
|
+
async run() {
|
|
16
|
+
const configPath = path_1.default.join(process.cwd(), '.skillsrc');
|
|
17
|
+
// Project detection
|
|
18
|
+
const detectionResults = {};
|
|
19
|
+
for (const framework of constants_1.SUPPORTED_FRAMEWORKS) {
|
|
20
|
+
let detected = false;
|
|
21
|
+
for (const file of framework.detectionFiles) {
|
|
22
|
+
if (await fs_extra_1.default.pathExists(file)) {
|
|
23
|
+
detected = true;
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
detectionResults[framework.id] = detected;
|
|
28
|
+
}
|
|
29
|
+
// Agent detection
|
|
30
|
+
const agentDetection = {};
|
|
31
|
+
for (const agent of constants_1.SUPPORTED_AGENTS) {
|
|
32
|
+
let detected = false;
|
|
33
|
+
for (const file of agent.detectionFiles) {
|
|
34
|
+
if (await fs_extra_1.default.pathExists(file)) {
|
|
35
|
+
detected = true;
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
agentDetection[agent.id] = detected;
|
|
40
|
+
}
|
|
41
|
+
const anyAgentDetected = Object.values(agentDetection).some((d) => d);
|
|
42
|
+
// Helper to determine if an agent should be pre-selected
|
|
43
|
+
const shouldCheck = (id) => anyAgentDetected ? agentDetection[id] : true;
|
|
44
|
+
// Supported categories are now determined by the registry contents if possible
|
|
45
|
+
// Default to a sane list if registry is unreachable
|
|
46
|
+
let supportedCategories = ['flutter', 'dart'];
|
|
47
|
+
let metadata = {};
|
|
48
|
+
const treeUrl = 'https://api.github.com/repos/HoangNguyen0403/agent-skills-standard/git/trees/main?recursive=1';
|
|
49
|
+
const metadataUrl = 'https://raw.githubusercontent.com/HoangNguyen0403/agent-skills-standard/main/skills/metadata.json';
|
|
50
|
+
try {
|
|
51
|
+
const [treeRes, metadataRes] = await Promise.all([
|
|
52
|
+
(0, node_fetch_1.default)(treeUrl, {
|
|
53
|
+
headers: { Accept: 'application/vnd.github.v3+json' },
|
|
54
|
+
}),
|
|
55
|
+
(0, node_fetch_1.default)(metadataUrl),
|
|
56
|
+
]);
|
|
57
|
+
if (metadataRes.ok) {
|
|
58
|
+
metadata = (await metadataRes.json());
|
|
59
|
+
}
|
|
60
|
+
if (treeRes.ok) {
|
|
61
|
+
const treeData = (await treeRes.json());
|
|
62
|
+
const allFiles = treeData.tree || [];
|
|
63
|
+
// Extract top-level folders in skills/
|
|
64
|
+
const categories = new Set();
|
|
65
|
+
allFiles.forEach((f) => {
|
|
66
|
+
if (f.path.startsWith('skills/') && f.type === 'tree') {
|
|
67
|
+
const parts = f.path.split('/');
|
|
68
|
+
if (parts.length === 2) {
|
|
69
|
+
categories.add(parts[1]);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
if (categories.size > 0) {
|
|
74
|
+
supportedCategories = Array.from(categories);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
80
|
+
console.error(picocolors_1.default.red(`❌ Failed to fetch registry metadata or tree: ${msg}`));
|
|
81
|
+
}
|
|
82
|
+
const choices = constants_1.SUPPORTED_FRAMEWORKS.map((f) => {
|
|
83
|
+
const isSupported = supportedCategories.includes(f.id);
|
|
84
|
+
return {
|
|
85
|
+
name: isSupported ? f.name : `${f.name} (Coming Soon)`,
|
|
86
|
+
value: f.id,
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
if (await fs_extra_1.default.pathExists(configPath)) {
|
|
90
|
+
const { overwrite } = await inquirer_1.default.prompt([
|
|
91
|
+
{
|
|
92
|
+
type: 'confirm',
|
|
93
|
+
name: 'overwrite',
|
|
94
|
+
message: '.skillsrc already exists. Do you want to overwrite it?',
|
|
95
|
+
default: false,
|
|
96
|
+
},
|
|
97
|
+
]);
|
|
98
|
+
if (!overwrite) {
|
|
99
|
+
console.log(picocolors_1.default.yellow('Aborted.'));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const answers = await inquirer_1.default.prompt([
|
|
104
|
+
{
|
|
105
|
+
type: 'list',
|
|
106
|
+
name: 'framework',
|
|
107
|
+
message: 'Select Framework:',
|
|
108
|
+
choices: choices,
|
|
109
|
+
default: constants_1.SUPPORTED_FRAMEWORKS.find((f) => detectionResults[f.id])?.id ||
|
|
110
|
+
'flutter',
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
type: 'checkbox',
|
|
114
|
+
name: 'agents',
|
|
115
|
+
message: 'Select AI Agents you use:',
|
|
116
|
+
choices: constants_1.SUPPORTED_AGENTS.map((a) => ({
|
|
117
|
+
name: `${a.name} (${a.path}/)`,
|
|
118
|
+
value: a.id,
|
|
119
|
+
checked: shouldCheck(a.id),
|
|
120
|
+
})),
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
type: 'input',
|
|
124
|
+
name: 'registry',
|
|
125
|
+
message: 'Skills Registry URL:',
|
|
126
|
+
default: 'https://github.com/HoangNguyen0403/agent-skills-standard',
|
|
127
|
+
},
|
|
128
|
+
]);
|
|
129
|
+
const frameworkId = answers.framework;
|
|
130
|
+
const selectedFramework = constants_1.SUPPORTED_FRAMEWORKS.find((f) => f.id === frameworkId);
|
|
131
|
+
const isSupported = supportedCategories.includes(frameworkId);
|
|
132
|
+
if (!isSupported) {
|
|
133
|
+
console.log(picocolors_1.default.yellow(`\nNotice: Skills for ${frameworkId} are not yet strictly defined and will be added soon.`));
|
|
134
|
+
console.log(picocolors_1.default.gray('The CLI will still generate rule files with global standards.\n'));
|
|
135
|
+
}
|
|
136
|
+
const neededSkills = new Set();
|
|
137
|
+
neededSkills.add(frameworkId);
|
|
138
|
+
if (selectedFramework) {
|
|
139
|
+
selectedFramework.languages.forEach((l) => neededSkills.add(l));
|
|
140
|
+
}
|
|
141
|
+
const config = {
|
|
142
|
+
registry: answers.registry,
|
|
143
|
+
agents: answers.agents,
|
|
144
|
+
skills: {},
|
|
145
|
+
custom_overrides: [],
|
|
146
|
+
};
|
|
147
|
+
// Initialize all potential skills from the registry folders we know
|
|
148
|
+
// This will be expanded as more frameworks are added to the repo
|
|
149
|
+
const allKnownCategories = [
|
|
150
|
+
...constants_1.SUPPORTED_FRAMEWORKS.map((f) => f.id),
|
|
151
|
+
...constants_1.SUPPORTED_FRAMEWORKS.flatMap((f) => f.languages),
|
|
152
|
+
];
|
|
153
|
+
for (const skill of [...new Set(allKnownCategories)]) {
|
|
154
|
+
if (neededSkills.has(skill)) {
|
|
155
|
+
const skillMeta = metadata.categories?.[skill];
|
|
156
|
+
let refStr;
|
|
157
|
+
if (skillMeta?.version && skillMeta?.tag_prefix) {
|
|
158
|
+
refStr = `${skillMeta.tag_prefix}${skillMeta.version}`;
|
|
159
|
+
}
|
|
160
|
+
config.skills[skill] = {
|
|
161
|
+
enabled: true,
|
|
162
|
+
ref: refStr,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
await fs_extra_1.default.writeFile(configPath, js_yaml_1.default.dump(config));
|
|
167
|
+
console.log(picocolors_1.default.green('\n✅ Initialized .skillsrc with your preferences!'));
|
|
168
|
+
console.log(picocolors_1.default.gray(` Selected framework: ${frameworkId}`));
|
|
169
|
+
console.log(picocolors_1.default.gray(` Auto-enabled languages: ${Array.from(neededSkills)
|
|
170
|
+
.filter((s) => s !== frameworkId)
|
|
171
|
+
.join(', ') || 'none'}`));
|
|
172
|
+
console.log(picocolors_1.default.cyan('\nNext step: Run `agent-skills sync` to generate rule files.'));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
exports.InitCommand = InitCommand;
|
|
@@ -0,0 +1,153 @@
|
|
|
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.SyncCommand = void 0;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const js_yaml_1 = __importDefault(require("js-yaml"));
|
|
9
|
+
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
12
|
+
const constants_1 = require("../constants");
|
|
13
|
+
class SyncCommand {
|
|
14
|
+
async run() {
|
|
15
|
+
const configPath = path_1.default.join(process.cwd(), '.skillsrc');
|
|
16
|
+
if (!(await fs_extra_1.default.pathExists(configPath))) {
|
|
17
|
+
console.log(picocolors_1.default.red('❌ Error: .skillsrc not found in current directory.'));
|
|
18
|
+
console.log(picocolors_1.default.yellow('Run `agent-skills init` first.'));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const fileContent = await fs_extra_1.default.readFile(configPath, 'utf8');
|
|
23
|
+
const config = js_yaml_1.default.load(fileContent);
|
|
24
|
+
console.log(picocolors_1.default.cyan(`🚀 Syncing skills from ${config.registry}...`));
|
|
25
|
+
const enabledCategories = Object.entries(config.skills)
|
|
26
|
+
.filter(([, value]) => value.enabled)
|
|
27
|
+
.map(([key]) => key);
|
|
28
|
+
const skills = await this.assembleFromRemote(enabledCategories, config);
|
|
29
|
+
await this.writeToTargets(skills, config);
|
|
30
|
+
console.log(picocolors_1.default.green('✅ All skills synced successfully!'));
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
console.error(picocolors_1.default.red('❌ Failed to sync skills:'), error);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async assembleFromRemote(categories, config) {
|
|
37
|
+
const collected = [];
|
|
38
|
+
// Parse owner and repo from registry URL
|
|
39
|
+
// Expected: https://github.com/owner/repo
|
|
40
|
+
const githubMatch = config.registry.match(/github\.com\/([^/]+)\/([^/]+)/i);
|
|
41
|
+
if (!githubMatch) {
|
|
42
|
+
console.log(picocolors_1.default.red('Error: Only GitHub registries are supported for auto-discovery.'));
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
const [owner, repo] = githubMatch.slice(1);
|
|
46
|
+
// We iterate categories individually to handle versioning (different refs)
|
|
47
|
+
for (const category of categories) {
|
|
48
|
+
const categoryConfig = config.skills[category];
|
|
49
|
+
const ref = categoryConfig.ref || 'main';
|
|
50
|
+
const rawBaseUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/skills/`;
|
|
51
|
+
const treeUrl = `https://api.github.com/repos/${owner}/${repo}/git/trees/${ref}?recursive=1`;
|
|
52
|
+
try {
|
|
53
|
+
console.log(picocolors_1.default.gray(` - Discovering ${category} skills via GitHub API (${ref})...`));
|
|
54
|
+
const treeRes = await (0, node_fetch_1.default)(treeUrl, {
|
|
55
|
+
headers: { Accept: 'application/vnd.github.v3+json' },
|
|
56
|
+
});
|
|
57
|
+
if (!treeRes.ok) {
|
|
58
|
+
console.log(picocolors_1.default.red(` ❌ Failed to fetch ${category}@${ref} (Status: ${treeRes.status}). Skipping.`));
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const treeData = (await treeRes.json());
|
|
62
|
+
const allFiles = treeData.tree || [];
|
|
63
|
+
// Find all skill folder names first
|
|
64
|
+
const skillFolders = Array.from(new Set(allFiles
|
|
65
|
+
.filter((f) => f.path.startsWith(`skills/${category}/`))
|
|
66
|
+
.map((f) => {
|
|
67
|
+
const parts = f.path.split('/');
|
|
68
|
+
return parts[2]; // skills/category/SKILL_NAME/file.md
|
|
69
|
+
})
|
|
70
|
+
.filter(Boolean)));
|
|
71
|
+
for (const skillFolderName of skillFolders) {
|
|
72
|
+
if (categoryConfig.include &&
|
|
73
|
+
!categoryConfig.include.includes(skillFolderName))
|
|
74
|
+
continue;
|
|
75
|
+
if (categoryConfig.exclude &&
|
|
76
|
+
categoryConfig.exclude.includes(skillFolderName))
|
|
77
|
+
continue;
|
|
78
|
+
const skillFiles = [];
|
|
79
|
+
// Find all files belonging to this specific skill
|
|
80
|
+
const skillSourceFiles = allFiles.filter((f) => f.path.startsWith(`skills/${category}/${skillFolderName}/`));
|
|
81
|
+
for (const fileItem of skillSourceFiles) {
|
|
82
|
+
// Get relative path within the skill folder (e.g., "SKILL.md" or "references/REFERENCE.md")
|
|
83
|
+
const relativePath = fileItem.path.replace(`skills/${category}/${skillFolderName}/`, '');
|
|
84
|
+
// Only sync supported files and directories based on standard
|
|
85
|
+
const isSupported = relativePath === 'SKILL.md' ||
|
|
86
|
+
relativePath.startsWith('references/') ||
|
|
87
|
+
relativePath.startsWith('scripts/') ||
|
|
88
|
+
relativePath.startsWith('assets/');
|
|
89
|
+
if (isSupported && fileItem.type === 'blob') {
|
|
90
|
+
const fileUrl = `${rawBaseUrl}${category}/${skillFolderName}/${relativePath}`;
|
|
91
|
+
const fileRes = await (0, node_fetch_1.default)(fileUrl);
|
|
92
|
+
if (fileRes.ok) {
|
|
93
|
+
const content = await fileRes.text();
|
|
94
|
+
skillFiles.push({ name: relativePath, content });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (skillFiles.length > 0) {
|
|
99
|
+
collected.push({
|
|
100
|
+
category,
|
|
101
|
+
skill: skillFolderName,
|
|
102
|
+
files: skillFiles,
|
|
103
|
+
});
|
|
104
|
+
console.log(picocolors_1.default.gray(` + Fetched ${category}/${skillFolderName} (${skillFiles.length} files)`));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
console.log(picocolors_1.default.red(`Error: Failed to fetch remote skills for ${category}. ${error}`));
|
|
110
|
+
}
|
|
111
|
+
} // End category loop
|
|
112
|
+
return collected;
|
|
113
|
+
}
|
|
114
|
+
async writeToTargets(skills, config) {
|
|
115
|
+
const agents = config.agents || constants_1.SUPPORTED_AGENTS.map((a) => a.id);
|
|
116
|
+
const overrides = config.custom_overrides || [];
|
|
117
|
+
for (const agentId of agents) {
|
|
118
|
+
const agentDef = constants_1.SUPPORTED_AGENTS.find((a) => a.id === agentId);
|
|
119
|
+
if (!agentDef)
|
|
120
|
+
continue;
|
|
121
|
+
const basePath = agentDef.path;
|
|
122
|
+
if (basePath) {
|
|
123
|
+
// We do NOT use emptyDir here because we want to preserve user's own custom skills
|
|
124
|
+
await fs_extra_1.default.ensureDir(basePath);
|
|
125
|
+
for (const skill of skills) {
|
|
126
|
+
const skillFolderName = `${skill.category}-${skill.skill}`;
|
|
127
|
+
const skillPath = path_1.default.join(basePath, skillFolderName);
|
|
128
|
+
await fs_extra_1.default.ensureDir(skillPath);
|
|
129
|
+
for (const fileItem of skill.files) {
|
|
130
|
+
const targetFilePath = path_1.default.join(skillPath, fileItem.name);
|
|
131
|
+
// Check if this specific file is in custom_overrides
|
|
132
|
+
// Supports both specific files and entire folders
|
|
133
|
+
const relativePath = path_1.default
|
|
134
|
+
.relative(process.cwd(), targetFilePath)
|
|
135
|
+
.replace(/\\/g, '/');
|
|
136
|
+
const isOverridden = overrides.some((o) => {
|
|
137
|
+
const overridePath = o.replace(/\\/g, '/');
|
|
138
|
+
return (relativePath === overridePath ||
|
|
139
|
+
relativePath.startsWith(`${overridePath.replace(/\/$/, '')}/`));
|
|
140
|
+
});
|
|
141
|
+
if (isOverridden) {
|
|
142
|
+
console.log(picocolors_1.default.yellow(` ⚠️ Skipping overridden item: ${relativePath}`));
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
await fs_extra_1.default.writeFile(targetFilePath, fileItem.content);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
console.log(picocolors_1.default.gray(` - Updated ${basePath}/ (${agentDef.name})`));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
exports.SyncCommand = SyncCommand;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface AgentDefinition {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
path: string;
|
|
5
|
+
detectionFiles: string[];
|
|
6
|
+
}
|
|
7
|
+
export interface FrameworkDefinition {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
languages: string[];
|
|
11
|
+
detectionFiles: string[];
|
|
12
|
+
}
|
|
13
|
+
export declare const SUPPORTED_AGENTS: AgentDefinition[];
|
|
14
|
+
export declare const SUPPORTED_FRAMEWORKS: FrameworkDefinition[];
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SUPPORTED_FRAMEWORKS = exports.SUPPORTED_AGENTS = void 0;
|
|
4
|
+
exports.SUPPORTED_AGENTS = [
|
|
5
|
+
{
|
|
6
|
+
id: 'cursor',
|
|
7
|
+
name: 'Cursor',
|
|
8
|
+
path: '.cursor/skills',
|
|
9
|
+
detectionFiles: ['.cursor', '.cursorrules'],
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
id: 'claude',
|
|
13
|
+
name: 'Claude Code',
|
|
14
|
+
path: '.claude/skills',
|
|
15
|
+
detectionFiles: ['.claude', 'CLAUDE.md'],
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: 'copilot',
|
|
19
|
+
name: 'GitHub Copilot',
|
|
20
|
+
path: '.github/skills',
|
|
21
|
+
detectionFiles: ['.github'],
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: 'antigravity',
|
|
25
|
+
name: 'Antigravity',
|
|
26
|
+
path: '.agent/skills',
|
|
27
|
+
detectionFiles: ['.agent'],
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: 'openai',
|
|
31
|
+
name: 'OpenAI/Generic',
|
|
32
|
+
path: '.codex/skills',
|
|
33
|
+
detectionFiles: ['.codex'],
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
exports.SUPPORTED_FRAMEWORKS = [
|
|
37
|
+
{
|
|
38
|
+
id: 'flutter',
|
|
39
|
+
name: 'Flutter',
|
|
40
|
+
languages: ['dart'],
|
|
41
|
+
detectionFiles: ['pubspec.yaml'],
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 'nestjs',
|
|
45
|
+
name: 'NestJS',
|
|
46
|
+
languages: ['typescript', 'javascript'],
|
|
47
|
+
detectionFiles: ['package.json'], // Can be improved with scanning package.json contents
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: 'golang',
|
|
51
|
+
name: 'Go (Golang)',
|
|
52
|
+
languages: ['go'],
|
|
53
|
+
detectionFiles: ['go.mod'],
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 'nextjs',
|
|
57
|
+
name: 'Next.js',
|
|
58
|
+
languages: ['typescript', 'javascript'],
|
|
59
|
+
detectionFiles: ['next.config.js', 'next.config.mjs'],
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: 'react',
|
|
63
|
+
name: 'React',
|
|
64
|
+
languages: ['typescript', 'javascript'],
|
|
65
|
+
detectionFiles: ['package.json'],
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: 'react-native',
|
|
69
|
+
name: 'React Native',
|
|
70
|
+
languages: ['typescript', 'javascript'],
|
|
71
|
+
detectionFiles: [],
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: 'angular',
|
|
75
|
+
name: 'Angular',
|
|
76
|
+
languages: ['typescript'],
|
|
77
|
+
detectionFiles: ['angular.json'],
|
|
78
|
+
},
|
|
79
|
+
];
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const init_1 = require("./commands/init");
|
|
6
|
+
const sync_1 = require("./commands/sync");
|
|
7
|
+
const program = new commander_1.Command();
|
|
8
|
+
program
|
|
9
|
+
.name('agent-skills')
|
|
10
|
+
.description('A CLI to manage and sync AI agent skills for Cursor, Claude, Copilot, and more.')
|
|
11
|
+
.version('1.0.0');
|
|
12
|
+
program
|
|
13
|
+
.command('init')
|
|
14
|
+
.description('Initialize a .skillsrc configuration file interactively')
|
|
15
|
+
.action(async () => {
|
|
16
|
+
const init = new init_1.InitCommand();
|
|
17
|
+
await init.run();
|
|
18
|
+
});
|
|
19
|
+
program
|
|
20
|
+
.command('sync')
|
|
21
|
+
.description('Sync skills to AI Agent skill directories')
|
|
22
|
+
.action(async () => {
|
|
23
|
+
const sync = new sync_1.SyncCommand();
|
|
24
|
+
await sync.run();
|
|
25
|
+
});
|
|
26
|
+
program.parse();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface GitHubTreeItem {
|
|
2
|
+
path: string;
|
|
3
|
+
mode: string;
|
|
4
|
+
type: 'blob' | 'tree';
|
|
5
|
+
sha: string;
|
|
6
|
+
size?: number;
|
|
7
|
+
url: string;
|
|
8
|
+
}
|
|
9
|
+
export interface GitHubTreeResponse {
|
|
10
|
+
sha: string;
|
|
11
|
+
url: string;
|
|
12
|
+
tree: GitHubTreeItem[];
|
|
13
|
+
truncated: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface CategoryMetadata {
|
|
16
|
+
version?: string;
|
|
17
|
+
last_updated?: string;
|
|
18
|
+
tag_prefix?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface RegistryMetadata {
|
|
21
|
+
global: {
|
|
22
|
+
author: string;
|
|
23
|
+
repository: string;
|
|
24
|
+
};
|
|
25
|
+
categories: {
|
|
26
|
+
[key: string]: CategoryMetadata;
|
|
27
|
+
};
|
|
28
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agent-skills-standard",
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"description": "A CLI to manage and sync AI agent skills standard for Cursor, Claude, Copilot, and more.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"agent-skills-standard": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"ai",
|
|
14
|
+
"agent",
|
|
15
|
+
"cursor",
|
|
16
|
+
"claude",
|
|
17
|
+
"copilot",
|
|
18
|
+
"cli",
|
|
19
|
+
"antigravity"
|
|
20
|
+
],
|
|
21
|
+
"author": "Hoang Nguyen",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"commander": "^11.1.0",
|
|
25
|
+
"fs-extra": "^11.2.0",
|
|
26
|
+
"inquirer": "^9.2.12",
|
|
27
|
+
"js-yaml": "^4.1.0",
|
|
28
|
+
"node-fetch": "^2.7.0",
|
|
29
|
+
"picocolors": "^1.0.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@eslint/js": "^9.39.2",
|
|
33
|
+
"@types/fs-extra": "^11.0.4",
|
|
34
|
+
"@types/inquirer": "^9.0.7",
|
|
35
|
+
"@types/js-yaml": "^4.0.9",
|
|
36
|
+
"@types/node": "^20.10.5",
|
|
37
|
+
"@types/node-fetch": "^2.6.9",
|
|
38
|
+
"eslint": "^9.39.2",
|
|
39
|
+
"eslint-config-prettier": "^10.1.8",
|
|
40
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
41
|
+
"globals": "^17.0.0",
|
|
42
|
+
"jiti": "^2.6.1",
|
|
43
|
+
"prettier": "3.8.0",
|
|
44
|
+
"ts-node": "^10.9.2",
|
|
45
|
+
"typescript": "^5.3.3",
|
|
46
|
+
"typescript-eslint": "^8.53.0"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsc",
|
|
50
|
+
"start": "node dist/index.js",
|
|
51
|
+
"dev": "ts-node src/index.ts",
|
|
52
|
+
"release-skill": "ts-node scripts/release-skill.ts",
|
|
53
|
+
"release-skill:dry": "ts-node scripts/release-skill.ts --dry-run",
|
|
54
|
+
"release-cli": "ts-node scripts/release-cli.ts",
|
|
55
|
+
"release-cli:dry": "ts-node scripts/release-cli.ts --dry-run",
|
|
56
|
+
"publish:dry": "pnpm publish --dry-run --no-git-checks",
|
|
57
|
+
"format": "prettier --write \"src/**/*.ts\" \"scripts/**/*.ts\"",
|
|
58
|
+
"lint": "eslint \"src/**/*.ts\" \"scripts/**/*.ts\" --fix"
|
|
59
|
+
}
|
|
60
|
+
}
|