@maccesar/aiskills 1.11.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.
Files changed (60) hide show
  1. package/README.md +43 -8
  2. package/lib/cleanup.js +42 -0
  3. package/lib/commands/skills.js +110 -8
  4. package/lib/config.js +17 -12
  5. package/lib/installer.js +5 -3
  6. package/lib/platform.js +1 -1
  7. package/lib/symlink.js +45 -3
  8. package/lib/utils.js +41 -0
  9. package/package.json +1 -1
  10. package/skills/audit-codebase/SKILL.md +70 -0
  11. package/skills/audit-codebase/agents/openai.yaml +4 -0
  12. package/skills/audit-codebase/references/comprehensive-audit.md +220 -0
  13. package/skills/audit-codebase/references/report-format.md +119 -0
  14. package/skills/humaniza/SKILL.md +55 -4
  15. package/skills/humaniza/references/ai-patterns-es.md +40 -0
  16. package/skills/humaniza/references/checklist.md +9 -0
  17. package/skills/humaniza/references/examples.md +16 -0
  18. package/skills/humaniza/references/lexicon-es-mx.md +18 -0
  19. package/skills/humaniza/references/structures-es.md +132 -0
  20. package/skills/humaniza/scripts/check_ai_patterns.py +216 -0
  21. package/skills/refactoring-ui/SKILL.md +65 -29
  22. package/skills/refactoring-ui/references/05-motion.md +124 -0
  23. package/skills/refactoring-ui/references/06-dark-mode.md +117 -0
  24. package/skills/refactoring-ui/references/07-component-patterns.md +181 -0
  25. package/skills/stitch-showcase/SKILL.md +24 -232
  26. package/skills/stitch-showcase/references/07-theme-system.md +12 -0
  27. package/skills/stitch-showcase/references/08-type-detection.md +9 -1
  28. package/skills/stitch-showcase/references/10-component-standardization.md +25 -0
  29. package/skills/stitch-showcase/references/12-video-embedding.md +113 -0
  30. package/skills/stitch-showcase/references/13-language-detection.md +82 -0
  31. package/skills/stitch-showcase/references/14-troubleshooting-known-issues.md +122 -0
  32. package/skills/stitch-showcase/references/15-build-flags.md +71 -0
  33. package/skills/stitch-showcase/references/16-design-md-format.md +107 -0
  34. package/skills/stitch-showcase/references/index.html +25 -19
  35. package/skills/stitch-showcase/references/viewer.html +24 -12
  36. package/skills/stitch-showcase/scripts/__pycache__/build_showcase.cpython-314.pyc +0 -0
  37. package/skills/stitch-showcase/scripts/__pycache__/component_utils.cpython-314.pyc +0 -0
  38. package/skills/stitch-showcase/scripts/__pycache__/detect_components.cpython-314.pyc +0 -0
  39. package/skills/stitch-showcase/scripts/__pycache__/extract_catalog.cpython-314.pyc +0 -0
  40. package/skills/stitch-showcase/scripts/__pycache__/extract_text.cpython-314.pyc +0 -0
  41. package/skills/stitch-showcase/scripts/__pycache__/extract_zips.cpython-314.pyc +0 -0
  42. package/skills/stitch-showcase/scripts/__pycache__/parse_design_md.cpython-314.pyc +0 -0
  43. package/skills/stitch-showcase/scripts/__pycache__/slug_demangle.cpython-314.pyc +0 -0
  44. package/skills/stitch-showcase/scripts/build_showcase.py +150 -10
  45. package/skills/stitch-showcase/scripts/parse_design_md.py +145 -12
  46. package/skills/stitch-showcase/scripts/slug_demangle.py +209 -0
  47. package/skills/vscode-extension-dev/SKILL.md +90 -41
  48. package/skills/vscode-extension-dev/references/api-additional.md +168 -0
  49. package/skills/vscode-extension-dev/references/api-progress.md +55 -0
  50. package/skills/vscode-extension-dev/references/api-quickpick.md +75 -0
  51. package/skills/vscode-extension-dev/references/api-secretstorage.md +57 -0
  52. package/skills/vscode-extension-dev/references/api-statusbar.md +38 -0
  53. package/skills/vscode-extension-dev/references/api-treeview.md +78 -0
  54. package/skills/vscode-extension-dev/references/api-webview.md +149 -0
  55. package/skills/vscode-extension-dev/references/architecture.md +67 -0
  56. package/skills/vscode-extension-dev/references/debugger.md +179 -0
  57. package/skills/vscode-extension-dev/references/lsp.md +175 -0
  58. package/skills/vscode-extension-dev/references/notebooks.md +208 -0
  59. package/skills/vscode-extension-dev/references/testing.md +208 -0
  60. 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/`, `~/.gemini/skills/`, or `~/.codex/skills/`
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,8 +58,8 @@ 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 | `~/.gemini/skills/` |
62
- | [Codex CLI](https://developers.openai.com/codex/cli/) | Supported | `~/.codex/skills/` |
61
+ | [Gemini CLI](https://github.com/google-gemini/gemini-cli) | Supported | `~/.agents/skills/` (auto-discovered) |
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.
65
65
 
@@ -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 | 4 files |
73
- | humaniza | Writing (es) | Curated Spanish/es-MX style rules | 6 files |
74
- | vscode-extension-dev | VS Code | VS Code Extension API docs | 4 files |
75
- | stitch-showcase | Design Tools | Google Stitch export workflow | 14 files |
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
@@ -9,6 +9,8 @@ import {
9
9
  LEGACY_COMMANDS,
10
10
  getAgentsSkillsDir,
11
11
  getClaudeCommandsDir,
12
+ getCodexSkillsDir,
13
+ getGeminiSkillsDir,
12
14
  } from './config.js';
13
15
  import { detectPlatforms } from './platform.js';
14
16
  import { existsSync, lstatSync, rmSync } from 'fs';
@@ -53,6 +55,37 @@ export function removeLegacySkillSymlinks(platformSkillsDir) {
53
55
  return removeSkillSymlinks(platformSkillsDir, { legacyOnly: true });
54
56
  }
55
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
+
72
+ // Codex reads skills from the canonical ~/.agents/skills/, so any aiskills-managed
73
+ // symlinks at ~/.codex/skills/ from earlier versions are redundant and should be
74
+ // cleaned up. Targets both active and legacy skill names.
75
+ export function removeCodexRedundantSymlinks(baseDir) {
76
+ const codexSkillsDir = getCodexSkillsDir(baseDir);
77
+ return removeSkillSymlinks(codexSkillsDir);
78
+ }
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
+
56
89
  export function removeSkills(baseDir, options = {}) {
57
90
  const skillsDir = getAgentsSkillsDir(baseDir);
58
91
  const skillList = getSkillList(options);
@@ -74,6 +107,9 @@ export function cleanupLegacyArtifacts(baseDir) {
74
107
  removeLegacySkillSymlinks(platform.skillsDir);
75
108
  }
76
109
 
110
+ removeCodexRedundantSymlinks(baseDir);
111
+ removeGeminiRedundantSymlinks(baseDir);
112
+
77
113
  if (baseDir) {
78
114
  removeSkills(undefined, { legacyOnly: true });
79
115
  removeCommands(undefined, { legacyOnly: true });
@@ -81,6 +117,8 @@ export function cleanupLegacyArtifacts(baseDir) {
81
117
  for (const platform of globalPlatforms) {
82
118
  removeLegacySkillSymlinks(platform.skillsDir);
83
119
  }
120
+ removeCodexRedundantSymlinks(undefined);
121
+ removeGeminiRedundantSymlinks(undefined);
84
122
  }
85
123
  }
86
124
 
@@ -89,6 +127,10 @@ export default {
89
127
  getCommandList,
90
128
  removeSkillSymlinks,
91
129
  removeLegacySkillSymlinks,
130
+ removeCodexRedundantSymlinks,
131
+ removeGeminiRedundantSymlinks,
132
+ removeUnselectedSkills,
133
+ removeUnselectedSymlinks,
92
134
  removeSkills,
93
135
  removeCommands,
94
136
  cleanupLegacyArtifacts,
@@ -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,8 +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 one of: Claude Code, Gemini CLI, or Codex CLI');
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.)');
90
111
  console.log('Or use: aiskills install --local');
91
112
  process.exit(1);
92
113
  }
@@ -172,14 +193,73 @@ export async function skillsCommand(options) {
172
193
  }
173
194
  }
174
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
+
175
242
  const selectedPlatformNames = new Set(selectedPlatforms.map((platform) => platform.name));
176
243
 
177
244
  try {
178
245
  if (!removeOnly) {
179
246
  // Install skills
180
247
  spinner.start('Installing skills...');
181
- const skillsResult = await installSkills(repoDir, baseDir);
182
- spinner.succeed(`${SKILLS.length} skill${SKILLS.length !== 1 ? 's' : ''} installed`);
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);
183
263
 
184
264
  // Install or remove slash commands based on Claude Code selection
185
265
  if (selectedPlatformNames.has('claude')) {
@@ -202,17 +282,20 @@ export async function skillsCommand(options) {
202
282
  // Create symlinks for selected platforms
203
283
  for (const platform of selectedPlatforms) {
204
284
  removeLegacySkillSymlinks(platform.skillsDir);
285
+ if (skillsToInstall.length !== SKILLS.length) {
286
+ removeUnselectedSymlinks(platform.skillsDir, skillsToInstall);
287
+ }
205
288
  spinner.start(`Linking ${platform.displayName}...`);
206
289
  const symlinkResult = await createSkillSymlinks(
207
290
  platform.skillsDir,
208
- SKILLS,
291
+ skillsToInstall,
209
292
  baseDir
210
293
  );
211
- if (symlinkResult.linked.length === SKILLS.length) {
294
+ if (symlinkResult.linked.length === skillsToInstall.length) {
212
295
  spinner.succeed(`${platform.displayName}: Skills linked`);
213
296
  } else {
214
297
  spinner.warn(
215
- `${platform.displayName}: ${symlinkResult.linked.length}/${SKILLS.length} skills linked`
298
+ `${platform.displayName}: ${symlinkResult.linked.length}/${skillsToInstall.length} skills linked`
216
299
  );
217
300
  }
218
301
  }
@@ -268,9 +351,28 @@ export async function skillsCommand(options) {
268
351
  }
269
352
  }
270
353
 
271
- // 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.
272
356
  console.log('');
273
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
+ }
274
376
  console.log('');
275
377
 
276
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,18 +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
- {
72
- name: 'codex',
73
- displayName: 'Codex CLI',
74
- skillsDir: getCodexSkillsDir(baseDir),
75
- configDir: path.join(baseDir, '.codex'),
76
- },
77
82
  ];
78
83
 
79
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 all skills to the agents skills directory
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 SKILLS) {
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/platform.js CHANGED
@@ -26,7 +26,7 @@ export function detectPlatforms(baseDir) {
26
26
 
27
27
  /**
28
28
  * Get platform by name
29
- * @param {string} name - Platform name (claude, gemini, codex)
29
+ * @param {string} name - Platform name (claude, gemini)
30
30
  * @param {string} baseDir - Optional base directory
31
31
  * @returns {Object|null} Platform object or null
32
32
  */
package/lib/symlink.js CHANGED
@@ -69,19 +69,49 @@ async function removePath(path) {
69
69
  }
70
70
 
71
71
  /**
72
- * Create symlinks for all skills to a platform directory
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 success/failure counts
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maccesar/aiskills",
3
- "version": "1.11.0",
3
+ "version": "1.15.0",
4
4
  "description": "AI coding assistant skills for Claude Code, Gemini CLI, and Codex CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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."