@skillsmith/mcp-server 0.3.4 → 0.3.5
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 -1
- package/dist/src/__tests__/LocalIndexer.test.d.ts +5 -0
- package/dist/src/__tests__/LocalIndexer.test.d.ts.map +1 -0
- package/dist/src/__tests__/LocalIndexer.test.js +396 -0
- package/dist/src/__tests__/LocalIndexer.test.js.map +1 -0
- package/dist/src/__tests__/get-skill.test.js +195 -0
- package/dist/src/__tests__/get-skill.test.js.map +1 -1
- package/dist/src/__tests__/index-local.test.d.ts +5 -0
- package/dist/src/__tests__/index-local.test.d.ts.map +1 -0
- package/dist/src/__tests__/index-local.test.js +203 -0
- package/dist/src/__tests__/index-local.test.js.map +1 -0
- package/dist/src/__tests__/recommend.test.d.ts +7 -0
- package/dist/src/__tests__/recommend.test.d.ts.map +1 -0
- package/dist/src/__tests__/recommend.test.js +277 -0
- package/dist/src/__tests__/recommend.test.js.map +1 -0
- package/dist/src/__tests__/search.test.js +138 -0
- package/dist/src/__tests__/search.test.js.map +1 -1
- package/dist/src/context.d.ts +6 -0
- package/dist/src/context.d.ts.map +1 -1
- package/dist/src/context.js +7 -1
- package/dist/src/context.js.map +1 -1
- package/dist/src/index.js +14 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/indexer/FrontmatterParser.d.ts +30 -0
- package/dist/src/indexer/FrontmatterParser.d.ts.map +1 -0
- package/dist/src/indexer/FrontmatterParser.js +109 -0
- package/dist/src/indexer/FrontmatterParser.js.map +1 -0
- package/dist/src/indexer/LocalIndexer.d.ts +136 -0
- package/dist/src/indexer/LocalIndexer.d.ts.map +1 -0
- package/dist/src/indexer/LocalIndexer.js +271 -0
- package/dist/src/indexer/LocalIndexer.js.map +1 -0
- package/dist/src/indexer/index.d.ts +8 -0
- package/dist/src/indexer/index.d.ts.map +1 -0
- package/dist/src/indexer/index.js +8 -0
- package/dist/src/indexer/index.js.map +1 -0
- package/dist/src/llm/failover.d.ts +11 -1
- package/dist/src/llm/failover.d.ts.map +1 -1
- package/dist/src/llm/failover.js.map +1 -1
- package/dist/src/middleware/errorFormatter.d.ts +27 -0
- package/dist/src/middleware/errorFormatter.d.ts.map +1 -1
- package/dist/src/middleware/errorFormatter.js +95 -0
- package/dist/src/middleware/errorFormatter.js.map +1 -1
- package/dist/src/middleware/index.d.ts +1 -1
- package/dist/src/middleware/index.d.ts.map +1 -1
- package/dist/src/middleware/index.js.map +1 -1
- package/dist/src/middleware/quota-helpers.d.ts +40 -0
- package/dist/src/middleware/quota-helpers.d.ts.map +1 -0
- package/dist/src/middleware/quota-helpers.js +90 -0
- package/dist/src/middleware/quota-helpers.js.map +1 -0
- package/dist/src/middleware/quota-types.d.ts +105 -0
- package/dist/src/middleware/quota-types.d.ts.map +1 -0
- package/dist/src/middleware/quota-types.js +4 -0
- package/dist/src/middleware/quota-types.js.map +1 -0
- package/dist/src/middleware/quota.d.ts +3 -97
- package/dist/src/middleware/quota.d.ts.map +1 -1
- package/dist/src/middleware/quota.js +2 -87
- package/dist/src/middleware/quota.js.map +1 -1
- package/dist/src/tools/LocalSkillSearch.d.ts +32 -0
- package/dist/src/tools/LocalSkillSearch.d.ts.map +1 -0
- package/dist/src/tools/LocalSkillSearch.js +74 -0
- package/dist/src/tools/LocalSkillSearch.js.map +1 -0
- package/dist/src/tools/compare.helpers.js.map +1 -1
- package/dist/src/tools/compare.types.d.ts +1 -0
- package/dist/src/tools/compare.types.d.ts.map +1 -1
- package/dist/src/tools/compare.types.js +2 -0
- package/dist/src/tools/compare.types.js.map +1 -1
- package/dist/src/tools/get-skill.js +3 -0
- package/dist/src/tools/get-skill.js.map +1 -1
- package/dist/src/tools/index-local.d.ts +117 -0
- package/dist/src/tools/index-local.d.ts.map +1 -0
- package/dist/src/tools/index-local.js +126 -0
- package/dist/src/tools/index-local.js.map +1 -0
- package/dist/src/tools/index.d.ts +2 -0
- package/dist/src/tools/index.d.ts.map +1 -1
- package/dist/src/tools/index.js +2 -0
- package/dist/src/tools/index.js.map +1 -1
- package/dist/src/tools/install.conflict-helpers.d.ts +64 -0
- package/dist/src/tools/install.conflict-helpers.d.ts.map +1 -0
- package/dist/src/tools/install.conflict-helpers.js +165 -0
- package/dist/src/tools/install.conflict-helpers.js.map +1 -0
- package/dist/src/tools/install.conflict-helpers.test.d.ts +15 -0
- package/dist/src/tools/install.conflict-helpers.test.d.ts.map +1 -0
- package/dist/src/tools/install.conflict-helpers.test.js +243 -0
- package/dist/src/tools/install.conflict-helpers.test.js.map +1 -0
- package/dist/src/tools/install.conflict.d.ts +58 -0
- package/dist/src/tools/install.conflict.d.ts.map +1 -0
- package/dist/src/tools/install.conflict.js +160 -0
- package/dist/src/tools/install.conflict.js.map +1 -0
- package/dist/src/tools/install.conflict.test.d.ts +15 -0
- package/dist/src/tools/install.conflict.test.d.ts.map +1 -0
- package/dist/src/tools/install.conflict.test.js +354 -0
- package/dist/src/tools/install.conflict.test.js.map +1 -0
- package/dist/src/tools/install.d.ts +5 -0
- package/dist/src/tools/install.d.ts.map +1 -1
- package/dist/src/tools/install.helpers.d.ts +5 -4
- package/dist/src/tools/install.helpers.d.ts.map +1 -1
- package/dist/src/tools/install.helpers.js +13 -4
- package/dist/src/tools/install.helpers.js.map +1 -1
- package/dist/src/tools/install.js +96 -17
- package/dist/src/tools/install.js.map +1 -1
- package/dist/src/tools/install.types.d.ts +75 -11
- package/dist/src/tools/install.types.d.ts.map +1 -1
- package/dist/src/tools/install.types.js +15 -1
- package/dist/src/tools/install.types.js.map +1 -1
- package/dist/src/tools/merge.d.ts +53 -0
- package/dist/src/tools/merge.d.ts.map +1 -0
- package/dist/src/tools/merge.js +276 -0
- package/dist/src/tools/merge.js.map +1 -0
- package/dist/src/tools/merge.test.d.ts +11 -0
- package/dist/src/tools/merge.test.d.ts.map +1 -0
- package/dist/src/tools/merge.test.js +224 -0
- package/dist/src/tools/merge.test.js.map +1 -0
- package/dist/src/tools/recommend.d.ts +1 -0
- package/dist/src/tools/recommend.d.ts.map +1 -1
- package/dist/src/tools/recommend.js +165 -38
- package/dist/src/tools/recommend.js.map +1 -1
- package/dist/src/tools/search.d.ts.map +1 -1
- package/dist/src/tools/search.js +31 -4
- package/dist/src/tools/search.js.map +1 -1
- package/dist/src/utils/validation.d.ts +6 -2
- package/dist/src/utils/validation.d.ts.map +1 -1
- package/dist/src/utils/validation.js +11 -2
- package/dist/src/utils/validation.js.map +1 -1
- package/dist/src/webhooks/webhook-endpoint.d.ts +4 -49
- package/dist/src/webhooks/webhook-endpoint.d.ts.map +1 -1
- package/dist/src/webhooks/webhook-endpoint.js +3 -125
- package/dist/src/webhooks/webhook-endpoint.js.map +1 -1
- package/dist/src/webhooks/webhook-helpers.d.ts +69 -0
- package/dist/src/webhooks/webhook-helpers.d.ts.map +1 -0
- package/dist/src/webhooks/webhook-helpers.js +146 -0
- package/dist/src/webhooks/webhook-helpers.js.map +1 -0
- package/dist/tests/e2e/conflict-resolution.e2e.test.d.ts +12 -0
- package/dist/tests/e2e/conflict-resolution.e2e.test.d.ts.map +1 -0
- package/dist/tests/e2e/conflict-resolution.e2e.test.js +343 -0
- package/dist/tests/e2e/conflict-resolution.e2e.test.js.map +1 -0
- package/dist/tests/integration/fixtures/development-skills.d.ts +22 -0
- package/dist/tests/integration/fixtures/development-skills.d.ts.map +1 -0
- package/dist/tests/integration/fixtures/development-skills.js +165 -0
- package/dist/tests/integration/fixtures/development-skills.js.map +1 -0
- package/dist/tests/integration/fixtures/devops-skills.d.ts +10 -0
- package/dist/tests/integration/fixtures/devops-skills.d.ts.map +1 -0
- package/dist/tests/integration/fixtures/devops-skills.js +70 -0
- package/dist/tests/integration/fixtures/devops-skills.js.map +1 -0
- package/dist/tests/integration/fixtures/experimental-skills.d.ts +14 -0
- package/dist/tests/integration/fixtures/experimental-skills.d.ts.map +1 -0
- package/dist/tests/integration/fixtures/experimental-skills.js +255 -0
- package/dist/tests/integration/fixtures/experimental-skills.js.map +1 -0
- package/dist/tests/integration/fixtures/skill-types.d.ts +18 -0
- package/dist/tests/integration/fixtures/skill-types.d.ts.map +1 -0
- package/dist/tests/integration/fixtures/skill-types.js +6 -0
- package/dist/tests/integration/fixtures/skill-types.js.map +1 -0
- package/dist/tests/integration/fixtures/test-skills.d.ts +10 -14
- package/dist/tests/integration/fixtures/test-skills.d.ts.map +1 -1
- package/dist/tests/integration/fixtures/test-skills.js +23 -590
- package/dist/tests/integration/fixtures/test-skills.js.map +1 -1
- package/dist/tests/integration/fixtures/testing-skills.d.ts +10 -0
- package/dist/tests/integration/fixtures/testing-skills.d.ts.map +1 -0
- package/dist/tests/integration/fixtures/testing-skills.js +70 -0
- package/dist/tests/integration/fixtures/testing-skills.js.map +1 -0
- package/dist/tests/integration/fixtures/verified-skills.d.ts +11 -0
- package/dist/tests/integration/fixtures/verified-skills.d.ts.map +1 -0
- package/dist/tests/integration/fixtures/verified-skills.js +91 -0
- package/dist/tests/integration/fixtures/verified-skills.js.map +1 -0
- package/dist/tests/integration/install-conflict.integration.test.d.ts +8 -0
- package/dist/tests/integration/install-conflict.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/install-conflict.integration.test.js +384 -0
- package/dist/tests/integration/install-conflict.integration.test.js.map +1 -0
- package/dist/tests/integration/install-trust-parsing.integration.test.d.ts +13 -0
- package/dist/tests/integration/install-trust-parsing.integration.test.d.ts.map +1 -0
- package/dist/tests/integration/install-trust-parsing.integration.test.js +290 -0
- package/dist/tests/integration/install-trust-parsing.integration.test.js.map +1 -0
- package/dist/tests/integration/install.integration.test.js +3 -0
- package/dist/tests/integration/install.integration.test.js.map +1 -1
- package/package.json +7 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LocalIndexer.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/LocalIndexer.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for SMI-1809: LocalIndexer - Local skill indexing
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect, beforeEach, afterEach, beforeAll, afterAll } from 'vitest';
|
|
5
|
+
import * as fs from 'node:fs';
|
|
6
|
+
import * as path from 'node:path';
|
|
7
|
+
import * as os from 'node:os';
|
|
8
|
+
import { LocalIndexer, getLocalIndexer, resetLocalIndexer, } from '../indexer/LocalIndexer.js';
|
|
9
|
+
import { parseFrontmatter } from '../indexer/FrontmatterParser.js';
|
|
10
|
+
// Test fixtures directory
|
|
11
|
+
let testSkillsDir;
|
|
12
|
+
/**
|
|
13
|
+
* Create a test skill directory with SKILL.md
|
|
14
|
+
*/
|
|
15
|
+
function createTestSkill(dir, name, frontmatter) {
|
|
16
|
+
const skillDir = path.join(dir, name);
|
|
17
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
18
|
+
if (frontmatter) {
|
|
19
|
+
let content = '---\n';
|
|
20
|
+
for (const [key, value] of Object.entries(frontmatter)) {
|
|
21
|
+
if (Array.isArray(value)) {
|
|
22
|
+
content += `${key}:\n`;
|
|
23
|
+
for (const item of value) {
|
|
24
|
+
content += ` - ${item}\n`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
content += `${key}: ${value}\n`;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
content += '---\n\n# ' + name + ' Skill\n\nThis is a test skill.';
|
|
32
|
+
fs.writeFileSync(path.join(skillDir, 'SKILL.md'), content);
|
|
33
|
+
}
|
|
34
|
+
return skillDir;
|
|
35
|
+
}
|
|
36
|
+
describe('LocalIndexer', () => {
|
|
37
|
+
beforeAll(() => {
|
|
38
|
+
// Create a temp directory for test skills
|
|
39
|
+
testSkillsDir = fs.mkdtempSync(path.join(os.tmpdir(), 'skillsmith-test-'));
|
|
40
|
+
});
|
|
41
|
+
afterAll(() => {
|
|
42
|
+
// Cleanup temp directory
|
|
43
|
+
fs.rmSync(testSkillsDir, { recursive: true, force: true });
|
|
44
|
+
});
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
// Clear test directory before each test
|
|
47
|
+
const entries = fs.readdirSync(testSkillsDir, { withFileTypes: true });
|
|
48
|
+
for (const entry of entries) {
|
|
49
|
+
fs.rmSync(path.join(testSkillsDir, entry.name), { recursive: true, force: true });
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
describe('parseFrontmatter', () => {
|
|
53
|
+
it('should parse basic frontmatter fields', () => {
|
|
54
|
+
const content = `---
|
|
55
|
+
name: test-skill
|
|
56
|
+
description: A test skill for testing
|
|
57
|
+
author: test-author
|
|
58
|
+
version: 1.0.0
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
# Test Skill`;
|
|
62
|
+
const result = parseFrontmatter(content);
|
|
63
|
+
expect(result.name).toBe('test-skill');
|
|
64
|
+
expect(result.description).toBe('A test skill for testing');
|
|
65
|
+
expect(result.author).toBe('test-author');
|
|
66
|
+
expect(result.version).toBe('1.0.0');
|
|
67
|
+
});
|
|
68
|
+
it('should parse tags as array', () => {
|
|
69
|
+
const content = `---
|
|
70
|
+
name: test-skill
|
|
71
|
+
tags:
|
|
72
|
+
- testing
|
|
73
|
+
- development
|
|
74
|
+
- automation
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
# Test Skill`;
|
|
78
|
+
const result = parseFrontmatter(content);
|
|
79
|
+
expect(result.tags).toEqual(['testing', 'development', 'automation']);
|
|
80
|
+
});
|
|
81
|
+
it('should parse inline array tags', () => {
|
|
82
|
+
const content = `---
|
|
83
|
+
name: test-skill
|
|
84
|
+
tags: [testing, development, automation]
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
# Test Skill`;
|
|
88
|
+
const result = parseFrontmatter(content);
|
|
89
|
+
expect(result.tags).toEqual(['testing', 'development', 'automation']);
|
|
90
|
+
});
|
|
91
|
+
it('should handle missing frontmatter', () => {
|
|
92
|
+
const content = '# Test Skill\n\nNo frontmatter here.';
|
|
93
|
+
const result = parseFrontmatter(content);
|
|
94
|
+
expect(result.name).toBeNull();
|
|
95
|
+
expect(result.description).toBeNull();
|
|
96
|
+
expect(result.tags).toEqual([]);
|
|
97
|
+
});
|
|
98
|
+
it('should handle unclosed frontmatter', () => {
|
|
99
|
+
const content = `---
|
|
100
|
+
name: test-skill
|
|
101
|
+
# Missing closing delimiter`;
|
|
102
|
+
const result = parseFrontmatter(content);
|
|
103
|
+
expect(result.name).toBeNull();
|
|
104
|
+
});
|
|
105
|
+
it('should handle quoted values', () => {
|
|
106
|
+
const content = `---
|
|
107
|
+
name: "quoted-skill"
|
|
108
|
+
description: 'Single quoted description'
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
# Test`;
|
|
112
|
+
const result = parseFrontmatter(content);
|
|
113
|
+
expect(result.name).toBe('quoted-skill');
|
|
114
|
+
expect(result.description).toBe('Single quoted description');
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
describe('calculateQualityScore', () => {
|
|
118
|
+
it('should score a fully documented skill highly', () => {
|
|
119
|
+
const indexer = new LocalIndexer(testSkillsDir);
|
|
120
|
+
const frontmatter = {
|
|
121
|
+
name: 'well-documented',
|
|
122
|
+
description: 'A comprehensive description that explains what this skill does in detail.',
|
|
123
|
+
author: 'test-author',
|
|
124
|
+
tags: ['testing', 'documentation', 'quality', 'best-practices', 'automation'],
|
|
125
|
+
version: '1.0.0',
|
|
126
|
+
triggers: [],
|
|
127
|
+
};
|
|
128
|
+
const score = indexer.calculateQualityScore(frontmatter, true);
|
|
129
|
+
// Should have high score with all fields present
|
|
130
|
+
expect(score).toBeGreaterThanOrEqual(80);
|
|
131
|
+
});
|
|
132
|
+
it('should score a minimal skill lower', () => {
|
|
133
|
+
const indexer = new LocalIndexer(testSkillsDir);
|
|
134
|
+
const frontmatter = {
|
|
135
|
+
name: null,
|
|
136
|
+
description: null,
|
|
137
|
+
author: null,
|
|
138
|
+
tags: [],
|
|
139
|
+
version: null,
|
|
140
|
+
triggers: [],
|
|
141
|
+
};
|
|
142
|
+
const score = indexer.calculateQualityScore(frontmatter, false);
|
|
143
|
+
// Should have low score with no fields
|
|
144
|
+
expect(score).toBe(0);
|
|
145
|
+
});
|
|
146
|
+
it('should give points for SKILL.md presence', () => {
|
|
147
|
+
const indexer = new LocalIndexer(testSkillsDir);
|
|
148
|
+
const frontmatter = {
|
|
149
|
+
name: null,
|
|
150
|
+
description: null,
|
|
151
|
+
author: null,
|
|
152
|
+
tags: [],
|
|
153
|
+
version: null,
|
|
154
|
+
triggers: [],
|
|
155
|
+
};
|
|
156
|
+
const scoreWithout = indexer.calculateQualityScore(frontmatter, false);
|
|
157
|
+
const scoreWith = indexer.calculateQualityScore(frontmatter, true);
|
|
158
|
+
expect(scoreWith).toBeGreaterThan(scoreWithout);
|
|
159
|
+
});
|
|
160
|
+
it('should reward longer descriptions', () => {
|
|
161
|
+
const indexer = new LocalIndexer(testSkillsDir);
|
|
162
|
+
const shortDesc = {
|
|
163
|
+
name: 'test',
|
|
164
|
+
description: 'Short',
|
|
165
|
+
author: null,
|
|
166
|
+
tags: [],
|
|
167
|
+
version: null,
|
|
168
|
+
triggers: [],
|
|
169
|
+
};
|
|
170
|
+
const longDesc = {
|
|
171
|
+
name: 'test',
|
|
172
|
+
description: 'A much longer description that provides more context and detail about what the skill does and how to use it effectively.',
|
|
173
|
+
author: null,
|
|
174
|
+
tags: [],
|
|
175
|
+
version: null,
|
|
176
|
+
triggers: [],
|
|
177
|
+
};
|
|
178
|
+
const shortScore = indexer.calculateQualityScore(shortDesc, true);
|
|
179
|
+
const longScore = indexer.calculateQualityScore(longDesc, true);
|
|
180
|
+
expect(longScore).toBeGreaterThan(shortScore);
|
|
181
|
+
});
|
|
182
|
+
it('should reward more tags (up to 5)', () => {
|
|
183
|
+
const indexer = new LocalIndexer(testSkillsDir);
|
|
184
|
+
const oneTags = {
|
|
185
|
+
name: 'test',
|
|
186
|
+
description: null,
|
|
187
|
+
author: null,
|
|
188
|
+
tags: ['one'],
|
|
189
|
+
version: null,
|
|
190
|
+
triggers: [],
|
|
191
|
+
};
|
|
192
|
+
const fiveTags = {
|
|
193
|
+
name: 'test',
|
|
194
|
+
description: null,
|
|
195
|
+
author: null,
|
|
196
|
+
tags: ['one', 'two', 'three', 'four', 'five'],
|
|
197
|
+
version: null,
|
|
198
|
+
triggers: [],
|
|
199
|
+
};
|
|
200
|
+
const oneScore = indexer.calculateQualityScore(oneTags, true);
|
|
201
|
+
const fiveScore = indexer.calculateQualityScore(fiveTags, true);
|
|
202
|
+
expect(fiveScore).toBeGreaterThan(oneScore);
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
describe('index', () => {
|
|
206
|
+
it('should index skills from directory', async () => {
|
|
207
|
+
// Create test skills
|
|
208
|
+
createTestSkill(testSkillsDir, 'skill-one', {
|
|
209
|
+
name: 'skill-one',
|
|
210
|
+
description: 'First test skill',
|
|
211
|
+
tags: ['testing'],
|
|
212
|
+
});
|
|
213
|
+
createTestSkill(testSkillsDir, 'skill-two', {
|
|
214
|
+
name: 'skill-two',
|
|
215
|
+
description: 'Second test skill',
|
|
216
|
+
author: 'test-author',
|
|
217
|
+
tags: ['testing', 'development'],
|
|
218
|
+
});
|
|
219
|
+
const indexer = new LocalIndexer(testSkillsDir);
|
|
220
|
+
const skills = await indexer.index();
|
|
221
|
+
expect(skills).toHaveLength(2);
|
|
222
|
+
expect(skills.map((s) => s.name)).toContain('skill-one');
|
|
223
|
+
expect(skills.map((s) => s.name)).toContain('skill-two');
|
|
224
|
+
});
|
|
225
|
+
it('should use directory name if no SKILL.md', async () => {
|
|
226
|
+
// Create skill without SKILL.md
|
|
227
|
+
fs.mkdirSync(path.join(testSkillsDir, 'no-skillmd-skill'));
|
|
228
|
+
const indexer = new LocalIndexer(testSkillsDir);
|
|
229
|
+
const skills = await indexer.index();
|
|
230
|
+
expect(skills).toHaveLength(1);
|
|
231
|
+
expect(skills[0].name).toBe('no-skillmd-skill');
|
|
232
|
+
expect(skills[0].hasSkillMd).toBe(false);
|
|
233
|
+
});
|
|
234
|
+
it('should skip hidden directories', async () => {
|
|
235
|
+
createTestSkill(testSkillsDir, 'visible-skill', { name: 'visible' });
|
|
236
|
+
fs.mkdirSync(path.join(testSkillsDir, '.hidden-skill'));
|
|
237
|
+
fs.writeFileSync(path.join(testSkillsDir, '.hidden-skill', 'SKILL.md'), '---\nname: hidden\n---');
|
|
238
|
+
const indexer = new LocalIndexer(testSkillsDir);
|
|
239
|
+
const skills = await indexer.index();
|
|
240
|
+
expect(skills).toHaveLength(1);
|
|
241
|
+
expect(skills[0].name).toBe('visible');
|
|
242
|
+
});
|
|
243
|
+
it('should return empty array for non-existent directory', async () => {
|
|
244
|
+
const indexer = new LocalIndexer('/non/existent/path');
|
|
245
|
+
const skills = await indexer.index();
|
|
246
|
+
expect(skills).toEqual([]);
|
|
247
|
+
});
|
|
248
|
+
it('should cache results', async () => {
|
|
249
|
+
createTestSkill(testSkillsDir, 'cached-skill', { name: 'cached' });
|
|
250
|
+
const indexer = new LocalIndexer(testSkillsDir, 60000); // 1 minute cache
|
|
251
|
+
const initialSkills = await indexer.index();
|
|
252
|
+
expect(initialSkills).toHaveLength(1);
|
|
253
|
+
// Add another skill
|
|
254
|
+
createTestSkill(testSkillsDir, 'new-skill', { name: 'new' });
|
|
255
|
+
// Should return cached results
|
|
256
|
+
const cachedSkills = await indexer.index();
|
|
257
|
+
expect(cachedSkills).toHaveLength(1);
|
|
258
|
+
// Force re-index should find new skill
|
|
259
|
+
const refreshedSkills = await indexer.index(true);
|
|
260
|
+
expect(refreshedSkills).toHaveLength(2);
|
|
261
|
+
});
|
|
262
|
+
it('should populate all LocalSkill fields', async () => {
|
|
263
|
+
createTestSkill(testSkillsDir, 'complete-skill', {
|
|
264
|
+
name: 'complete-skill',
|
|
265
|
+
description: 'A complete test skill with all fields',
|
|
266
|
+
author: 'test-author',
|
|
267
|
+
tags: ['testing', 'complete'],
|
|
268
|
+
});
|
|
269
|
+
const indexer = new LocalIndexer(testSkillsDir);
|
|
270
|
+
const skills = await indexer.index();
|
|
271
|
+
expect(skills).toHaveLength(1);
|
|
272
|
+
const skill = skills[0];
|
|
273
|
+
expect(skill.id).toBe('local/complete-skill');
|
|
274
|
+
expect(skill.name).toBe('complete-skill');
|
|
275
|
+
expect(skill.description).toBe('A complete test skill with all fields');
|
|
276
|
+
expect(skill.author).toBe('test-author');
|
|
277
|
+
expect(skill.tags).toEqual(['testing', 'complete']);
|
|
278
|
+
expect(skill.trustTier).toBe('local');
|
|
279
|
+
expect(skill.source).toBe('local');
|
|
280
|
+
expect(skill.hasSkillMd).toBe(true);
|
|
281
|
+
expect(skill.qualityScore).toBeGreaterThan(0);
|
|
282
|
+
expect(skill.path).toBe(path.join(testSkillsDir, 'complete-skill'));
|
|
283
|
+
expect(skill.lastModified).not.toBeNull();
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
describe('indexSync', () => {
|
|
287
|
+
it('should synchronously index skills', () => {
|
|
288
|
+
createTestSkill(testSkillsDir, 'sync-skill', { name: 'sync-skill' });
|
|
289
|
+
const indexer = new LocalIndexer(testSkillsDir);
|
|
290
|
+
const skills = indexer.indexSync();
|
|
291
|
+
expect(skills).toHaveLength(1);
|
|
292
|
+
expect(skills[0].name).toBe('sync-skill');
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
describe('search', () => {
|
|
296
|
+
let indexer;
|
|
297
|
+
let testSkills;
|
|
298
|
+
beforeEach(async () => {
|
|
299
|
+
createTestSkill(testSkillsDir, 'docker', {
|
|
300
|
+
name: 'docker',
|
|
301
|
+
description: 'Docker container management skill',
|
|
302
|
+
author: 'devops-team',
|
|
303
|
+
tags: ['docker', 'containers', 'devops'],
|
|
304
|
+
});
|
|
305
|
+
createTestSkill(testSkillsDir, 'git-commit', {
|
|
306
|
+
name: 'git-commit',
|
|
307
|
+
description: 'Generate semantic commit messages',
|
|
308
|
+
author: 'git-experts',
|
|
309
|
+
tags: ['git', 'commits', 'automation'],
|
|
310
|
+
});
|
|
311
|
+
createTestSkill(testSkillsDir, 'jest-testing', {
|
|
312
|
+
name: 'jest-testing',
|
|
313
|
+
description: 'Jest test generation and helpers',
|
|
314
|
+
author: 'testing-team',
|
|
315
|
+
tags: ['jest', 'testing', 'react'],
|
|
316
|
+
});
|
|
317
|
+
indexer = new LocalIndexer(testSkillsDir);
|
|
318
|
+
testSkills = await indexer.index(true);
|
|
319
|
+
});
|
|
320
|
+
it('should search by name', () => {
|
|
321
|
+
const results = indexer.search('docker', testSkills);
|
|
322
|
+
expect(results).toHaveLength(1);
|
|
323
|
+
expect(results[0].name).toBe('docker');
|
|
324
|
+
});
|
|
325
|
+
it('should search by description', () => {
|
|
326
|
+
const results = indexer.search('semantic commit', testSkills);
|
|
327
|
+
expect(results).toHaveLength(1);
|
|
328
|
+
expect(results[0].name).toBe('git-commit');
|
|
329
|
+
});
|
|
330
|
+
it('should search by tags', () => {
|
|
331
|
+
const results = indexer.search('testing', testSkills);
|
|
332
|
+
expect(results).toHaveLength(1);
|
|
333
|
+
expect(results[0].name).toBe('jest-testing');
|
|
334
|
+
});
|
|
335
|
+
it('should search by author', () => {
|
|
336
|
+
const results = indexer.search('devops-team', testSkills);
|
|
337
|
+
expect(results).toHaveLength(1);
|
|
338
|
+
expect(results[0].name).toBe('docker');
|
|
339
|
+
});
|
|
340
|
+
it('should be case-insensitive', () => {
|
|
341
|
+
const results = indexer.search('DOCKER', testSkills);
|
|
342
|
+
expect(results).toHaveLength(1);
|
|
343
|
+
expect(results[0].name).toBe('docker');
|
|
344
|
+
});
|
|
345
|
+
it('should return empty for no matches', () => {
|
|
346
|
+
const results = indexer.search('nonexistent', testSkills);
|
|
347
|
+
expect(results).toEqual([]);
|
|
348
|
+
});
|
|
349
|
+
it('should use cached skills if none provided', () => {
|
|
350
|
+
const results = indexer.search('git');
|
|
351
|
+
expect(results).toHaveLength(1);
|
|
352
|
+
expect(results[0].name).toBe('git-commit');
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
describe('clearCache', () => {
|
|
356
|
+
it('should clear the internal cache', async () => {
|
|
357
|
+
createTestSkill(testSkillsDir, 'cache-test', { name: 'cache-test' });
|
|
358
|
+
const indexer = new LocalIndexer(testSkillsDir, 60000);
|
|
359
|
+
await indexer.index();
|
|
360
|
+
// Add another skill
|
|
361
|
+
createTestSkill(testSkillsDir, 'new-skill', { name: 'new' });
|
|
362
|
+
// Clear cache
|
|
363
|
+
indexer.clearCache();
|
|
364
|
+
// Should find new skill without force
|
|
365
|
+
const skills = await indexer.index();
|
|
366
|
+
expect(skills).toHaveLength(2);
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
describe('getSkillsDir', () => {
|
|
370
|
+
it('should return the configured skills directory', () => {
|
|
371
|
+
const indexer = new LocalIndexer(testSkillsDir);
|
|
372
|
+
expect(indexer.getSkillsDir()).toBe(testSkillsDir);
|
|
373
|
+
});
|
|
374
|
+
it('should default to ~/.claude/skills/', () => {
|
|
375
|
+
const indexer = new LocalIndexer();
|
|
376
|
+
expect(indexer.getSkillsDir()).toBe(path.join(os.homedir(), '.claude', 'skills'));
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
describe('Singleton functions', () => {
|
|
381
|
+
afterEach(() => {
|
|
382
|
+
resetLocalIndexer();
|
|
383
|
+
});
|
|
384
|
+
it('getLocalIndexer should return singleton instance', () => {
|
|
385
|
+
const indexer1 = getLocalIndexer();
|
|
386
|
+
const indexer2 = getLocalIndexer();
|
|
387
|
+
expect(indexer1).toBe(indexer2);
|
|
388
|
+
});
|
|
389
|
+
it('resetLocalIndexer should clear singleton', () => {
|
|
390
|
+
const indexer1 = getLocalIndexer();
|
|
391
|
+
resetLocalIndexer();
|
|
392
|
+
const indexer2 = getLocalIndexer();
|
|
393
|
+
expect(indexer1).not.toBe(indexer2);
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
//# sourceMappingURL=LocalIndexer.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LocalIndexer.test.js","sourceRoot":"","sources":["../../../src/__tests__/LocalIndexer.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -169,4 +169,199 @@ describe('Get Skill Tool', () => {
|
|
|
169
169
|
});
|
|
170
170
|
});
|
|
171
171
|
});
|
|
172
|
+
/**
|
|
173
|
+
* SMI-1785: Tests for formatSkillDetails with various skill configurations
|
|
174
|
+
* Covers scoreBreakdown display, security status display, and trust tier formatting
|
|
175
|
+
*/
|
|
176
|
+
describe('formatSkillDetails branch coverage', () => {
|
|
177
|
+
it('should format skill with scoreBreakdown', () => {
|
|
178
|
+
const response = {
|
|
179
|
+
skill: {
|
|
180
|
+
id: 'test/skill',
|
|
181
|
+
name: 'test-skill',
|
|
182
|
+
description: 'A test skill',
|
|
183
|
+
author: 'test',
|
|
184
|
+
version: '1.0.0',
|
|
185
|
+
category: 'development',
|
|
186
|
+
trustTier: 'verified',
|
|
187
|
+
score: 90,
|
|
188
|
+
scoreBreakdown: {
|
|
189
|
+
quality: 95,
|
|
190
|
+
popularity: 80,
|
|
191
|
+
maintenance: 92,
|
|
192
|
+
security: 88,
|
|
193
|
+
documentation: 85,
|
|
194
|
+
},
|
|
195
|
+
tags: ['test'],
|
|
196
|
+
installCommand: 'claude skill add test/skill',
|
|
197
|
+
createdAt: '2024-01-01T00:00:00.000Z',
|
|
198
|
+
updatedAt: '2024-01-01T00:00:00.000Z',
|
|
199
|
+
},
|
|
200
|
+
installCommand: 'claude skill add test/skill',
|
|
201
|
+
timing: { totalMs: 10 },
|
|
202
|
+
};
|
|
203
|
+
const formatted = formatSkillDetails(response);
|
|
204
|
+
expect(formatted).toContain('Score Breakdown:');
|
|
205
|
+
expect(formatted).toContain('Quality:');
|
|
206
|
+
expect(formatted).toContain('Popularity:');
|
|
207
|
+
expect(formatted).toContain('Maintenance:');
|
|
208
|
+
expect(formatted).toContain('Security:');
|
|
209
|
+
expect(formatted).toContain('Documentation:');
|
|
210
|
+
expect(formatted).toContain('[');
|
|
211
|
+
expect(formatted).toContain(']');
|
|
212
|
+
});
|
|
213
|
+
it('should format skill with security passed=null (not scanned)', () => {
|
|
214
|
+
const response = {
|
|
215
|
+
skill: {
|
|
216
|
+
id: 'test/skill',
|
|
217
|
+
name: 'test-skill',
|
|
218
|
+
description: 'A test skill',
|
|
219
|
+
author: 'test',
|
|
220
|
+
category: 'development',
|
|
221
|
+
trustTier: 'community',
|
|
222
|
+
score: 80,
|
|
223
|
+
tags: [],
|
|
224
|
+
installCommand: 'claude skill add test/skill',
|
|
225
|
+
createdAt: '2024-01-01T00:00:00.000Z',
|
|
226
|
+
updatedAt: '2024-01-01T00:00:00.000Z',
|
|
227
|
+
security: {
|
|
228
|
+
passed: null,
|
|
229
|
+
riskScore: null,
|
|
230
|
+
findingsCount: 0,
|
|
231
|
+
scannedAt: null,
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
installCommand: 'claude skill add test/skill',
|
|
235
|
+
timing: { totalMs: 10 },
|
|
236
|
+
};
|
|
237
|
+
const formatted = formatSkillDetails(response);
|
|
238
|
+
expect(formatted).toContain('Status: Not scanned');
|
|
239
|
+
});
|
|
240
|
+
it('should format skill with security passed=true', () => {
|
|
241
|
+
const response = {
|
|
242
|
+
skill: {
|
|
243
|
+
id: 'test/skill',
|
|
244
|
+
name: 'test-skill',
|
|
245
|
+
description: 'A test skill',
|
|
246
|
+
author: 'test',
|
|
247
|
+
category: 'development',
|
|
248
|
+
trustTier: 'community',
|
|
249
|
+
score: 80,
|
|
250
|
+
tags: [],
|
|
251
|
+
installCommand: 'claude skill add test/skill',
|
|
252
|
+
createdAt: '2024-01-01T00:00:00.000Z',
|
|
253
|
+
updatedAt: '2024-01-01T00:00:00.000Z',
|
|
254
|
+
security: {
|
|
255
|
+
passed: true,
|
|
256
|
+
riskScore: 15,
|
|
257
|
+
findingsCount: 0,
|
|
258
|
+
scannedAt: '2024-01-15T12:00:00.000Z',
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
installCommand: 'claude skill add test/skill',
|
|
262
|
+
timing: { totalMs: 10 },
|
|
263
|
+
};
|
|
264
|
+
const formatted = formatSkillDetails(response);
|
|
265
|
+
expect(formatted).toContain('Status: PASSED');
|
|
266
|
+
expect(formatted).toContain('Risk Score: 15/100');
|
|
267
|
+
expect(formatted).toContain('Findings: 0');
|
|
268
|
+
expect(formatted).toContain('Scanned:');
|
|
269
|
+
});
|
|
270
|
+
it('should format skill with security passed=false', () => {
|
|
271
|
+
const response = {
|
|
272
|
+
skill: {
|
|
273
|
+
id: 'test/skill',
|
|
274
|
+
name: 'test-skill',
|
|
275
|
+
description: 'A test skill',
|
|
276
|
+
author: 'test',
|
|
277
|
+
category: 'development',
|
|
278
|
+
trustTier: 'experimental',
|
|
279
|
+
score: 60,
|
|
280
|
+
tags: [],
|
|
281
|
+
installCommand: 'claude skill add test/skill',
|
|
282
|
+
createdAt: '2024-01-01T00:00:00.000Z',
|
|
283
|
+
updatedAt: '2024-01-01T00:00:00.000Z',
|
|
284
|
+
security: {
|
|
285
|
+
passed: false,
|
|
286
|
+
riskScore: 75,
|
|
287
|
+
findingsCount: 5,
|
|
288
|
+
scannedAt: '2024-01-15T12:00:00.000Z',
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
installCommand: 'claude skill add test/skill',
|
|
292
|
+
timing: { totalMs: 10 },
|
|
293
|
+
};
|
|
294
|
+
const formatted = formatSkillDetails(response);
|
|
295
|
+
expect(formatted).toContain('Status: FAILED');
|
|
296
|
+
expect(formatted).toContain('Risk Score: 75/100 (HIGH)');
|
|
297
|
+
expect(formatted).toContain('Findings: 5');
|
|
298
|
+
expect(formatted).toContain('WARNING');
|
|
299
|
+
expect(formatted).toContain('Scanned:');
|
|
300
|
+
});
|
|
301
|
+
it('should format skill without security info', () => {
|
|
302
|
+
const response = {
|
|
303
|
+
skill: {
|
|
304
|
+
id: 'test/skill',
|
|
305
|
+
name: 'test-skill',
|
|
306
|
+
description: 'A test skill',
|
|
307
|
+
author: 'test',
|
|
308
|
+
category: 'development',
|
|
309
|
+
trustTier: 'unknown',
|
|
310
|
+
score: 50,
|
|
311
|
+
tags: [],
|
|
312
|
+
installCommand: 'claude skill add test/skill',
|
|
313
|
+
createdAt: '2024-01-01T00:00:00.000Z',
|
|
314
|
+
updatedAt: '2024-01-01T00:00:00.000Z',
|
|
315
|
+
},
|
|
316
|
+
installCommand: 'claude skill add test/skill',
|
|
317
|
+
timing: { totalMs: 10 },
|
|
318
|
+
};
|
|
319
|
+
const formatted = formatSkillDetails(response);
|
|
320
|
+
expect(formatted).toContain('Status: Not scanned');
|
|
321
|
+
expect(formatted).toContain('UNKNOWN');
|
|
322
|
+
});
|
|
323
|
+
it('should format skill without repository', () => {
|
|
324
|
+
const response = {
|
|
325
|
+
skill: {
|
|
326
|
+
id: 'test/skill',
|
|
327
|
+
name: 'test-skill',
|
|
328
|
+
description: 'A test skill',
|
|
329
|
+
author: 'test',
|
|
330
|
+
category: 'development',
|
|
331
|
+
trustTier: 'community',
|
|
332
|
+
score: 80,
|
|
333
|
+
tags: [],
|
|
334
|
+
installCommand: 'claude skill add test/skill',
|
|
335
|
+
createdAt: '2024-01-01T00:00:00.000Z',
|
|
336
|
+
updatedAt: '2024-01-01T00:00:00.000Z',
|
|
337
|
+
repository: undefined,
|
|
338
|
+
},
|
|
339
|
+
installCommand: 'claude skill add test/skill',
|
|
340
|
+
timing: { totalMs: 10 },
|
|
341
|
+
};
|
|
342
|
+
const formatted = formatSkillDetails(response);
|
|
343
|
+
expect(formatted).not.toContain('Repository:');
|
|
344
|
+
});
|
|
345
|
+
it('should format skill without tags', () => {
|
|
346
|
+
const response = {
|
|
347
|
+
skill: {
|
|
348
|
+
id: 'test/skill',
|
|
349
|
+
name: 'test-skill',
|
|
350
|
+
description: 'A test skill',
|
|
351
|
+
author: 'test',
|
|
352
|
+
category: 'development',
|
|
353
|
+
trustTier: 'community',
|
|
354
|
+
score: 80,
|
|
355
|
+
tags: [],
|
|
356
|
+
installCommand: 'claude skill add test/skill',
|
|
357
|
+
createdAt: '2024-01-01T00:00:00.000Z',
|
|
358
|
+
updatedAt: '2024-01-01T00:00:00.000Z',
|
|
359
|
+
},
|
|
360
|
+
installCommand: 'claude skill add test/skill',
|
|
361
|
+
timing: { totalMs: 10 },
|
|
362
|
+
};
|
|
363
|
+
const formatted = formatSkillDetails(response);
|
|
364
|
+
expect(formatted).not.toContain('Tags:');
|
|
365
|
+
});
|
|
366
|
+
});
|
|
172
367
|
//# sourceMappingURL=get-skill.test.js.map
|