@skillmark/cli 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/cli-entry-point.d.ts +3 -0
- package/dist/cli-entry-point.d.ts.map +1 -0
- package/dist/cli-entry-point.js +207 -0
- package/dist/cli-entry-point.js.map +1 -0
- package/dist/commands/auth-setup-and-token-storage-command.d.ts +21 -0
- package/dist/commands/auth-setup-and-token-storage-command.d.ts.map +1 -0
- package/dist/commands/auth-setup-and-token-storage-command.js +166 -0
- package/dist/commands/auth-setup-and-token-storage-command.js.map +1 -0
- package/dist/commands/publish-results-command.d.ts +21 -0
- package/dist/commands/publish-results-command.d.ts.map +1 -0
- package/dist/commands/publish-results-command.js +256 -0
- package/dist/commands/publish-results-command.js.map +1 -0
- package/dist/commands/run-benchmark-command.d.ts +6 -0
- package/dist/commands/run-benchmark-command.d.ts.map +1 -0
- package/dist/commands/run-benchmark-command.js +331 -0
- package/dist/commands/run-benchmark-command.js.map +1 -0
- package/dist/commands/view-leaderboard-command.d.ts +8 -0
- package/dist/commands/view-leaderboard-command.d.ts.map +1 -0
- package/dist/commands/view-leaderboard-command.js +169 -0
- package/dist/commands/view-leaderboard-command.js.map +1 -0
- package/dist/config/api-key-config-reader.d.ts +14 -0
- package/dist/config/api-key-config-reader.d.ts.map +1 -0
- package/dist/config/api-key-config-reader.js +107 -0
- package/dist/config/api-key-config-reader.js.map +1 -0
- package/dist/config/api-key-config-reader.test.d.ts +2 -0
- package/dist/config/api-key-config-reader.test.d.ts.map +1 -0
- package/dist/config/api-key-config-reader.test.js +21 -0
- package/dist/config/api-key-config-reader.test.js.map +1 -0
- package/dist/engine/claude-cli-executor.d.ts +33 -0
- package/dist/engine/claude-cli-executor.d.ts.map +1 -0
- package/dist/engine/claude-cli-executor.js +251 -0
- package/dist/engine/claude-cli-executor.js.map +1 -0
- package/dist/engine/concept-accuracy-scorer.d.ts +24 -0
- package/dist/engine/concept-accuracy-scorer.d.ts.map +1 -0
- package/dist/engine/concept-accuracy-scorer.js +186 -0
- package/dist/engine/concept-accuracy-scorer.js.map +1 -0
- package/dist/engine/concept-accuracy-scorer.test.d.ts +2 -0
- package/dist/engine/concept-accuracy-scorer.test.d.ts.map +1 -0
- package/dist/engine/concept-accuracy-scorer.test.js +230 -0
- package/dist/engine/concept-accuracy-scorer.test.js.map +1 -0
- package/dist/engine/enhanced-test-prompt-builder.d.ts +30 -0
- package/dist/engine/enhanced-test-prompt-builder.d.ts.map +1 -0
- package/dist/engine/enhanced-test-prompt-builder.js +134 -0
- package/dist/engine/enhanced-test-prompt-builder.js.map +1 -0
- package/dist/engine/markdown-test-definition-parser.d.ts +18 -0
- package/dist/engine/markdown-test-definition-parser.d.ts.map +1 -0
- package/dist/engine/markdown-test-definition-parser.js +525 -0
- package/dist/engine/markdown-test-definition-parser.js.map +1 -0
- package/dist/engine/markdown-test-definition-parser.test.d.ts +2 -0
- package/dist/engine/markdown-test-definition-parser.test.d.ts.map +1 -0
- package/dist/engine/markdown-test-definition-parser.test.js +265 -0
- package/dist/engine/markdown-test-definition-parser.test.js.map +1 -0
- package/dist/engine/retry-with-degrade-utils.d.ts +58 -0
- package/dist/engine/retry-with-degrade-utils.d.ts.map +1 -0
- package/dist/engine/retry-with-degrade-utils.js +86 -0
- package/dist/engine/retry-with-degrade-utils.js.map +1 -0
- package/dist/engine/skill-content-collector.d.ts +53 -0
- package/dist/engine/skill-content-collector.d.ts.map +1 -0
- package/dist/engine/skill-content-collector.js +157 -0
- package/dist/engine/skill-content-collector.js.map +1 -0
- package/dist/engine/skill-creator-invoker.d.ts +36 -0
- package/dist/engine/skill-creator-invoker.d.ts.map +1 -0
- package/dist/engine/skill-creator-invoker.js +222 -0
- package/dist/engine/skill-creator-invoker.js.map +1 -0
- package/dist/engine/transcript-jsonl-parser.d.ts +28 -0
- package/dist/engine/transcript-jsonl-parser.d.ts.map +1 -0
- package/dist/engine/transcript-jsonl-parser.js +175 -0
- package/dist/engine/transcript-jsonl-parser.js.map +1 -0
- package/dist/sources/git-repository-skill-source-handler.d.ts +18 -0
- package/dist/sources/git-repository-skill-source-handler.d.ts.map +1 -0
- package/dist/sources/git-repository-skill-source-handler.js +119 -0
- package/dist/sources/git-repository-skill-source-handler.js.map +1 -0
- package/dist/sources/local-skill-source-handler.d.ts +21 -0
- package/dist/sources/local-skill-source-handler.d.ts.map +1 -0
- package/dist/sources/local-skill-source-handler.js +138 -0
- package/dist/sources/local-skill-source-handler.js.map +1 -0
- package/dist/sources/local-skill-source-handler.test.d.ts +2 -0
- package/dist/sources/local-skill-source-handler.test.d.ts.map +1 -0
- package/dist/sources/local-skill-source-handler.test.js +55 -0
- package/dist/sources/local-skill-source-handler.test.js.map +1 -0
- package/dist/sources/skillsh-registry-source-handler.d.ts +18 -0
- package/dist/sources/skillsh-registry-source-handler.d.ts.map +1 -0
- package/dist/sources/skillsh-registry-source-handler.js +130 -0
- package/dist/sources/skillsh-registry-source-handler.js.map +1 -0
- package/dist/sources/unified-skill-source-resolver.d.ts +20 -0
- package/dist/sources/unified-skill-source-resolver.d.ts.map +1 -0
- package/dist/sources/unified-skill-source-resolver.js +64 -0
- package/dist/sources/unified-skill-source-resolver.js.map +1 -0
- package/dist/sources/unified-skill-source-resolver.test.d.ts +2 -0
- package/dist/sources/unified-skill-source-resolver.test.d.ts.map +1 -0
- package/dist/sources/unified-skill-source-resolver.test.js +84 -0
- package/dist/sources/unified-skill-source-resolver.test.js.map +1 -0
- package/dist/types/benchmark-types.d.ts +142 -0
- package/dist/types/benchmark-types.d.ts.map +1 -0
- package/dist/types/benchmark-types.js +5 -0
- package/dist/types/benchmark-types.js.map +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local skill source handler - loads skills from local filesystem paths
|
|
3
|
+
*/
|
|
4
|
+
import { access, readdir, readFile, stat } from 'node:fs/promises';
|
|
5
|
+
import { basename, join, resolve } from 'node:path';
|
|
6
|
+
/** Files that indicate a skill directory */
|
|
7
|
+
const SKILL_INDICATORS = ['SKILL.md', 'skill.md', 'README.md', 'index.ts', 'index.js'];
|
|
8
|
+
/**
|
|
9
|
+
* Check if a path is a local skill source
|
|
10
|
+
*/
|
|
11
|
+
export function isLocalSource(source) {
|
|
12
|
+
// Local paths start with /, ./, ../, or are just directory names
|
|
13
|
+
return (source.startsWith('/') ||
|
|
14
|
+
source.startsWith('./') ||
|
|
15
|
+
source.startsWith('../') ||
|
|
16
|
+
source.startsWith('~') ||
|
|
17
|
+
(!source.includes('://') && !source.includes('/') && !source.startsWith('skill.sh')));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Resolve a local skill source
|
|
21
|
+
*/
|
|
22
|
+
export async function resolveLocalSource(source) {
|
|
23
|
+
// Expand ~ to home directory
|
|
24
|
+
let resolvedPath = source;
|
|
25
|
+
if (source.startsWith('~')) {
|
|
26
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
27
|
+
resolvedPath = source.replace('~', home);
|
|
28
|
+
}
|
|
29
|
+
// Make absolute
|
|
30
|
+
resolvedPath = resolve(resolvedPath);
|
|
31
|
+
// Verify path exists
|
|
32
|
+
try {
|
|
33
|
+
await access(resolvedPath);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
throw new Error(`Skill path not found: ${source}`);
|
|
37
|
+
}
|
|
38
|
+
// Check if it's a directory or file
|
|
39
|
+
const stats = await stat(resolvedPath);
|
|
40
|
+
if (stats.isFile()) {
|
|
41
|
+
// Single file skill (e.g., SKILL.md)
|
|
42
|
+
return {
|
|
43
|
+
type: 'local',
|
|
44
|
+
original: source,
|
|
45
|
+
localPath: resolvedPath,
|
|
46
|
+
name: extractSkillName(resolvedPath),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (stats.isDirectory()) {
|
|
50
|
+
// Validate it looks like a skill directory
|
|
51
|
+
const isValid = await validateSkillDirectory(resolvedPath);
|
|
52
|
+
if (!isValid) {
|
|
53
|
+
throw new Error(`Directory does not appear to be a skill: ${source}\n` +
|
|
54
|
+
`Expected one of: ${SKILL_INDICATORS.join(', ')}`);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
type: 'local',
|
|
58
|
+
original: source,
|
|
59
|
+
localPath: resolvedPath,
|
|
60
|
+
name: extractSkillName(resolvedPath),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
throw new Error(`Invalid skill path (not a file or directory): ${source}`);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Validate that a directory contains skill files
|
|
67
|
+
*/
|
|
68
|
+
async function validateSkillDirectory(dirPath) {
|
|
69
|
+
try {
|
|
70
|
+
const files = await readdir(dirPath);
|
|
71
|
+
return SKILL_INDICATORS.some((indicator) => files.some((f) => f.toLowerCase() === indicator.toLowerCase()));
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Extract skill name from path
|
|
79
|
+
*/
|
|
80
|
+
function extractSkillName(skillPath) {
|
|
81
|
+
const base = basename(skillPath);
|
|
82
|
+
// If it's a file, use parent directory name
|
|
83
|
+
if (base.includes('.')) {
|
|
84
|
+
const parentDir = basename(resolve(skillPath, '..'));
|
|
85
|
+
return parentDir;
|
|
86
|
+
}
|
|
87
|
+
return base;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Find test files in a skill directory
|
|
91
|
+
*/
|
|
92
|
+
export async function findTestsInSkillDir(skillPath) {
|
|
93
|
+
const testsDir = join(skillPath, 'tests');
|
|
94
|
+
try {
|
|
95
|
+
await access(testsDir);
|
|
96
|
+
const files = await readdir(testsDir);
|
|
97
|
+
return files
|
|
98
|
+
.filter((f) => f.endsWith('.md'))
|
|
99
|
+
.map((f) => join(testsDir, f));
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// No tests directory, look for test files in root
|
|
103
|
+
try {
|
|
104
|
+
const files = await readdir(skillPath);
|
|
105
|
+
return files
|
|
106
|
+
.filter((f) => f.endsWith('.test.md') || f.startsWith('test-'))
|
|
107
|
+
.map((f) => join(skillPath, f));
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Read skill metadata from SKILL.md or README.md
|
|
116
|
+
*/
|
|
117
|
+
export async function readSkillMetadata(skillPath) {
|
|
118
|
+
const stats = await stat(skillPath);
|
|
119
|
+
const dir = stats.isDirectory() ? skillPath : resolve(skillPath, '..');
|
|
120
|
+
for (const filename of ['SKILL.md', 'skill.md', 'README.md']) {
|
|
121
|
+
const filePath = join(dir, filename);
|
|
122
|
+
try {
|
|
123
|
+
const content = await readFile(filePath, 'utf-8');
|
|
124
|
+
// Extract name from first heading
|
|
125
|
+
const nameMatch = content.match(/^#\s+(.+)$/m);
|
|
126
|
+
const name = nameMatch ? nameMatch[1].trim() : basename(dir);
|
|
127
|
+
// Extract description from first paragraph after heading
|
|
128
|
+
const descMatch = content.match(/^#.+\n\n(.+?)(?:\n\n|$)/s);
|
|
129
|
+
const description = descMatch ? descMatch[1].trim() : '';
|
|
130
|
+
return { name, description };
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=local-skill-source-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-skill-source-handler.js","sourceRoot":"","sources":["../../src/sources/local-skill-source-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-skill-source-handler.test.d.ts","sourceRoot":"","sources":["../../src/sources/local-skill-source-handler.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for local-skill-source-handler.ts
|
|
3
|
+
* Verifies local path detection and validation
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, expect } from 'vitest';
|
|
6
|
+
import { isLocalSource } from './local-skill-source-handler.js';
|
|
7
|
+
describe('isLocalSource', () => {
|
|
8
|
+
describe('absolute paths', () => {
|
|
9
|
+
it('returns true for paths starting with /', () => {
|
|
10
|
+
expect(isLocalSource('/Users/me/skill')).toBe(true);
|
|
11
|
+
expect(isLocalSource('/home/user/.claude/skills/test')).toBe(true);
|
|
12
|
+
expect(isLocalSource('/')).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
describe('relative paths', () => {
|
|
16
|
+
it('returns true for paths starting with ./', () => {
|
|
17
|
+
expect(isLocalSource('./skill')).toBe(true);
|
|
18
|
+
expect(isLocalSource('./path/to/skill')).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
it('returns true for paths starting with ../', () => {
|
|
21
|
+
expect(isLocalSource('../skill')).toBe(true);
|
|
22
|
+
expect(isLocalSource('../../skills/test')).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
describe('home directory paths', () => {
|
|
26
|
+
it('returns true for paths starting with ~', () => {
|
|
27
|
+
expect(isLocalSource('~/.claude/skills/my-skill')).toBe(true);
|
|
28
|
+
expect(isLocalSource('~/skills')).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe('simple directory names', () => {
|
|
32
|
+
it('returns true for names without slashes or protocols', () => {
|
|
33
|
+
expect(isLocalSource('my-skill')).toBe(true);
|
|
34
|
+
expect(isLocalSource('test-skill-v2')).toBe(true);
|
|
35
|
+
expect(isLocalSource('skill_name')).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe('non-local sources', () => {
|
|
39
|
+
it('returns false for URLs with protocol', () => {
|
|
40
|
+
expect(isLocalSource('https://github.com/user/repo')).toBe(false);
|
|
41
|
+
expect(isLocalSource('git://github.com/user/repo')).toBe(false);
|
|
42
|
+
expect(isLocalSource('http://example.com/skill')).toBe(false);
|
|
43
|
+
});
|
|
44
|
+
it('returns false for skill.sh references', () => {
|
|
45
|
+
expect(isLocalSource('skill.sh/user/my-skill')).toBe(false);
|
|
46
|
+
expect(isLocalSource('skill.sh/org/test')).toBe(false);
|
|
47
|
+
});
|
|
48
|
+
it('returns false for paths with slashes that look like org/repo', () => {
|
|
49
|
+
// These are treated as potential git shorthand (user/repo)
|
|
50
|
+
expect(isLocalSource('user/repo')).toBe(false);
|
|
51
|
+
expect(isLocalSource('org/skill-name')).toBe(false);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
//# sourceMappingURL=local-skill-source-handler.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-skill-source-handler.test.js","sourceRoot":"","sources":["../../src/sources/local-skill-source-handler.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SkillSource } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Check if a source is a skill.sh reference
|
|
4
|
+
*/
|
|
5
|
+
export declare function isSkillshSource(source: string): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Resolve a skill.sh source by downloading the skill
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveSkillshSource(source: string): Promise<SkillSource>;
|
|
10
|
+
/**
|
|
11
|
+
* List available skills from a user on skill.sh
|
|
12
|
+
*/
|
|
13
|
+
export declare function listUserSkills(user: string): Promise<string[]>;
|
|
14
|
+
/**
|
|
15
|
+
* Clean up skill.sh cache
|
|
16
|
+
*/
|
|
17
|
+
export declare function cleanSkillshCache(): Promise<void>;
|
|
18
|
+
//# sourceMappingURL=skillsh-registry-source-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillsh-registry-source-handler.d.ts","sourceRoot":"","sources":["../../src/sources/skillsh-registry-source-handler.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAerD;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEvD;AAyBD;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA4C/E;AA8BD;;GAEG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAcpE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAMvD"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skill.sh registry source handler - downloads skills from skill.sh registry
|
|
3
|
+
*/
|
|
4
|
+
import { mkdir, rm, writeFile } from 'node:fs/promises';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
/** skill.sh URL patterns */
|
|
7
|
+
const SKILLSH_PATTERNS = [
|
|
8
|
+
/^skill\.sh\//,
|
|
9
|
+
/^https?:\/\/skill\.sh\//,
|
|
10
|
+
/^skillsh:/,
|
|
11
|
+
];
|
|
12
|
+
/** Cache directory for skill.sh downloads */
|
|
13
|
+
const CACHE_DIR = join(process.env.HOME || '/tmp', '.skillmark', 'skillsh-cache');
|
|
14
|
+
/** skill.sh API base URL */
|
|
15
|
+
const SKILLSH_API = 'https://skill.sh/api';
|
|
16
|
+
/**
|
|
17
|
+
* Check if a source is a skill.sh reference
|
|
18
|
+
*/
|
|
19
|
+
export function isSkillshSource(source) {
|
|
20
|
+
return SKILLSH_PATTERNS.some((pattern) => pattern.test(source));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Parse skill.sh reference to get user and skill name
|
|
24
|
+
*/
|
|
25
|
+
function parseSkillshRef(source) {
|
|
26
|
+
// Remove prefix
|
|
27
|
+
let cleaned = source
|
|
28
|
+
.replace(/^skill\.sh\//, '')
|
|
29
|
+
.replace(/^https?:\/\/skill\.sh\//, '')
|
|
30
|
+
.replace(/^skillsh:/, '');
|
|
31
|
+
// Parse user/name@version format
|
|
32
|
+
const versionMatch = cleaned.match(/^(.+)@(.+)$/);
|
|
33
|
+
if (versionMatch) {
|
|
34
|
+
cleaned = versionMatch[1];
|
|
35
|
+
const version = versionMatch[2];
|
|
36
|
+
const [user, name] = cleaned.split('/');
|
|
37
|
+
return { user, name, version };
|
|
38
|
+
}
|
|
39
|
+
const [user, name] = cleaned.split('/');
|
|
40
|
+
return { user, name };
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Resolve a skill.sh source by downloading the skill
|
|
44
|
+
*/
|
|
45
|
+
export async function resolveSkillshSource(source) {
|
|
46
|
+
const { user, name, version } = parseSkillshRef(source);
|
|
47
|
+
const cacheId = version ? `${user}-${name}-${version}` : `${user}-${name}`;
|
|
48
|
+
const localPath = join(CACHE_DIR, cacheId);
|
|
49
|
+
await mkdir(CACHE_DIR, { recursive: true });
|
|
50
|
+
try {
|
|
51
|
+
// Try to fetch from skill.sh API
|
|
52
|
+
const skillContent = await fetchSkillFromRegistry(user, name, version);
|
|
53
|
+
// Write to cache
|
|
54
|
+
await rm(localPath, { recursive: true, force: true });
|
|
55
|
+
await mkdir(localPath, { recursive: true });
|
|
56
|
+
// Write SKILL.md
|
|
57
|
+
await writeFile(join(localPath, 'SKILL.md'), skillContent);
|
|
58
|
+
return {
|
|
59
|
+
type: 'skillsh',
|
|
60
|
+
original: source,
|
|
61
|
+
localPath,
|
|
62
|
+
name: `${user}/${name}`,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
// Fallback: try to clone from GitHub if skill.sh API fails
|
|
67
|
+
// Many skill.sh skills are hosted on GitHub
|
|
68
|
+
const githubUrl = `https://github.com/${user}/${name}`;
|
|
69
|
+
try {
|
|
70
|
+
const { resolveGitSource } = await import('./git-repository-skill-source-handler.js');
|
|
71
|
+
const gitSource = await resolveGitSource(githubUrl);
|
|
72
|
+
return {
|
|
73
|
+
...gitSource,
|
|
74
|
+
type: 'skillsh',
|
|
75
|
+
original: source,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
throw new Error(`Failed to fetch skill from skill.sh: ${source}\n` +
|
|
80
|
+
`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Fetch skill content from skill.sh registry
|
|
86
|
+
*/
|
|
87
|
+
async function fetchSkillFromRegistry(user, name, version) {
|
|
88
|
+
const url = version
|
|
89
|
+
? `${SKILLSH_API}/skills/${user}/${name}/versions/${version}`
|
|
90
|
+
: `${SKILLSH_API}/skills/${user}/${name}/latest`;
|
|
91
|
+
const response = await fetch(url);
|
|
92
|
+
if (!response.ok) {
|
|
93
|
+
throw new Error(`skill.sh API returned ${response.status}: ${response.statusText}`);
|
|
94
|
+
}
|
|
95
|
+
const data = (await response.json());
|
|
96
|
+
const content = data.content || data.skill?.content;
|
|
97
|
+
if (!content) {
|
|
98
|
+
throw new Error('No skill content found in response');
|
|
99
|
+
}
|
|
100
|
+
return content;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* List available skills from a user on skill.sh
|
|
104
|
+
*/
|
|
105
|
+
export async function listUserSkills(user) {
|
|
106
|
+
const url = `${SKILLSH_API}/users/${user}/skills`;
|
|
107
|
+
try {
|
|
108
|
+
const response = await fetch(url);
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
const data = (await response.json());
|
|
113
|
+
return data.skills?.map((s) => s.name) || [];
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Clean up skill.sh cache
|
|
121
|
+
*/
|
|
122
|
+
export async function cleanSkillshCache() {
|
|
123
|
+
try {
|
|
124
|
+
await rm(CACHE_DIR, { recursive: true, force: true });
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Ignore errors
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=skillsh-registry-source-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillsh-registry-source-handler.js","sourceRoot":"","sources":["../../src/sources/skillsh-registry-source-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified skill source resolver - routes to appropriate handler based on source type
|
|
3
|
+
*/
|
|
4
|
+
import type { SkillSource } from '../types/index.js';
|
|
5
|
+
/**
|
|
6
|
+
* Detect source type from input string
|
|
7
|
+
*/
|
|
8
|
+
export declare function detectSourceType(source: string): 'local' | 'git' | 'skillsh' | 'unknown';
|
|
9
|
+
/**
|
|
10
|
+
* Resolve any skill source to a local path
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveSkillSource(source: string): Promise<SkillSource>;
|
|
13
|
+
/**
|
|
14
|
+
* Format source for display
|
|
15
|
+
*/
|
|
16
|
+
export declare function formatSourceDisplay(source: SkillSource): string;
|
|
17
|
+
export { isLocalSource, resolveLocalSource } from './local-skill-source-handler.js';
|
|
18
|
+
export { isGitSource, resolveGitSource, cleanGitCache } from './git-repository-skill-source-handler.js';
|
|
19
|
+
export { isSkillshSource, resolveSkillshSource, cleanSkillshCache } from './skillsh-registry-source-handler.js';
|
|
20
|
+
//# sourceMappingURL=unified-skill-source-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unified-skill-source-resolver.d.ts","sourceRoot":"","sources":["../../src/sources/unified-skill-source-resolver.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKrD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,CAKxF;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA6B7E;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAW/D;AAGD,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AACxG,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { isLocalSource, resolveLocalSource } from './local-skill-source-handler.js';
|
|
2
|
+
import { isGitSource, resolveGitSource } from './git-repository-skill-source-handler.js';
|
|
3
|
+
import { isSkillshSource, resolveSkillshSource } from './skillsh-registry-source-handler.js';
|
|
4
|
+
/**
|
|
5
|
+
* Detect source type from input string
|
|
6
|
+
*/
|
|
7
|
+
export function detectSourceType(source) {
|
|
8
|
+
if (isSkillshSource(source))
|
|
9
|
+
return 'skillsh';
|
|
10
|
+
if (isGitSource(source))
|
|
11
|
+
return 'git';
|
|
12
|
+
if (isLocalSource(source))
|
|
13
|
+
return 'local';
|
|
14
|
+
return 'unknown';
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resolve any skill source to a local path
|
|
18
|
+
*/
|
|
19
|
+
export async function resolveSkillSource(source) {
|
|
20
|
+
const sourceType = detectSourceType(source);
|
|
21
|
+
switch (sourceType) {
|
|
22
|
+
case 'local':
|
|
23
|
+
return resolveLocalSource(source);
|
|
24
|
+
case 'git':
|
|
25
|
+
return resolveGitSource(source);
|
|
26
|
+
case 'skillsh':
|
|
27
|
+
return resolveSkillshSource(source);
|
|
28
|
+
case 'unknown':
|
|
29
|
+
default:
|
|
30
|
+
// Try local first, then git
|
|
31
|
+
try {
|
|
32
|
+
return await resolveLocalSource(source);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
try {
|
|
36
|
+
return await resolveGitSource(`https://github.com/${source}`);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
throw new Error(`Unable to resolve skill source: ${source}\n` +
|
|
40
|
+
'Expected: local path, git URL, or skill.sh reference');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Format source for display
|
|
47
|
+
*/
|
|
48
|
+
export function formatSourceDisplay(source) {
|
|
49
|
+
switch (source.type) {
|
|
50
|
+
case 'local':
|
|
51
|
+
return `Local: ${source.localPath}`;
|
|
52
|
+
case 'git':
|
|
53
|
+
return `Git: ${source.original}`;
|
|
54
|
+
case 'skillsh':
|
|
55
|
+
return `skill.sh: ${source.original}`;
|
|
56
|
+
default:
|
|
57
|
+
return source.original;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Re-export individual handlers for direct use
|
|
61
|
+
export { isLocalSource, resolveLocalSource } from './local-skill-source-handler.js';
|
|
62
|
+
export { isGitSource, resolveGitSource, cleanGitCache } from './git-repository-skill-source-handler.js';
|
|
63
|
+
export { isSkillshSource, resolveSkillshSource, cleanSkillshCache } from './skillsh-registry-source-handler.js';
|
|
64
|
+
//# sourceMappingURL=unified-skill-source-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unified-skill-source-resolver.js","sourceRoot":"","sources":["../../src/sources/unified-skill-source-resolver.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AACzF,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAE7F;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,IAAI,eAAe,CAAC,MAAM,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,IAAI,WAAW,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IACtC,IAAI,aAAa,CAAC,MAAM,CAAC;QAAE,OAAO,OAAO,CAAC;IAC1C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAc;IACrD,MAAM,UAAU,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAE5C,QAAQ,UAAU,EAAE,CAAC;QACnB,KAAK,OAAO;YACV,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAC;QAEpC,KAAK,KAAK;YACR,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAElC,KAAK,SAAS;YACZ,OAAO,oBAAoB,CAAC,MAAM,CAAC,CAAC;QAEtC,KAAK,SAAS,CAAC;QACf;YACE,4BAA4B;YAC5B,IAAI,CAAC;gBACH,OAAO,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC;YAC1C,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,CAAC;oBACH,OAAO,MAAM,gBAAgB,CAAC,sBAAsB,MAAM,EAAE,CAAC,CAAC;gBAChE,CAAC;gBAAC,MAAM,CAAC;oBACP,MAAM,IAAI,KAAK,CACb,mCAAmC,MAAM,IAAI;wBAC3C,sDAAsD,CACzD,CAAC;gBACJ,CAAC;YACH,CAAC;IACL,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAmB;IACrD,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,OAAO;YACV,OAAO,UAAU,MAAM,CAAC,SAAS,EAAE,CAAC;QACtC,KAAK,KAAK;YACR,OAAO,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;QACnC,KAAK,SAAS;YACZ,OAAO,aAAa,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxC;YACE,OAAO,MAAM,CAAC,QAAQ,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,+CAA+C;AAC/C,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AACxG,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unified-skill-source-resolver.test.d.ts","sourceRoot":"","sources":["../../src/sources/unified-skill-source-resolver.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for unified-skill-source-resolver.ts
|
|
3
|
+
* Verifies source type detection and routing logic
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it, expect } from 'vitest';
|
|
6
|
+
import { detectSourceType, formatSourceDisplay } from './unified-skill-source-resolver.js';
|
|
7
|
+
describe('detectSourceType', () => {
|
|
8
|
+
describe('local sources', () => {
|
|
9
|
+
it('detects absolute paths starting with /', () => {
|
|
10
|
+
expect(detectSourceType('/Users/me/skills/my-skill')).toBe('local');
|
|
11
|
+
expect(detectSourceType('/home/user/.claude/skills/test')).toBe('local');
|
|
12
|
+
});
|
|
13
|
+
it('detects relative paths starting with ./', () => {
|
|
14
|
+
expect(detectSourceType('./my-skill')).toBe('local');
|
|
15
|
+
expect(detectSourceType('./path/to/skill')).toBe('local');
|
|
16
|
+
});
|
|
17
|
+
it('detects parent relative paths starting with ../', () => {
|
|
18
|
+
expect(detectSourceType('../my-skill')).toBe('local');
|
|
19
|
+
expect(detectSourceType('../../skills/test')).toBe('local');
|
|
20
|
+
});
|
|
21
|
+
it('detects home directory paths starting with ~', () => {
|
|
22
|
+
expect(detectSourceType('~/.claude/skills/my-skill')).toBe('local');
|
|
23
|
+
expect(detectSourceType('~/skills/test')).toBe('local');
|
|
24
|
+
});
|
|
25
|
+
it('detects simple directory names without slashes', () => {
|
|
26
|
+
expect(detectSourceType('my-skill')).toBe('local');
|
|
27
|
+
expect(detectSourceType('test-skill-v2')).toBe('local');
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
describe('git sources', () => {
|
|
31
|
+
it('detects https:// git URLs', () => {
|
|
32
|
+
expect(detectSourceType('https://github.com/user/repo')).toBe('git');
|
|
33
|
+
expect(detectSourceType('https://gitlab.com/user/repo.git')).toBe('git');
|
|
34
|
+
});
|
|
35
|
+
it('detects git:// protocol URLs', () => {
|
|
36
|
+
expect(detectSourceType('git://github.com/user/repo')).toBe('git');
|
|
37
|
+
});
|
|
38
|
+
it('detects SSH git URLs', () => {
|
|
39
|
+
expect(detectSourceType('git@github.com:user/repo.git')).toBe('git');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe('skill.sh sources', () => {
|
|
43
|
+
it('detects skill.sh/ prefixed references', () => {
|
|
44
|
+
expect(detectSourceType('skill.sh/user/my-skill')).toBe('skillsh');
|
|
45
|
+
expect(detectSourceType('skill.sh/org/advanced-skill')).toBe('skillsh');
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
describe('unknown sources', () => {
|
|
49
|
+
it('returns unknown for unrecognized patterns', () => {
|
|
50
|
+
// Note: This case is handled by fallback logic in resolveSkillSource
|
|
51
|
+
// detectSourceType may classify some edge cases differently
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
describe('formatSourceDisplay', () => {
|
|
56
|
+
it('formats local source correctly', () => {
|
|
57
|
+
const source = {
|
|
58
|
+
type: 'local',
|
|
59
|
+
original: './my-skill',
|
|
60
|
+
localPath: '/Users/me/projects/my-skill',
|
|
61
|
+
name: 'my-skill',
|
|
62
|
+
};
|
|
63
|
+
expect(formatSourceDisplay(source)).toBe('Local: /Users/me/projects/my-skill');
|
|
64
|
+
});
|
|
65
|
+
it('formats git source correctly', () => {
|
|
66
|
+
const source = {
|
|
67
|
+
type: 'git',
|
|
68
|
+
original: 'https://github.com/user/skill-repo',
|
|
69
|
+
localPath: '/tmp/skillmark-cache/skill-repo',
|
|
70
|
+
name: 'skill-repo',
|
|
71
|
+
};
|
|
72
|
+
expect(formatSourceDisplay(source)).toBe('Git: https://github.com/user/skill-repo');
|
|
73
|
+
});
|
|
74
|
+
it('formats skill.sh source correctly', () => {
|
|
75
|
+
const source = {
|
|
76
|
+
type: 'skillsh',
|
|
77
|
+
original: 'skill.sh/user/my-skill',
|
|
78
|
+
localPath: '/tmp/skillmark-cache/my-skill',
|
|
79
|
+
name: 'my-skill',
|
|
80
|
+
};
|
|
81
|
+
expect(formatSourceDisplay(source)).toBe('skill.sh: skill.sh/user/my-skill');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=unified-skill-source-resolver.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unified-skill-source-resolver.test.js","sourceRoot":"","sources":["../../src/sources/unified-skill-source-resolver.test.ts"],"names":[],"mappings":"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"}
|