@skillsmith/mcp-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -0
- package/dist/src/__tests__/get-skill.test.d.ts +6 -0
- package/dist/src/__tests__/get-skill.test.d.ts.map +1 -0
- package/dist/src/__tests__/get-skill.test.js +88 -0
- package/dist/src/__tests__/get-skill.test.js.map +1 -0
- package/dist/src/__tests__/middleware/errorFormatter.test.d.ts +7 -0
- package/dist/src/__tests__/middleware/errorFormatter.test.d.ts.map +1 -0
- package/dist/src/__tests__/middleware/errorFormatter.test.js +304 -0
- package/dist/src/__tests__/middleware/errorFormatter.test.js.map +1 -0
- package/dist/src/__tests__/middleware/license.test.d.ts +7 -0
- package/dist/src/__tests__/middleware/license.test.d.ts.map +1 -0
- package/dist/src/__tests__/middleware/license.test.js +500 -0
- package/dist/src/__tests__/middleware/license.test.js.map +1 -0
- package/dist/src/__tests__/search.test.d.ts +6 -0
- package/dist/src/__tests__/search.test.d.ts.map +1 -0
- package/dist/src/__tests__/search.test.js +86 -0
- package/dist/src/__tests__/search.test.js.map +1 -0
- package/dist/src/__tests__/test-utils.d.ts +19 -0
- package/dist/src/__tests__/test-utils.d.ts.map +1 -0
- package/dist/src/__tests__/test-utils.js +87 -0
- package/dist/src/__tests__/test-utils.js.map +1 -0
- package/dist/src/context/index.d.ts +19 -0
- package/dist/src/context/index.d.ts.map +1 -0
- package/dist/src/context/index.js +25 -0
- package/dist/src/context/index.js.map +1 -0
- package/dist/src/context/project-detector.d.ts +145 -0
- package/dist/src/context/project-detector.d.ts.map +1 -0
- package/dist/src/context/project-detector.js +321 -0
- package/dist/src/context/project-detector.js.map +1 -0
- package/dist/src/context.d.ts +100 -0
- package/dist/src/context.d.ts.map +1 -0
- package/dist/src/context.js +157 -0
- package/dist/src/context.js.map +1 -0
- package/dist/src/core-shim.d.ts +7 -0
- package/dist/src/core-shim.d.ts.map +1 -0
- package/dist/src/core-shim.js +9 -0
- package/dist/src/core-shim.js.map +1 -0
- package/dist/src/health/healthCheck.d.ts +88 -0
- package/dist/src/health/healthCheck.d.ts.map +1 -0
- package/dist/src/health/healthCheck.js +117 -0
- package/dist/src/health/healthCheck.js.map +1 -0
- package/dist/src/health/index.d.ts +21 -0
- package/dist/src/health/index.d.ts.map +1 -0
- package/dist/src/health/index.js +21 -0
- package/dist/src/health/index.js.map +1 -0
- package/dist/src/health/readinessCheck.d.ts +139 -0
- package/dist/src/health/readinessCheck.d.ts.map +1 -0
- package/dist/src/health/readinessCheck.js +266 -0
- package/dist/src/health/readinessCheck.js.map +1 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +178 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/index.test.d.ts +2 -0
- package/dist/src/index.test.d.ts.map +1 -0
- package/dist/src/index.test.js +43 -0
- package/dist/src/index.test.js.map +1 -0
- package/dist/src/logger.d.ts +26 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +179 -0
- package/dist/src/logger.js.map +1 -0
- package/dist/src/middleware/__tests__/csp.test.d.ts +2 -0
- package/dist/src/middleware/__tests__/csp.test.d.ts.map +1 -0
- package/dist/src/middleware/__tests__/csp.test.js +389 -0
- package/dist/src/middleware/__tests__/csp.test.js.map +1 -0
- package/dist/src/middleware/csp.d.ts +87 -0
- package/dist/src/middleware/csp.d.ts.map +1 -0
- package/dist/src/middleware/csp.js +273 -0
- package/dist/src/middleware/csp.js.map +1 -0
- package/dist/src/middleware/degradation.d.ts +99 -0
- package/dist/src/middleware/degradation.d.ts.map +1 -0
- package/dist/src/middleware/degradation.js +315 -0
- package/dist/src/middleware/degradation.js.map +1 -0
- package/dist/src/middleware/errorFormatter.d.ts +119 -0
- package/dist/src/middleware/errorFormatter.d.ts.map +1 -0
- package/dist/src/middleware/errorFormatter.js +294 -0
- package/dist/src/middleware/errorFormatter.js.map +1 -0
- package/dist/src/middleware/index.d.ts +10 -0
- package/dist/src/middleware/index.d.ts.map +1 -0
- package/dist/src/middleware/index.js +14 -0
- package/dist/src/middleware/index.js.map +1 -0
- package/dist/src/middleware/license.d.ts +161 -0
- package/dist/src/middleware/license.d.ts.map +1 -0
- package/dist/src/middleware/license.js +281 -0
- package/dist/src/middleware/license.js.map +1 -0
- package/dist/src/middleware/toolFeatureMapping.d.ts +36 -0
- package/dist/src/middleware/toolFeatureMapping.d.ts.map +1 -0
- package/dist/src/middleware/toolFeatureMapping.js +90 -0
- package/dist/src/middleware/toolFeatureMapping.js.map +1 -0
- package/dist/src/onboarding/first-run.d.ts +64 -0
- package/dist/src/onboarding/first-run.d.ts.map +1 -0
- package/dist/src/onboarding/first-run.js +77 -0
- package/dist/src/onboarding/first-run.js.map +1 -0
- package/dist/src/onboarding/index.d.ts +7 -0
- package/dist/src/onboarding/index.d.ts.map +1 -0
- package/dist/src/onboarding/index.js +7 -0
- package/dist/src/onboarding/index.js.map +1 -0
- package/dist/src/suggestions/index.d.ts +21 -0
- package/dist/src/suggestions/index.d.ts.map +1 -0
- package/dist/src/suggestions/index.js +20 -0
- package/dist/src/suggestions/index.js.map +1 -0
- package/dist/src/suggestions/suggestion-engine.d.ts +185 -0
- package/dist/src/suggestions/suggestion-engine.d.ts.map +1 -0
- package/dist/src/suggestions/suggestion-engine.js +352 -0
- package/dist/src/suggestions/suggestion-engine.js.map +1 -0
- package/dist/src/suggestions/types.d.ts +88 -0
- package/dist/src/suggestions/types.d.ts.map +1 -0
- package/dist/src/suggestions/types.js +21 -0
- package/dist/src/suggestions/types.js.map +1 -0
- package/dist/src/tools/analyze.d.ts +151 -0
- package/dist/src/tools/analyze.d.ts.map +1 -0
- package/dist/src/tools/analyze.js +205 -0
- package/dist/src/tools/analyze.js.map +1 -0
- package/dist/src/tools/compare.d.ts +149 -0
- package/dist/src/tools/compare.d.ts.map +1 -0
- package/dist/src/tools/compare.js +464 -0
- package/dist/src/tools/compare.js.map +1 -0
- package/dist/src/tools/get-skill.d.ts +116 -0
- package/dist/src/tools/get-skill.d.ts.map +1 -0
- package/dist/src/tools/get-skill.js +224 -0
- package/dist/src/tools/get-skill.js.map +1 -0
- package/dist/src/tools/index.d.ts +20 -0
- package/dist/src/tools/index.d.ts.map +1 -0
- package/dist/src/tools/index.js +20 -0
- package/dist/src/tools/index.js.map +1 -0
- package/dist/src/tools/install.d.ts +122 -0
- package/dist/src/tools/install.d.ts.map +1 -0
- package/dist/src/tools/install.js +314 -0
- package/dist/src/tools/install.js.map +1 -0
- package/dist/src/tools/recommend.d.ts +171 -0
- package/dist/src/tools/recommend.d.ts.map +1 -0
- package/dist/src/tools/recommend.js +325 -0
- package/dist/src/tools/recommend.js.map +1 -0
- package/dist/src/tools/search.d.ts +121 -0
- package/dist/src/tools/search.d.ts.map +1 -0
- package/dist/src/tools/search.js +249 -0
- package/dist/src/tools/search.js.map +1 -0
- package/dist/src/tools/suggest.d.ts +181 -0
- package/dist/src/tools/suggest.d.ts.map +1 -0
- package/dist/src/tools/suggest.js +342 -0
- package/dist/src/tools/suggest.js.map +1 -0
- package/dist/src/tools/uninstall.d.ts +123 -0
- package/dist/src/tools/uninstall.d.ts.map +1 -0
- package/dist/src/tools/uninstall.js +250 -0
- package/dist/src/tools/uninstall.js.map +1 -0
- package/dist/src/tools/validate.d.ts +122 -0
- package/dist/src/tools/validate.d.ts.map +1 -0
- package/dist/src/tools/validate.js +497 -0
- package/dist/src/tools/validate.js.map +1 -0
- package/dist/src/utils/installed-skills.d.ts +101 -0
- package/dist/src/utils/installed-skills.d.ts.map +1 -0
- package/dist/src/utils/installed-skills.js +220 -0
- package/dist/src/utils/installed-skills.js.map +1 -0
- package/dist/src/utils/validation.d.ts +76 -0
- package/dist/src/utils/validation.d.ts.map +1 -0
- package/dist/src/utils/validation.js +153 -0
- package/dist/src/utils/validation.js.map +1 -0
- package/dist/src/webhooks/index.d.ts +8 -0
- package/dist/src/webhooks/index.d.ts.map +1 -0
- package/dist/src/webhooks/index.js +9 -0
- package/dist/src/webhooks/index.js.map +1 -0
- package/dist/src/webhooks/webhook-endpoint.d.ts +149 -0
- package/dist/src/webhooks/webhook-endpoint.d.ts.map +1 -0
- package/dist/src/webhooks/webhook-endpoint.js +339 -0
- package/dist/src/webhooks/webhook-endpoint.js.map +1 -0
- package/dist/tests/compare.test.d.ts +6 -0
- package/dist/tests/compare.test.d.ts.map +1 -0
- package/dist/tests/compare.test.js +225 -0
- package/dist/tests/compare.test.js.map +1 -0
- package/dist/tests/context/project-detector.test.d.ts +6 -0
- package/dist/tests/context/project-detector.test.d.ts.map +1 -0
- package/dist/tests/context/project-detector.test.js +719 -0
- package/dist/tests/context/project-detector.test.js.map +1 -0
- package/dist/tests/e2e/compare.e2e.test.d.ts +10 -0
- package/dist/tests/e2e/compare.e2e.test.d.ts.map +1 -0
- package/dist/tests/e2e/compare.e2e.test.js +286 -0
- package/dist/tests/e2e/compare.e2e.test.js.map +1 -0
- package/dist/tests/e2e/install-flow.e2e.test.d.ts +10 -0
- package/dist/tests/e2e/install-flow.e2e.test.d.ts.map +1 -0
- package/dist/tests/e2e/install-flow.e2e.test.js +209 -0
- package/dist/tests/e2e/install-flow.e2e.test.js.map +1 -0
- package/dist/tests/e2e/recommend.e2e.test.d.ts +12 -0
- package/dist/tests/e2e/recommend.e2e.test.d.ts.map +1 -0
- package/dist/tests/e2e/recommend.e2e.test.js +347 -0
- package/dist/tests/e2e/recommend.e2e.test.js.map +1 -0
- package/dist/tests/e2e/skill-flow.e2e.test.d.ts +10 -0
- package/dist/tests/e2e/skill-flow.e2e.test.d.ts.map +1 -0
- package/dist/tests/e2e/skill-flow.e2e.test.js +280 -0
- package/dist/tests/e2e/skill-flow.e2e.test.js.map +1 -0
- package/dist/tests/e2e/suggest.e2e.test.d.ts +13 -0
- package/dist/tests/e2e/suggest.e2e.test.d.ts.map +1 -0
- package/dist/tests/e2e/suggest.e2e.test.js +347 -0
- package/dist/tests/e2e/suggest.e2e.test.js.map +1 -0
- package/dist/tests/e2e/utils/baseline-collector.d.ts +107 -0
- package/dist/tests/e2e/utils/baseline-collector.d.ts.map +1 -0
- package/dist/tests/e2e/utils/baseline-collector.js +211 -0
- package/dist/tests/e2e/utils/baseline-collector.js.map +1 -0
- package/dist/tests/e2e/utils/hardcoded-detector.d.ts +46 -0
- package/dist/tests/e2e/utils/hardcoded-detector.d.ts.map +1 -0
- package/dist/tests/e2e/utils/hardcoded-detector.js +255 -0
- package/dist/tests/e2e/utils/hardcoded-detector.js.map +1 -0
- package/dist/tests/e2e/utils/index.d.ts +7 -0
- package/dist/tests/e2e/utils/index.d.ts.map +1 -0
- package/dist/tests/e2e/utils/index.js +7 -0
- package/dist/tests/e2e/utils/index.js.map +1 -0
- package/dist/tests/e2e/utils/linear-reporter.d.ts +60 -0
- package/dist/tests/e2e/utils/linear-reporter.d.ts.map +1 -0
- package/dist/tests/e2e/utils/linear-reporter.js +232 -0
- package/dist/tests/e2e/utils/linear-reporter.js.map +1 -0
- package/dist/tests/health.test.d.ts +9 -0
- package/dist/tests/health.test.d.ts.map +1 -0
- package/dist/tests/health.test.js +308 -0
- package/dist/tests/health.test.js.map +1 -0
- package/dist/tests/integration/analyze.integration.test.d.ts +2 -0
- package/dist/tests/integration/analyze.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/analyze.integration.test.js +244 -0
- package/dist/tests/integration/analyze.integration.test.js.map +1 -0
- package/dist/tests/integration/compare.integration.test.d.ts +2 -0
- package/dist/tests/integration/compare.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/compare.integration.test.js +120 -0
- package/dist/tests/integration/compare.integration.test.js.map +1 -0
- package/dist/tests/integration/fixtures/test-skills.d.ts +62 -0
- package/dist/tests/integration/fixtures/test-skills.d.ts.map +1 -0
- package/dist/tests/integration/fixtures/test-skills.js +644 -0
- package/dist/tests/integration/fixtures/test-skills.js.map +1 -0
- package/dist/tests/integration/get-skill.integration.test.d.ts +6 -0
- package/dist/tests/integration/get-skill.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/get-skill.integration.test.js +203 -0
- package/dist/tests/integration/get-skill.integration.test.js.map +1 -0
- package/dist/tests/integration/github-api.integration.test.d.ts +14 -0
- package/dist/tests/integration/github-api.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/github-api.integration.test.js +190 -0
- package/dist/tests/integration/github-api.integration.test.js.map +1 -0
- package/dist/tests/integration/install.integration.test.d.ts +6 -0
- package/dist/tests/integration/install.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/install.integration.test.js +282 -0
- package/dist/tests/integration/install.integration.test.js.map +1 -0
- package/dist/tests/integration/recommend.integration.test.d.ts +2 -0
- package/dist/tests/integration/recommend.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/recommend.integration.test.js +215 -0
- package/dist/tests/integration/recommend.integration.test.js.map +1 -0
- package/dist/tests/integration/search.integration.test.d.ts +6 -0
- package/dist/tests/integration/search.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/search.integration.test.js +229 -0
- package/dist/tests/integration/search.integration.test.js.map +1 -0
- package/dist/tests/integration/setup.d.ts +71 -0
- package/dist/tests/integration/setup.d.ts.map +1 -0
- package/dist/tests/integration/setup.js +124 -0
- package/dist/tests/integration/setup.js.map +1 -0
- package/dist/tests/integration/uninstall.integration.test.d.ts +6 -0
- package/dist/tests/integration/uninstall.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/uninstall.integration.test.js +296 -0
- package/dist/tests/integration/uninstall.integration.test.js.map +1 -0
- package/dist/tests/integration/validate.integration.test.d.ts +2 -0
- package/dist/tests/integration/validate.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/validate.integration.test.js +181 -0
- package/dist/tests/integration/validate.integration.test.js.map +1 -0
- package/dist/tests/onboarding/first-run.test.d.ts +7 -0
- package/dist/tests/onboarding/first-run.test.d.ts.map +1 -0
- package/dist/tests/onboarding/first-run.test.js +258 -0
- package/dist/tests/onboarding/first-run.test.js.map +1 -0
- package/dist/tests/performance/search-performance.test.d.ts +10 -0
- package/dist/tests/performance/search-performance.test.d.ts.map +1 -0
- package/dist/tests/performance/search-performance.test.js +218 -0
- package/dist/tests/performance/search-performance.test.js.map +1 -0
- package/dist/tests/recommend.test.d.ts +6 -0
- package/dist/tests/recommend.test.d.ts.map +1 -0
- package/dist/tests/recommend.test.js +208 -0
- package/dist/tests/recommend.test.js.map +1 -0
- package/dist/tests/suggestions/suggestion-engine.test.d.ts +6 -0
- package/dist/tests/suggestions/suggestion-engine.test.d.ts.map +1 -0
- package/dist/tests/suggestions/suggestion-engine.test.js +448 -0
- package/dist/tests/suggestions/suggestion-engine.test.js.map +1 -0
- package/dist/tests/test-utils.d.ts +74 -0
- package/dist/tests/test-utils.d.ts.map +1 -0
- package/dist/tests/test-utils.js +98 -0
- package/dist/tests/test-utils.js.map +1 -0
- package/dist/tests/tools.test.d.ts +5 -0
- package/dist/tests/tools.test.d.ts.map +1 -0
- package/dist/tests/tools.test.js +138 -0
- package/dist/tests/tools.test.js.map +1 -0
- package/dist/tests/unit/installed-skills.test.d.ts +6 -0
- package/dist/tests/unit/installed-skills.test.d.ts.map +1 -0
- package/dist/tests/unit/installed-skills.test.js +285 -0
- package/dist/tests/unit/installed-skills.test.js.map +1 -0
- package/dist/tests/unit/logger.test.d.ts +6 -0
- package/dist/tests/unit/logger.test.d.ts.map +1 -0
- package/dist/tests/unit/logger.test.js +281 -0
- package/dist/tests/unit/logger.test.js.map +1 -0
- package/dist/tests/validate.test.d.ts +5 -0
- package/dist/tests/validate.test.d.ts.map +1 -0
- package/dist/tests/validate.test.js +303 -0
- package/dist/tests/validate.test.js.map +1 -0
- package/dist/tests/webhooks/proxy-trust.security.test.d.ts +8 -0
- package/dist/tests/webhooks/proxy-trust.security.test.d.ts.map +1 -0
- package/dist/tests/webhooks/proxy-trust.security.test.js +145 -0
- package/dist/tests/webhooks/proxy-trust.security.test.js.map +1 -0
- package/dist/tests/webhooks/rate-limiter.security.test.d.ts +8 -0
- package/dist/tests/webhooks/rate-limiter.security.test.d.ts.map +1 -0
- package/dist/tests/webhooks/rate-limiter.security.test.js +122 -0
- package/dist/tests/webhooks/rate-limiter.security.test.js.map +1 -0
- package/dist/vitest.config.d.ts +6 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/vitest.config.js +13 -0
- package/dist/vitest.config.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview MCP Skill Validate Tool for validating SKILL.md files
|
|
3
|
+
* @module @skillsmith/mcp-server/tools/validate
|
|
4
|
+
* @see SMI-742: Add MCP Tool skill_validate
|
|
5
|
+
*
|
|
6
|
+
* Validates skill definition files against the Skillsmith specification:
|
|
7
|
+
* - YAML frontmatter structure
|
|
8
|
+
* - Required fields (name, description)
|
|
9
|
+
* - Field length limits
|
|
10
|
+
* - Security patterns (SSRF, path traversal)
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* // Basic validation
|
|
14
|
+
* const result = await executeValidate({
|
|
15
|
+
* skill_path: '/path/to/SKILL.md'
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // Strict validation
|
|
20
|
+
* const result = await executeValidate({
|
|
21
|
+
* skill_path: '/path/to/skill-directory',
|
|
22
|
+
* strict: true
|
|
23
|
+
* });
|
|
24
|
+
*/
|
|
25
|
+
import { z } from 'zod';
|
|
26
|
+
import { promises as fs } from 'fs';
|
|
27
|
+
import { join } from 'path';
|
|
28
|
+
import { SkillsmithError, ErrorCodes } from '@skillsmith/core';
|
|
29
|
+
/**
|
|
30
|
+
* Zod schema for validate tool input
|
|
31
|
+
*/
|
|
32
|
+
export const validateInputSchema = z.object({
|
|
33
|
+
/** Path to SKILL.md file or skill directory */
|
|
34
|
+
skill_path: z.string().min(1, 'skill_path is required'),
|
|
35
|
+
/** Enable strict validation (default false) */
|
|
36
|
+
strict: z.boolean().default(false),
|
|
37
|
+
});
|
|
38
|
+
/**
|
|
39
|
+
* MCP tool schema definition for skill_validate
|
|
40
|
+
*/
|
|
41
|
+
export const validateToolSchema = {
|
|
42
|
+
name: 'skill_validate',
|
|
43
|
+
description: 'Validate a SKILL.md file or skill directory against Skillsmith specification. Checks structure, required fields, and security patterns.',
|
|
44
|
+
inputSchema: {
|
|
45
|
+
type: 'object',
|
|
46
|
+
properties: {
|
|
47
|
+
skill_path: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
description: 'Path to SKILL.md file or skill directory containing SKILL.md',
|
|
50
|
+
},
|
|
51
|
+
strict: {
|
|
52
|
+
type: 'boolean',
|
|
53
|
+
description: 'Enable strict validation mode (default false). Strict mode treats warnings as errors.',
|
|
54
|
+
default: false,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
required: ['skill_path'],
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Maximum field lengths for validation
|
|
62
|
+
*/
|
|
63
|
+
const FIELD_LIMITS = {
|
|
64
|
+
name: 64,
|
|
65
|
+
description: 1024,
|
|
66
|
+
author: 128,
|
|
67
|
+
version: 32,
|
|
68
|
+
category: 64,
|
|
69
|
+
license: 64,
|
|
70
|
+
tagLength: 32,
|
|
71
|
+
maxTags: 20,
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Dangerous URL patterns for SSRF prevention
|
|
75
|
+
*/
|
|
76
|
+
const SSRF_PATTERNS = [
|
|
77
|
+
/^file:\/\//i,
|
|
78
|
+
/^gopher:\/\//i,
|
|
79
|
+
/^dict:\/\//i,
|
|
80
|
+
/^ldap:\/\//i,
|
|
81
|
+
/localhost/i,
|
|
82
|
+
/127\.0\.0\.\d+/,
|
|
83
|
+
/0\.0\.0\.0/,
|
|
84
|
+
/\[::1\]/,
|
|
85
|
+
/10\.\d+\.\d+\.\d+/,
|
|
86
|
+
/172\.(1[6-9]|2\d|3[01])\.\d+\.\d+/,
|
|
87
|
+
/192\.168\.\d+\.\d+/,
|
|
88
|
+
];
|
|
89
|
+
/**
|
|
90
|
+
* Path traversal patterns
|
|
91
|
+
*/
|
|
92
|
+
const PATH_TRAVERSAL_PATTERNS = [/\.\./, /\.\.%2[fF]/, /%2[eE]%2[eE]/, /\\\.\\./];
|
|
93
|
+
/**
|
|
94
|
+
* Parse YAML frontmatter from markdown content
|
|
95
|
+
*/
|
|
96
|
+
function parseYamlFrontmatter(content) {
|
|
97
|
+
const trimmed = content.trim();
|
|
98
|
+
if (!trimmed.startsWith('---')) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
const endIndex = trimmed.indexOf('---', 3);
|
|
102
|
+
if (endIndex === -1) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
const yamlContent = trimmed.slice(3, endIndex).trim();
|
|
106
|
+
const result = {};
|
|
107
|
+
const lines = yamlContent.split('\n');
|
|
108
|
+
let currentKey = null;
|
|
109
|
+
let arrayBuffer = [];
|
|
110
|
+
let inArray = false;
|
|
111
|
+
for (const line of lines) {
|
|
112
|
+
const trimmedLine = line.trim();
|
|
113
|
+
if (!trimmedLine || trimmedLine.startsWith('#')) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (trimmedLine.startsWith('- ')) {
|
|
117
|
+
if (currentKey && inArray) {
|
|
118
|
+
const value = trimmedLine
|
|
119
|
+
.slice(2)
|
|
120
|
+
.trim()
|
|
121
|
+
.replace(/^["']|["']$/g, '');
|
|
122
|
+
arrayBuffer.push(value);
|
|
123
|
+
}
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const colonIndex = trimmedLine.indexOf(':');
|
|
127
|
+
if (colonIndex > 0) {
|
|
128
|
+
if (currentKey && inArray && arrayBuffer.length > 0) {
|
|
129
|
+
result[currentKey] = arrayBuffer;
|
|
130
|
+
arrayBuffer = [];
|
|
131
|
+
}
|
|
132
|
+
const key = trimmedLine.slice(0, colonIndex).trim();
|
|
133
|
+
const value = trimmedLine.slice(colonIndex + 1).trim();
|
|
134
|
+
if (value === '' || value === '|' || value === '>') {
|
|
135
|
+
currentKey = key;
|
|
136
|
+
inArray = true;
|
|
137
|
+
arrayBuffer = [];
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
currentKey = null;
|
|
141
|
+
inArray = false;
|
|
142
|
+
let parsedValue = value;
|
|
143
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
144
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
145
|
+
parsedValue = value.slice(1, -1);
|
|
146
|
+
}
|
|
147
|
+
else if (value === 'true') {
|
|
148
|
+
parsedValue = true;
|
|
149
|
+
}
|
|
150
|
+
else if (value === 'false') {
|
|
151
|
+
parsedValue = false;
|
|
152
|
+
}
|
|
153
|
+
else if (/^-?\d+(\.\d+)?$/.test(value)) {
|
|
154
|
+
parsedValue = parseFloat(value);
|
|
155
|
+
}
|
|
156
|
+
else if (value.startsWith('[') && value.endsWith(']')) {
|
|
157
|
+
parsedValue = value
|
|
158
|
+
.slice(1, -1)
|
|
159
|
+
.split(',')
|
|
160
|
+
.map((item) => item.trim().replace(/^["']|["']$/g, ''))
|
|
161
|
+
.filter((item) => item.length > 0);
|
|
162
|
+
}
|
|
163
|
+
result[key] = parsedValue;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (currentKey && inArray && arrayBuffer.length > 0) {
|
|
168
|
+
result[currentKey] = arrayBuffer;
|
|
169
|
+
}
|
|
170
|
+
return result;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Check for SSRF patterns in a URL
|
|
174
|
+
*/
|
|
175
|
+
function hasSsrfPattern(url) {
|
|
176
|
+
return SSRF_PATTERNS.some((pattern) => pattern.test(url));
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Check for path traversal patterns
|
|
180
|
+
*/
|
|
181
|
+
function hasPathTraversal(path) {
|
|
182
|
+
return PATH_TRAVERSAL_PATTERNS.some((pattern) => pattern.test(path));
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Validate skill metadata
|
|
186
|
+
*/
|
|
187
|
+
function validateMetadata(metadata, strict) {
|
|
188
|
+
const errors = [];
|
|
189
|
+
// Required fields
|
|
190
|
+
if (!metadata.name) {
|
|
191
|
+
errors.push({
|
|
192
|
+
field: 'name',
|
|
193
|
+
message: 'Required field "name" is missing',
|
|
194
|
+
severity: 'error',
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
else if (typeof metadata.name !== 'string') {
|
|
198
|
+
errors.push({
|
|
199
|
+
field: 'name',
|
|
200
|
+
message: 'Field "name" must be a string',
|
|
201
|
+
severity: 'error',
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
else if (metadata.name.length > FIELD_LIMITS.name) {
|
|
205
|
+
errors.push({
|
|
206
|
+
field: 'name',
|
|
207
|
+
message: `Field "name" exceeds maximum length of ${FIELD_LIMITS.name} characters`,
|
|
208
|
+
severity: 'error',
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
// Description validation
|
|
212
|
+
if (!metadata.description) {
|
|
213
|
+
errors.push({
|
|
214
|
+
field: 'description',
|
|
215
|
+
message: 'Required field "description" is missing',
|
|
216
|
+
severity: strict ? 'error' : 'warning',
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
else if (typeof metadata.description !== 'string') {
|
|
220
|
+
errors.push({
|
|
221
|
+
field: 'description',
|
|
222
|
+
message: 'Field "description" must be a string',
|
|
223
|
+
severity: 'error',
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
else if (metadata.description.length > FIELD_LIMITS.description) {
|
|
227
|
+
errors.push({
|
|
228
|
+
field: 'description',
|
|
229
|
+
message: `Field "description" exceeds maximum length of ${FIELD_LIMITS.description} characters`,
|
|
230
|
+
severity: 'error',
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
// Author validation
|
|
234
|
+
if (metadata.author !== undefined) {
|
|
235
|
+
if (typeof metadata.author !== 'string') {
|
|
236
|
+
errors.push({
|
|
237
|
+
field: 'author',
|
|
238
|
+
message: 'Field "author" must be a string',
|
|
239
|
+
severity: 'error',
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
else if (metadata.author.length > FIELD_LIMITS.author) {
|
|
243
|
+
errors.push({
|
|
244
|
+
field: 'author',
|
|
245
|
+
message: `Field "author" exceeds maximum length of ${FIELD_LIMITS.author} characters`,
|
|
246
|
+
severity: 'error',
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// Version validation
|
|
251
|
+
if (metadata.version !== undefined) {
|
|
252
|
+
if (typeof metadata.version !== 'string') {
|
|
253
|
+
errors.push({
|
|
254
|
+
field: 'version',
|
|
255
|
+
message: 'Field "version" must be a string',
|
|
256
|
+
severity: 'error',
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
else if (metadata.version.length > FIELD_LIMITS.version) {
|
|
260
|
+
errors.push({
|
|
261
|
+
field: 'version',
|
|
262
|
+
message: `Field "version" exceeds maximum length of ${FIELD_LIMITS.version} characters`,
|
|
263
|
+
severity: 'error',
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
else if (strict) {
|
|
268
|
+
errors.push({
|
|
269
|
+
field: 'version',
|
|
270
|
+
message: 'Field "version" is recommended',
|
|
271
|
+
severity: 'warning',
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
// Tags validation
|
|
275
|
+
if (metadata.tags !== undefined) {
|
|
276
|
+
if (!Array.isArray(metadata.tags)) {
|
|
277
|
+
errors.push({
|
|
278
|
+
field: 'tags',
|
|
279
|
+
message: 'Field "tags" must be an array',
|
|
280
|
+
severity: 'error',
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
if (metadata.tags.length > FIELD_LIMITS.maxTags) {
|
|
285
|
+
errors.push({
|
|
286
|
+
field: 'tags',
|
|
287
|
+
message: `Field "tags" exceeds maximum count of ${FIELD_LIMITS.maxTags}`,
|
|
288
|
+
severity: 'error',
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
for (let i = 0; i < metadata.tags.length; i++) {
|
|
292
|
+
const tag = metadata.tags[i];
|
|
293
|
+
if (typeof tag !== 'string') {
|
|
294
|
+
errors.push({
|
|
295
|
+
field: `tags[${i}]`,
|
|
296
|
+
message: 'Tag must be a string',
|
|
297
|
+
severity: 'error',
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
else if (tag.length > FIELD_LIMITS.tagLength) {
|
|
301
|
+
errors.push({
|
|
302
|
+
field: `tags[${i}]`,
|
|
303
|
+
message: `Tag exceeds maximum length of ${FIELD_LIMITS.tagLength} characters`,
|
|
304
|
+
severity: 'error',
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
else if (strict) {
|
|
311
|
+
errors.push({
|
|
312
|
+
field: 'tags',
|
|
313
|
+
message: 'Field "tags" is recommended for discoverability',
|
|
314
|
+
severity: 'warning',
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
// Security: Check repository URL for SSRF
|
|
318
|
+
if (metadata.repository !== undefined) {
|
|
319
|
+
if (typeof metadata.repository !== 'string') {
|
|
320
|
+
errors.push({
|
|
321
|
+
field: 'repository',
|
|
322
|
+
message: 'Field "repository" must be a string',
|
|
323
|
+
severity: 'error',
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
else if (hasSsrfPattern(metadata.repository)) {
|
|
327
|
+
errors.push({
|
|
328
|
+
field: 'repository',
|
|
329
|
+
message: 'Field "repository" contains potentially dangerous URL pattern',
|
|
330
|
+
severity: 'error',
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
// Security: Check homepage URL for SSRF
|
|
335
|
+
if (metadata.homepage !== undefined) {
|
|
336
|
+
if (typeof metadata.homepage !== 'string') {
|
|
337
|
+
errors.push({
|
|
338
|
+
field: 'homepage',
|
|
339
|
+
message: 'Field "homepage" must be a string',
|
|
340
|
+
severity: 'error',
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
else if (hasSsrfPattern(metadata.homepage)) {
|
|
344
|
+
errors.push({
|
|
345
|
+
field: 'homepage',
|
|
346
|
+
message: 'Field "homepage" contains potentially dangerous URL pattern',
|
|
347
|
+
severity: 'error',
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
// Security: Check for path traversal in any string fields
|
|
352
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
353
|
+
if (typeof value === 'string' && hasPathTraversal(value)) {
|
|
354
|
+
errors.push({
|
|
355
|
+
field: key,
|
|
356
|
+
message: `Field "${key}" contains path traversal pattern`,
|
|
357
|
+
severity: 'error',
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return errors;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Execute skill validation.
|
|
365
|
+
*
|
|
366
|
+
* Validates a SKILL.md file against the Skillsmith specification.
|
|
367
|
+
* Checks structure, required fields, field lengths, and security patterns.
|
|
368
|
+
*
|
|
369
|
+
* @param input - Validation parameters
|
|
370
|
+
* @returns Promise resolving to validation response
|
|
371
|
+
* @throws {SkillsmithError} When path is invalid or file cannot be read
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* const response = await executeValidate({
|
|
375
|
+
* skill_path: './skills/my-skill/SKILL.md',
|
|
376
|
+
* strict: true
|
|
377
|
+
* });
|
|
378
|
+
* if (response.valid) {
|
|
379
|
+
* console.log('Skill is valid:', response.metadata);
|
|
380
|
+
* } else {
|
|
381
|
+
* console.log('Errors:', response.errors);
|
|
382
|
+
* }
|
|
383
|
+
*/
|
|
384
|
+
export async function executeValidate(input, _context) {
|
|
385
|
+
const startTime = performance.now();
|
|
386
|
+
// Validate input with Zod
|
|
387
|
+
const validated = validateInputSchema.parse(input);
|
|
388
|
+
const { skill_path, strict } = validated;
|
|
389
|
+
// Security: Check for path traversal in input path
|
|
390
|
+
if (hasPathTraversal(skill_path)) {
|
|
391
|
+
throw new SkillsmithError(ErrorCodes.VALIDATION_INVALID_TYPE, 'Path contains path traversal pattern', { details: { path: skill_path } });
|
|
392
|
+
}
|
|
393
|
+
// Determine actual file path
|
|
394
|
+
let filePath = skill_path;
|
|
395
|
+
let isDirectory = false;
|
|
396
|
+
try {
|
|
397
|
+
const stats = await fs.stat(skill_path);
|
|
398
|
+
isDirectory = stats.isDirectory();
|
|
399
|
+
if (isDirectory) {
|
|
400
|
+
filePath = join(skill_path, 'SKILL.md');
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
// Path doesn't exist or is inaccessible
|
|
405
|
+
throw new SkillsmithError(ErrorCodes.SKILL_NOT_FOUND, `Path not found: ${skill_path}`, {
|
|
406
|
+
details: { path: skill_path },
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
// Read file content
|
|
410
|
+
let content;
|
|
411
|
+
try {
|
|
412
|
+
content = await fs.readFile(filePath, 'utf-8');
|
|
413
|
+
}
|
|
414
|
+
catch {
|
|
415
|
+
throw new SkillsmithError(ErrorCodes.SKILL_NOT_FOUND, `Cannot read file: ${filePath}`, {
|
|
416
|
+
details: { path: filePath },
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
// Parse frontmatter
|
|
420
|
+
const metadata = parseYamlFrontmatter(content);
|
|
421
|
+
const errors = [];
|
|
422
|
+
if (!metadata) {
|
|
423
|
+
errors.push({
|
|
424
|
+
field: 'frontmatter',
|
|
425
|
+
message: 'Failed to parse YAML frontmatter. Ensure file starts with "---" and ends with "---"',
|
|
426
|
+
severity: 'error',
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
// Validate metadata
|
|
431
|
+
errors.push(...validateMetadata(metadata, strict));
|
|
432
|
+
}
|
|
433
|
+
// Determine validity
|
|
434
|
+
const hasErrors = errors.some((e) => e.severity === 'error');
|
|
435
|
+
const valid = !hasErrors;
|
|
436
|
+
const endTime = performance.now();
|
|
437
|
+
return {
|
|
438
|
+
valid,
|
|
439
|
+
errors,
|
|
440
|
+
metadata: valid && metadata ? metadata : null,
|
|
441
|
+
path: filePath,
|
|
442
|
+
timing: {
|
|
443
|
+
totalMs: Math.round(endTime - startTime),
|
|
444
|
+
},
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Format validation results for terminal display
|
|
449
|
+
*/
|
|
450
|
+
export function formatValidationResults(response) {
|
|
451
|
+
const lines = [];
|
|
452
|
+
lines.push('\n=== Skill Validation Results ===\n');
|
|
453
|
+
lines.push(`Path: ${response.path}`);
|
|
454
|
+
lines.push('');
|
|
455
|
+
if (response.valid) {
|
|
456
|
+
lines.push('Status: VALID');
|
|
457
|
+
lines.push('');
|
|
458
|
+
if (response.metadata) {
|
|
459
|
+
lines.push('Metadata:');
|
|
460
|
+
if (response.metadata.name) {
|
|
461
|
+
lines.push(` Name: ${response.metadata.name}`);
|
|
462
|
+
}
|
|
463
|
+
if (response.metadata.description) {
|
|
464
|
+
const desc = String(response.metadata.description);
|
|
465
|
+
lines.push(` Description: ${desc.slice(0, 80)}${desc.length > 80 ? '...' : ''}`);
|
|
466
|
+
}
|
|
467
|
+
if (response.metadata.author) {
|
|
468
|
+
lines.push(` Author: ${response.metadata.author}`);
|
|
469
|
+
}
|
|
470
|
+
if (response.metadata.version) {
|
|
471
|
+
lines.push(` Version: ${response.metadata.version}`);
|
|
472
|
+
}
|
|
473
|
+
if (response.metadata.tags && Array.isArray(response.metadata.tags)) {
|
|
474
|
+
lines.push(` Tags: ${response.metadata.tags.join(', ')}`);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
lines.push('Status: INVALID');
|
|
480
|
+
lines.push('');
|
|
481
|
+
}
|
|
482
|
+
if (response.errors.length > 0) {
|
|
483
|
+
const errorCount = response.errors.filter((e) => e.severity === 'error').length;
|
|
484
|
+
const warningCount = response.errors.filter((e) => e.severity === 'warning').length;
|
|
485
|
+
lines.push(`Issues: ${errorCount} error(s), ${warningCount} warning(s)`);
|
|
486
|
+
lines.push('');
|
|
487
|
+
for (const error of response.errors) {
|
|
488
|
+
const prefix = error.severity === 'error' ? '[ERROR]' : '[WARN]';
|
|
489
|
+
lines.push(` ${prefix} ${error.field}: ${error.message}`);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
lines.push('');
|
|
493
|
+
lines.push('---');
|
|
494
|
+
lines.push(`Completed in ${response.timing.totalMs}ms`);
|
|
495
|
+
return lines.join('\n');
|
|
496
|
+
}
|
|
497
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/tools/validate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Utility for auto-detecting installed skills from ~/.claude/skills/
|
|
3
|
+
* @module @skillsmith/mcp-server/utils/installed-skills
|
|
4
|
+
* @see SMI-906: Auto-detect installed skills from ~/.claude/skills/
|
|
5
|
+
*
|
|
6
|
+
* Scans the user's skills directory and extracts skill IDs from SKILL.md files.
|
|
7
|
+
* Falls back to folder name if no SKILL.md or no ID found in frontmatter.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* const skills = await getInstalledSkills();
|
|
11
|
+
* // Returns: ["docker", "linear", "varlock"]
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Result from parsing a SKILL.md file
|
|
15
|
+
*/
|
|
16
|
+
interface SkillMdParsed {
|
|
17
|
+
/** Skill ID from name field */
|
|
18
|
+
id: string | null;
|
|
19
|
+
/** Skill name from name field */
|
|
20
|
+
name: string | null;
|
|
21
|
+
/** Skill description from description field */
|
|
22
|
+
description: string | null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Parse SKILL.md frontmatter to extract skill metadata.
|
|
26
|
+
*
|
|
27
|
+
* Extracts the `name` field from YAML frontmatter in SKILL.md files.
|
|
28
|
+
* Frontmatter is delimited by `---` lines at the start of the file.
|
|
29
|
+
*
|
|
30
|
+
* @param content - Content of the SKILL.md file
|
|
31
|
+
* @returns Parsed skill metadata, or null values if parsing fails
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* const content = `---
|
|
35
|
+
* name: docker
|
|
36
|
+
* description: Docker skill
|
|
37
|
+
* ---
|
|
38
|
+
* # Docker Skill`;
|
|
39
|
+
* parseSkillMd(content); // { id: "docker", name: "docker", description: "Docker skill" }
|
|
40
|
+
*/
|
|
41
|
+
export declare function parseSkillMd(content: string): SkillMdParsed;
|
|
42
|
+
/**
|
|
43
|
+
* Get the skill ID from a skill directory.
|
|
44
|
+
*
|
|
45
|
+
* Looks for SKILL.md in the directory and extracts the ID from frontmatter.
|
|
46
|
+
* Falls back to the directory name if no SKILL.md or no ID found.
|
|
47
|
+
*
|
|
48
|
+
* @param skillDir - Path to the skill directory
|
|
49
|
+
* @param dirName - Name of the directory (used as fallback)
|
|
50
|
+
* @returns Skill ID
|
|
51
|
+
*/
|
|
52
|
+
export declare function getSkillIdFromDir(skillDir: string, dirName: string): string;
|
|
53
|
+
/**
|
|
54
|
+
* Auto-detect installed skills from ~/.claude/skills/ directory.
|
|
55
|
+
*
|
|
56
|
+
* Scans the skills directory for subdirectories containing SKILL.md files.
|
|
57
|
+
* Extracts the skill ID from the `name` field in SKILL.md frontmatter.
|
|
58
|
+
* Falls back to directory name if no SKILL.md or no name field found.
|
|
59
|
+
*
|
|
60
|
+
* @param skillsDir - Optional custom skills directory path (defaults to ~/.claude/skills/)
|
|
61
|
+
* @returns Promise resolving to array of skill IDs
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* const skills = await getInstalledSkills();
|
|
65
|
+
* // Returns: ["docker", "linear", "varlock"]
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* // With custom directory
|
|
69
|
+
* const skills = await getInstalledSkills('/path/to/custom/skills');
|
|
70
|
+
*/
|
|
71
|
+
export declare function getInstalledSkills(skillsDir?: string): Promise<string[]>;
|
|
72
|
+
/**
|
|
73
|
+
* Synchronous version of getInstalledSkills for use in non-async contexts.
|
|
74
|
+
*
|
|
75
|
+
* @param skillsDir - Optional custom skills directory path (defaults to ~/.claude/skills/)
|
|
76
|
+
* @returns Array of skill IDs
|
|
77
|
+
*/
|
|
78
|
+
export declare function getInstalledSkillsSync(skillsDir?: string): string[];
|
|
79
|
+
/**
|
|
80
|
+
* Get detailed information about installed skills.
|
|
81
|
+
*
|
|
82
|
+
* Returns full parsed information from SKILL.md files, not just IDs.
|
|
83
|
+
*
|
|
84
|
+
* @param skillsDir - Optional custom skills directory path
|
|
85
|
+
* @returns Array of skill information objects
|
|
86
|
+
*/
|
|
87
|
+
export interface InstalledSkillInfo {
|
|
88
|
+
/** Skill ID (from name field or directory name) */
|
|
89
|
+
id: string;
|
|
90
|
+
/** Directory name */
|
|
91
|
+
directory: string;
|
|
92
|
+
/** Full path to skill directory */
|
|
93
|
+
path: string;
|
|
94
|
+
/** Whether SKILL.md was found */
|
|
95
|
+
hasSkillMd: boolean;
|
|
96
|
+
/** Description from SKILL.md if available */
|
|
97
|
+
description: string | null;
|
|
98
|
+
}
|
|
99
|
+
export declare function getInstalledSkillsDetailed(skillsDir?: string): Promise<InstalledSkillInfo[]>;
|
|
100
|
+
export {};
|
|
101
|
+
//# sourceMappingURL=installed-skills.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installed-skills.d.ts","sourceRoot":"","sources":["../../../src/utils/installed-skills.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAWH;;GAEG;AACH,UAAU,aAAa;IACrB,+BAA+B;IAC/B,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IACjB,iCAAiC;IACjC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,+CAA+C;IAC/C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAuC3D;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAoB3E;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAgC9E;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAgCnE;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAA;IACV,qBAAqB;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,iCAAiC;IACjC,UAAU,EAAE,OAAO,CAAA;IACnB,6CAA6C;IAC7C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3B;AAED,wBAAsB,0BAA0B,CAC9C,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,kBAAkB,EAAE,CAAC,CA4D/B"}
|