@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,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-616: Install Skill Tool Integration Tests
|
|
3
|
+
* Tests the install_skill tool with mocked GitHub and real filesystem
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
6
|
+
import * as fs from 'fs/promises';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import { createTestFilesystem, createMockManifest, createMockGitHubFetch, fileExists, readJsonFile, } from './setup.js';
|
|
9
|
+
// We need to mock the paths used by the install module
|
|
10
|
+
// Since the install.ts uses os.homedir(), we'll test the core logic
|
|
11
|
+
describe('Install Skill Tool Integration Tests', () => {
|
|
12
|
+
let fsContext;
|
|
13
|
+
beforeEach(async () => {
|
|
14
|
+
fsContext = await createTestFilesystem();
|
|
15
|
+
});
|
|
16
|
+
afterEach(async () => {
|
|
17
|
+
await fsContext.cleanup();
|
|
18
|
+
vi.restoreAllMocks();
|
|
19
|
+
});
|
|
20
|
+
describe('Skill ID Parsing', () => {
|
|
21
|
+
it('should parse owner/repo format correctly', () => {
|
|
22
|
+
const parseSkillId = (input) => {
|
|
23
|
+
if (input.startsWith('https://github.com/')) {
|
|
24
|
+
const url = new URL(input);
|
|
25
|
+
const parts = url.pathname.split('/').filter(Boolean);
|
|
26
|
+
return {
|
|
27
|
+
owner: parts[0],
|
|
28
|
+
repo: parts[1],
|
|
29
|
+
path: parts.slice(2).join('/') || '',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (input.includes('/')) {
|
|
33
|
+
const [owner, ...rest] = input.split('/');
|
|
34
|
+
const repo = rest[0];
|
|
35
|
+
const skillPath = rest.slice(1).join('/');
|
|
36
|
+
return { owner, repo, path: skillPath };
|
|
37
|
+
}
|
|
38
|
+
throw new Error('Invalid skill ID format');
|
|
39
|
+
};
|
|
40
|
+
const result1 = parseSkillId('anthropic/claude-skills/commit');
|
|
41
|
+
expect(result1).toEqual({
|
|
42
|
+
owner: 'anthropic',
|
|
43
|
+
repo: 'claude-skills',
|
|
44
|
+
path: 'commit',
|
|
45
|
+
});
|
|
46
|
+
const result2 = parseSkillId('owner/repo');
|
|
47
|
+
expect(result2).toEqual({
|
|
48
|
+
owner: 'owner',
|
|
49
|
+
repo: 'repo',
|
|
50
|
+
path: '',
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
it('should parse GitHub URL correctly', () => {
|
|
54
|
+
const parseSkillId = (input) => {
|
|
55
|
+
if (input.startsWith('https://github.com/')) {
|
|
56
|
+
const url = new URL(input);
|
|
57
|
+
const parts = url.pathname.split('/').filter(Boolean);
|
|
58
|
+
return {
|
|
59
|
+
owner: parts[0],
|
|
60
|
+
repo: parts[1],
|
|
61
|
+
path: parts.slice(2).join('/') || '',
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
throw new Error('Invalid URL');
|
|
65
|
+
};
|
|
66
|
+
const result = parseSkillId('https://github.com/anthropic/claude-skills/tree/main/commit');
|
|
67
|
+
expect(result.owner).toBe('anthropic');
|
|
68
|
+
expect(result.repo).toBe('claude-skills');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('SKILL.md Validation', () => {
|
|
72
|
+
it('should accept valid SKILL.md content', () => {
|
|
73
|
+
const validateSkillMd = (content) => {
|
|
74
|
+
const errors = [];
|
|
75
|
+
if (!content.includes('# ')) {
|
|
76
|
+
errors.push('Missing title (# heading)');
|
|
77
|
+
}
|
|
78
|
+
if (content.length < 100) {
|
|
79
|
+
errors.push('SKILL.md is too short (minimum 100 characters)');
|
|
80
|
+
}
|
|
81
|
+
return { valid: errors.length === 0, errors };
|
|
82
|
+
};
|
|
83
|
+
const validContent = `# My Amazing Skill
|
|
84
|
+
|
|
85
|
+
This is a comprehensive skill that helps developers with their daily tasks.
|
|
86
|
+
It provides utilities for code generation, refactoring, and more.
|
|
87
|
+
|
|
88
|
+
## Usage
|
|
89
|
+
|
|
90
|
+
Use this skill by mentioning it in Claude Code.
|
|
91
|
+
`;
|
|
92
|
+
const result = validateSkillMd(validContent);
|
|
93
|
+
expect(result.valid).toBe(true);
|
|
94
|
+
expect(result.errors).toEqual([]);
|
|
95
|
+
});
|
|
96
|
+
it('should reject SKILL.md without title', () => {
|
|
97
|
+
const validateSkillMd = (content) => {
|
|
98
|
+
const errors = [];
|
|
99
|
+
if (!content.includes('# ')) {
|
|
100
|
+
errors.push('Missing title');
|
|
101
|
+
}
|
|
102
|
+
if (content.length < 100) {
|
|
103
|
+
errors.push('Too short');
|
|
104
|
+
}
|
|
105
|
+
return { valid: errors.length === 0, errors };
|
|
106
|
+
};
|
|
107
|
+
const invalidContent = 'This content has no title heading and is long enough but still invalid.'.repeat(3);
|
|
108
|
+
const result = validateSkillMd(invalidContent);
|
|
109
|
+
expect(result.valid).toBe(false);
|
|
110
|
+
expect(result.errors).toContain('Missing title');
|
|
111
|
+
});
|
|
112
|
+
it('should reject SKILL.md that is too short', () => {
|
|
113
|
+
const validateSkillMd = (content) => {
|
|
114
|
+
const errors = [];
|
|
115
|
+
if (!content.includes('# ')) {
|
|
116
|
+
errors.push('Missing title');
|
|
117
|
+
}
|
|
118
|
+
if (content.length < 100) {
|
|
119
|
+
errors.push('Too short');
|
|
120
|
+
}
|
|
121
|
+
return { valid: errors.length === 0, errors };
|
|
122
|
+
};
|
|
123
|
+
const shortContent = '# Short\n\nToo short.';
|
|
124
|
+
const result = validateSkillMd(shortContent);
|
|
125
|
+
expect(result.valid).toBe(false);
|
|
126
|
+
expect(result.errors).toContain('Too short');
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe('Filesystem Operations', () => {
|
|
130
|
+
it('should create skill directory', async () => {
|
|
131
|
+
const skillPath = path.join(fsContext.skillsDir, 'test-skill');
|
|
132
|
+
await fs.mkdir(skillPath, { recursive: true });
|
|
133
|
+
const exists = await fileExists(skillPath);
|
|
134
|
+
expect(exists).toBe(true);
|
|
135
|
+
});
|
|
136
|
+
it('should write SKILL.md file', async () => {
|
|
137
|
+
const skillPath = path.join(fsContext.skillsDir, 'test-skill');
|
|
138
|
+
await fs.mkdir(skillPath, { recursive: true });
|
|
139
|
+
const content = '# Test Skill\n\nThis is test content with enough characters to pass validation requirements.';
|
|
140
|
+
await fs.writeFile(path.join(skillPath, 'SKILL.md'), content);
|
|
141
|
+
const exists = await fileExists(path.join(skillPath, 'SKILL.md'));
|
|
142
|
+
expect(exists).toBe(true);
|
|
143
|
+
const readContent = await fs.readFile(path.join(skillPath, 'SKILL.md'), 'utf-8');
|
|
144
|
+
expect(readContent).toBe(content);
|
|
145
|
+
});
|
|
146
|
+
it('should create and update manifest', async () => {
|
|
147
|
+
await createMockManifest(fsContext.manifestDir, {});
|
|
148
|
+
const manifestPath = path.join(fsContext.manifestDir, 'manifest.json');
|
|
149
|
+
const manifest = await readJsonFile(manifestPath);
|
|
150
|
+
expect(manifest.version).toBe('1.0.0');
|
|
151
|
+
expect(manifest.installedSkills).toEqual({});
|
|
152
|
+
// Add a skill to manifest
|
|
153
|
+
manifest.installedSkills['test-skill'] = {
|
|
154
|
+
id: 'owner/test-skill',
|
|
155
|
+
name: 'test-skill',
|
|
156
|
+
version: '1.0.0',
|
|
157
|
+
source: 'github:owner/test-skill',
|
|
158
|
+
installPath: path.join(fsContext.skillsDir, 'test-skill'),
|
|
159
|
+
installedAt: new Date().toISOString(),
|
|
160
|
+
lastUpdated: new Date().toISOString(),
|
|
161
|
+
};
|
|
162
|
+
await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
|
|
163
|
+
const updatedManifest = await readJsonFile(manifestPath);
|
|
164
|
+
expect(updatedManifest.installedSkills['test-skill']).toBeDefined();
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
describe('Duplicate Installation Detection', () => {
|
|
168
|
+
it('should detect already installed skill', async () => {
|
|
169
|
+
// Create manifest with existing skill
|
|
170
|
+
await createMockManifest(fsContext.manifestDir, {
|
|
171
|
+
'existing-skill': {
|
|
172
|
+
id: 'owner/existing-skill',
|
|
173
|
+
name: 'existing-skill',
|
|
174
|
+
version: '1.0.0',
|
|
175
|
+
source: 'github:owner/existing-skill',
|
|
176
|
+
installPath: path.join(fsContext.skillsDir, 'existing-skill'),
|
|
177
|
+
installedAt: new Date().toISOString(),
|
|
178
|
+
lastUpdated: new Date().toISOString(),
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
const manifestPath = path.join(fsContext.manifestDir, 'manifest.json');
|
|
182
|
+
const manifest = await readJsonFile(manifestPath);
|
|
183
|
+
expect(manifest.installedSkills['existing-skill']).toBeDefined();
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
describe('GitHub Fetch Mocking', () => {
|
|
187
|
+
it('should mock successful GitHub fetch', async () => {
|
|
188
|
+
const mockFetch = createMockGitHubFetch({
|
|
189
|
+
'raw.githubusercontent.com/owner/repo/main/SKILL.md': {
|
|
190
|
+
status: 200,
|
|
191
|
+
body: '# Mock Skill\n\nThis is a mock skill with sufficient content for validation testing purposes.',
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
const response = await mockFetch('https://raw.githubusercontent.com/owner/repo/main/SKILL.md');
|
|
195
|
+
expect(response.status).toBe(200);
|
|
196
|
+
const body = await response.text();
|
|
197
|
+
expect(body).toContain('# Mock Skill');
|
|
198
|
+
});
|
|
199
|
+
it('should mock 404 for non-existent files', async () => {
|
|
200
|
+
const mockFetch = createMockGitHubFetch({});
|
|
201
|
+
const response = await mockFetch('https://raw.githubusercontent.com/owner/repo/main/NONEXISTENT.md');
|
|
202
|
+
expect(response.status).toBe(404);
|
|
203
|
+
});
|
|
204
|
+
it('should try master branch if main fails', async () => {
|
|
205
|
+
const mockFetch = createMockGitHubFetch({
|
|
206
|
+
'raw.githubusercontent.com/owner/repo/master/SKILL.md': {
|
|
207
|
+
status: 200,
|
|
208
|
+
body: '# Master Branch Skill\n\nContent from master branch with enough text for validation.',
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
// Simulate the logic of trying main then master
|
|
212
|
+
let response = await mockFetch('https://raw.githubusercontent.com/owner/repo/main/SKILL.md');
|
|
213
|
+
if (response.status === 404) {
|
|
214
|
+
response = await mockFetch('https://raw.githubusercontent.com/owner/repo/master/SKILL.md');
|
|
215
|
+
}
|
|
216
|
+
expect(response.status).toBe(200);
|
|
217
|
+
const body = await response.text();
|
|
218
|
+
expect(body).toContain('Master Branch');
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
describe('Post-Install Tips', () => {
|
|
222
|
+
it('should generate correct tips', () => {
|
|
223
|
+
const generateTips = (skillName) => [
|
|
224
|
+
`Skill "${skillName}" installed successfully!`,
|
|
225
|
+
`To use this skill, mention it in Claude Code: "Use the ${skillName} skill to..."`,
|
|
226
|
+
'View installed skills: ls ~/.claude/skills/',
|
|
227
|
+
'To uninstall: use the uninstall_skill tool',
|
|
228
|
+
];
|
|
229
|
+
const tips = generateTips('my-skill');
|
|
230
|
+
expect(tips[0]).toContain('my-skill');
|
|
231
|
+
expect(tips[1]).toContain('my-skill');
|
|
232
|
+
expect(tips.length).toBe(4);
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
describe('Full Installation Flow Simulation', () => {
|
|
236
|
+
it('should complete full installation flow', async () => {
|
|
237
|
+
const skillName = 'complete-skill';
|
|
238
|
+
const skillPath = path.join(fsContext.skillsDir, skillName);
|
|
239
|
+
// 1. Create skill directory
|
|
240
|
+
await fs.mkdir(skillPath, { recursive: true });
|
|
241
|
+
// 2. Write SKILL.md
|
|
242
|
+
const skillContent = `# Complete Skill
|
|
243
|
+
|
|
244
|
+
A comprehensive skill for testing the full installation flow.
|
|
245
|
+
This content is long enough to pass the validation requirements.
|
|
246
|
+
|
|
247
|
+
## Features
|
|
248
|
+
|
|
249
|
+
- Feature 1
|
|
250
|
+
- Feature 2
|
|
251
|
+
|
|
252
|
+
## Usage
|
|
253
|
+
|
|
254
|
+
Use this skill by mentioning it in Claude Code.
|
|
255
|
+
`;
|
|
256
|
+
await fs.writeFile(path.join(skillPath, 'SKILL.md'), skillContent);
|
|
257
|
+
// 3. Write optional README.md
|
|
258
|
+
await fs.writeFile(path.join(skillPath, 'README.md'), '# Complete Skill\n\nAdditional documentation.');
|
|
259
|
+
// 4. Update manifest
|
|
260
|
+
const manifestPath = path.join(fsContext.manifestDir, 'manifest.json');
|
|
261
|
+
await createMockManifest(fsContext.manifestDir, {
|
|
262
|
+
[skillName]: {
|
|
263
|
+
id: 'owner/complete-skill',
|
|
264
|
+
name: skillName,
|
|
265
|
+
version: '1.0.0',
|
|
266
|
+
source: 'github:owner/complete-skill',
|
|
267
|
+
installPath: skillPath,
|
|
268
|
+
installedAt: new Date().toISOString(),
|
|
269
|
+
lastUpdated: new Date().toISOString(),
|
|
270
|
+
},
|
|
271
|
+
});
|
|
272
|
+
// Verify installation
|
|
273
|
+
expect(await fileExists(skillPath)).toBe(true);
|
|
274
|
+
expect(await fileExists(path.join(skillPath, 'SKILL.md'))).toBe(true);
|
|
275
|
+
expect(await fileExists(path.join(skillPath, 'README.md'))).toBe(true);
|
|
276
|
+
expect(await fileExists(manifestPath)).toBe(true);
|
|
277
|
+
const manifest = await readJsonFile(manifestPath);
|
|
278
|
+
expect(manifest.installedSkills[skillName]).toBeDefined();
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
//# sourceMappingURL=install.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.integration.test.js","sourceRoot":"","sources":["../../../tests/integration/install.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recommend.integration.test.d.ts","sourceRoot":"","sources":["../../../tests/integration/recommend.integration.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SMI-756: Integration tests for recommend MCP tool
|
|
3
|
+
* Tests skill recommendations with real database and matching
|
|
4
|
+
* Updated for SMI-902: Use real database instead of hardcoded skills
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
7
|
+
import { createTestDatabase } from './setup.js';
|
|
8
|
+
import { executeRecommend, formatRecommendations } from '../../src/tools/recommend.js';
|
|
9
|
+
describe('Recommend Tool Integration', () => {
|
|
10
|
+
let ctx;
|
|
11
|
+
let toolContext;
|
|
12
|
+
beforeEach(async () => {
|
|
13
|
+
ctx = await createTestDatabase();
|
|
14
|
+
toolContext = {
|
|
15
|
+
db: ctx.db,
|
|
16
|
+
searchService: ctx.searchService,
|
|
17
|
+
skillRepository: ctx.skillRepository,
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
afterEach(async () => {
|
|
21
|
+
await ctx.cleanup();
|
|
22
|
+
});
|
|
23
|
+
describe('executeRecommend', () => {
|
|
24
|
+
it('should return recommendations with auto-detected skills when installed skills is empty', async () => {
|
|
25
|
+
// SMI-906: Empty installed_skills now triggers auto-detection from ~/.claude/skills/
|
|
26
|
+
const result = await executeRecommend({
|
|
27
|
+
installed_skills: [],
|
|
28
|
+
limit: 5,
|
|
29
|
+
}, toolContext);
|
|
30
|
+
expect(result.recommendations).toBeDefined();
|
|
31
|
+
expect(result.recommendations.length).toBeGreaterThan(0);
|
|
32
|
+
expect(result.recommendations.length).toBeLessThanOrEqual(5);
|
|
33
|
+
// installed_count may be > 0 due to auto-detection from ~/.claude/skills/
|
|
34
|
+
expect(result.context.installed_count).toBeGreaterThanOrEqual(0);
|
|
35
|
+
expect(result.context.using_semantic_matching).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
it('should return recommendations based on installed skills', async () => {
|
|
38
|
+
const result = await executeRecommend({
|
|
39
|
+
installed_skills: ['anthropic/commit'],
|
|
40
|
+
detect_overlap: false,
|
|
41
|
+
limit: 5,
|
|
42
|
+
}, toolContext);
|
|
43
|
+
expect(result.recommendations).toBeDefined();
|
|
44
|
+
expect(result.recommendations.length).toBeGreaterThan(0);
|
|
45
|
+
expect(result.context.installed_count).toBe(1);
|
|
46
|
+
// Should not include installed skill
|
|
47
|
+
const ids = result.recommendations.map((r) => r.skill_id);
|
|
48
|
+
expect(ids).not.toContain('anthropic/commit');
|
|
49
|
+
});
|
|
50
|
+
it('should filter overlapping skills when enabled', async () => {
|
|
51
|
+
const withOverlap = await executeRecommend({
|
|
52
|
+
installed_skills: ['anthropic/commit'],
|
|
53
|
+
detect_overlap: true,
|
|
54
|
+
limit: 10,
|
|
55
|
+
}, toolContext);
|
|
56
|
+
const withoutOverlap = await executeRecommend({
|
|
57
|
+
installed_skills: ['anthropic/commit'],
|
|
58
|
+
detect_overlap: false,
|
|
59
|
+
limit: 10,
|
|
60
|
+
}, toolContext);
|
|
61
|
+
// With overlap detection, fewer skills may be recommended
|
|
62
|
+
expect(withOverlap.overlap_filtered).toBeGreaterThanOrEqual(0);
|
|
63
|
+
expect(withoutOverlap.overlap_filtered).toBe(0);
|
|
64
|
+
});
|
|
65
|
+
it('should respect project context', async () => {
|
|
66
|
+
const result = await executeRecommend({
|
|
67
|
+
installed_skills: [],
|
|
68
|
+
project_context: 'React frontend with Jest testing',
|
|
69
|
+
detect_overlap: false,
|
|
70
|
+
limit: 10,
|
|
71
|
+
}, toolContext);
|
|
72
|
+
expect(result.context.has_project_context).toBe(true);
|
|
73
|
+
expect(result.recommendations.length).toBeGreaterThan(0);
|
|
74
|
+
});
|
|
75
|
+
it('should respect minimum similarity threshold', async () => {
|
|
76
|
+
const highThreshold = await executeRecommend({
|
|
77
|
+
installed_skills: ['anthropic/commit'],
|
|
78
|
+
detect_overlap: false,
|
|
79
|
+
min_similarity: 0.9,
|
|
80
|
+
limit: 10,
|
|
81
|
+
}, toolContext);
|
|
82
|
+
const lowThreshold = await executeRecommend({
|
|
83
|
+
installed_skills: ['anthropic/commit'],
|
|
84
|
+
detect_overlap: false,
|
|
85
|
+
min_similarity: 0.1,
|
|
86
|
+
limit: 10,
|
|
87
|
+
}, toolContext);
|
|
88
|
+
// Lower threshold should return more results
|
|
89
|
+
expect(lowThreshold.recommendations.length).toBeGreaterThanOrEqual(highThreshold.recommendations.length);
|
|
90
|
+
});
|
|
91
|
+
it('should include quality scores and trust tiers', async () => {
|
|
92
|
+
const result = await executeRecommend({
|
|
93
|
+
installed_skills: [],
|
|
94
|
+
detect_overlap: false,
|
|
95
|
+
limit: 5,
|
|
96
|
+
}, toolContext);
|
|
97
|
+
for (const rec of result.recommendations) {
|
|
98
|
+
expect(rec.quality_score).toBeGreaterThanOrEqual(0);
|
|
99
|
+
expect(rec.quality_score).toBeLessThanOrEqual(100);
|
|
100
|
+
expect(['verified', 'community', 'standard', 'unverified']).toContain(rec.trust_tier);
|
|
101
|
+
expect(rec.reason).toBeDefined();
|
|
102
|
+
expect(rec.similarity_score).toBeGreaterThanOrEqual(0);
|
|
103
|
+
expect(rec.similarity_score).toBeLessThanOrEqual(1);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
it('should respect limit parameter', async () => {
|
|
107
|
+
const result = await executeRecommend({
|
|
108
|
+
installed_skills: [],
|
|
109
|
+
detect_overlap: false,
|
|
110
|
+
limit: 3,
|
|
111
|
+
}, toolContext);
|
|
112
|
+
expect(result.recommendations.length).toBeLessThanOrEqual(3);
|
|
113
|
+
});
|
|
114
|
+
it('should track timing information', async () => {
|
|
115
|
+
const result = await executeRecommend({
|
|
116
|
+
installed_skills: [],
|
|
117
|
+
limit: 5,
|
|
118
|
+
}, toolContext);
|
|
119
|
+
expect(result.timing.totalMs).toBeGreaterThanOrEqual(0);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
// SMI-907: Tests for improved overlap detection with semantically similar names
|
|
123
|
+
describe('SMI-907: Name-based overlap detection', () => {
|
|
124
|
+
it('should NOT recommend docker-compose when docker is installed', async () => {
|
|
125
|
+
const result = await executeRecommend({
|
|
126
|
+
installed_skills: ['community/docker'],
|
|
127
|
+
detect_overlap: false, // Disable semantic overlap to test name-based filtering
|
|
128
|
+
limit: 50,
|
|
129
|
+
}, toolContext);
|
|
130
|
+
const recommendedIds = result.recommendations.map((r) => r.skill_id);
|
|
131
|
+
// docker-compose should be filtered because "docker-compose" contains "docker"
|
|
132
|
+
expect(recommendedIds).not.toContain('community/docker-compose');
|
|
133
|
+
// Also verify the installed skill itself is not recommended
|
|
134
|
+
expect(recommendedIds).not.toContain('community/docker');
|
|
135
|
+
});
|
|
136
|
+
it('should still recommend vitest-helper when jest-helper is installed', async () => {
|
|
137
|
+
const result = await executeRecommend({
|
|
138
|
+
installed_skills: ['community/jest-helper'],
|
|
139
|
+
detect_overlap: false, // Disable semantic overlap to test name-based filtering
|
|
140
|
+
limit: 50,
|
|
141
|
+
}, toolContext);
|
|
142
|
+
const recommendedIds = result.recommendations.map((r) => r.skill_id);
|
|
143
|
+
// vitest-helper should still be recommended - different testing framework
|
|
144
|
+
// "jest-helper" and "vitest-helper" don't share name containment
|
|
145
|
+
expect(recommendedIds).toContain('community/vitest-helper');
|
|
146
|
+
// jest-helper itself should not be recommended (installed)
|
|
147
|
+
expect(recommendedIds).not.toContain('community/jest-helper');
|
|
148
|
+
});
|
|
149
|
+
it('should NOT recommend git-commit-helper when commit is installed', async () => {
|
|
150
|
+
const result = await executeRecommend({
|
|
151
|
+
installed_skills: ['anthropic/commit'],
|
|
152
|
+
detect_overlap: false, // Disable semantic overlap to test name-based filtering
|
|
153
|
+
limit: 50,
|
|
154
|
+
}, toolContext);
|
|
155
|
+
const recommendedIds = result.recommendations.map((r) => r.skill_id);
|
|
156
|
+
// git-commit-helper should be filtered because "git-commit-helper" contains "commit"
|
|
157
|
+
expect(recommendedIds).not.toContain('community/git-commit-helper');
|
|
158
|
+
// The installed skill itself should not be recommended
|
|
159
|
+
expect(recommendedIds).not.toContain('anthropic/commit');
|
|
160
|
+
});
|
|
161
|
+
it('should filter skills when only skill name (not full ID) is provided', async () => {
|
|
162
|
+
// Test with just "docker" as installed (simulating user-provided short name)
|
|
163
|
+
const result = await executeRecommend({
|
|
164
|
+
installed_skills: ['docker'],
|
|
165
|
+
detect_overlap: false,
|
|
166
|
+
limit: 50,
|
|
167
|
+
}, toolContext);
|
|
168
|
+
const recommendedIds = result.recommendations.map((r) => r.skill_id);
|
|
169
|
+
// Should filter docker-compose because "docker-compose" contains "docker"
|
|
170
|
+
expect(recommendedIds).not.toContain('community/docker-compose');
|
|
171
|
+
});
|
|
172
|
+
it('should handle case-insensitive name matching', async () => {
|
|
173
|
+
const result = await executeRecommend({
|
|
174
|
+
installed_skills: ['COMMUNITY/DOCKER'],
|
|
175
|
+
detect_overlap: false,
|
|
176
|
+
limit: 50,
|
|
177
|
+
}, toolContext);
|
|
178
|
+
const recommendedIds = result.recommendations.map((r) => r.skill_id);
|
|
179
|
+
// Should still filter docker-compose with case-insensitive matching
|
|
180
|
+
expect(recommendedIds).not.toContain('community/docker-compose');
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
describe('formatRecommendations', () => {
|
|
184
|
+
it('should format recommendations for terminal display', async () => {
|
|
185
|
+
const result = await executeRecommend({
|
|
186
|
+
installed_skills: [],
|
|
187
|
+
detect_overlap: false,
|
|
188
|
+
limit: 3,
|
|
189
|
+
}, toolContext);
|
|
190
|
+
const formatted = formatRecommendations(result);
|
|
191
|
+
expect(formatted).toContain('Skill Recommendations');
|
|
192
|
+
expect(formatted).toContain('Candidates considered:');
|
|
193
|
+
expect(formatted).toContain('Semantic matching: enabled');
|
|
194
|
+
});
|
|
195
|
+
it('should show no recommendations message when empty', async () => {
|
|
196
|
+
// Create a result with no recommendations
|
|
197
|
+
const emptyResult = {
|
|
198
|
+
recommendations: [],
|
|
199
|
+
candidates_considered: 0,
|
|
200
|
+
overlap_filtered: 0,
|
|
201
|
+
context: {
|
|
202
|
+
installed_count: 0,
|
|
203
|
+
has_project_context: false,
|
|
204
|
+
using_semantic_matching: true,
|
|
205
|
+
auto_detected: false,
|
|
206
|
+
},
|
|
207
|
+
timing: { totalMs: 1 },
|
|
208
|
+
};
|
|
209
|
+
const formatted = formatRecommendations(emptyResult);
|
|
210
|
+
expect(formatted).toContain('No recommendations found');
|
|
211
|
+
expect(formatted).toContain('Suggestions:');
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
//# sourceMappingURL=recommend.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recommend.integration.test.js","sourceRoot":"","sources":["../../../tests/integration/recommend.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.integration.test.d.ts","sourceRoot":"","sources":["../../../tests/integration/search.integration.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|