openskills-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/LICENSE +21 -0
- package/README.md +99 -0
- package/dist/bin/cli.d.ts +10 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +133 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/src/modes/install.d.ts +32 -0
- package/dist/src/modes/install.d.ts.map +1 -0
- package/dist/src/modes/install.js +215 -0
- package/dist/src/modes/install.js.map +1 -0
- package/dist/src/modes/mcp-proxy.d.ts +16 -0
- package/dist/src/modes/mcp-proxy.d.ts.map +1 -0
- package/dist/src/modes/mcp-proxy.js +117 -0
- package/dist/src/modes/mcp-proxy.js.map +1 -0
- package/dist/src/services/downloader.d.ts +32 -0
- package/dist/src/services/downloader.d.ts.map +1 -0
- package/dist/src/services/downloader.js +125 -0
- package/dist/src/services/downloader.js.map +1 -0
- package/dist/src/services/extractor.d.ts +38 -0
- package/dist/src/services/extractor.d.ts.map +1 -0
- package/dist/src/services/extractor.js +82 -0
- package/dist/src/services/extractor.js.map +1 -0
- package/dist/src/services/symlink.d.ts +64 -0
- package/dist/src/services/symlink.d.ts.map +1 -0
- package/dist/src/services/symlink.js +153 -0
- package/dist/src/services/symlink.js.map +1 -0
- package/dist/src/types/index.d.ts +75 -0
- package/dist/src/types/index.d.ts.map +1 -0
- package/dist/src/types/index.js +5 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/utils/agent-dirs.d.ts +49 -0
- package/dist/src/utils/agent-dirs.d.ts.map +1 -0
- package/dist/src/utils/agent-dirs.js +116 -0
- package/dist/src/utils/agent-dirs.js.map +1 -0
- package/dist/src/utils/constants.d.ts +16 -0
- package/dist/src/utils/constants.d.ts.map +1 -0
- package/dist/src/utils/constants.js +21 -0
- package/dist/src/utils/constants.js.map +1 -0
- package/dist/src/utils/errors.d.ts +72 -0
- package/dist/src/utils/errors.d.ts.map +1 -0
- package/dist/src/utils/errors.js +108 -0
- package/dist/src/utils/errors.js.map +1 -0
- package/dist/src/utils/logger.d.ts +41 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/src/utils/logger.js +85 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/dist/src/utils/mode-detector.d.ts +74 -0
- package/dist/src/utils/mode-detector.d.ts.map +1 -0
- package/dist/src/utils/mode-detector.js +156 -0
- package/dist/src/utils/mode-detector.js.map +1 -0
- package/dist/src/utils/prompts.d.ts +22 -0
- package/dist/src/utils/prompts.d.ts.map +1 -0
- package/dist/src/utils/prompts.js +69 -0
- package/dist/src/utils/prompts.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-proxy.js","sourceRoot":"","sources":["../../../src/modes/mcp-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Downloader service for fetching skills.
|
|
3
|
+
*
|
|
4
|
+
* Uses server-side sparse checkout with on-demand zip generation.
|
|
5
|
+
* No git required on client - server handles everything.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Fetch skill zip from backend (server generates on-demand).
|
|
9
|
+
*
|
|
10
|
+
* @param skillSlug - Skill identifier (e.g., 'pdf-processing')
|
|
11
|
+
* @param outputDir - Directory to save zip file
|
|
12
|
+
* @returns Path to downloaded zip file
|
|
13
|
+
* @throws Error if skill not found or download fails
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const zipPath = await fetchSkillZip('pdf-processing', '/tmp');
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function fetchSkillZip(skillSlug: string, outputDir: string): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Validate zip file integrity.
|
|
23
|
+
*
|
|
24
|
+
* Checks:
|
|
25
|
+
* - File exists
|
|
26
|
+
* - File is not empty
|
|
27
|
+
*
|
|
28
|
+
* @param zipPath - Path to zip file
|
|
29
|
+
* @throws Error if validation fails
|
|
30
|
+
*/
|
|
31
|
+
export declare function validateZip(zipPath: string): void;
|
|
32
|
+
//# sourceMappingURL=downloader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"downloader.d.ts","sourceRoot":"","sources":["../../../src/services/downloader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2BH;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkFzF;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAUjD"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Downloader service for fetching skills.
|
|
3
|
+
*
|
|
4
|
+
* Uses server-side sparse checkout with on-demand zip generation.
|
|
5
|
+
* No git required on client - server handles everything.
|
|
6
|
+
*/
|
|
7
|
+
import fetch from 'node-fetch';
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
const BACKEND_URL = process.env.OPENSKILLS_BACKEND_URL || 'https://sangrasi-openskills-mcp.hf.space';
|
|
11
|
+
const MAX_RETRIES = 3;
|
|
12
|
+
const INITIAL_RETRY_DELAY = 1000; // 1 second
|
|
13
|
+
/**
|
|
14
|
+
* Exponential backoff delay calculation.
|
|
15
|
+
*
|
|
16
|
+
* @param attempt - Retry attempt number (0-indexed)
|
|
17
|
+
* @returns Delay in milliseconds
|
|
18
|
+
*/
|
|
19
|
+
function getRetryDelay(attempt) {
|
|
20
|
+
return INITIAL_RETRY_DELAY * Math.pow(2, attempt);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Sleep for specified milliseconds.
|
|
24
|
+
*/
|
|
25
|
+
function sleep(ms) {
|
|
26
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Fetch skill zip from backend (server generates on-demand).
|
|
30
|
+
*
|
|
31
|
+
* @param skillSlug - Skill identifier (e.g., 'pdf-processing')
|
|
32
|
+
* @param outputDir - Directory to save zip file
|
|
33
|
+
* @returns Path to downloaded zip file
|
|
34
|
+
* @throws Error if skill not found or download fails
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* const zipPath = await fetchSkillZip('pdf-processing', '/tmp');
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export async function fetchSkillZip(skillSlug, outputDir) {
|
|
42
|
+
const url = `${BACKEND_URL}/api/v1/download/${skillSlug}`;
|
|
43
|
+
const zipPath = path.join(outputDir, `${skillSlug}.zip`);
|
|
44
|
+
let lastError = null;
|
|
45
|
+
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
46
|
+
try {
|
|
47
|
+
console.log(` Downloading from server...`);
|
|
48
|
+
const response = await fetch(url);
|
|
49
|
+
if (response.ok) {
|
|
50
|
+
// Ensure output directory exists
|
|
51
|
+
if (!fs.existsSync(outputDir)) {
|
|
52
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
53
|
+
}
|
|
54
|
+
// Get content length for progress
|
|
55
|
+
const contentLength = parseInt(response.headers.get('content-length') || '0');
|
|
56
|
+
const showProgress = contentLength > 1024 * 1024; // Show for files >1MB
|
|
57
|
+
// Write to file
|
|
58
|
+
const fileStream = fs.createWriteStream(zipPath);
|
|
59
|
+
let downloadedBytes = 0;
|
|
60
|
+
if (!response.body) {
|
|
61
|
+
throw new Error('Response body is null');
|
|
62
|
+
}
|
|
63
|
+
for await (const chunk of response.body) {
|
|
64
|
+
fileStream.write(chunk);
|
|
65
|
+
downloadedBytes += chunk.length;
|
|
66
|
+
if (showProgress && contentLength > 0) {
|
|
67
|
+
const percent = ((downloadedBytes / contentLength) * 100).toFixed(1);
|
|
68
|
+
process.stderr.write(`\r Downloading: ${percent}%`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Wait for stream to finish
|
|
72
|
+
await new Promise((resolve, reject) => {
|
|
73
|
+
fileStream.end(() => resolve());
|
|
74
|
+
fileStream.on('error', reject);
|
|
75
|
+
});
|
|
76
|
+
if (showProgress) {
|
|
77
|
+
process.stderr.write('\r Downloading: 100%\n');
|
|
78
|
+
}
|
|
79
|
+
console.log(` ✓ Downloaded from server`);
|
|
80
|
+
return zipPath;
|
|
81
|
+
}
|
|
82
|
+
// Handle error responses
|
|
83
|
+
if (response.status === 404) {
|
|
84
|
+
const errorData = await response.json();
|
|
85
|
+
throw new Error(errorData.detail?.message || `Skill '${skillSlug}' not found`);
|
|
86
|
+
}
|
|
87
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
lastError = error;
|
|
91
|
+
// Don't retry on 404 errors
|
|
92
|
+
if (lastError.message.includes('not found')) {
|
|
93
|
+
throw lastError;
|
|
94
|
+
}
|
|
95
|
+
// Retry on network errors
|
|
96
|
+
if (attempt < MAX_RETRIES - 1) {
|
|
97
|
+
const delay = getRetryDelay(attempt);
|
|
98
|
+
console.error(`✗ Attempt ${attempt + 1} failed: ${lastError.message}`);
|
|
99
|
+
console.error(` Retrying in ${delay}ms...`);
|
|
100
|
+
await sleep(delay);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
throw new Error(`Failed to download after ${MAX_RETRIES} attempts: ${lastError?.message}`);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Validate zip file integrity.
|
|
108
|
+
*
|
|
109
|
+
* Checks:
|
|
110
|
+
* - File exists
|
|
111
|
+
* - File is not empty
|
|
112
|
+
*
|
|
113
|
+
* @param zipPath - Path to zip file
|
|
114
|
+
* @throws Error if validation fails
|
|
115
|
+
*/
|
|
116
|
+
export function validateZip(zipPath) {
|
|
117
|
+
if (!fs.existsSync(zipPath)) {
|
|
118
|
+
throw new Error(`Zip file not found: ${zipPath}`);
|
|
119
|
+
}
|
|
120
|
+
const stats = fs.statSync(zipPath);
|
|
121
|
+
if (stats.size === 0) {
|
|
122
|
+
throw new Error('Zip file is empty');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=downloader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"downloader.js","sourceRoot":"","sources":["../../../src/services/downloader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extractor service for unpacking skill zip files.
|
|
3
|
+
*
|
|
4
|
+
* Handles zip extraction with error recovery and SKILL.md validation.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Extract skill zip file to target directory.
|
|
8
|
+
*
|
|
9
|
+
* @param zipPath - Path to zip file
|
|
10
|
+
* @param targetDir - Directory to extract to
|
|
11
|
+
* @returns Path to extracted directory
|
|
12
|
+
* @throws Error if extraction fails
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* await extractSkill('/tmp/pdf-processing.zip', '.agents/skills/pdf-processing');
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function extractSkill(zipPath: string, targetDir: string): Promise<string>;
|
|
20
|
+
/**
|
|
21
|
+
* Validate SKILL.md exists in extracted folder.
|
|
22
|
+
*
|
|
23
|
+
* @param skillDir - Path to extracted skill directory
|
|
24
|
+
* @throws Error if SKILL.md is missing
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* validateSkillMd('.agents/skills/pdf-processing');
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function validateSkillMd(skillDir: string): void;
|
|
32
|
+
/**
|
|
33
|
+
* Clean up temporary files.
|
|
34
|
+
*
|
|
35
|
+
* @param paths - Array of file/directory paths to remove
|
|
36
|
+
*/
|
|
37
|
+
export declare function cleanup(...paths: string[]): void;
|
|
38
|
+
//# sourceMappingURL=extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../../src/services/extractor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAmBtF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAOtD;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAgBhD"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extractor service for unpacking skill zip files.
|
|
3
|
+
*
|
|
4
|
+
* Handles zip extraction with error recovery and SKILL.md validation.
|
|
5
|
+
*/
|
|
6
|
+
import extract from 'extract-zip';
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
/**
|
|
10
|
+
* Extract skill zip file to target directory.
|
|
11
|
+
*
|
|
12
|
+
* @param zipPath - Path to zip file
|
|
13
|
+
* @param targetDir - Directory to extract to
|
|
14
|
+
* @returns Path to extracted directory
|
|
15
|
+
* @throws Error if extraction fails
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* await extractSkill('/tmp/pdf-processing.zip', '.agents/skills/pdf-processing');
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export async function extractSkill(zipPath, targetDir) {
|
|
23
|
+
try {
|
|
24
|
+
// Ensure target directory exists
|
|
25
|
+
if (!fs.existsSync(targetDir)) {
|
|
26
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
// Extract zip
|
|
29
|
+
await extract(zipPath, { dir: path.resolve(targetDir) });
|
|
30
|
+
return targetDir;
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
// Clean up on failure
|
|
34
|
+
if (fs.existsSync(targetDir)) {
|
|
35
|
+
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
36
|
+
}
|
|
37
|
+
throw new Error(`Failed to extract skill: ${error.message}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Validate SKILL.md exists in extracted folder.
|
|
42
|
+
*
|
|
43
|
+
* @param skillDir - Path to extracted skill directory
|
|
44
|
+
* @throws Error if SKILL.md is missing
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* validateSkillMd('.agents/skills/pdf-processing');
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export function validateSkillMd(skillDir) {
|
|
52
|
+
const skillMdPath = path.join(skillDir, 'SKILL.md');
|
|
53
|
+
// Check if SKILL.md exists
|
|
54
|
+
if (!fs.existsSync(skillMdPath)) {
|
|
55
|
+
throw new Error('SKILL.md not found in extracted skill folder');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Clean up temporary files.
|
|
60
|
+
*
|
|
61
|
+
* @param paths - Array of file/directory paths to remove
|
|
62
|
+
*/
|
|
63
|
+
export function cleanup(...paths) {
|
|
64
|
+
for (const p of paths) {
|
|
65
|
+
try {
|
|
66
|
+
if (fs.existsSync(p)) {
|
|
67
|
+
const stats = fs.statSync(p);
|
|
68
|
+
if (stats.isDirectory()) {
|
|
69
|
+
fs.rmSync(p, { recursive: true, force: true });
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
fs.unlinkSync(p);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
// Ignore cleanup errors
|
|
78
|
+
console.error(`Warning: Failed to clean up ${p}: ${error.message}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor.js","sourceRoot":"","sources":["../../../src/services/extractor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,OAAO,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAe,EAAE,SAAiB;IACnE,IAAI,CAAC;QACH,iCAAiC;QACjC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9B,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,CAAC;QAED,cAAc;QACd,MAAM,OAAO,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAEzD,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,sBAAsB;QACtB,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7B,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,4BAA6B,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAEpD,2BAA2B;IAC3B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,OAAO,CAAC,GAAG,KAAe;IACxC,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;gBACrB,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAC7B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;oBACxB,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBACjD,CAAC;qBAAM,CAAC;oBACN,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;gBACnB,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,wBAAwB;YACxB,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,KAAM,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;QACjF,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Symlink service for creating cross-platform symlinks.
|
|
3
|
+
*
|
|
4
|
+
* Handles Windows junction points and Unix directory symlinks.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Create symlink with platform-specific handling.
|
|
8
|
+
*
|
|
9
|
+
* - Windows: Uses junction points (no admin rights required)
|
|
10
|
+
* - Unix/Mac: Uses directory symlinks
|
|
11
|
+
*
|
|
12
|
+
* @param target - Path to target directory (what the symlink points to)
|
|
13
|
+
* @param linkPath - Path where symlink should be created
|
|
14
|
+
* @throws Error if symlink creation fails
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* // Create symlink: .claude/skills/pdf -> .agents/skills/pdf
|
|
19
|
+
* await createSymlink(
|
|
20
|
+
* '.agents/skills/pdf-processing',
|
|
21
|
+
* '.claude/skills/pdf-processing'
|
|
22
|
+
* );
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function createSymlink(target: string, linkPath: string): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Validate symlink points to correct target.
|
|
28
|
+
*
|
|
29
|
+
* @param linkPath - Path to symlink
|
|
30
|
+
* @param expectedTarget - Expected target path
|
|
31
|
+
* @returns True if symlink is valid
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const isValid = validateSymlink(
|
|
36
|
+
* '.claude/skills/pdf-processing',
|
|
37
|
+
* '.agents/skills/pdf-processing'
|
|
38
|
+
* );
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function validateSymlink(linkPath: string, expectedTarget: string): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Check if symlink exists and is valid.
|
|
44
|
+
*
|
|
45
|
+
* @param linkPath - Path to check
|
|
46
|
+
* @returns True if valid symlink exists
|
|
47
|
+
*/
|
|
48
|
+
export declare function symlinkExists(linkPath: string): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Resolve home directory path.
|
|
51
|
+
*
|
|
52
|
+
* Expands ~ to user's home directory.
|
|
53
|
+
*
|
|
54
|
+
* @param p - Path that may contain ~
|
|
55
|
+
* @returns Resolved absolute path
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* resolveHome('~/.claude/skills') // '/home/user/.claude/skills'
|
|
60
|
+
* resolveHome('.claude/skills') // '<cwd>/.claude/skills'
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare function resolveHome(p: string): string;
|
|
64
|
+
//# sourceMappingURL=symlink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symlink.d.ts","sourceRoot":"","sources":["../../../src/services/symlink.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqDnF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAmBjF;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAWvD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAK7C"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Symlink service for creating cross-platform symlinks.
|
|
3
|
+
*
|
|
4
|
+
* Handles Windows junction points and Unix directory symlinks.
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import * as os from 'os';
|
|
9
|
+
/**
|
|
10
|
+
* Detect current platform.
|
|
11
|
+
*/
|
|
12
|
+
function isWindows() {
|
|
13
|
+
return process.platform === 'win32';
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Create symlink with platform-specific handling.
|
|
17
|
+
*
|
|
18
|
+
* - Windows: Uses junction points (no admin rights required)
|
|
19
|
+
* - Unix/Mac: Uses directory symlinks
|
|
20
|
+
*
|
|
21
|
+
* @param target - Path to target directory (what the symlink points to)
|
|
22
|
+
* @param linkPath - Path where symlink should be created
|
|
23
|
+
* @throws Error if symlink creation fails
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* // Create symlink: .claude/skills/pdf -> .agents/skills/pdf
|
|
28
|
+
* await createSymlink(
|
|
29
|
+
* '.agents/skills/pdf-processing',
|
|
30
|
+
* '.claude/skills/pdf-processing'
|
|
31
|
+
* );
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export async function createSymlink(target, linkPath) {
|
|
35
|
+
try {
|
|
36
|
+
// Resolve absolute paths
|
|
37
|
+
const absoluteTarget = path.resolve(target);
|
|
38
|
+
const absoluteLinkPath = path.resolve(linkPath);
|
|
39
|
+
// Ensure target exists
|
|
40
|
+
if (!fs.existsSync(absoluteTarget)) {
|
|
41
|
+
throw new Error(`Target directory does not exist: ${absoluteTarget}`);
|
|
42
|
+
}
|
|
43
|
+
// Ensure parent directory of link exists
|
|
44
|
+
const linkDir = path.dirname(absoluteLinkPath);
|
|
45
|
+
if (!fs.existsSync(linkDir)) {
|
|
46
|
+
fs.mkdirSync(linkDir, { recursive: true });
|
|
47
|
+
}
|
|
48
|
+
// Remove existing symlink if it exists
|
|
49
|
+
if (fs.existsSync(absoluteLinkPath)) {
|
|
50
|
+
const stats = fs.lstatSync(absoluteLinkPath);
|
|
51
|
+
if (stats.isSymbolicLink() || stats.isDirectory()) {
|
|
52
|
+
fs.rmSync(absoluteLinkPath, { recursive: true, force: true });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Create symlink with platform-specific type
|
|
56
|
+
if (isWindows()) {
|
|
57
|
+
// Windows: Use junction (no admin rights required)
|
|
58
|
+
fs.symlinkSync(absoluteTarget, absoluteLinkPath, 'junction');
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
// Unix/Mac: Use directory symlink
|
|
62
|
+
fs.symlinkSync(absoluteTarget, absoluteLinkPath, 'dir');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
const err = error;
|
|
67
|
+
// Provide helpful error messages
|
|
68
|
+
if (err.code === 'EPERM') {
|
|
69
|
+
if (isWindows()) {
|
|
70
|
+
throw new Error('Permission denied. Enable Developer Mode in Windows Settings or run as Administrator.');
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
throw new Error('Permission denied. Check directory permissions.');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (err.code === 'EEXIST') {
|
|
77
|
+
throw new Error(`Symlink already exists: ${linkPath}`);
|
|
78
|
+
}
|
|
79
|
+
throw new Error(`Failed to create symlink: ${err.message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Validate symlink points to correct target.
|
|
84
|
+
*
|
|
85
|
+
* @param linkPath - Path to symlink
|
|
86
|
+
* @param expectedTarget - Expected target path
|
|
87
|
+
* @returns True if symlink is valid
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* const isValid = validateSymlink(
|
|
92
|
+
* '.claude/skills/pdf-processing',
|
|
93
|
+
* '.agents/skills/pdf-processing'
|
|
94
|
+
* );
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export function validateSymlink(linkPath, expectedTarget) {
|
|
98
|
+
try {
|
|
99
|
+
if (!fs.existsSync(linkPath)) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
const stats = fs.lstatSync(linkPath);
|
|
103
|
+
if (!stats.isSymbolicLink()) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
const actualTarget = fs.readlinkSync(linkPath);
|
|
107
|
+
const resolvedActual = path.resolve(path.dirname(linkPath), actualTarget);
|
|
108
|
+
const resolvedExpected = path.resolve(expectedTarget);
|
|
109
|
+
return resolvedActual === resolvedExpected;
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Check if symlink exists and is valid.
|
|
117
|
+
*
|
|
118
|
+
* @param linkPath - Path to check
|
|
119
|
+
* @returns True if valid symlink exists
|
|
120
|
+
*/
|
|
121
|
+
export function symlinkExists(linkPath) {
|
|
122
|
+
try {
|
|
123
|
+
if (!fs.existsSync(linkPath)) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
const stats = fs.lstatSync(linkPath);
|
|
127
|
+
return stats.isSymbolicLink();
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Resolve home directory path.
|
|
135
|
+
*
|
|
136
|
+
* Expands ~ to user's home directory.
|
|
137
|
+
*
|
|
138
|
+
* @param p - Path that may contain ~
|
|
139
|
+
* @returns Resolved absolute path
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```typescript
|
|
143
|
+
* resolveHome('~/.claude/skills') // '/home/user/.claude/skills'
|
|
144
|
+
* resolveHome('.claude/skills') // '<cwd>/.claude/skills'
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
export function resolveHome(p) {
|
|
148
|
+
if (p.startsWith('~/') || p === '~') {
|
|
149
|
+
return path.join(os.homedir(), p.slice(2));
|
|
150
|
+
}
|
|
151
|
+
return p;
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=symlink.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symlink.js","sourceRoot":"","sources":["../../../src/services/symlink.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript type definitions for the OpenSkills CLI.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Installation options parsed from CLI arguments.
|
|
6
|
+
* Supports both single-agent and multi-agent installations.
|
|
7
|
+
*/
|
|
8
|
+
export interface InstallOptions {
|
|
9
|
+
skill: string;
|
|
10
|
+
agent: string | string[];
|
|
11
|
+
global: boolean;
|
|
12
|
+
force: boolean;
|
|
13
|
+
multiAgent: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Agent directory mapping configuration.
|
|
17
|
+
*/
|
|
18
|
+
export interface AgentMapping {
|
|
19
|
+
agent_name: string;
|
|
20
|
+
project_dir: string;
|
|
21
|
+
global_dir: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Download metadata response from backend API.
|
|
25
|
+
* Supports both legacy (download_url) and new (sparse_checkout) methods.
|
|
26
|
+
*/
|
|
27
|
+
export interface DownloadMetadata {
|
|
28
|
+
skill_slug: string;
|
|
29
|
+
source_repo?: string;
|
|
30
|
+
skill_path?: string;
|
|
31
|
+
install_method?: 'sparse_checkout' | 'download';
|
|
32
|
+
download_url?: string;
|
|
33
|
+
asset_size_bytes?: number;
|
|
34
|
+
asset_name?: string;
|
|
35
|
+
release_tag?: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
tags?: string[];
|
|
38
|
+
stars?: number;
|
|
39
|
+
verified?: boolean;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Error response from backend API.
|
|
43
|
+
*/
|
|
44
|
+
export interface ErrorResponse {
|
|
45
|
+
error: string;
|
|
46
|
+
message: string;
|
|
47
|
+
skill_slug?: string;
|
|
48
|
+
suggestions?: string[];
|
|
49
|
+
retry_after?: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Installation log entry (JSON Lines format).
|
|
53
|
+
*/
|
|
54
|
+
export interface InstallLogEntry {
|
|
55
|
+
timestamp: string;
|
|
56
|
+
event: 'start' | 'download_begin' | 'download_complete' | 'extract_begin' | 'extract_complete' | 'symlink_created' | 'complete' | 'error';
|
|
57
|
+
skill_slug: string;
|
|
58
|
+
agent_name: string;
|
|
59
|
+
installation_scope: 'project' | 'global';
|
|
60
|
+
duration_ms?: number;
|
|
61
|
+
target_path?: string;
|
|
62
|
+
symlink_path?: string;
|
|
63
|
+
error?: string;
|
|
64
|
+
agent?: string;
|
|
65
|
+
agents?: number;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Logger function type for installation events.
|
|
69
|
+
*/
|
|
70
|
+
export type InstallLogger = (event: InstallLogEntry['event'], extra?: Partial<InstallLogEntry>) => void;
|
|
71
|
+
/**
|
|
72
|
+
* CLI mode detection result.
|
|
73
|
+
*/
|
|
74
|
+
export type CliMode = 'install' | 'mcp' | 'help' | 'version';
|
|
75
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IAGnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,iBAAiB,GAAG,UAAU,CAAC;IAGhD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,GAAG,gBAAgB,GAAG,mBAAmB,GAAG,eAAe,GAAG,kBAAkB,GAAG,iBAAiB,GAAG,UAAU,GAAG,OAAO,CAAC;IAC1I,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,SAAS,GAAG,QAAQ,CAAC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,CAC1B,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,EAC/B,KAAK,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,KAC7B,IAAI,CAAC;AAEV;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|