@valentia-ai-skills/framework 1.0.0
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 +103 -0
- package/bin/cli.js +482 -0
- package/package.json +42 -0
- package/scripts/postinstall.js +18 -0
- package/skills/global/api-design/SKILL.md +248 -0
- package/skills/global/api-design/tests/test-prompts.md +25 -0
- package/skills/global/code-standards/SKILL.md +245 -0
- package/skills/global/code-standards/tests/test-prompts.md +26 -0
- package/skills/global/deployment/SKILL.md +240 -0
- package/skills/global/deployment/tests/test-prompts.md +27 -0
- package/skills/global/documentation/SKILL.md +298 -0
- package/skills/global/documentation/tests/test-prompts.md +26 -0
- package/skills/global/git-workflow/SKILL.md +177 -0
- package/skills/global/git-workflow/tests/test-prompts.md +11 -0
- package/skills/global/security-baseline/SKILL.md +239 -0
- package/skills/global/security-baseline/tests/test-prompts.md +23 -0
- package/skills/global/testing-standards/SKILL.md +257 -0
- package/skills/global/testing-standards/tests/test-prompts.md +25 -0
- package/skills/onboarding/SKILL.md +110 -0
- package/skills/stack/devops/SKILL.md +220 -0
- package/skills/stack/devops/tests/test-prompts.md +29 -0
- package/skills/stack/node-backend/SKILL.md +304 -0
- package/skills/stack/node-backend/tests/test-prompts.md +27 -0
- package/skills/stack/python-backend/SKILL.md +304 -0
- package/skills/stack/python-backend/tests/test-prompts.md +27 -0
- package/skills/stack/react/SKILL.md +251 -0
- package/skills/stack/react/tests/test-prompts.md +26 -0
- package/skills/stack/react-native/SKILL.md +255 -0
- package/skills/stack/react-native/tests/test-prompts.md +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# AI Skills Framework
|
|
2
|
+
|
|
3
|
+
Centralized coding standards, security patterns, and SOPs for AI-assisted development.
|
|
4
|
+
|
|
5
|
+
**One install. All AI tools. Every team follows the same rules.**
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Install
|
|
11
|
+
npm install --save-dev @valentia-ai-skills/framework
|
|
12
|
+
|
|
13
|
+
# Setup (auto-detects your AI tools)
|
|
14
|
+
npx ai-skills setup
|
|
15
|
+
|
|
16
|
+
# Done. Your AI tools now follow your org's standards.
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## What It Does
|
|
20
|
+
|
|
21
|
+
This package installs your organization's coding standards into whatever AI coding tool your team uses:
|
|
22
|
+
|
|
23
|
+
| AI Tool | What Gets Created |
|
|
24
|
+
|---------|------------------|
|
|
25
|
+
| **Claude Code** | Individual skill folders in `.claude/skills/` |
|
|
26
|
+
| **Cursor** | Merged rules file at `.cursor/rules/ai-skills.mdc` |
|
|
27
|
+
| **GitHub Copilot** | Merged rules at `.github/copilot-instructions.md` |
|
|
28
|
+
| **Windsurf** | Merged rules at `.windsurfrules` |
|
|
29
|
+
| **Any other tool** | Generic `.ai-rules` file |
|
|
30
|
+
|
|
31
|
+
The CLI auto-detects which tools you're using and installs the right format.
|
|
32
|
+
|
|
33
|
+
## Included Skills
|
|
34
|
+
|
|
35
|
+
### Global (all teams)
|
|
36
|
+
- **code-standards** — Naming, file structure, formatting, error handling
|
|
37
|
+
- **git-workflow** — Branching, commits, PRs, releases
|
|
38
|
+
- **security-baseline** — Auth, validation, secrets, XSS, SQL injection
|
|
39
|
+
- **api-design** — REST URLs, status codes, pagination, versioning
|
|
40
|
+
- **testing-standards** — Coverage, AAA pattern, mocking, integration/E2E
|
|
41
|
+
- **documentation** — READMEs, API docs, ADRs, changelogs, runbooks
|
|
42
|
+
- **deployment** — CI/CD, Docker, environments, rollback, feature flags
|
|
43
|
+
|
|
44
|
+
### Stack-specific
|
|
45
|
+
- **react** — Components, hooks, state management, performance
|
|
46
|
+
- **react-native** — Navigation, FlatList, offline-first, platform code
|
|
47
|
+
- **node-backend** — Layered architecture, DI, error handling, health checks
|
|
48
|
+
- **python-backend** — FastAPI, Pydantic, async patterns, pytest
|
|
49
|
+
- **devops** — Terraform, Kubernetes, monitoring, SLOs, alerting
|
|
50
|
+
|
|
51
|
+
## Commands
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npx ai-skills setup # First-time setup
|
|
55
|
+
npx ai-skills update # Update to latest skills
|
|
56
|
+
npx ai-skills status # Check what's installed
|
|
57
|
+
npx ai-skills list # Show all available skills
|
|
58
|
+
npx ai-skills doctor # Health check
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Updating
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Update the package
|
|
65
|
+
npm update @valentia-ai-skills/framework
|
|
66
|
+
|
|
67
|
+
# Refresh the installed skills
|
|
68
|
+
npx ai-skills update
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## How It Works
|
|
72
|
+
|
|
73
|
+
1. **Install** — `npm install` adds the package to your project
|
|
74
|
+
2. **Setup** — `npx ai-skills setup` detects your AI tools and writes config files
|
|
75
|
+
3. **Code** — When you use any AI coding tool, it reads those config files and follows the rules
|
|
76
|
+
4. **Update** — `npm update` + `npx ai-skills update` refreshes everything
|
|
77
|
+
|
|
78
|
+
The skills never touch your application code. They only tell AI tools what conventions to follow.
|
|
79
|
+
|
|
80
|
+
## For Team Leads
|
|
81
|
+
|
|
82
|
+
Add this to your project's `package.json` so every developer gets the skills on `npm install`:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"devDependencies": {
|
|
87
|
+
"@valentia-ai-skills/framework": "^1.0.0"
|
|
88
|
+
},
|
|
89
|
+
"scripts": {
|
|
90
|
+
"postinstall": "npx ai-skills setup"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Now every `git clone` + `npm install` automatically configures AI skills.
|
|
96
|
+
|
|
97
|
+
## Customization
|
|
98
|
+
|
|
99
|
+
After setup, a `.ai-skills.json` config file tracks your preferences. The generated rules files can be committed to git so the whole team shares the same setup.
|
|
100
|
+
|
|
101
|
+
## Contributing
|
|
102
|
+
|
|
103
|
+
To add or modify skills, edit the SKILL.md files in the `skills/` directory and publish a new package version.
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ai-skills CLI
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx ai-skills setup # First-time setup — detects your AI tools and installs skills
|
|
8
|
+
* npx ai-skills update # Pull latest skills into your project
|
|
9
|
+
* npx ai-skills status # Show which skills are installed and which tools are configured
|
|
10
|
+
* npx ai-skills list # List all available skills
|
|
11
|
+
* npx ai-skills add <skill> # Add a specific skill
|
|
12
|
+
* npx ai-skills remove <skill> # Remove a specific skill
|
|
13
|
+
* npx ai-skills doctor # Check setup health
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require("fs");
|
|
17
|
+
const path = require("path");
|
|
18
|
+
|
|
19
|
+
// ── Constants ──
|
|
20
|
+
|
|
21
|
+
const SKILLS_SOURCE = path.join(__dirname, "..", "skills");
|
|
22
|
+
const PROJECT_ROOT = process.cwd();
|
|
23
|
+
|
|
24
|
+
const TOOL_CONFIGS = {
|
|
25
|
+
"claude-code": {
|
|
26
|
+
name: "Claude Code",
|
|
27
|
+
skillsDir: ".claude/skills",
|
|
28
|
+
rulesFile: null,
|
|
29
|
+
detect: () => fs.existsSync(path.join(PROJECT_ROOT, ".claude")) || shellHas("claude"),
|
|
30
|
+
format: "skill-folder", // copies full SKILL.md folder structure
|
|
31
|
+
},
|
|
32
|
+
cursor: {
|
|
33
|
+
name: "Cursor",
|
|
34
|
+
skillsDir: null,
|
|
35
|
+
rulesFile: ".cursor/rules/ai-skills.mdc",
|
|
36
|
+
detect: () =>
|
|
37
|
+
fs.existsSync(path.join(PROJECT_ROOT, ".cursor")) ||
|
|
38
|
+
fs.existsSync(path.join(PROJECT_ROOT, ".cursorules")),
|
|
39
|
+
format: "rules-file", // merges into a single rules file
|
|
40
|
+
},
|
|
41
|
+
copilot: {
|
|
42
|
+
name: "GitHub Copilot",
|
|
43
|
+
skillsDir: null,
|
|
44
|
+
rulesFile: ".github/copilot-instructions.md",
|
|
45
|
+
detect: () =>
|
|
46
|
+
fs.existsSync(path.join(PROJECT_ROOT, ".github")) ||
|
|
47
|
+
fs.existsSync(path.join(PROJECT_ROOT, ".github/copilot-instructions.md")),
|
|
48
|
+
format: "rules-file",
|
|
49
|
+
},
|
|
50
|
+
windsurf: {
|
|
51
|
+
name: "Windsurf",
|
|
52
|
+
skillsDir: null,
|
|
53
|
+
rulesFile: ".windsurfrules",
|
|
54
|
+
detect: () => fs.existsSync(path.join(PROJECT_ROOT, ".windsurfrules")),
|
|
55
|
+
format: "rules-file",
|
|
56
|
+
},
|
|
57
|
+
generic: {
|
|
58
|
+
name: "Generic (.ai-rules)",
|
|
59
|
+
skillsDir: null,
|
|
60
|
+
rulesFile: ".ai-rules",
|
|
61
|
+
detect: () => true, // always available as fallback
|
|
62
|
+
format: "rules-file",
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const COLORS = {
|
|
67
|
+
green: "\x1b[32m",
|
|
68
|
+
yellow: "\x1b[33m",
|
|
69
|
+
blue: "\x1b[34m",
|
|
70
|
+
red: "\x1b[31m",
|
|
71
|
+
dim: "\x1b[2m",
|
|
72
|
+
bold: "\x1b[1m",
|
|
73
|
+
reset: "\x1b[0m",
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// ── Helpers ──
|
|
77
|
+
|
|
78
|
+
function c(color, text) {
|
|
79
|
+
return `${COLORS[color]}${text}${COLORS.reset}`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function shellHas(cmd) {
|
|
83
|
+
try {
|
|
84
|
+
require("child_process").execSync(`which ${cmd} 2>/dev/null`, { stdio: "ignore" });
|
|
85
|
+
return true;
|
|
86
|
+
} catch {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function getAllSkills() {
|
|
92
|
+
const skills = [];
|
|
93
|
+
if (!fs.existsSync(SKILLS_SOURCE)) return skills;
|
|
94
|
+
|
|
95
|
+
for (const category of ["global", "stack", "onboarding"]) {
|
|
96
|
+
const catDir = path.join(SKILLS_SOURCE, category);
|
|
97
|
+
if (!fs.existsSync(catDir)) continue;
|
|
98
|
+
|
|
99
|
+
if (category === "onboarding") {
|
|
100
|
+
if (fs.existsSync(path.join(catDir, "SKILL.md"))) {
|
|
101
|
+
skills.push({ name: "onboarding", category, path: catDir });
|
|
102
|
+
}
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
for (const item of fs.readdirSync(catDir)) {
|
|
107
|
+
const itemPath = path.join(catDir, item);
|
|
108
|
+
if (fs.statSync(itemPath).isDirectory() && fs.existsSync(path.join(itemPath, "SKILL.md"))) {
|
|
109
|
+
skills.push({ name: item, category, path: itemPath });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return skills;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function readSkillContent(skillPath) {
|
|
117
|
+
const skillMd = path.join(skillPath, "SKILL.md");
|
|
118
|
+
if (!fs.existsSync(skillMd)) return null;
|
|
119
|
+
return fs.readFileSync(skillMd, "utf-8");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function extractSkillRules(content) {
|
|
123
|
+
// Remove YAML frontmatter
|
|
124
|
+
const withoutFrontmatter = content.replace(/^---[\s\S]*?---\n*/m, "");
|
|
125
|
+
return withoutFrontmatter.trim();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function mkdirp(dirPath) {
|
|
129
|
+
if (!fs.existsSync(dirPath)) {
|
|
130
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function copyDir(src, dest) {
|
|
135
|
+
mkdirp(dest);
|
|
136
|
+
for (const item of fs.readdirSync(src)) {
|
|
137
|
+
const srcItem = path.join(src, item);
|
|
138
|
+
const destItem = path.join(dest, item);
|
|
139
|
+
if (item === "tests") continue; // skip test prompts in installed version
|
|
140
|
+
if (fs.statSync(srcItem).isDirectory()) {
|
|
141
|
+
copyDir(srcItem, destItem);
|
|
142
|
+
} else {
|
|
143
|
+
fs.copyFileSync(srcItem, destItem);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function detectTools() {
|
|
149
|
+
const detected = [];
|
|
150
|
+
for (const [key, config] of Object.entries(TOOL_CONFIGS)) {
|
|
151
|
+
if (key === "generic") continue;
|
|
152
|
+
if (config.detect()) {
|
|
153
|
+
detected.push(key);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return detected;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function loadProjectConfig() {
|
|
160
|
+
const configPath = path.join(PROJECT_ROOT, ".ai-skills.json");
|
|
161
|
+
if (fs.existsSync(configPath)) {
|
|
162
|
+
return JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
163
|
+
}
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function saveProjectConfig(config) {
|
|
168
|
+
const configPath = path.join(PROJECT_ROOT, ".ai-skills.json");
|
|
169
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ── Commands ──
|
|
173
|
+
|
|
174
|
+
function cmdSetup() {
|
|
175
|
+
console.log(c("blue", "\n━━━ AI Skills Framework — Setup ━━━\n"));
|
|
176
|
+
|
|
177
|
+
// 1. Detect AI tools
|
|
178
|
+
const tools = detectTools();
|
|
179
|
+
if (tools.length === 0) {
|
|
180
|
+
console.log(c("yellow", "No AI coding tools detected in this project."));
|
|
181
|
+
console.log("Will create a generic .ai-rules file that works with any tool.\n");
|
|
182
|
+
tools.push("generic");
|
|
183
|
+
} else {
|
|
184
|
+
console.log(`Detected AI tools: ${tools.map((t) => c("green", TOOL_CONFIGS[t].name)).join(", ")}\n`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// 2. Get all available skills
|
|
188
|
+
const allSkills = getAllSkills();
|
|
189
|
+
const globalSkills = allSkills.filter((s) => s.category === "global");
|
|
190
|
+
const stackSkills = allSkills.filter((s) => s.category === "stack");
|
|
191
|
+
|
|
192
|
+
console.log(`Available skills: ${c("bold", allSkills.length)}`);
|
|
193
|
+
console.log(` Global: ${globalSkills.map((s) => s.name).join(", ")}`);
|
|
194
|
+
console.log(` Stack: ${stackSkills.map((s) => s.name).join(", ")}\n`);
|
|
195
|
+
|
|
196
|
+
// 3. Install for each detected tool
|
|
197
|
+
let installedCount = 0;
|
|
198
|
+
|
|
199
|
+
for (const toolKey of tools) {
|
|
200
|
+
const tool = TOOL_CONFIGS[toolKey];
|
|
201
|
+
console.log(c("yellow", `Setting up for ${tool.name}...`));
|
|
202
|
+
|
|
203
|
+
if (tool.format === "skill-folder") {
|
|
204
|
+
// Claude Code: copy individual SKILL.md folders
|
|
205
|
+
const skillsDir = path.join(PROJECT_ROOT, tool.skillsDir);
|
|
206
|
+
for (const skill of allSkills) {
|
|
207
|
+
const dest = path.join(skillsDir, skill.name);
|
|
208
|
+
copyDir(skill.path, dest);
|
|
209
|
+
console.log(` ${c("green", "✓")} ${skill.name}`);
|
|
210
|
+
installedCount++;
|
|
211
|
+
}
|
|
212
|
+
} else if (tool.format === "rules-file") {
|
|
213
|
+
// Cursor / Copilot / Windsurf / Generic: merge into single rules file
|
|
214
|
+
const rulesPath = path.join(PROJECT_ROOT, tool.rulesFile);
|
|
215
|
+
mkdirp(path.dirname(rulesPath));
|
|
216
|
+
|
|
217
|
+
let rulesContent = `# AI Development Skills Framework\n`;
|
|
218
|
+
rulesContent += `# Auto-generated by @valentia-ai-skills/framework\n`;
|
|
219
|
+
rulesContent += `# Do not edit manually — run 'npx ai-skills update' to refresh\n`;
|
|
220
|
+
rulesContent += `# Last updated: ${new Date().toISOString().split("T")[0]}\n\n`;
|
|
221
|
+
|
|
222
|
+
for (const skill of allSkills) {
|
|
223
|
+
const content = readSkillContent(skill.path);
|
|
224
|
+
if (content) {
|
|
225
|
+
const rules = extractSkillRules(content);
|
|
226
|
+
rulesContent += `\n${"=".repeat(60)}\n`;
|
|
227
|
+
rulesContent += `# SKILL: ${skill.name} (${skill.category})\n`;
|
|
228
|
+
rulesContent += `${"=".repeat(60)}\n\n`;
|
|
229
|
+
rulesContent += rules + "\n";
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
fs.writeFileSync(rulesPath, rulesContent);
|
|
234
|
+
console.log(` ${c("green", "✓")} Written to ${tool.rulesFile} (${allSkills.length} skills merged)`);
|
|
235
|
+
installedCount += allSkills.length;
|
|
236
|
+
}
|
|
237
|
+
console.log("");
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// 4. Save project config
|
|
241
|
+
const config = {
|
|
242
|
+
version: "1.0.0",
|
|
243
|
+
installedAt: new Date().toISOString(),
|
|
244
|
+
tools,
|
|
245
|
+
skills: allSkills.map((s) => ({ name: s.name, category: s.category })),
|
|
246
|
+
};
|
|
247
|
+
saveProjectConfig(config);
|
|
248
|
+
|
|
249
|
+
// 5. Summary
|
|
250
|
+
console.log(c("blue", "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"));
|
|
251
|
+
console.log(c("green", `✅ Setup complete!`));
|
|
252
|
+
console.log(` ${allSkills.length} skills installed for ${tools.length} tool(s)\n`);
|
|
253
|
+
console.log(`Config saved to ${c("dim", ".ai-skills.json")}`);
|
|
254
|
+
console.log(`To update later: ${c("bold", "npx ai-skills update")}`);
|
|
255
|
+
console.log(`To check status: ${c("bold", "npx ai-skills status")}\n`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function cmdUpdate() {
|
|
259
|
+
console.log(c("blue", "\n━━━ AI Skills Framework — Update ━━━\n"));
|
|
260
|
+
|
|
261
|
+
const config = loadProjectConfig();
|
|
262
|
+
if (!config) {
|
|
263
|
+
console.log(c("yellow", "No .ai-skills.json found. Run 'npx ai-skills setup' first."));
|
|
264
|
+
process.exit(1);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Re-run setup with saved tool preferences
|
|
268
|
+
const tools = config.tools || detectTools();
|
|
269
|
+
const allSkills = getAllSkills();
|
|
270
|
+
|
|
271
|
+
for (const toolKey of tools) {
|
|
272
|
+
const tool = TOOL_CONFIGS[toolKey];
|
|
273
|
+
if (!tool) continue;
|
|
274
|
+
|
|
275
|
+
console.log(c("yellow", `Updating ${tool.name}...`));
|
|
276
|
+
|
|
277
|
+
if (tool.format === "skill-folder") {
|
|
278
|
+
const skillsDir = path.join(PROJECT_ROOT, tool.skillsDir);
|
|
279
|
+
for (const skill of allSkills) {
|
|
280
|
+
const dest = path.join(skillsDir, skill.name);
|
|
281
|
+
copyDir(skill.path, dest);
|
|
282
|
+
console.log(` ${c("green", "✓")} ${skill.name}`);
|
|
283
|
+
}
|
|
284
|
+
} else if (tool.format === "rules-file") {
|
|
285
|
+
const rulesPath = path.join(PROJECT_ROOT, tool.rulesFile);
|
|
286
|
+
mkdirp(path.dirname(rulesPath));
|
|
287
|
+
|
|
288
|
+
let rulesContent = `# AI Development Skills Framework\n`;
|
|
289
|
+
rulesContent += `# Auto-generated by @valentia-ai-skills/framework\n`;
|
|
290
|
+
rulesContent += `# Do not edit manually — run 'npx ai-skills update' to refresh\n`;
|
|
291
|
+
rulesContent += `# Last updated: ${new Date().toISOString().split("T")[0]}\n\n`;
|
|
292
|
+
|
|
293
|
+
for (const skill of allSkills) {
|
|
294
|
+
const content = readSkillContent(skill.path);
|
|
295
|
+
if (content) {
|
|
296
|
+
const rules = extractSkillRules(content);
|
|
297
|
+
rulesContent += `\n${"=".repeat(60)}\n`;
|
|
298
|
+
rulesContent += `# SKILL: ${skill.name} (${skill.category})\n`;
|
|
299
|
+
rulesContent += `${"=".repeat(60)}\n\n`;
|
|
300
|
+
rulesContent += rules + "\n";
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
fs.writeFileSync(rulesPath, rulesContent);
|
|
305
|
+
console.log(` ${c("green", "✓")} ${tool.rulesFile} updated`);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Update config
|
|
310
|
+
config.updatedAt = new Date().toISOString();
|
|
311
|
+
config.skills = allSkills.map((s) => ({ name: s.name, category: s.category }));
|
|
312
|
+
saveProjectConfig(config);
|
|
313
|
+
|
|
314
|
+
console.log(c("green", `\n✅ Updated ${allSkills.length} skills!\n`));
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function cmdStatus() {
|
|
318
|
+
console.log(c("blue", "\n━━━ AI Skills Framework — Status ━━━\n"));
|
|
319
|
+
|
|
320
|
+
const config = loadProjectConfig();
|
|
321
|
+
const allSkills = getAllSkills();
|
|
322
|
+
const tools = detectTools();
|
|
323
|
+
|
|
324
|
+
// Package version
|
|
325
|
+
const pkg = require(path.join(__dirname, "..", "package.json"));
|
|
326
|
+
console.log(`Package version: ${c("bold", pkg.version)}`);
|
|
327
|
+
console.log(`Skills available: ${c("bold", allSkills.length)}`);
|
|
328
|
+
|
|
329
|
+
// Installed status
|
|
330
|
+
if (config) {
|
|
331
|
+
console.log(`Installed: ${c("green", "Yes")} (${config.installedAt.split("T")[0]})`);
|
|
332
|
+
if (config.updatedAt) {
|
|
333
|
+
console.log(`Last updated: ${config.updatedAt.split("T")[0]}`);
|
|
334
|
+
}
|
|
335
|
+
console.log(`Tools configured: ${config.tools.map((t) => TOOL_CONFIGS[t]?.name || t).join(", ")}`);
|
|
336
|
+
} else {
|
|
337
|
+
console.log(`Installed: ${c("red", "No")} — run 'npx ai-skills setup'`);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Detected tools
|
|
341
|
+
console.log(`\nDetected AI tools in this project:`);
|
|
342
|
+
for (const [key, toolConfig] of Object.entries(TOOL_CONFIGS)) {
|
|
343
|
+
if (key === "generic") continue;
|
|
344
|
+
const detected = toolConfig.detect();
|
|
345
|
+
console.log(` ${detected ? c("green", "●") : c("dim", "○")} ${toolConfig.name}`);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Skill inventory
|
|
349
|
+
console.log(`\nSkill inventory:`);
|
|
350
|
+
for (const skill of allSkills) {
|
|
351
|
+
const content = readSkillContent(skill.path);
|
|
352
|
+
const versionMatch = content?.match(/version:\s*["']?([^"'\n]+)/);
|
|
353
|
+
const version = versionMatch ? versionMatch[1].trim() : "?";
|
|
354
|
+
console.log(` ${c("green", "✓")} ${skill.name} ${c("dim", `v${version}`)} ${c("dim", `(${skill.category})`)}`);
|
|
355
|
+
}
|
|
356
|
+
console.log("");
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function cmdList() {
|
|
360
|
+
const allSkills = getAllSkills();
|
|
361
|
+
console.log(c("blue", "\n━━━ Available Skills ━━━\n"));
|
|
362
|
+
|
|
363
|
+
const categories = {};
|
|
364
|
+
for (const skill of allSkills) {
|
|
365
|
+
if (!categories[skill.category]) categories[skill.category] = [];
|
|
366
|
+
categories[skill.category].push(skill);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
for (const [cat, skills] of Object.entries(categories)) {
|
|
370
|
+
console.log(c("yellow", `${cat.toUpperCase()}`));
|
|
371
|
+
for (const s of skills) {
|
|
372
|
+
const content = readSkillContent(s.path);
|
|
373
|
+
const descMatch = content?.match(/description:\s*>?\s*\n?\s*(.+)/);
|
|
374
|
+
const desc = descMatch ? descMatch[1].trim().slice(0, 70) + "..." : "";
|
|
375
|
+
console.log(` ${s.name.padEnd(22)} ${c("dim", desc)}`);
|
|
376
|
+
}
|
|
377
|
+
console.log("");
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function cmdDoctor() {
|
|
382
|
+
console.log(c("blue", "\n━━━ AI Skills — Health Check ━━━\n"));
|
|
383
|
+
|
|
384
|
+
let issues = 0;
|
|
385
|
+
const allSkills = getAllSkills();
|
|
386
|
+
|
|
387
|
+
// Check skills source exists
|
|
388
|
+
if (allSkills.length === 0) {
|
|
389
|
+
console.log(c("red", "✗ No skills found in package. Package may be corrupted."));
|
|
390
|
+
issues++;
|
|
391
|
+
} else {
|
|
392
|
+
console.log(c("green", `✓ ${allSkills.length} skills found in package`));
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Check project config
|
|
396
|
+
const config = loadProjectConfig();
|
|
397
|
+
if (!config) {
|
|
398
|
+
console.log(c("yellow", "⚠ No .ai-skills.json — run 'npx ai-skills setup'"));
|
|
399
|
+
issues++;
|
|
400
|
+
} else {
|
|
401
|
+
console.log(c("green", `✓ Project configured (${config.tools.length} tool(s))`));
|
|
402
|
+
|
|
403
|
+
// Check each tool's files exist
|
|
404
|
+
for (const toolKey of config.tools) {
|
|
405
|
+
const tool = TOOL_CONFIGS[toolKey];
|
|
406
|
+
if (!tool) continue;
|
|
407
|
+
|
|
408
|
+
if (tool.format === "skill-folder") {
|
|
409
|
+
const dir = path.join(PROJECT_ROOT, tool.skillsDir);
|
|
410
|
+
if (fs.existsSync(dir)) {
|
|
411
|
+
const count = fs.readdirSync(dir).filter(
|
|
412
|
+
(f) => fs.existsSync(path.join(dir, f, "SKILL.md"))
|
|
413
|
+
).length;
|
|
414
|
+
console.log(c("green", `✓ ${tool.name}: ${count} skills in ${tool.skillsDir}/`));
|
|
415
|
+
} else {
|
|
416
|
+
console.log(c("red", `✗ ${tool.name}: ${tool.skillsDir}/ missing`));
|
|
417
|
+
issues++;
|
|
418
|
+
}
|
|
419
|
+
} else if (tool.rulesFile) {
|
|
420
|
+
const rulesPath = path.join(PROJECT_ROOT, tool.rulesFile);
|
|
421
|
+
if (fs.existsSync(rulesPath)) {
|
|
422
|
+
console.log(c("green", `✓ ${tool.name}: ${tool.rulesFile} exists`));
|
|
423
|
+
} else {
|
|
424
|
+
console.log(c("red", `✗ ${tool.name}: ${tool.rulesFile} missing`));
|
|
425
|
+
issues++;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
console.log(issues === 0
|
|
432
|
+
? c("green", "\n✅ Everything looks good!\n")
|
|
433
|
+
: c("yellow", `\n⚠ ${issues} issue(s) found. Run 'npx ai-skills setup' to fix.\n`)
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// ── Main ──
|
|
438
|
+
|
|
439
|
+
const command = process.argv[2] || "setup";
|
|
440
|
+
|
|
441
|
+
switch (command) {
|
|
442
|
+
case "setup":
|
|
443
|
+
cmdSetup();
|
|
444
|
+
break;
|
|
445
|
+
case "update":
|
|
446
|
+
cmdUpdate();
|
|
447
|
+
break;
|
|
448
|
+
case "status":
|
|
449
|
+
cmdStatus();
|
|
450
|
+
break;
|
|
451
|
+
case "list":
|
|
452
|
+
cmdList();
|
|
453
|
+
break;
|
|
454
|
+
case "doctor":
|
|
455
|
+
cmdDoctor();
|
|
456
|
+
break;
|
|
457
|
+
case "help":
|
|
458
|
+
case "--help":
|
|
459
|
+
case "-h":
|
|
460
|
+
console.log(`
|
|
461
|
+
${c("blue", "AI Skills Framework")}
|
|
462
|
+
|
|
463
|
+
Usage:
|
|
464
|
+
npx ai-skills setup Setup skills for detected AI tools
|
|
465
|
+
npx ai-skills update Update skills to latest version
|
|
466
|
+
npx ai-skills status Show installed skills and tools
|
|
467
|
+
npx ai-skills list List all available skills
|
|
468
|
+
npx ai-skills doctor Check setup health
|
|
469
|
+
npx ai-skills help Show this help
|
|
470
|
+
|
|
471
|
+
How it works:
|
|
472
|
+
1. Install: npm install --save-dev @valentia-ai-skills/framework
|
|
473
|
+
2. Setup: npx ai-skills setup
|
|
474
|
+
3. Code: Your AI tools now follow your org's standards
|
|
475
|
+
4. Update: npm update @valentia-ai-skills/framework && npx ai-skills update
|
|
476
|
+
`);
|
|
477
|
+
break;
|
|
478
|
+
default:
|
|
479
|
+
console.log(c("red", `Unknown command: ${command}`));
|
|
480
|
+
console.log("Run 'npx ai-skills help' for usage info.");
|
|
481
|
+
process.exit(1);
|
|
482
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@valentia-ai-skills/framework",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "AI development skills framework — centralized coding standards, security patterns, and SOPs for AI-assisted development. Works with Claude Code, Cursor, Copilot, Windsurf, and any AI coding tool.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai-skills",
|
|
7
|
+
"claude-code",
|
|
8
|
+
"cursor",
|
|
9
|
+
"copilot",
|
|
10
|
+
"windsurf",
|
|
11
|
+
"coding-standards",
|
|
12
|
+
"development-framework",
|
|
13
|
+
"ai-development"
|
|
14
|
+
],
|
|
15
|
+
"author": "Valentia",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/codearraydev/valentia-awsome-skills.git"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"bin": {
|
|
25
|
+
"ai-skills": "./bin/cli.js"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"postinstall": "node scripts/postinstall.js",
|
|
29
|
+
"setup": "node bin/cli.js setup",
|
|
30
|
+
"update": "node bin/cli.js update"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"bin/",
|
|
34
|
+
"src/",
|
|
35
|
+
"skills/",
|
|
36
|
+
"scripts/",
|
|
37
|
+
"README.md"
|
|
38
|
+
],
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=18"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Runs after npm install. Prints a friendly message.
|
|
5
|
+
* Does NOT auto-setup — that's intentional so devs can choose.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const G = "\x1b[32m";
|
|
9
|
+
const B = "\x1b[34m";
|
|
10
|
+
const R = "\x1b[0m";
|
|
11
|
+
const D = "\x1b[2m";
|
|
12
|
+
|
|
13
|
+
console.log(`
|
|
14
|
+
${B}━━━ AI Skills Framework installed ━━━${R}
|
|
15
|
+
|
|
16
|
+
Run ${G}npx ai-skills setup${R} to configure for your AI tools.
|
|
17
|
+
${D}(Claude Code, Cursor, Copilot, Windsurf auto-detected)${R}
|
|
18
|
+
`);
|