@vibe-agent-toolkit/cli 0.1.9 → 0.1.12

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 (71) hide show
  1. package/dist/bin/vat +174 -0
  2. package/dist/bin.js +2 -0
  3. package/dist/bin.js.map +1 -1
  4. package/dist/commands/audit/hierarchical-output.d.ts.map +1 -1
  5. package/dist/commands/audit/hierarchical-output.js +74 -13
  6. package/dist/commands/audit/hierarchical-output.js.map +1 -1
  7. package/dist/commands/audit.d.ts.map +1 -1
  8. package/dist/commands/audit.js +57 -33
  9. package/dist/commands/audit.js.map +1 -1
  10. package/dist/commands/resources/index.d.ts.map +1 -1
  11. package/dist/commands/resources/index.js +19 -4
  12. package/dist/commands/resources/index.js.map +1 -1
  13. package/dist/commands/resources/validate.d.ts +2 -0
  14. package/dist/commands/resources/validate.d.ts.map +1 -1
  15. package/dist/commands/resources/validate.js +6 -3
  16. package/dist/commands/resources/validate.js.map +1 -1
  17. package/dist/commands/skills/build.d.ts +13 -0
  18. package/dist/commands/skills/build.d.ts.map +1 -0
  19. package/dist/commands/skills/build.js +253 -0
  20. package/dist/commands/skills/build.js.map +1 -0
  21. package/dist/commands/skills/command-helpers.d.ts +46 -0
  22. package/dist/commands/skills/command-helpers.d.ts.map +1 -0
  23. package/dist/commands/skills/command-helpers.js +70 -0
  24. package/dist/commands/skills/command-helpers.js.map +1 -0
  25. package/dist/commands/skills/index.d.ts +8 -0
  26. package/dist/commands/skills/index.d.ts.map +1 -0
  27. package/dist/commands/skills/index.js +96 -0
  28. package/dist/commands/skills/index.js.map +1 -0
  29. package/dist/commands/skills/install-helpers.d.ts +45 -0
  30. package/dist/commands/skills/install-helpers.d.ts.map +1 -0
  31. package/dist/commands/skills/install-helpers.js +125 -0
  32. package/dist/commands/skills/install-helpers.js.map +1 -0
  33. package/dist/commands/skills/install.d.ts +20 -0
  34. package/dist/commands/skills/install.d.ts.map +1 -0
  35. package/dist/commands/skills/install.js +287 -0
  36. package/dist/commands/skills/install.js.map +1 -0
  37. package/dist/commands/skills/list.d.ts +12 -0
  38. package/dist/commands/skills/list.d.ts.map +1 -0
  39. package/dist/commands/skills/list.js +124 -0
  40. package/dist/commands/skills/list.js.map +1 -0
  41. package/dist/commands/skills/package.d.ts +16 -0
  42. package/dist/commands/skills/package.d.ts.map +1 -0
  43. package/dist/commands/skills/package.js +293 -0
  44. package/dist/commands/skills/package.js.map +1 -0
  45. package/dist/commands/skills/shared.d.ts +23 -0
  46. package/dist/commands/skills/shared.d.ts.map +1 -0
  47. package/dist/commands/skills/shared.js +33 -0
  48. package/dist/commands/skills/shared.js.map +1 -0
  49. package/dist/commands/skills/validate-command.d.ts +6 -0
  50. package/dist/commands/skills/validate-command.d.ts.map +1 -0
  51. package/dist/commands/skills/validate-command.js +89 -0
  52. package/dist/commands/skills/validate-command.js.map +1 -0
  53. package/dist/commands/skills/validate.d.ts +19 -0
  54. package/dist/commands/skills/validate.d.ts.map +1 -0
  55. package/dist/commands/skills/validate.js +180 -0
  56. package/dist/commands/skills/validate.js.map +1 -0
  57. package/dist/utils/claude-paths.d.ts +32 -0
  58. package/dist/utils/claude-paths.d.ts.map +1 -0
  59. package/dist/utils/claude-paths.js +34 -0
  60. package/dist/utils/claude-paths.js.map +1 -0
  61. package/dist/utils/skill-discovery.d.ts +49 -0
  62. package/dist/utils/skill-discovery.d.ts.map +1 -0
  63. package/dist/utils/skill-discovery.js +73 -0
  64. package/dist/utils/skill-discovery.js.map +1 -0
  65. package/dist/utils/user-context-scanner.d.ts +31 -0
  66. package/dist/utils/user-context-scanner.d.ts.map +1 -0
  67. package/dist/utils/user-context-scanner.js +60 -0
  68. package/dist/utils/user-context-scanner.js.map +1 -0
  69. package/docs/audit.md +1 -0
  70. package/docs/skills.md +561 -0
  71. package/package.json +18 -12
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Skills validate command - validate skills for packaging
3
+ *
4
+ * Validates skills declared in package.json vat.skills using validateSkillForPackaging.
5
+ * Supports validation overrides and expiration checking.
6
+ */
7
+ import { validateSkillForPackaging, } from '@vibe-agent-toolkit/agent-skills';
8
+ import * as yaml from 'js-yaml';
9
+ import { formatDurationSecs } from '../../utils/duration.js';
10
+ import { filterSkillsByName, handleCommandError, setupCommandContext, } from './command-helpers.js';
11
+ import { readPackageJson, validateSkillSource } from './shared.js';
12
+ /**
13
+ * Strip excludedReferences from results metadata for non-verbose YAML output.
14
+ * Keeps excludedReferenceCount for summary info, but removes the full path list
15
+ * which can be noisy. Operates on a deep copy to avoid mutating original results.
16
+ */
17
+ function stripExcludedReferencePaths(results) {
18
+ return results.map((result) => {
19
+ const { skillLines, totalLines, fileCount, directFileCount, maxLinkDepth, excludedReferenceCount } = result.metadata;
20
+ return {
21
+ ...result,
22
+ metadata: { skillLines, totalLines, fileCount, directFileCount, maxLinkDepth, excludedReferenceCount },
23
+ };
24
+ });
25
+ }
26
+ /**
27
+ * Output YAML summary to stdout
28
+ */
29
+ function outputYamlSummary(results, duration, verbose) {
30
+ const outputResults = verbose ? results : stripExcludedReferencePaths(results);
31
+ const output = {
32
+ status: results.some((r) => r.status === 'error') ? 'error' : 'success',
33
+ skillsValidated: results.length,
34
+ results: outputResults,
35
+ durationSecs: formatDurationSecs(duration),
36
+ };
37
+ console.log(yaml.dump(output, { indent: 2, lineWidth: -1, noRefs: true }));
38
+ }
39
+ /**
40
+ * Output a single validation error
41
+ */
42
+ function outputSingleError(error) {
43
+ console.error(` [${String(error.code)}] ${String(error.message)}`);
44
+ if (error.location) {
45
+ console.error(` Location: ${String(error.location)}`);
46
+ }
47
+ if (error.fix) {
48
+ console.error(` Fix: ${String(error.fix)}`);
49
+ }
50
+ }
51
+ /**
52
+ * Output detailed errors for a skill
53
+ */
54
+ function outputSkillErrors(result) {
55
+ console.error(`Skill: ${result.skillName}`);
56
+ // Show active errors
57
+ if (result.activeErrors.length > 0) {
58
+ console.error(` Active errors (${result.activeErrors.length}):`);
59
+ for (const error of result.activeErrors) {
60
+ outputSingleError(error);
61
+ }
62
+ }
63
+ // Show ignored errors (with reasons)
64
+ if (result.ignoredErrors.length > 0) {
65
+ console.error(` Ignored errors (${result.ignoredErrors.length}):`);
66
+ for (const { error, reason } of result.ignoredErrors) {
67
+ console.error(` [${String(error.code)}] ${String(error.message)} (ignored: ${reason})`);
68
+ }
69
+ }
70
+ // Show expired overrides as errors
71
+ if (result.expiredOverrides.length > 0) {
72
+ console.error(` Expired overrides (${result.expiredOverrides.length}):`);
73
+ for (const { error, reason, expiredDate } of result.expiredOverrides) {
74
+ console.error(` [${String(error.code)}] ${String(error.message)}`);
75
+ console.error(` Override expired: ${expiredDate} (reason: ${reason})`);
76
+ }
77
+ }
78
+ console.error('');
79
+ }
80
+ /**
81
+ * Output validation report to stdout (YAML) and stderr (human-readable)
82
+ */
83
+ function outputValidationReport(results, duration, logger, verbose) {
84
+ // Output YAML to stdout (for programmatic parsing)
85
+ outputYamlSummary(results, duration, verbose);
86
+ // Output human-readable summary to stderr
87
+ const failedSkills = results.filter((r) => r.status === 'error');
88
+ if (failedSkills.length === 0) {
89
+ logger.info('\n✅ All validations passed');
90
+ return;
91
+ }
92
+ console.error('\n❌ Validation errors:\n');
93
+ for (const result of failedSkills) {
94
+ outputSkillErrors(result);
95
+ }
96
+ }
97
+ /**
98
+ * Log error status progress
99
+ */
100
+ function logErrorProgress(skill, result, logger) {
101
+ const activeCount = result.activeErrors.length;
102
+ const ignoredCount = result.ignoredErrors.length;
103
+ const expiredCount = result.expiredOverrides.length;
104
+ if (activeCount > 0) {
105
+ logger.error(` ❌ ${skill.name}: ${activeCount} error${activeCount === 1 ? '' : 's'}`);
106
+ }
107
+ if (ignoredCount > 0) {
108
+ logger.info(` (${ignoredCount} ignored by overrides)`);
109
+ }
110
+ if (expiredCount > 0) {
111
+ logger.error(` (${expiredCount} expired override${expiredCount === 1 ? '' : 's'})`);
112
+ }
113
+ }
114
+ /**
115
+ * Log success status progress
116
+ */
117
+ function logSuccessProgress(skill, ignoredCount, logger) {
118
+ if (ignoredCount > 0) {
119
+ logger.info(` ✅ ${skill.name} (${ignoredCount} ignored by overrides)`);
120
+ }
121
+ else {
122
+ logger.info(` ✅ ${skill.name}`);
123
+ }
124
+ }
125
+ /**
126
+ * Log validation progress for a single skill
127
+ */
128
+ function logSkillProgress(skill, result, logger) {
129
+ if (result.status === 'error') {
130
+ logErrorProgress(skill, result, logger);
131
+ }
132
+ else {
133
+ logSuccessProgress(skill, result.ignoredErrors.length, logger);
134
+ }
135
+ }
136
+ /**
137
+ * Validate a single skill
138
+ */
139
+ async function validateSingleSkill(skill, cwd, logger) {
140
+ const sourcePath = validateSkillSource(skill, cwd, logger);
141
+ logger.info(` Validating: ${skill.name}`);
142
+ logger.debug(` Source: ${skill.source}`);
143
+ const result = await validateSkillForPackaging(sourcePath, skill);
144
+ logSkillProgress(skill, result, logger);
145
+ return result;
146
+ }
147
+ /**
148
+ * Skills validate command implementation
149
+ */
150
+ export async function validateCommand(pathArg, options) {
151
+ const { logger, cwd, startTime } = setupCommandContext(pathArg, options.debug);
152
+ try {
153
+ // Read package.json and filter skills
154
+ const packageJson = await readPackageJson(cwd);
155
+ const skills = packageJson.vat?.skills ?? [];
156
+ if (skills.length === 0) {
157
+ logger.info('ℹ️ No skills found in package.json vat.skills');
158
+ logger.info(' To add skills, define them in package.json under the vat.skills field');
159
+ process.exit(0);
160
+ }
161
+ const skillsToValidate = filterSkillsByName(skills, options.skill);
162
+ logger.info(`🔍 Found ${skillsToValidate.length} skill(s) to validate\n`);
163
+ // Validate each skill
164
+ const results = [];
165
+ for (const skill of skillsToValidate) {
166
+ const result = await validateSingleSkill(skill, cwd, logger);
167
+ results.push(result);
168
+ }
169
+ // Output report and exit
170
+ const duration = Date.now() - startTime;
171
+ const verbose = options.verbose === true;
172
+ outputValidationReport(results, duration, logger, verbose);
173
+ const hasErrors = results.some((r) => r.activeErrors.length > 0 || r.expiredOverrides.length > 0);
174
+ process.exit(hasErrors ? 1 : 0);
175
+ }
176
+ catch (error) {
177
+ handleCommandError(error, logger, startTime, 'SkillsValidate');
178
+ }
179
+ }
180
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/commands/skills/validate.ts"],"names":[],"mappings":"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"}
@@ -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