@maccesar/aiskills 1.12.0 → 1.15.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 +42 -7
- package/lib/cleanup.js +29 -0
- package/lib/commands/skills.js +110 -9
- package/lib/config.js +17 -9
- package/lib/installer.js +5 -3
- package/lib/symlink.js +45 -3
- package/lib/utils.js +41 -0
- package/package.json +1 -1
- package/skills/audit-codebase/SKILL.md +70 -0
- package/skills/audit-codebase/agents/openai.yaml +4 -0
- package/skills/audit-codebase/references/comprehensive-audit.md +220 -0
- package/skills/audit-codebase/references/report-format.md +119 -0
- package/skills/humaniza/SKILL.md +55 -4
- package/skills/humaniza/references/ai-patterns-es.md +40 -0
- package/skills/humaniza/references/checklist.md +9 -0
- package/skills/humaniza/references/examples.md +16 -0
- package/skills/humaniza/references/lexicon-es-mx.md +18 -0
- package/skills/humaniza/references/structures-es.md +132 -0
- package/skills/humaniza/scripts/check_ai_patterns.py +216 -0
- package/skills/refactoring-ui/SKILL.md +65 -29
- package/skills/refactoring-ui/references/05-motion.md +124 -0
- package/skills/refactoring-ui/references/06-dark-mode.md +117 -0
- package/skills/refactoring-ui/references/07-component-patterns.md +181 -0
- package/skills/stitch-showcase/SKILL.md +24 -232
- package/skills/stitch-showcase/references/07-theme-system.md +12 -0
- package/skills/stitch-showcase/references/08-type-detection.md +9 -1
- package/skills/stitch-showcase/references/10-component-standardization.md +25 -0
- package/skills/stitch-showcase/references/12-video-embedding.md +113 -0
- package/skills/stitch-showcase/references/13-language-detection.md +82 -0
- package/skills/stitch-showcase/references/14-troubleshooting-known-issues.md +122 -0
- package/skills/stitch-showcase/references/15-build-flags.md +71 -0
- package/skills/stitch-showcase/references/16-design-md-format.md +107 -0
- package/skills/stitch-showcase/references/index.html +25 -19
- package/skills/stitch-showcase/references/viewer.html +24 -12
- package/skills/stitch-showcase/scripts/__pycache__/build_showcase.cpython-314.pyc +0 -0
- package/skills/stitch-showcase/scripts/__pycache__/component_utils.cpython-314.pyc +0 -0
- package/skills/stitch-showcase/scripts/__pycache__/detect_components.cpython-314.pyc +0 -0
- package/skills/stitch-showcase/scripts/__pycache__/extract_catalog.cpython-314.pyc +0 -0
- package/skills/stitch-showcase/scripts/__pycache__/extract_text.cpython-314.pyc +0 -0
- package/skills/stitch-showcase/scripts/__pycache__/extract_zips.cpython-314.pyc +0 -0
- package/skills/stitch-showcase/scripts/__pycache__/parse_design_md.cpython-314.pyc +0 -0
- package/skills/stitch-showcase/scripts/__pycache__/slug_demangle.cpython-314.pyc +0 -0
- package/skills/stitch-showcase/scripts/build_showcase.py +150 -10
- package/skills/stitch-showcase/scripts/parse_design_md.py +145 -12
- package/skills/stitch-showcase/scripts/slug_demangle.py +209 -0
- package/skills/vscode-extension-dev/SKILL.md +90 -41
- package/skills/vscode-extension-dev/references/api-additional.md +168 -0
- package/skills/vscode-extension-dev/references/api-progress.md +55 -0
- package/skills/vscode-extension-dev/references/api-quickpick.md +75 -0
- package/skills/vscode-extension-dev/references/api-secretstorage.md +57 -0
- package/skills/vscode-extension-dev/references/api-statusbar.md +38 -0
- package/skills/vscode-extension-dev/references/api-treeview.md +78 -0
- package/skills/vscode-extension-dev/references/api-webview.md +149 -0
- package/skills/vscode-extension-dev/references/architecture.md +67 -0
- package/skills/vscode-extension-dev/references/debugger.md +179 -0
- package/skills/vscode-extension-dev/references/lsp.md +175 -0
- package/skills/vscode-extension-dev/references/notebooks.md +208 -0
- package/skills/vscode-extension-dev/references/testing.md +208 -0
- package/skills/vscode-extension-dev/references/api-patterns.md +0 -625
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ claude # or gemini, or codex
|
|
|
40
40
|
|
|
41
41
|
Installed files:
|
|
42
42
|
- All skills to `~/.agents/skills/`
|
|
43
|
-
- Platform symlinks in `~/.claude/skills/` and
|
|
43
|
+
- Platform symlinks in `~/.claude/skills/` (Gemini CLI and Codex CLI auto-discover from `~/.agents/skills/` — no platform-specific symlink needed)
|
|
44
44
|
|
|
45
45
|
### Which option should I use?
|
|
46
46
|
|
|
@@ -58,7 +58,7 @@ Installed files:
|
|
|
58
58
|
| Platform | Status | Installation Path |
|
|
59
59
|
| --------------------------------------------------------- | --------- | ------------------- |
|
|
60
60
|
| [Claude Code](https://claude.ai/claude-code) | Supported | `~/.claude/skills/` |
|
|
61
|
-
| [Gemini CLI](https://github.com/google-gemini/gemini-cli) | Supported | `~/.
|
|
61
|
+
| [Gemini CLI](https://github.com/google-gemini/gemini-cli) | Supported | `~/.agents/skills/` (auto-discovered) |
|
|
62
62
|
| [Codex CLI](https://developers.openai.com/codex/cli/) | Supported | `~/.agents/skills/` (auto-discovered) |
|
|
63
63
|
|
|
64
64
|
All three platforms use the same Agent Skills format: a `SKILL.md` file with YAML frontmatter that tells the assistant when to use the skill and what to do.
|
|
@@ -69,10 +69,11 @@ All three platforms use the same Agent Skills format: a `SKILL.md` file with YAM
|
|
|
69
69
|
|
|
70
70
|
| Skill | Domain | Source | Reference Files |
|
|
71
71
|
| -------------------- | ------------ | ------------------------------------ | --------------- |
|
|
72
|
-
| refactoring-ui | Design | "Refactoring UI" by Wathan & Schoger |
|
|
73
|
-
| humaniza | Writing (es) | Curated Spanish/es-MX style rules |
|
|
74
|
-
|
|
|
75
|
-
|
|
|
72
|
+
| refactoring-ui | Design | "Refactoring UI" by Wathan & Schoger | 7 files |
|
|
73
|
+
| humaniza | Writing (es) | Curated Spanish/es-MX style rules | 7 files |
|
|
74
|
+
| audit-codebase | Auditing | Evidence-based audit methodology | 2 files |
|
|
75
|
+
| vscode-extension-dev | VS Code | VS Code Extension API docs | 14 files |
|
|
76
|
+
| stitch-showcase | Design Tools | Google Stitch export workflow | 16 files |
|
|
76
77
|
|
|
77
78
|
Use `aiskills list` to see available skills from the command line. Pull requests are welcome.
|
|
78
79
|
|
|
@@ -192,7 +193,7 @@ Reference files:
|
|
|
192
193
|
|
|
193
194
|
### humaniza
|
|
194
195
|
|
|
195
|
-
An editor for Spanish text (es-MX). It removes common AI writing patterns and rewrites the text so it sounds natural without changing the meaning.
|
|
196
|
+
An editor for Spanish text (es-MX). Based on curated es-MX style rules and adapted techniques from Hardik Pandya's Stop Slop skill (cut filler, break formulaic structures, active voice, specificity, varied rhythm). It removes common AI writing patterns and rewrites the text so it sounds natural without changing the meaning.
|
|
196
197
|
|
|
197
198
|
When it activates:
|
|
198
199
|
- User asks to "humanize" a text in Spanish
|
|
@@ -224,6 +225,7 @@ Reference files:
|
|
|
224
225
|
| ----------------- | --------------------------------------------------------------- |
|
|
225
226
|
| ai-patterns-es.md | AI writing tics in Spanish: inflated phrases, filler, templates |
|
|
226
227
|
| lexicon-es-mx.md | Preferred es-MX vocabulary vs. Spain Spanish |
|
|
228
|
+
| structures-es.md | Structural patterns to avoid: binary contrasts, false agency... |
|
|
227
229
|
| modes-es-mx.md | Rules per mode (marketing, technical, support, etc.) |
|
|
228
230
|
| voice-es-mx.md | How to add human voice: rhythm, concreteness, variety |
|
|
229
231
|
| checklist.md | Final QA before delivering the text |
|
|
@@ -238,6 +240,39 @@ Scope:
|
|
|
238
240
|
|
|
239
241
|
---
|
|
240
242
|
|
|
243
|
+
### audit-codebase
|
|
244
|
+
|
|
245
|
+
A senior software auditor that reviews an entire project — architecture, security, compatibility, performance, maintainability, and tests — and delivers an evidence-based diagnosis with a decision matrix and correction plan. Works in two stages: a read-only audit first, then an authorized implementation of the approved plan. Every restrictive security recommendation must name the legitimate use cases it could break and the less-restrictive alternative that was evaluated. The report is written in the user's language.
|
|
246
|
+
|
|
247
|
+
When it activates:
|
|
248
|
+
- Asking for a full technical audit or security review of a project
|
|
249
|
+
- Checking if a project is ready for production
|
|
250
|
+
- Reviewing architecture, dependencies, compatibility, or test coverage
|
|
251
|
+
- Implementing an approved audit correction plan
|
|
252
|
+
|
|
253
|
+
Example prompts:
|
|
254
|
+
```
|
|
255
|
+
"Audit this project end to end"
|
|
256
|
+
"Is this backend ready for production?"
|
|
257
|
+
"Do a security review without breaking the anonymous flows"
|
|
258
|
+
"Find real problems before we ship"
|
|
259
|
+
"Implement the audit plan we approved"
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Reference files:
|
|
263
|
+
| File | Topics |
|
|
264
|
+
| ---------------------- | --------------------------------------------------------------------------- |
|
|
265
|
+
| comprehensive-audit.md | Mandatory principles, 24-area technical scope, 5-phase method, severity |
|
|
266
|
+
| report-format.md | Executive summary, findings table, decision matrix, correction plan formats |
|
|
267
|
+
|
|
268
|
+
Scope:
|
|
269
|
+
- Stage 1 never modifies files; the first deliverable is always diagnosis + plan
|
|
270
|
+
- Every confirmed finding gets an explicit disposition (fix now, later, accept, won't fix)
|
|
271
|
+
- Findings are classified as Confirmed / Conditional risk / Unverified — no pattern-matched "vulnerabilities" without evidence
|
|
272
|
+
- Stage 2 only starts after the user approves the decision matrix, and implements it completely
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
241
276
|
### vscode-extension-dev
|
|
242
277
|
|
|
243
278
|
A guide for building VS Code extensions from scaffolding to publishing. Based on the official VS Code Extension API docs.
|
package/lib/cleanup.js
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
getAgentsSkillsDir,
|
|
11
11
|
getClaudeCommandsDir,
|
|
12
12
|
getCodexSkillsDir,
|
|
13
|
+
getGeminiSkillsDir,
|
|
13
14
|
} from './config.js';
|
|
14
15
|
import { detectPlatforms } from './platform.js';
|
|
15
16
|
import { existsSync, lstatSync, rmSync } from 'fs';
|
|
@@ -54,6 +55,20 @@ export function removeLegacySkillSymlinks(platformSkillsDir) {
|
|
|
54
55
|
return removeSkillSymlinks(platformSkillsDir, { legacyOnly: true });
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
// When the user de-selects some skills during an install, anything previously
|
|
59
|
+
// installed for those skills (in ~/.agents/skills/ and as platform symlinks)
|
|
60
|
+
// must be cleaned up so the on-disk state matches the user's selection.
|
|
61
|
+
export function removeUnselectedSkills(baseDir, selectedSkills) {
|
|
62
|
+
const skillsDir = getAgentsSkillsDir(baseDir);
|
|
63
|
+
const unselected = SKILLS.filter((s) => !selectedSkills.includes(s));
|
|
64
|
+
return removeEntriesAtDir(skillsDir, unselected, { recursive: true });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function removeUnselectedSymlinks(platformSkillsDir, selectedSkills) {
|
|
68
|
+
const unselected = SKILLS.filter((s) => !selectedSkills.includes(s));
|
|
69
|
+
return removeEntriesAtDir(platformSkillsDir, unselected, { recursive: true });
|
|
70
|
+
}
|
|
71
|
+
|
|
57
72
|
// Codex reads skills from the canonical ~/.agents/skills/, so any aiskills-managed
|
|
58
73
|
// symlinks at ~/.codex/skills/ from earlier versions are redundant and should be
|
|
59
74
|
// cleaned up. Targets both active and legacy skill names.
|
|
@@ -62,6 +77,15 @@ export function removeCodexRedundantSymlinks(baseDir) {
|
|
|
62
77
|
return removeSkillSymlinks(codexSkillsDir);
|
|
63
78
|
}
|
|
64
79
|
|
|
80
|
+
// Gemini CLI also auto-discovers skills from ~/.agents/skills/ per the
|
|
81
|
+
// agentskills.io standard. Symlinks at ~/.gemini/skills/ from earlier
|
|
82
|
+
// versions produce "Skill conflict detected" warnings on Gemini startup
|
|
83
|
+
// because the same skill is found in both locations.
|
|
84
|
+
export function removeGeminiRedundantSymlinks(baseDir) {
|
|
85
|
+
const geminiSkillsDir = getGeminiSkillsDir(baseDir);
|
|
86
|
+
return removeSkillSymlinks(geminiSkillsDir);
|
|
87
|
+
}
|
|
88
|
+
|
|
65
89
|
export function removeSkills(baseDir, options = {}) {
|
|
66
90
|
const skillsDir = getAgentsSkillsDir(baseDir);
|
|
67
91
|
const skillList = getSkillList(options);
|
|
@@ -84,6 +108,7 @@ export function cleanupLegacyArtifacts(baseDir) {
|
|
|
84
108
|
}
|
|
85
109
|
|
|
86
110
|
removeCodexRedundantSymlinks(baseDir);
|
|
111
|
+
removeGeminiRedundantSymlinks(baseDir);
|
|
87
112
|
|
|
88
113
|
if (baseDir) {
|
|
89
114
|
removeSkills(undefined, { legacyOnly: true });
|
|
@@ -93,6 +118,7 @@ export function cleanupLegacyArtifacts(baseDir) {
|
|
|
93
118
|
removeLegacySkillSymlinks(platform.skillsDir);
|
|
94
119
|
}
|
|
95
120
|
removeCodexRedundantSymlinks(undefined);
|
|
121
|
+
removeGeminiRedundantSymlinks(undefined);
|
|
96
122
|
}
|
|
97
123
|
}
|
|
98
124
|
|
|
@@ -102,6 +128,9 @@ export default {
|
|
|
102
128
|
removeSkillSymlinks,
|
|
103
129
|
removeLegacySkillSymlinks,
|
|
104
130
|
removeCodexRedundantSymlinks,
|
|
131
|
+
removeGeminiRedundantSymlinks,
|
|
132
|
+
removeUnselectedSkills,
|
|
133
|
+
removeUnselectedSymlinks,
|
|
105
134
|
removeSkills,
|
|
106
135
|
removeCommands,
|
|
107
136
|
cleanupLegacyArtifacts,
|
package/lib/commands/skills.js
CHANGED
|
@@ -22,6 +22,9 @@ import {
|
|
|
22
22
|
removeLegacySkillSymlinks,
|
|
23
23
|
removeSkills,
|
|
24
24
|
removeCommands,
|
|
25
|
+
removeUnselectedSkills,
|
|
26
|
+
removeUnselectedSymlinks,
|
|
27
|
+
cleanupLegacyArtifacts,
|
|
25
28
|
} from '../cleanup.js';
|
|
26
29
|
import {
|
|
27
30
|
installSkills,
|
|
@@ -31,6 +34,7 @@ import {
|
|
|
31
34
|
import { downloadRepoArchive } from '../downloader.js';
|
|
32
35
|
import { createSkillSymlinks } from '../symlink.js';
|
|
33
36
|
import { installHook } from '../hooks.js';
|
|
37
|
+
import { readSkillDescription, shortenSkillDescription } from '../utils.js';
|
|
34
38
|
import { mkdtemp } from 'fs/promises';
|
|
35
39
|
import { existsSync } from 'fs';
|
|
36
40
|
import { join, resolve } from 'path';
|
|
@@ -64,6 +68,22 @@ export async function skillsCommand(options) {
|
|
|
64
68
|
} else {
|
|
65
69
|
console.log(chalk.cyan('Mode: Global installation (user home)'));
|
|
66
70
|
}
|
|
71
|
+
const skillsLocation = isLocal
|
|
72
|
+
? './.agents/skills/'
|
|
73
|
+
: (customPath ? `${baseDir}/.agents/skills/` : '~/.agents/skills/');
|
|
74
|
+
console.log('');
|
|
75
|
+
console.log(
|
|
76
|
+
chalk.yellow('▸'),
|
|
77
|
+
'Skills install to',
|
|
78
|
+
chalk.cyan.bold(skillsLocation),
|
|
79
|
+
chalk.dim('(agentskills.io standard)')
|
|
80
|
+
);
|
|
81
|
+
console.log(
|
|
82
|
+
' ' + chalk.dim('Read directly by Gemini, Codex, Cursor, Cline, Amp, GitHub Copilot, +more.')
|
|
83
|
+
);
|
|
84
|
+
console.log(
|
|
85
|
+
' ' + chalk.dim('Below: extra symlink mirrors for Claude Code.')
|
|
86
|
+
);
|
|
67
87
|
console.log('');
|
|
68
88
|
|
|
69
89
|
// Detect installed platforms at the target base directory
|
|
@@ -85,9 +105,9 @@ export async function skillsCommand(options) {
|
|
|
85
105
|
}
|
|
86
106
|
|
|
87
107
|
if (detectedPlatforms.length === 0 && !options.path && !isLocal) {
|
|
88
|
-
console.log(chalk.yellow('No AI coding assistants detected globally.'));
|
|
89
|
-
console.log('Install
|
|
90
|
-
console.log('(
|
|
108
|
+
console.log(chalk.yellow('No AI coding assistants detected globally that need platform symlinks.'));
|
|
109
|
+
console.log('Install Claude Code if you want aiskills to create skill symlinks for it.');
|
|
110
|
+
console.log('(Gemini CLI and Codex CLI auto-discover skills from ~/.agents/skills/ — no platform-specific symlink needed.)');
|
|
91
111
|
console.log('Or use: aiskills install --local');
|
|
92
112
|
process.exit(1);
|
|
93
113
|
}
|
|
@@ -173,14 +193,73 @@ export async function skillsCommand(options) {
|
|
|
173
193
|
}
|
|
174
194
|
}
|
|
175
195
|
|
|
196
|
+
// Skill selection prompt — pre-checks all skills; the user can uncheck the
|
|
197
|
+
// ones they don't want. Skipped under --all (CI/automation) and removeOnly.
|
|
198
|
+
// Each line shows the skill name + a one-liner hint in dim gray, like
|
|
199
|
+
// skills.sh, so the rendered row height stays constant and the list does
|
|
200
|
+
// not "jump" when the cursor moves between skills with different-length
|
|
201
|
+
// descriptions.
|
|
202
|
+
let skillsToInstall = SKILLS;
|
|
203
|
+
if (!removeOnly && !options.all && !options.path) {
|
|
204
|
+
const skillChoices = SKILLS.map((name) => {
|
|
205
|
+
const fullDescription = readSkillDescription(repoDir, name);
|
|
206
|
+
const hint = shortenSkillDescription(fullDescription);
|
|
207
|
+
const label = hint
|
|
208
|
+
? `${name} ${chalk.dim(`(${hint})`)}`
|
|
209
|
+
: name;
|
|
210
|
+
return { name: label, value: name, short: name, checked: true };
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
try {
|
|
214
|
+
const selected = await checkbox({
|
|
215
|
+
message: 'Select skills to install:',
|
|
216
|
+
choices: [...skillChoices, new Separator(' ')],
|
|
217
|
+
theme: {
|
|
218
|
+
style: {
|
|
219
|
+
renderSelectedChoices: () => '',
|
|
220
|
+
prefix: () => chalk.cyan('?'),
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
if (selected.includes('cancel')) {
|
|
226
|
+
console.log('Cancelled.');
|
|
227
|
+
process.exit(0);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
skillsToInstall = SKILLS.filter((s) => selected.includes(s));
|
|
231
|
+
} catch (error) {
|
|
232
|
+
console.log('\nCancelled.');
|
|
233
|
+
process.exit(0);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (skillsToInstall.length === 0) {
|
|
237
|
+
console.log(chalk.yellow('No skills selected. Nothing to install.'));
|
|
238
|
+
process.exit(0);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
176
242
|
const selectedPlatformNames = new Set(selectedPlatforms.map((platform) => platform.name));
|
|
177
243
|
|
|
178
244
|
try {
|
|
179
245
|
if (!removeOnly) {
|
|
180
246
|
// Install skills
|
|
181
247
|
spinner.start('Installing skills...');
|
|
182
|
-
const skillsResult = await installSkills(repoDir, baseDir);
|
|
183
|
-
spinner.succeed(`${
|
|
248
|
+
const skillsResult = await installSkills(repoDir, baseDir, skillsToInstall);
|
|
249
|
+
spinner.succeed(`${skillsToInstall.length} skill${skillsToInstall.length !== 1 ? 's' : ''} installed`);
|
|
250
|
+
|
|
251
|
+
// If the user deselected some skills, sweep any previously-installed
|
|
252
|
+
// copies and their platform symlinks so on-disk state matches selection.
|
|
253
|
+
if (skillsToInstall.length !== SKILLS.length) {
|
|
254
|
+
removeUnselectedSkills(baseDir, skillsToInstall);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Sweep legacy skills, legacy commands, and redundant symlinks at platforms
|
|
258
|
+
// that no longer need aiskills-managed mirrors (Gemini, Codex). Without
|
|
259
|
+
// this, users that ran older aiskills versions keep stale symlinks at
|
|
260
|
+
// ~/.gemini/skills/ and ~/.codex/skills/ that Gemini reports as "Skill
|
|
261
|
+
// conflict detected" warnings on startup.
|
|
262
|
+
cleanupLegacyArtifacts(baseDir);
|
|
184
263
|
|
|
185
264
|
// Install or remove slash commands based on Claude Code selection
|
|
186
265
|
if (selectedPlatformNames.has('claude')) {
|
|
@@ -203,17 +282,20 @@ export async function skillsCommand(options) {
|
|
|
203
282
|
// Create symlinks for selected platforms
|
|
204
283
|
for (const platform of selectedPlatforms) {
|
|
205
284
|
removeLegacySkillSymlinks(platform.skillsDir);
|
|
285
|
+
if (skillsToInstall.length !== SKILLS.length) {
|
|
286
|
+
removeUnselectedSymlinks(platform.skillsDir, skillsToInstall);
|
|
287
|
+
}
|
|
206
288
|
spinner.start(`Linking ${platform.displayName}...`);
|
|
207
289
|
const symlinkResult = await createSkillSymlinks(
|
|
208
290
|
platform.skillsDir,
|
|
209
|
-
|
|
291
|
+
skillsToInstall,
|
|
210
292
|
baseDir
|
|
211
293
|
);
|
|
212
|
-
if (symlinkResult.linked.length ===
|
|
294
|
+
if (symlinkResult.linked.length === skillsToInstall.length) {
|
|
213
295
|
spinner.succeed(`${platform.displayName}: Skills linked`);
|
|
214
296
|
} else {
|
|
215
297
|
spinner.warn(
|
|
216
|
-
`${platform.displayName}: ${symlinkResult.linked.length}/${
|
|
298
|
+
`${platform.displayName}: ${symlinkResult.linked.length}/${skillsToInstall.length} skills linked`
|
|
217
299
|
);
|
|
218
300
|
}
|
|
219
301
|
}
|
|
@@ -269,9 +351,28 @@ export async function skillsCommand(options) {
|
|
|
269
351
|
}
|
|
270
352
|
}
|
|
271
353
|
|
|
272
|
-
// Summary
|
|
354
|
+
// Summary — show where the skills landed and which agents read them.
|
|
355
|
+
// This is the "did it actually work" confirmation the user needs.
|
|
273
356
|
console.log('');
|
|
274
357
|
console.log(chalk.green('✓ Skills sync complete!'));
|
|
358
|
+
if (!removeOnly) {
|
|
359
|
+
console.log('');
|
|
360
|
+
console.log(
|
|
361
|
+
' ' + chalk.bold(skillsLocation) + chalk.dim(' (') +
|
|
362
|
+
chalk.dim(skillsToInstall.length + ' skill' + (skillsToInstall.length !== 1 ? 's' : '')) +
|
|
363
|
+
chalk.dim(')')
|
|
364
|
+
);
|
|
365
|
+
console.log(
|
|
366
|
+
' ' + chalk.dim('• universal: ') +
|
|
367
|
+
'Gemini, Codex, Cursor, Cline, Amp, GitHub Copilot ' + chalk.dim('+more')
|
|
368
|
+
);
|
|
369
|
+
if (selectedPlatformNames.has('claude')) {
|
|
370
|
+
console.log(
|
|
371
|
+
' ' + chalk.dim('• symlinked: ') +
|
|
372
|
+
'Claude Code ' + chalk.dim('(~/.claude/skills/)')
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
275
376
|
console.log('');
|
|
276
377
|
|
|
277
378
|
if (!removeOnly && !isLocal && detectOS() === 'windows') {
|
package/lib/config.js
CHANGED
|
@@ -27,6 +27,7 @@ export const REPO_API_URL = 'https://api.github.com/repos/macCesar/aiskills';
|
|
|
27
27
|
|
|
28
28
|
// Skills to install
|
|
29
29
|
export const SKILLS = [
|
|
30
|
+
'audit-codebase',
|
|
30
31
|
'humaniza',
|
|
31
32
|
'refactoring-ui',
|
|
32
33
|
'stitch-showcase',
|
|
@@ -54,7 +55,23 @@ export const getClaudeCommandsDir = (baseDir = os.homedir()) => path.join(baseDi
|
|
|
54
55
|
export const getGeminiSkillsDir = (baseDir = os.homedir()) => path.join(baseDir, '.gemini', 'skills');
|
|
55
56
|
export const getCodexSkillsDir = (baseDir = os.homedir()) => path.join(baseDir, '.codex', 'skills');
|
|
56
57
|
|
|
58
|
+
// Name of the Claude marketplace and plugin where this CLI publishes itself.
|
|
59
|
+
// Used to detect when a skill is already installed via the marketplace plugin
|
|
60
|
+
// and avoid creating a duplicate symlink in ~/.claude/skills/.
|
|
61
|
+
export const CLAUDE_PLUGIN_MARKETPLACE = 'maccesar-aiskills';
|
|
62
|
+
export const CLAUDE_PLUGIN_NAME = 'aiskills';
|
|
63
|
+
export const getClaudePluginSkillsPath = (baseDir = os.homedir()) =>
|
|
64
|
+
path.join(baseDir, '.claude', 'plugins', 'cache', CLAUDE_PLUGIN_MARKETPLACE, CLAUDE_PLUGIN_NAME);
|
|
65
|
+
|
|
57
66
|
// AI platform detection
|
|
67
|
+
//
|
|
68
|
+
// Only platforms that need aiskills-managed symlinks appear here.
|
|
69
|
+
// Gemini CLI and Codex CLI auto-discover skills from the canonical
|
|
70
|
+
// ~/.agents/skills/ per the agentskills.io standard, so creating
|
|
71
|
+
// platform-specific symlinks at ~/.gemini/skills/ or ~/.codex/skills/
|
|
72
|
+
// would be redundant — and in Gemini's case actively harmful, since it
|
|
73
|
+
// reads both locations and reports "Skill conflict detected" warnings
|
|
74
|
+
// when the same skill exists in both.
|
|
58
75
|
export const getPlatforms = (baseDir = os.homedir()) => [
|
|
59
76
|
{
|
|
60
77
|
name: 'claude',
|
|
@@ -62,15 +79,6 @@ export const getPlatforms = (baseDir = os.homedir()) => [
|
|
|
62
79
|
skillsDir: getClaudeSkillsDir(baseDir),
|
|
63
80
|
configDir: path.join(baseDir, '.claude'),
|
|
64
81
|
},
|
|
65
|
-
{
|
|
66
|
-
name: 'gemini',
|
|
67
|
-
displayName: 'Gemini CLI',
|
|
68
|
-
skillsDir: getGeminiSkillsDir(baseDir),
|
|
69
|
-
configDir: path.join(baseDir, '.gemini'),
|
|
70
|
-
},
|
|
71
|
-
// Codex CLI is intentionally omitted: it auto-discovers skills from the
|
|
72
|
-
// canonical ~/.agents/skills/ per the agentskills.io standard, so a
|
|
73
|
-
// platform-specific symlink at ~/.codex/skills/ would be redundant.
|
|
74
82
|
];
|
|
75
83
|
|
|
76
84
|
// API configuration
|
package/lib/installer.js
CHANGED
|
@@ -61,12 +61,14 @@ export async function installSkill(repoDir, skillName, baseDir = os.homedir()) {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
|
-
* Install
|
|
64
|
+
* Install skills to the agents skills directory
|
|
65
65
|
* @param {string} repoDir - Repository directory
|
|
66
66
|
* @param {string} baseDir - Base directory for installation
|
|
67
|
+
* @param {string[]} [skillsToInstall] - Subset of skills to install (defaults to all SKILLS)
|
|
67
68
|
* @returns {Promise<Object>} Results object with success/failure counts
|
|
68
69
|
*/
|
|
69
|
-
export async function installSkills(repoDir, baseDir = os.homedir()) {
|
|
70
|
+
export async function installSkills(repoDir, baseDir = os.homedir(), skillsToInstall) {
|
|
71
|
+
const list = skillsToInstall || SKILLS;
|
|
70
72
|
const results = {
|
|
71
73
|
installed: [],
|
|
72
74
|
failed: [],
|
|
@@ -83,7 +85,7 @@ export async function installSkills(repoDir, baseDir = os.homedir()) {
|
|
|
83
85
|
results.failed.push(...legacyGlobal.failed);
|
|
84
86
|
}
|
|
85
87
|
|
|
86
|
-
for (const skill of
|
|
88
|
+
for (const skill of list) {
|
|
87
89
|
if (await installSkill(repoDir, skill, baseDir)) {
|
|
88
90
|
results.installed.push(skill);
|
|
89
91
|
} else {
|
package/lib/symlink.js
CHANGED
|
@@ -69,19 +69,49 @@ async function removePath(path) {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
|
-
*
|
|
72
|
+
* Check if a skill is already available via the maccesar-aiskills Claude marketplace plugin.
|
|
73
|
+
* When the plugin is installed, Claude Code lists the skill from
|
|
74
|
+
* ~/.claude/plugins/cache/maccesar-aiskills/aiskills/<version>/skills/<skill>/
|
|
75
|
+
* and an additional symlink at ~/.claude/skills/<skill> produces a duplicate
|
|
76
|
+
* entry in the slash-command autocomplete. This helper lets the symlink step
|
|
77
|
+
* skip Claude when the plugin already covers it.
|
|
78
|
+
* @param {string} skillName - Skill name (e.g. 'stitch-showcase')
|
|
79
|
+
* @param {string} baseDir - Optional base directory (defaults to homedir via config)
|
|
80
|
+
* @returns {Promise<boolean>} True if the plugin provides this skill
|
|
81
|
+
*/
|
|
82
|
+
export async function isClaudePluginSkillInstalled(skillName, baseDir) {
|
|
83
|
+
const { readdir } = await import('fs/promises');
|
|
84
|
+
const { getClaudePluginSkillsPath } = await import('./config.js');
|
|
85
|
+
const pluginBase = getClaudePluginSkillsPath(baseDir);
|
|
86
|
+
if (!existsSync(pluginBase)) return false;
|
|
87
|
+
try {
|
|
88
|
+
const versions = await readdir(pluginBase);
|
|
89
|
+
return versions.some((v) => existsSync(join(pluginBase, v, 'skills', skillName)));
|
|
90
|
+
} catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Create symlinks for all skills to a platform directory.
|
|
97
|
+
* For the Claude platform, skills already provided by the maccesar-aiskills
|
|
98
|
+
* marketplace plugin are skipped to avoid duplicate slash-command entries;
|
|
99
|
+
* if a stale symlink from a previous install exists, it is removed.
|
|
73
100
|
* @param {string} platformSkillsDir - Platform skills directory
|
|
74
101
|
* @param {Array} skills - List of skill names
|
|
75
102
|
* @param {string} baseDir - Optional base directory for target resolution
|
|
76
|
-
* @returns {Promise<Object>} Results object with
|
|
103
|
+
* @returns {Promise<Object>} Results object with linked / failed / skipped arrays
|
|
77
104
|
*/
|
|
78
105
|
export async function createSkillSymlinks(platformSkillsDir, skills, baseDir) {
|
|
79
|
-
const { getAgentsSkillsDir } = await import('./config.js');
|
|
106
|
+
const { getAgentsSkillsDir, getClaudeSkillsDir } = await import('./config.js');
|
|
80
107
|
const agentsSkillsDir = getAgentsSkillsDir(baseDir);
|
|
108
|
+
const claudeSkillsDir = getClaudeSkillsDir(baseDir);
|
|
109
|
+
const isClaudePlatform = platformSkillsDir === claudeSkillsDir;
|
|
81
110
|
|
|
82
111
|
const results = {
|
|
83
112
|
linked: [],
|
|
84
113
|
failed: [],
|
|
114
|
+
skipped: [],
|
|
85
115
|
};
|
|
86
116
|
|
|
87
117
|
// Ensure platform directory exists
|
|
@@ -93,6 +123,17 @@ export async function createSkillSymlinks(platformSkillsDir, skills, baseDir) {
|
|
|
93
123
|
const useRelative = !!baseDir;
|
|
94
124
|
|
|
95
125
|
for (const skill of skills) {
|
|
126
|
+
// Skip Claude when the marketplace plugin already provides this skill;
|
|
127
|
+
// clean up any stale symlink left from a previous CLI install.
|
|
128
|
+
if (isClaudePlatform && await isClaudePluginSkillInstalled(skill, baseDir)) {
|
|
129
|
+
const stalePath = join(platformSkillsDir, skill);
|
|
130
|
+
if (existsSync(stalePath)) {
|
|
131
|
+
await removePath(stalePath);
|
|
132
|
+
}
|
|
133
|
+
results.skipped.push(skill);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
|
|
96
137
|
const target = join(agentsSkillsDir, skill);
|
|
97
138
|
const linkPath = join(platformSkillsDir, skill);
|
|
98
139
|
|
|
@@ -148,6 +189,7 @@ export async function updateSymlink(target, path) {
|
|
|
148
189
|
export default {
|
|
149
190
|
createSymlinkOrCopy,
|
|
150
191
|
createSkillSymlinks,
|
|
192
|
+
isClaudePluginSkillInstalled,
|
|
151
193
|
isSymlink,
|
|
152
194
|
resolveSymlink,
|
|
153
195
|
updateSymlink,
|
package/lib/utils.js
CHANGED
|
@@ -2,6 +2,45 @@
|
|
|
2
2
|
* Utility functions
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { readFileSync } from 'fs';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Read the description field from a skill's SKILL.md frontmatter.
|
|
10
|
+
* @param {string} repoDir - Repository directory containing skills/
|
|
11
|
+
* @param {string} skillName - Skill name (directory under skills/)
|
|
12
|
+
* @returns {string} Description text, or empty string if not available.
|
|
13
|
+
*/
|
|
14
|
+
export function readSkillDescription(repoDir, skillName) {
|
|
15
|
+
try {
|
|
16
|
+
const skillPath = join(repoDir, 'skills', skillName, 'SKILL.md');
|
|
17
|
+
const content = readFileSync(skillPath, 'utf8');
|
|
18
|
+
const fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
19
|
+
if (!fmMatch) return '';
|
|
20
|
+
const descMatch = fmMatch[1].match(/^description:\s*["']?(.+?)["']?\s*$/m);
|
|
21
|
+
return descMatch ? descMatch[1].trim() : '';
|
|
22
|
+
} catch {
|
|
23
|
+
return '';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Compress a skill description to a one-line summary suitable for an inline
|
|
29
|
+
* checkbox preview. Picks the first segment of the description and trims it
|
|
30
|
+
* to `maxLen` characters, appending an ellipsis when the source is longer.
|
|
31
|
+
*
|
|
32
|
+
* @param {string} description - The full SKILL.md description.
|
|
33
|
+
* @param {number} maxLen - Maximum characters of the output (excluding ellipsis).
|
|
34
|
+
* @returns {string} Trimmed one-liner, or empty string if input was empty.
|
|
35
|
+
*/
|
|
36
|
+
export function shortenSkillDescription(description, maxLen = 60) {
|
|
37
|
+
if (!description) return '';
|
|
38
|
+
let firstSegment = description.split(/\s*[—.:;]\s*/)[0].trim();
|
|
39
|
+
firstSegment = firstSegment.replace(/\s+/g, ' ');
|
|
40
|
+
if (firstSegment.length <= maxLen) return firstSegment;
|
|
41
|
+
return firstSegment.slice(0, maxLen).trimEnd() + '…';
|
|
42
|
+
}
|
|
43
|
+
|
|
5
44
|
/**
|
|
6
45
|
* Format a list of items for display
|
|
7
46
|
* @param {Array} items - Array of strings
|
|
@@ -43,6 +82,8 @@ export function compareVersions(v1, v2) {
|
|
|
43
82
|
}
|
|
44
83
|
|
|
45
84
|
export default {
|
|
85
|
+
readSkillDescription,
|
|
86
|
+
shortenSkillDescription,
|
|
46
87
|
formatList,
|
|
47
88
|
parseVersion,
|
|
48
89
|
compareVersions,
|
package/package.json
CHANGED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: audit-codebase
|
|
3
|
+
description: 'Audit a whole codebase, app, backend, or API as one unit and prepare or (once approved) implement an evidence-based correction plan, preserving legitimate use cases and avoiding disproportionate security controls. One sweep across security, production-readiness, architecture, dependencies, compatibility, performance, maintainability, and tests, in any language. Use even when the user just says "audit this project", "go through the whole app end to end", "is it safe to ship to prod / run on the public internet?", "do a real security review of my API", "find real problems before we launch", "what''s actually broken vs. just ugly?", "audit it and implement the fixes", or "implement the audit plan / decision matrix we already approved". Do NOT use for narrow work — a single bug, one regex or snippet, a small PR/diff, or tests for one module — nor for non-code audits like cloud bills or resumes.'
|
|
4
|
+
allowed-tools: Read, Grep, Glob, Bash, Edit, Write, AskUserQuestion
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Audit Codebase
|
|
8
|
+
|
|
9
|
+
Act as a senior software, security, and architecture auditor. Review the whole project end to end before drawing any conclusions.
|
|
10
|
+
|
|
11
|
+
The work has two stages separated by an explicit user authorization. The separation exists because the value of an audit depends on a neutral diagnosis: if you edit while you audit, you contaminate the evidence and take away the user's decision about what to change. The first deliverable is always diagnosis and plan; code is only touched after the user approves the decision matrix.
|
|
12
|
+
|
|
13
|
+
Respond in the user's language. This skill is written in English for portability, but the audit report should match whatever language the user is writing in.
|
|
14
|
+
|
|
15
|
+
## How the user invokes this
|
|
16
|
+
|
|
17
|
+
- **Audit only** ("audit this", "is it production-ready?", "security review") — run stage 1 and stop at the decision matrix + plan. Don't touch code.
|
|
18
|
+
- **Audit and fix** ("audit and implement the fixes", "find problems and fix them", "clean this up before we ship") — run stage 1, then present the decision matrix and stop for a single go/no-go before stage 2. Even when the user asks up front to fix everything, show the matrix first: it takes seconds to approve and it's the checkpoint that lets you change code on their own repo without guessing which product tradeoffs are acceptable. Once they approve (a plain "yes, go" is enough), implement the full matrix.
|
|
19
|
+
- **Implement a prior plan** ("implement the audit plan we approved") — skip discovery, go straight to stage 2 against the approved matrix.
|
|
20
|
+
|
|
21
|
+
If the user explicitly says to skip the checkpoint ("just fix everything, don't ask"), honor it — but still surface any finding whose fix would break a documented use case before applying that specific change, because that's a product decision you can't infer.
|
|
22
|
+
|
|
23
|
+
## Before you start
|
|
24
|
+
|
|
25
|
+
Read `references/comprehensive-audit.md`. It holds the mandatory principles, the full technical scope (24 areas), the phased method, the severity classification, and the recommendation rules. Don't audit from memory: the file exists so the review is systematic and doesn't depend on which areas you happen to recall in the moment.
|
|
26
|
+
|
|
27
|
+
Before writing any deliverable (diagnosis, decision matrix, or implementation report), read `references/report-format.md` and use those exact structures. A stable format lets audits be compared across projects and guarantees that no finding is left without a disposition.
|
|
28
|
+
|
|
29
|
+
## Stage 1 — Audit (no modifications)
|
|
30
|
+
|
|
31
|
+
Do not modify the project during this stage. This covers the whole project tree, not just source files: don't leave build output, compiled bytecode (`__pycache__`, `.pyc`), caches, lockfiles, `node_modules`, coverage reports, or any generated artifact behind. Verification tools often write into the tree as a side effect — `python -m py_compile` drops `__pycache__`, test runners and bundlers create caches, `npm install` writes `node_modules`. When you need to run such a tool, run it so its output lands outside the project (e.g. set `PYTHONPYCACHEPREFIX` to a temp dir, use a flag that disables writes, or copy the file elsewhere first); if you can't, skip it and record the check as unverified with the reason. A clean read-only pass is what lets the user trust that the diagnosis changed nothing.
|
|
32
|
+
|
|
33
|
+
If a critical finding needs immediate attention, report it first, but continue the full audit — don't stop at the first serious problem.
|
|
34
|
+
|
|
35
|
+
1. **Discovery** — Identify the stack and real versions. Inventory entrypoints, routes, models, migrations, services, and commands. Read README, CHANGELOG, configuration, tests, and examples to understand the project's intent.
|
|
36
|
+
2. **Existing use cases** — Build the list of real capabilities and actors (anonymous visitor, authenticated user, resource owner, admin, API client, internal processes) **before** recommending any change. This list is the yardstick every restrictive recommendation is measured against.
|
|
37
|
+
3. **Evidence** — Run available tests, lint, static analysis, and dependency audits. Verify authorization with at least two users/tenants when it applies. Confirm every claim before reporting it.
|
|
38
|
+
4. **Findings** — Document each problem with concrete evidence (file, line, configuration, reproducible behavior) and a status: **Confirmed**, **Conditional risk**, or **Unverified**.
|
|
39
|
+
5. **Decision matrix** — Every confirmed finding, medium and low included, gets an explicit proposed disposition. None is silently discarded.
|
|
40
|
+
6. **Correction plan** — Organized by implementation phase, with compatibility, tests, and rollback. Stop here and wait for the user's approval.
|
|
41
|
+
|
|
42
|
+
### Stage 1 critical rules
|
|
43
|
+
|
|
44
|
+
- **Evidence before patterns.** Don't flag something as vulnerable just because it resembles a known pattern. A finding without evidence is noise that erodes trust in the real findings.
|
|
45
|
+
- **Proportional security, not absolute.** Before recommending mandatory auth, allowlists, or route blocking, identify which legitimate use cases would break and evaluate the least-restrictive alternative (signatures, opaque tokens, ownership, rate limiting, expiration).
|
|
46
|
+
- **Severity is not scope.** Severity signals risk; the disposition (fix now, later phase, accept, won't fix) is a separate decision that every finding must receive explicitly.
|
|
47
|
+
- **Don't turn product decisions into technical assumptions.** Ask only what cannot be inferred from the repository.
|
|
48
|
+
|
|
49
|
+
## Stage 2 — Authorized implementation
|
|
50
|
+
|
|
51
|
+
Start only when the user approves the decision matrix.
|
|
52
|
+
|
|
53
|
+
1. Implement the **full** approved matrix, not just the critical and high findings.
|
|
54
|
+
2. If a change contradicts an existing use case discovered in stage 1, stop and present it before applying the restriction.
|
|
55
|
+
3. Keep or add regression tests for every affected behavior.
|
|
56
|
+
4. Update configuration, documentation, examples, and CHANGELOG when a public contract changes.
|
|
57
|
+
5. Re-run all verifications and review the full diff: every changed line must trace back to an approved finding. No cosmetic cleanup, no unrelated features.
|
|
58
|
+
6. Explicitly list any finding you did not implement and the approved reason it was left pending.
|
|
59
|
+
|
|
60
|
+
## Closing condition
|
|
61
|
+
|
|
62
|
+
The audit or implementation is complete only when:
|
|
63
|
+
|
|
64
|
+
1. Every finding has evidence and a status.
|
|
65
|
+
2. Every confirmed finding has an explicit disposition.
|
|
66
|
+
3. Existing capabilities and legitimate use cases are documented.
|
|
67
|
+
4. The plan (or final report) includes compatibility, tests, and rollback.
|
|
68
|
+
5. In stage 1, no code was modified.
|
|
69
|
+
|
|
70
|
+
Do not declare the work "complete" if any finding is left without an explicit disposition.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "Audit Codebase"
|
|
3
|
+
short_description: "End-to-end technical audit and evidence-based correction plan"
|
|
4
|
+
default_prompt: "Run a comprehensive technical audit of this project: architecture, security, compatibility, performance, maintainability, and tests. Deliver a diagnosis, decision matrix, and correction plan without modifying code."
|