@vibe-agent-toolkit/cli 0.1.9 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/vat +174 -0
- package/dist/bin.js +2 -0
- package/dist/bin.js.map +1 -1
- package/dist/commands/audit/hierarchical-output.d.ts.map +1 -1
- package/dist/commands/audit/hierarchical-output.js +74 -13
- package/dist/commands/audit/hierarchical-output.js.map +1 -1
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +36 -32
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/skills/build.d.ts +13 -0
- package/dist/commands/skills/build.d.ts.map +1 -0
- package/dist/commands/skills/build.js +205 -0
- package/dist/commands/skills/build.js.map +1 -0
- package/dist/commands/skills/command-helpers.d.ts +30 -0
- package/dist/commands/skills/command-helpers.d.ts.map +1 -0
- package/dist/commands/skills/command-helpers.js +54 -0
- package/dist/commands/skills/command-helpers.js.map +1 -0
- package/dist/commands/skills/index.d.ts +8 -0
- package/dist/commands/skills/index.d.ts.map +1 -0
- package/dist/commands/skills/index.js +96 -0
- package/dist/commands/skills/index.js.map +1 -0
- package/dist/commands/skills/install-helpers.d.ts +45 -0
- package/dist/commands/skills/install-helpers.d.ts.map +1 -0
- package/dist/commands/skills/install-helpers.js +120 -0
- package/dist/commands/skills/install-helpers.js.map +1 -0
- package/dist/commands/skills/install.d.ts +20 -0
- package/dist/commands/skills/install.d.ts.map +1 -0
- package/dist/commands/skills/install.js +287 -0
- package/dist/commands/skills/install.js.map +1 -0
- package/dist/commands/skills/list.d.ts +12 -0
- package/dist/commands/skills/list.d.ts.map +1 -0
- package/dist/commands/skills/list.js +124 -0
- package/dist/commands/skills/list.js.map +1 -0
- package/dist/commands/skills/package.d.ts +16 -0
- package/dist/commands/skills/package.d.ts.map +1 -0
- package/dist/commands/skills/package.js +293 -0
- package/dist/commands/skills/package.js.map +1 -0
- package/dist/commands/skills/validate-command.d.ts +6 -0
- package/dist/commands/skills/validate-command.d.ts.map +1 -0
- package/dist/commands/skills/validate-command.js +76 -0
- package/dist/commands/skills/validate-command.js.map +1 -0
- package/dist/commands/skills/validate.d.ts +24 -0
- package/dist/commands/skills/validate.d.ts.map +1 -0
- package/dist/commands/skills/validate.js +264 -0
- package/dist/commands/skills/validate.js.map +1 -0
- package/dist/utils/claude-paths.d.ts +32 -0
- package/dist/utils/claude-paths.d.ts.map +1 -0
- package/dist/utils/claude-paths.js +34 -0
- package/dist/utils/claude-paths.js.map +1 -0
- package/dist/utils/skill-discovery.d.ts +49 -0
- package/dist/utils/skill-discovery.d.ts.map +1 -0
- package/dist/utils/skill-discovery.js +73 -0
- package/dist/utils/skill-discovery.js.map +1 -0
- package/dist/utils/user-context-scanner.d.ts +31 -0
- package/dist/utils/user-context-scanner.d.ts.map +1 -0
- package/dist/utils/user-context-scanner.js +60 -0
- package/dist/utils/user-context-scanner.js.map +1 -0
- package/docs/audit.md +1 -0
- package/docs/skills.md +561 -0
- package/package.json +18 -12
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills validate command - unified validation for SKILL.md files
|
|
3
|
+
*
|
|
4
|
+
* Combines resource validation (markdown, links, frontmatter) with
|
|
5
|
+
* skill-specific validation (reserved words, XML tags, console compatibility).
|
|
6
|
+
*
|
|
7
|
+
* Supports three modes:
|
|
8
|
+
* 1. Project context (default): Validate project skills with strict filename validation
|
|
9
|
+
* 2. User context (--user flag): Validate ~/.claude skills with permissive validation
|
|
10
|
+
* 3. Path context (explicit path): Validate skills at specific path
|
|
11
|
+
*/
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
import { validateSkill } from '@vibe-agent-toolkit/agent-skills';
|
|
14
|
+
import { scan } from '@vibe-agent-toolkit/discovery';
|
|
15
|
+
import { ResourceRegistry } from '@vibe-agent-toolkit/resources';
|
|
16
|
+
import { GitTracker } from '@vibe-agent-toolkit/utils';
|
|
17
|
+
import * as yaml from 'js-yaml';
|
|
18
|
+
import { loadConfig } from '../../utils/config-loader.js';
|
|
19
|
+
import { formatDurationSecs } from '../../utils/duration.js';
|
|
20
|
+
import { createLogger } from '../../utils/logger.js';
|
|
21
|
+
import { discoverSkills, validateSkillFilename } from '../../utils/skill-discovery.js';
|
|
22
|
+
import { scanUserContext } from '../../utils/user-context-scanner.js';
|
|
23
|
+
import { handleCommandError } from './command-helpers.js';
|
|
24
|
+
/**
|
|
25
|
+
* Validate a SKILL.md file using resource validation (links, frontmatter)
|
|
26
|
+
*/
|
|
27
|
+
async function validateSkillAsResource(skillPath, rootDir, gitTracker) {
|
|
28
|
+
const registry = new ResourceRegistry({
|
|
29
|
+
rootDir,
|
|
30
|
+
...(gitTracker !== undefined && { gitTracker })
|
|
31
|
+
});
|
|
32
|
+
// Add the entire resources directory to ensure all linked files are available for validation
|
|
33
|
+
// This is necessary because SKILL.md links to agent markdown files in ../agents/
|
|
34
|
+
const resourcesDir = path.resolve(path.dirname(skillPath), '..');
|
|
35
|
+
await registry.crawl({ baseDir: resourcesDir, include: ['**/*.md'] });
|
|
36
|
+
// Validate (no frontmatter schema by default)
|
|
37
|
+
const result = await registry.validate();
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Build issues array from validation results
|
|
42
|
+
*/
|
|
43
|
+
function buildIssuesArray(skillPath, filenameValidation, strictMode, resourceErrors, skillErrors, skillWarnings) {
|
|
44
|
+
const issues = [];
|
|
45
|
+
// Add filename validation issues
|
|
46
|
+
if (!filenameValidation.valid && filenameValidation.message) {
|
|
47
|
+
issues.push({
|
|
48
|
+
source: 'filename',
|
|
49
|
+
severity: strictMode ? 'error' : 'warning',
|
|
50
|
+
code: 'non-standard-filename',
|
|
51
|
+
message: filenameValidation.message,
|
|
52
|
+
location: skillPath,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
// Add resource issues
|
|
56
|
+
for (const issue of resourceErrors) {
|
|
57
|
+
const location = issue.line === undefined ? skillPath : `${skillPath}:${issue.line}`;
|
|
58
|
+
issues.push({
|
|
59
|
+
source: 'resource',
|
|
60
|
+
severity: 'error',
|
|
61
|
+
code: issue.type,
|
|
62
|
+
message: issue.message,
|
|
63
|
+
location,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
// Add skill issues
|
|
67
|
+
for (const issue of [...skillErrors, ...skillWarnings]) {
|
|
68
|
+
issues.push({
|
|
69
|
+
source: 'skill',
|
|
70
|
+
severity: issue.severity,
|
|
71
|
+
code: issue.code,
|
|
72
|
+
message: issue.message,
|
|
73
|
+
location: issue.location,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return issues;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Merge resource, skill, and filename validation results
|
|
80
|
+
*/
|
|
81
|
+
function mergeValidationResults(skillPath, resourceResult, skillResult, filenameValidation, strictMode) {
|
|
82
|
+
const skillName = skillResult.metadata?.name ?? path.basename(path.dirname(skillPath));
|
|
83
|
+
// Extract resource errors (exclude external_url which are informational)
|
|
84
|
+
const resourceErrors = resourceResult.issues.filter(i => i.type !== 'external_url');
|
|
85
|
+
const resourceErrorCount = resourceErrors.length;
|
|
86
|
+
// Extract skill errors and warnings
|
|
87
|
+
const skillErrors = skillResult.issues.filter(i => i.severity === 'error');
|
|
88
|
+
const skillWarnings = skillResult.issues.filter(i => i.severity === 'warning');
|
|
89
|
+
const skillErrorCount = skillErrors.length;
|
|
90
|
+
const skillWarningCount = skillWarnings.length;
|
|
91
|
+
// Count filename issues
|
|
92
|
+
const filenameErrorCount = !filenameValidation.valid && strictMode ? 1 : 0;
|
|
93
|
+
const filenameWarningCount = !filenameValidation.valid && !strictMode ? 1 : 0;
|
|
94
|
+
const totalErrors = resourceErrorCount + skillErrorCount + filenameErrorCount;
|
|
95
|
+
const totalWarnings = skillWarningCount + filenameWarningCount;
|
|
96
|
+
// Build unified issues array
|
|
97
|
+
const issues = buildIssuesArray(skillPath, filenameValidation, strictMode, resourceErrors, skillErrors, skillWarnings);
|
|
98
|
+
const baseResult = {
|
|
99
|
+
skill: skillName,
|
|
100
|
+
path: skillPath,
|
|
101
|
+
status: totalErrors > 0 ? 'error' : 'success',
|
|
102
|
+
resourceValidation: {
|
|
103
|
+
status: resourceErrorCount > 0 ? 'error' : 'success',
|
|
104
|
+
linksChecked: resourceResult.linksByType ? Object.values(resourceResult.linksByType).reduce((sum, count) => sum + count, 0) : 0,
|
|
105
|
+
errors: resourceErrorCount,
|
|
106
|
+
},
|
|
107
|
+
skillValidation: {
|
|
108
|
+
status: (skillErrorCount + filenameErrorCount) > 0 ? 'error' : 'success',
|
|
109
|
+
errors: skillErrorCount + filenameErrorCount,
|
|
110
|
+
warnings: skillWarningCount + filenameWarningCount,
|
|
111
|
+
},
|
|
112
|
+
totalErrors,
|
|
113
|
+
totalWarnings,
|
|
114
|
+
};
|
|
115
|
+
// Only add issues property if there are issues
|
|
116
|
+
if (issues.length > 0) {
|
|
117
|
+
return { ...baseResult, issues };
|
|
118
|
+
}
|
|
119
|
+
return baseResult;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Format skill status for console output
|
|
123
|
+
*/
|
|
124
|
+
function formatSkillStatus(result) {
|
|
125
|
+
if (result.status === 'error') {
|
|
126
|
+
const errorText = `${result.totalErrors} error${result.totalErrors === 1 ? '' : 's'}`;
|
|
127
|
+
const warningPlural = result.totalWarnings === 1 ? '' : 's';
|
|
128
|
+
const warningText = result.totalWarnings > 0
|
|
129
|
+
? `, ${result.totalWarnings} warning${warningPlural}`
|
|
130
|
+
: '';
|
|
131
|
+
return ` ❌ ${result.skill} (${errorText}${warningText})`;
|
|
132
|
+
}
|
|
133
|
+
if (result.totalWarnings > 0) {
|
|
134
|
+
const warningPlural = result.totalWarnings === 1 ? '' : 's';
|
|
135
|
+
return ` ⚠️ ${result.skill} (${result.totalWarnings} warning${warningPlural})`;
|
|
136
|
+
}
|
|
137
|
+
return ` ✅ ${result.skill}`;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Output detailed error for a single issue
|
|
141
|
+
*/
|
|
142
|
+
function outputDetailedIssue(issue) {
|
|
143
|
+
console.error(` [${issue.source}] ${issue.severity}: ${issue.message} (${issue.code})`);
|
|
144
|
+
if (issue.location !== undefined) {
|
|
145
|
+
console.error(` Location: ${issue.location}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Output unified validation report
|
|
150
|
+
*/
|
|
151
|
+
function outputUnifiedReport(results, duration) {
|
|
152
|
+
const output = {
|
|
153
|
+
status: results.some(r => r.status === 'error') ? 'error' : 'success',
|
|
154
|
+
skillsValidated: results.length,
|
|
155
|
+
results,
|
|
156
|
+
durationSecs: formatDurationSecs(duration),
|
|
157
|
+
};
|
|
158
|
+
// Output YAML to stdout (for programmatic parsing)
|
|
159
|
+
// js-yaml has truncation issues with very large objects (>80 results)
|
|
160
|
+
// Use JSON for large outputs to avoid truncation
|
|
161
|
+
if (results.length > 80) {
|
|
162
|
+
console.log(JSON.stringify(output, null, 2));
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
console.log(yaml.dump(output, { indent: 2, lineWidth: -1, noRefs: true }));
|
|
166
|
+
}
|
|
167
|
+
// If there are errors, also write detailed errors to stderr
|
|
168
|
+
const failedSkills = results.filter(r => r.status === 'error');
|
|
169
|
+
if (failedSkills.length === 0) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
console.error('\n❌ Validation errors:\n');
|
|
173
|
+
for (const result of failedSkills) {
|
|
174
|
+
console.error(` ${result.path}:`);
|
|
175
|
+
if (result.issues) {
|
|
176
|
+
for (const issue of result.issues) {
|
|
177
|
+
outputDetailedIssue(issue);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
console.error('');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Skills validate command implementation
|
|
185
|
+
*/
|
|
186
|
+
export async function validateCommand(pathArg, options) {
|
|
187
|
+
const logger = createLogger(options.debug ? { debug: true } : {});
|
|
188
|
+
const startTime = Date.now();
|
|
189
|
+
try {
|
|
190
|
+
// Step 1: Determine context and discover skills
|
|
191
|
+
let skillPaths;
|
|
192
|
+
let strictMode;
|
|
193
|
+
let rootDir;
|
|
194
|
+
if (options.user) {
|
|
195
|
+
// User context: scan ~/.claude
|
|
196
|
+
logger.info('🔍 Validating user-installed skills in ~/.claude');
|
|
197
|
+
const { plugins, skills } = await scanUserContext();
|
|
198
|
+
const allResources = [...plugins, ...skills];
|
|
199
|
+
const discoveredSkills = discoverSkills(allResources);
|
|
200
|
+
skillPaths = discoveredSkills.map(s => s.path);
|
|
201
|
+
strictMode = false; // Permissive with warnings
|
|
202
|
+
rootDir = process.cwd(); // Use cwd for resource validation context
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
// Project context: use resources config
|
|
206
|
+
rootDir = pathArg ?? process.cwd();
|
|
207
|
+
logger.info(`🔍 Validating skills in: ${rootDir}`);
|
|
208
|
+
// Load project config
|
|
209
|
+
const config = loadConfig(rootDir);
|
|
210
|
+
// Use discovery package with config boundaries
|
|
211
|
+
const scanResult = await scan({
|
|
212
|
+
path: rootDir,
|
|
213
|
+
recursive: true,
|
|
214
|
+
include: config.resources?.include ?? ['**/*.md'],
|
|
215
|
+
exclude: config.resources?.exclude ?? [],
|
|
216
|
+
});
|
|
217
|
+
// Filter for skills (case-insensitive discovery)
|
|
218
|
+
const discoveredSkills = discoverSkills(scanResult.results);
|
|
219
|
+
skillPaths = discoveredSkills.map(s => s.path);
|
|
220
|
+
strictMode = true; // Strict errors
|
|
221
|
+
}
|
|
222
|
+
if (skillPaths.length === 0) {
|
|
223
|
+
logger.info(' No SKILL.md files found');
|
|
224
|
+
console.log(yaml.dump({
|
|
225
|
+
status: 'success',
|
|
226
|
+
skillsValidated: 0,
|
|
227
|
+
results: [],
|
|
228
|
+
durationSecs: formatDurationSecs(Date.now() - startTime),
|
|
229
|
+
}, { indent: 2, lineWidth: -1 }));
|
|
230
|
+
process.exit(0);
|
|
231
|
+
}
|
|
232
|
+
logger.info(` Found ${skillPaths.length} skill${skillPaths.length === 1 ? '' : 's'}\n`);
|
|
233
|
+
// Create GitTracker for efficient git-ignore checking across all skills
|
|
234
|
+
// This caches git operations and avoids spawning hundreds of git subprocesses
|
|
235
|
+
const gitTracker = new GitTracker(rootDir);
|
|
236
|
+
await gitTracker.initialize();
|
|
237
|
+
const results = [];
|
|
238
|
+
// Step 2: Validate each skill
|
|
239
|
+
for (const skillPath of skillPaths) {
|
|
240
|
+
// 2a: Validate filename
|
|
241
|
+
const filenameCheck = validateSkillFilename(skillPath);
|
|
242
|
+
// 2b: Resource validation (markdown, links)
|
|
243
|
+
const resourceResult = await validateSkillAsResource(skillPath, rootDir, gitTracker);
|
|
244
|
+
// 2c: Skill-specific validation (reserved words, etc.)
|
|
245
|
+
const skillResult = await validateSkill({ skillPath, rootDir });
|
|
246
|
+
// 2d: Merge results
|
|
247
|
+
const unified = mergeValidationResults(skillPath, resourceResult, skillResult, filenameCheck, strictMode);
|
|
248
|
+
results.push(unified);
|
|
249
|
+
// Show progress
|
|
250
|
+
logger.info(formatSkillStatus(unified));
|
|
251
|
+
}
|
|
252
|
+
// Step 3: Output unified report
|
|
253
|
+
const duration = Date.now() - startTime;
|
|
254
|
+
logger.info('');
|
|
255
|
+
outputUnifiedReport(results, duration);
|
|
256
|
+
// Step 4: Exit with appropriate code
|
|
257
|
+
const hasErrors = results.some(r => r.totalErrors > 0);
|
|
258
|
+
process.exit(hasErrors ? 1 : 0);
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
handleCommandError(error, logger, startTime, 'SkillsValidate');
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/commands/skills/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,aAAa,EAAyB,MAAM,kCAAkC,CAAC;AACxF,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAqD,MAAM,+BAA+B,CAAC;AACpH,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAEhC,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvF,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AAEtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAkD1D;;GAEG;AACH,KAAK,UAAU,uBAAuB,CACpC,SAAiB,EACjB,OAAe,EACf,UAAuB;IAEvB,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC;QACpC,OAAO;QACP,GAAG,CAAC,UAAU,KAAK,SAAS,IAAI,EAAE,UAAU,EAAE,CAAC;KAChD,CAAC,CAAC;IAEH,6FAA6F;IAC7F,iFAAiF;IACjF,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC;IACjE,MAAM,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAEtE,8CAA8C;IAC9C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAC;IAEzC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CACvB,SAAiB,EACjB,kBAAwD,EACxD,UAAmB,EACnB,cAAkD,EAClD,WAAuC,EACvC,aAAyC;IAQzC,MAAM,MAAM,GAMP,EAAE,CAAC;IAER,iCAAiC;IACjC,IAAI,CAAC,kBAAkB,CAAC,KAAK,IAAI,kBAAkB,CAAC,OAAO,EAAE,CAAC;QAC5D,MAAM,CAAC,IAAI,CAAC;YACV,MAAM,EAAE,UAAU;YAClB,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;YAC1C,IAAI,EAAE,uBAAuB;YAC7B,OAAO,EAAE,kBAAkB,CAAC,OAAO;YACnC,QAAQ,EAAE,SAAS;SACpB,CAAC,CAAC;IACL,CAAC;IAED,sBAAsB;IACtB,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACrF,MAAM,CAAC,IAAI,CAAC;YACV,MAAM,EAAE,UAAU;YAClB,QAAQ,EAAE,OAAO;YACjB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,QAAQ;SACT,CAAC,CAAC;IACL,CAAC;IAED,mBAAmB;IACnB,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,WAAW,EAAE,GAAG,aAAa,CAAC,EAAE,CAAC;QACvD,MAAM,CAAC,IAAI,CAAC;YACV,MAAM,EAAE,OAAO;YACf,QAAQ,EAAE,KAAK,CAAC,QAAyB;YACzC,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;SACzB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,sBAAsB,CAC7B,SAAiB,EACjB,cAAwC,EACxC,WAA6B,EAC7B,kBAAwD,EACxD,UAAmB;IAEnB,MAAM,SAAS,GAAG,WAAW,CAAC,QAAQ,EAAE,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;IAEvF,yEAAyE;IACzE,MAAM,cAAc,GAAG,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,CAAC;IACpF,MAAM,kBAAkB,GAAG,cAAc,CAAC,MAAM,CAAC;IAEjD,oCAAoC;IACpC,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IAC3E,MAAM,aAAa,GAAG,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;IAC/E,MAAM,eAAe,GAAG,WAAW,CAAC,MAAM,CAAC;IAC3C,MAAM,iBAAiB,GAAG,aAAa,CAAC,MAAM,CAAC;IAE/C,wBAAwB;IACxB,MAAM,kBAAkB,GAAG,CAAC,kBAAkB,CAAC,KAAK,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3E,MAAM,oBAAoB,GAAG,CAAC,kBAAkB,CAAC,KAAK,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9E,MAAM,WAAW,GAAG,kBAAkB,GAAG,eAAe,GAAG,kBAAkB,CAAC;IAC9E,MAAM,aAAa,GAAG,iBAAiB,GAAG,oBAAoB,CAAC;IAE/D,6BAA6B;IAC7B,MAAM,MAAM,GAAG,gBAAgB,CAC7B,SAAS,EACT,kBAAkB,EAClB,UAAU,EACV,cAAc,EACd,WAAW,EACX,aAAa,CACd,CAAC;IAEF,MAAM,UAAU,GAAiC;QAC/C,KAAK,EAAE,SAAS;QAChB,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;QAC7C,kBAAkB,EAAE;YAClB,MAAM,EAAE,kBAAkB,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;YACpD,YAAY,EAAE,cAAc,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/H,MAAM,EAAE,kBAAkB;SAC3B;QACD,eAAe,EAAE;YACf,MAAM,EAAE,CAAC,eAAe,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;YACxE,MAAM,EAAE,eAAe,GAAG,kBAAkB;YAC5C,QAAQ,EAAE,iBAAiB,GAAG,oBAAoB;SACnD;QACD,WAAW;QACX,aAAa;KACd,CAAC;IAEF,+CAA+C;IAC/C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,GAAG,UAAU,EAAE,MAAM,EAAkC,CAAC;IACnE,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,MAAoC;IAC7D,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;QAC9B,MAAM,SAAS,GAAG,GAAG,MAAM,CAAC,WAAW,SAAS,MAAM,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QACtF,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAC5D,MAAM,WAAW,GAAG,MAAM,CAAC,aAAa,GAAG,CAAC;YAC1C,CAAC,CAAC,KAAK,MAAM,CAAC,aAAa,WAAW,aAAa,EAAE;YACrD,CAAC,CAAC,EAAE,CAAC;QACP,OAAO,QAAQ,MAAM,CAAC,KAAK,KAAK,SAAS,GAAG,WAAW,GAAG,CAAC;IAC7D,CAAC;IAED,IAAI,MAAM,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAC5D,OAAO,UAAU,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,aAAa,WAAW,aAAa,GAAG,CAAC;IACpF,CAAC;IAED,OAAO,QAAQ,MAAM,CAAC,KAAK,EAAE,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,SAAS,mBAAmB,CAAC,KAM5B;IACC,OAAO,CAAC,KAAK,CAAC,UAAU,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,OAAO,KAAK,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;IAC7F,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,CAAC,KAAK,CAAC,mBAAmB,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,mBAAmB,CAAC,OAAuC,EAAE,QAAgB;IACpF,MAAM,MAAM,GAA4B;QACtC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;QACrE,eAAe,EAAE,OAAO,CAAC,MAAM;QAC/B,OAAO;QACP,YAAY,EAAE,kBAAkB,CAAC,QAAQ,CAAC;KAC3C,CAAC;IAEF,mDAAmD;IACnD,sEAAsE;IACtE,iDAAiD;IACjD,IAAI,OAAO,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC7E,CAAC;IAED,4DAA4D;IAC5D,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC;IAC/D,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO;IACT,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC1C,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,MAAM,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;QACpC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAClC,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAUD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAA2B,EAC3B,OAAqC;IAErC,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAClE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,IAAI,CAAC;QACH,gDAAgD;QAChD,IAAI,UAAoB,CAAC;QACzB,IAAI,UAAmB,CAAC;QACxB,IAAI,OAAe,CAAC;QAEpB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,+BAA+B;YAC/B,MAAM,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;YAChE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,eAAe,EAAE,CAAC;YACpD,MAAM,YAAY,GAAG,CAAC,GAAG,OAAO,EAAE,GAAG,MAAM,CAAC,CAAC;YAC7C,MAAM,gBAAgB,GAAG,cAAc,CAAC,YAAY,CAAC,CAAC;YACtD,UAAU,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAC/C,UAAU,GAAG,KAAK,CAAC,CAAC,2BAA2B;YAC/C,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,0CAA0C;QACrE,CAAC;aAAM,CAAC;YACN,wCAAwC;YACxC,OAAO,GAAG,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,4BAA4B,OAAO,EAAE,CAAC,CAAC;YAEnD,sBAAsB;YACtB,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;YAEnC,+CAA+C;YAC/C,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC;gBAC5B,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,IAAI;gBACf,OAAO,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,IAAI,CAAC,SAAS,CAAC;gBACjD,OAAO,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,IAAI,EAAE;aACzC,CAAC,CAAC;YAEH,iDAAiD;YACjD,MAAM,gBAAgB,GAAG,cAAc,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YAC5D,UAAU,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAC/C,UAAU,GAAG,IAAI,CAAC,CAAC,gBAAgB;QACrC,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;gBACpB,MAAM,EAAE,SAAS;gBACjB,eAAe,EAAE,CAAC;gBAClB,OAAO,EAAE,EAAE;gBACX,YAAY,EAAE,kBAAkB,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;aACzD,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,YAAY,UAAU,CAAC,MAAM,SAAS,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAE1F,wEAAwE;QACxE,8EAA8E;QAC9E,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;QAC3C,MAAM,UAAU,CAAC,UAAU,EAAE,CAAC;QAE9B,MAAM,OAAO,GAAmC,EAAE,CAAC;QAEnD,8BAA8B;QAC9B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,wBAAwB;YACxB,MAAM,aAAa,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAC;YAEvD,4CAA4C;YAC5C,MAAM,cAAc,GAAG,MAAM,uBAAuB,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;YAErF,uDAAuD;YACvD,MAAM,WAAW,GAAG,MAAM,aAAa,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;YAEhE,oBAAoB;YACpB,MAAM,OAAO,GAAG,sBAAsB,CACpC,SAAS,EACT,cAAc,EACd,WAAW,EACX,aAAa,EACb,UAAU,CACX,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAEtB,gBAAgB;YAChB,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC;QAC1C,CAAC;QAED,gCAAgC;QAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChB,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAEvC,qCAAqC;QACrC,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;QACvD,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAElC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,gBAAgB,CAAC,CAAC;IACjE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude user directory paths
|
|
3
|
+
*
|
|
4
|
+
* Cross-platform utilities for accessing Claude's user-level directories.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Get user-level Claude directories
|
|
8
|
+
*
|
|
9
|
+
* Returns absolute paths to Claude user directories.
|
|
10
|
+
* Paths are constructed but not checked for existence (caller's responsibility).
|
|
11
|
+
*
|
|
12
|
+
* @returns Object containing absolute paths to Claude directories
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const { claudeDir, pluginsDir, skillsDir } = getClaudeUserPaths();
|
|
17
|
+
* // claudeDir: /Users/username/.claude
|
|
18
|
+
* // pluginsDir: /Users/username/.claude/plugins
|
|
19
|
+
* // skillsDir: /Users/username/.claude/skills
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function getClaudeUserPaths(): {
|
|
23
|
+
/** ~/.claude directory */
|
|
24
|
+
claudeDir: string;
|
|
25
|
+
/** ~/.claude/plugins directory */
|
|
26
|
+
pluginsDir: string;
|
|
27
|
+
/** ~/.claude/skills directory */
|
|
28
|
+
skillsDir: string;
|
|
29
|
+
/** ~/.claude/marketplaces directory */
|
|
30
|
+
marketplacesDir: string;
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=claude-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-paths.d.ts","sourceRoot":"","sources":["../../src/utils/claude-paths.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,IAAI;IACpC,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,eAAe,EAAE,MAAM,CAAC;CACzB,CAUA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude user directory paths
|
|
3
|
+
*
|
|
4
|
+
* Cross-platform utilities for accessing Claude's user-level directories.
|
|
5
|
+
*/
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
/**
|
|
9
|
+
* Get user-level Claude directories
|
|
10
|
+
*
|
|
11
|
+
* Returns absolute paths to Claude user directories.
|
|
12
|
+
* Paths are constructed but not checked for existence (caller's responsibility).
|
|
13
|
+
*
|
|
14
|
+
* @returns Object containing absolute paths to Claude directories
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const { claudeDir, pluginsDir, skillsDir } = getClaudeUserPaths();
|
|
19
|
+
* // claudeDir: /Users/username/.claude
|
|
20
|
+
* // pluginsDir: /Users/username/.claude/plugins
|
|
21
|
+
* // skillsDir: /Users/username/.claude/skills
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function getClaudeUserPaths() {
|
|
25
|
+
const home = homedir();
|
|
26
|
+
const claudeDir = join(home, '.claude');
|
|
27
|
+
return {
|
|
28
|
+
claudeDir,
|
|
29
|
+
pluginsDir: join(claudeDir, 'plugins'),
|
|
30
|
+
skillsDir: join(claudeDir, 'skills'),
|
|
31
|
+
marketplacesDir: join(claudeDir, 'marketplaces'),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=claude-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-paths.js","sourceRoot":"","sources":["../../src/utils/claude-paths.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,kBAAkB;IAUhC,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAExC,OAAO;QACL,SAAS;QACT,UAAU,EAAE,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC;QACtC,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC;QACpC,eAAe,EAAE,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC;KACjD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill discovery utilities
|
|
3
|
+
*
|
|
4
|
+
* Find and validate SKILL.md files within a bounded set of resources.
|
|
5
|
+
* Uses case-insensitive matching for discovery but validates proper casing.
|
|
6
|
+
*/
|
|
7
|
+
import type { ScanResult } from '@vibe-agent-toolkit/discovery';
|
|
8
|
+
/**
|
|
9
|
+
* Discover SKILL.md files from a set of scanned resources
|
|
10
|
+
*
|
|
11
|
+
* Uses case-insensitive matching to find all SKILL.md variants.
|
|
12
|
+
* Does NOT validate that the filename is exactly "SKILL.md" - use
|
|
13
|
+
* validateSkillFilename() for that.
|
|
14
|
+
*
|
|
15
|
+
* @param resources - Array of scan results from discovery package
|
|
16
|
+
* @returns Filtered array containing only SKILL.md files
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const allResources = await scan({ path: '~/.claude/plugins', recursive: true });
|
|
21
|
+
* const skills = discoverSkills(allResources.results);
|
|
22
|
+
* // Returns only resources with SKILL.md basename (any case)
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function discoverSkills(resources: ScanResult[]): ScanResult[];
|
|
26
|
+
/**
|
|
27
|
+
* Validate that a skill file has the exact correct filename
|
|
28
|
+
*
|
|
29
|
+
* SKILL.md must be uppercase. Lowercase (skill.md) or mixed case (Skill.md)
|
|
30
|
+
* may work on case-insensitive filesystems (macOS, Windows) but will fail
|
|
31
|
+
* on Linux.
|
|
32
|
+
*
|
|
33
|
+
* @param skillPath - Absolute path to skill file
|
|
34
|
+
* @returns Validation result with helpful error message if invalid
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* const validation = validateSkillFilename('/path/to/skill.md');
|
|
39
|
+
* if (!validation.valid) {
|
|
40
|
+
* console.error(validation.message); // "Filename must be exactly SKILL.md..."
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare function validateSkillFilename(skillPath: string): {
|
|
45
|
+
valid: boolean;
|
|
46
|
+
basename: string;
|
|
47
|
+
message?: string;
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=skill-discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-discovery.d.ts","sourceRoot":"","sources":["../../src/utils/skill-discovery.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAchE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CAEpE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG;IACxD,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAiBA"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill discovery utilities
|
|
3
|
+
*
|
|
4
|
+
* Find and validate SKILL.md files within a bounded set of resources.
|
|
5
|
+
* Uses case-insensitive matching for discovery but validates proper casing.
|
|
6
|
+
*/
|
|
7
|
+
import { basename } from 'node:path';
|
|
8
|
+
import picomatch from 'picomatch';
|
|
9
|
+
/**
|
|
10
|
+
* Case-insensitive matcher for SKILL.md files
|
|
11
|
+
*
|
|
12
|
+
* Matches SKILL.md anywhere in the path, regardless of case.
|
|
13
|
+
* Examples: SKILL.md, skill.md, Skill.md, path/to/SKILL.md
|
|
14
|
+
*/
|
|
15
|
+
const isSkillFile = picomatch('**/SKILL.md', {
|
|
16
|
+
nocase: true, // Case-insensitive matching
|
|
17
|
+
matchBase: true, // Match basename anywhere in path
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Discover SKILL.md files from a set of scanned resources
|
|
21
|
+
*
|
|
22
|
+
* Uses case-insensitive matching to find all SKILL.md variants.
|
|
23
|
+
* Does NOT validate that the filename is exactly "SKILL.md" - use
|
|
24
|
+
* validateSkillFilename() for that.
|
|
25
|
+
*
|
|
26
|
+
* @param resources - Array of scan results from discovery package
|
|
27
|
+
* @returns Filtered array containing only SKILL.md files
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const allResources = await scan({ path: '~/.claude/plugins', recursive: true });
|
|
32
|
+
* const skills = discoverSkills(allResources.results);
|
|
33
|
+
* // Returns only resources with SKILL.md basename (any case)
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export function discoverSkills(resources) {
|
|
37
|
+
return resources.filter(resource => isSkillFile(resource.path));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Validate that a skill file has the exact correct filename
|
|
41
|
+
*
|
|
42
|
+
* SKILL.md must be uppercase. Lowercase (skill.md) or mixed case (Skill.md)
|
|
43
|
+
* may work on case-insensitive filesystems (macOS, Windows) but will fail
|
|
44
|
+
* on Linux.
|
|
45
|
+
*
|
|
46
|
+
* @param skillPath - Absolute path to skill file
|
|
47
|
+
* @returns Validation result with helpful error message if invalid
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const validation = validateSkillFilename('/path/to/skill.md');
|
|
52
|
+
* if (!validation.valid) {
|
|
53
|
+
* console.error(validation.message); // "Filename must be exactly SKILL.md..."
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function validateSkillFilename(skillPath) {
|
|
58
|
+
// Normalize path separators for cross-platform support
|
|
59
|
+
const normalizedPath = skillPath.replaceAll('\\', '/');
|
|
60
|
+
const filename = basename(normalizedPath);
|
|
61
|
+
if (filename === 'SKILL.md') {
|
|
62
|
+
return {
|
|
63
|
+
valid: true,
|
|
64
|
+
basename: filename,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
valid: false,
|
|
69
|
+
basename: filename,
|
|
70
|
+
message: `Filename must be exactly "SKILL.md" (case-sensitive). Found "${filename}". This may work on case-insensitive filesystems (macOS, Windows) but will fail on Linux.`,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=skill-discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-discovery.js","sourceRoot":"","sources":["../../src/utils/skill-discovery.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAGrC,OAAO,SAAS,MAAM,WAAW,CAAC;AAElC;;;;;GAKG;AACH,MAAM,WAAW,GAAG,SAAS,CAAC,aAAa,EAAE;IAC3C,MAAM,EAAE,IAAI,EAAO,4BAA4B;IAC/C,SAAS,EAAE,IAAI,EAAI,kCAAkC;CACtD,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,cAAc,CAAC,SAAuB;IACpD,OAAO,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAClE,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,qBAAqB,CAAC,SAAiB;IAKrD,uDAAuD;IACvD,MAAM,cAAc,GAAG,SAAS,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAC;IAE1C,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;QAC5B,OAAO;YACL,KAAK,EAAE,IAAI;YACX,QAAQ,EAAE,QAAQ;SACnB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,KAAK,EAAE,KAAK;QACZ,QAAQ,EAAE,QAAQ;QAClB,OAAO,EAAE,gEAAgE,QAAQ,2FAA2F;KAC7K,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User context scanner
|
|
3
|
+
*
|
|
4
|
+
* Scan user-level Claude directories for plugins, skills, and marketplaces.
|
|
5
|
+
*/
|
|
6
|
+
import { type ScanResult } from '@vibe-agent-toolkit/discovery';
|
|
7
|
+
/**
|
|
8
|
+
* Scan user-level Claude directories for skills and plugins
|
|
9
|
+
*
|
|
10
|
+
* Scans:
|
|
11
|
+
* - ~/.claude/plugins for SKILL.md and .claude-plugin directories
|
|
12
|
+
* - ~/.claude/skills for SKILL.md files
|
|
13
|
+
* - ~/.claude/marketplaces (reserved for future use)
|
|
14
|
+
*
|
|
15
|
+
* Returns empty arrays if directories don't exist (not an error).
|
|
16
|
+
*
|
|
17
|
+
* @returns Object containing separate arrays for plugins, skills, marketplaces
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const context = await scanUserContext();
|
|
22
|
+
* console.log(`Found ${context.plugins.length} plugins`);
|
|
23
|
+
* console.log(`Found ${context.skills.length} skills`);
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function scanUserContext(): Promise<{
|
|
27
|
+
plugins: ScanResult[];
|
|
28
|
+
skills: ScanResult[];
|
|
29
|
+
marketplaces: ScanResult[];
|
|
30
|
+
}>;
|
|
31
|
+
//# sourceMappingURL=user-context-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-context-scanner.d.ts","sourceRoot":"","sources":["../../src/utils/user-context-scanner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAItE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC;IAC/C,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,YAAY,EAAE,UAAU,EAAE,CAAC;CAC5B,CAAC,CAmCD"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User context scanner
|
|
3
|
+
*
|
|
4
|
+
* Scan user-level Claude directories for plugins, skills, and marketplaces.
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync } from 'node:fs';
|
|
7
|
+
import { scan } from '@vibe-agent-toolkit/discovery';
|
|
8
|
+
import { getClaudeUserPaths } from './claude-paths.js';
|
|
9
|
+
/**
|
|
10
|
+
* Scan user-level Claude directories for skills and plugins
|
|
11
|
+
*
|
|
12
|
+
* Scans:
|
|
13
|
+
* - ~/.claude/plugins for SKILL.md and .claude-plugin directories
|
|
14
|
+
* - ~/.claude/skills for SKILL.md files
|
|
15
|
+
* - ~/.claude/marketplaces (reserved for future use)
|
|
16
|
+
*
|
|
17
|
+
* Returns empty arrays if directories don't exist (not an error).
|
|
18
|
+
*
|
|
19
|
+
* @returns Object containing separate arrays for plugins, skills, marketplaces
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const context = await scanUserContext();
|
|
24
|
+
* console.log(`Found ${context.plugins.length} plugins`);
|
|
25
|
+
* console.log(`Found ${context.skills.length} skills`);
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export async function scanUserContext() {
|
|
29
|
+
const { pluginsDir, skillsDir } = getClaudeUserPaths();
|
|
30
|
+
// Scan plugins directory (SKILL.md and .claude-plugin directories)
|
|
31
|
+
let plugins = [];
|
|
32
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- User's home directory is safe
|
|
33
|
+
if (existsSync(pluginsDir)) {
|
|
34
|
+
const pluginsScan = await scan({
|
|
35
|
+
path: pluginsDir,
|
|
36
|
+
recursive: true,
|
|
37
|
+
include: ['**/SKILL.md', '**/.claude-plugin/**'],
|
|
38
|
+
});
|
|
39
|
+
plugins = pluginsScan.results;
|
|
40
|
+
}
|
|
41
|
+
// Scan skills directory (SKILL.md files)
|
|
42
|
+
let skills = [];
|
|
43
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- User's home directory is safe
|
|
44
|
+
if (existsSync(skillsDir)) {
|
|
45
|
+
const skillsScan = await scan({
|
|
46
|
+
path: skillsDir,
|
|
47
|
+
recursive: true,
|
|
48
|
+
include: ['**/SKILL.md'],
|
|
49
|
+
});
|
|
50
|
+
skills = skillsScan.results;
|
|
51
|
+
}
|
|
52
|
+
// Marketplaces reserved for future use
|
|
53
|
+
const marketplaces = [];
|
|
54
|
+
return {
|
|
55
|
+
plugins,
|
|
56
|
+
skills,
|
|
57
|
+
marketplaces,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=user-context-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-context-scanner.js","sourceRoot":"","sources":["../../src/utils/user-context-scanner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EAAE,IAAI,EAAmB,MAAM,+BAA+B,CAAC;AAEtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IAKnC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,kBAAkB,EAAE,CAAC;IAEvD,mEAAmE;IACnE,IAAI,OAAO,GAAiB,EAAE,CAAC;IAC/B,oGAAoG;IACpG,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC;YAC7B,IAAI,EAAE,UAAU;YAChB,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,CAAC,aAAa,EAAE,sBAAsB,CAAC;SACjD,CAAC,CAAC;QACH,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;IAChC,CAAC;IAED,yCAAyC;IACzC,IAAI,MAAM,GAAiB,EAAE,CAAC;IAC9B,oGAAoG;IACpG,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC;YAC5B,IAAI,EAAE,SAAS;YACf,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,CAAC,aAAa,CAAC;SACzB,CAAC,CAAC;QACH,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC;IAC9B,CAAC;IAED,uCAAuC;IACvC,MAAM,YAAY,GAAiB,EAAE,CAAC;IAEtC,OAAO;QACL,OAAO;QACP,MAAM;QACN,YAAY;KACb,CAAC;AACJ,CAAC"}
|
package/docs/audit.md
CHANGED
|
@@ -224,6 +224,7 @@ Warnings indicate potential issues but don't prevent usage:
|
|
|
224
224
|
| `SKILL_NAME_XML_TAGS` | error | Name contains XML-like tags | Remove XML tags from name |
|
|
225
225
|
| `SKILL_DESCRIPTION_XML_TAGS` | error | Description contains XML-like tags | Remove XML tags from description |
|
|
226
226
|
| `SKILL_DESCRIPTION_EMPTY` | error | Description is empty or whitespace | Provide meaningful description |
|
|
227
|
+
| `SKILL_MISCONFIGURED_LOCATION` | error | Standalone skill in `~/.claude/plugins/` won't be recognized | Move to `~/.claude/skills/` for standalone skills, or add `.claude-plugin/plugin.json` for a proper plugin |
|
|
227
228
|
| `PATH_STYLE_WINDOWS` | error | Windows-style backslashes in paths | Use forward slashes (/) instead |
|
|
228
229
|
| `LINK_INTEGRITY_BROKEN` | error | Link to non-existent file | Fix or remove broken link |
|
|
229
230
|
|