@salesforce/b2c-tooling-sdk 0.0.0-nightly.20260120023917 → 0.0.0-nightly.20260121201541
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/cjs/cli/base-command.d.ts +5 -0
- package/dist/cjs/cli/base-command.js +22 -2
- package/dist/cjs/cli/base-command.js.map +1 -1
- package/dist/cjs/cli/hooks.d.ts +13 -5
- package/dist/cjs/cli/hooks.js.map +1 -1
- package/dist/cjs/config/resolver.d.ts +2 -1
- package/dist/cjs/config/resolver.js +11 -7
- package/dist/cjs/config/resolver.js.map +1 -1
- package/dist/cjs/config/sources/dw-json-source.d.ts +1 -0
- package/dist/cjs/config/sources/dw-json-source.js +1 -0
- package/dist/cjs/config/sources/dw-json-source.js.map +1 -1
- package/dist/cjs/config/sources/index.d.ts +1 -0
- package/dist/cjs/config/sources/index.js +1 -0
- package/dist/cjs/config/sources/index.js.map +1 -1
- package/dist/cjs/config/sources/mobify-source.d.ts +1 -0
- package/dist/cjs/config/sources/mobify-source.js +1 -0
- package/dist/cjs/config/sources/mobify-source.js.map +1 -1
- package/dist/cjs/config/sources/package-json-source.d.ts +14 -0
- package/dist/cjs/config/sources/package-json-source.js +86 -0
- package/dist/cjs/config/sources/package-json-source.js.map +1 -0
- package/dist/cjs/config/types.d.ts +12 -0
- package/dist/cjs/skills/agents.d.ts +41 -0
- package/dist/cjs/skills/agents.js +159 -0
- package/dist/cjs/skills/agents.js.map +1 -0
- package/dist/cjs/skills/github.d.ts +47 -0
- package/dist/cjs/skills/github.js +246 -0
- package/dist/cjs/skills/github.js.map +1 -0
- package/dist/cjs/skills/index.d.ts +42 -0
- package/dist/cjs/skills/index.js +14 -0
- package/dist/cjs/skills/index.js.map +1 -0
- package/dist/cjs/skills/installer.d.ts +34 -0
- package/dist/cjs/skills/installer.js +181 -0
- package/dist/cjs/skills/installer.js.map +1 -0
- package/dist/cjs/skills/parser.d.ts +39 -0
- package/dist/cjs/skills/parser.js +131 -0
- package/dist/cjs/skills/parser.js.map +1 -0
- package/dist/cjs/skills/types.d.ts +134 -0
- package/dist/cjs/skills/types.js +7 -0
- package/dist/cjs/skills/types.js.map +1 -0
- package/dist/cjs/test-utils/config-isolation.d.ts +2 -0
- package/dist/cjs/test-utils/config-isolation.js +41 -0
- package/dist/cjs/test-utils/config-isolation.js.map +1 -0
- package/dist/cjs/test-utils/index.d.ts +1 -0
- package/dist/cjs/test-utils/index.js +7 -0
- package/dist/cjs/test-utils/index.js.map +1 -0
- package/dist/esm/cli/base-command.d.ts +5 -0
- package/dist/esm/cli/base-command.js +22 -2
- package/dist/esm/cli/base-command.js.map +1 -1
- package/dist/esm/cli/hooks.d.ts +13 -5
- package/dist/esm/cli/hooks.js.map +1 -1
- package/dist/esm/config/resolver.d.ts +2 -1
- package/dist/esm/config/resolver.js +11 -7
- package/dist/esm/config/resolver.js.map +1 -1
- package/dist/esm/config/sources/dw-json-source.d.ts +1 -0
- package/dist/esm/config/sources/dw-json-source.js +1 -0
- package/dist/esm/config/sources/dw-json-source.js.map +1 -1
- package/dist/esm/config/sources/index.d.ts +1 -0
- package/dist/esm/config/sources/index.js +1 -0
- package/dist/esm/config/sources/index.js.map +1 -1
- package/dist/esm/config/sources/mobify-source.d.ts +1 -0
- package/dist/esm/config/sources/mobify-source.js +1 -0
- package/dist/esm/config/sources/mobify-source.js.map +1 -1
- package/dist/esm/config/sources/package-json-source.d.ts +14 -0
- package/dist/esm/config/sources/package-json-source.js +86 -0
- package/dist/esm/config/sources/package-json-source.js.map +1 -0
- package/dist/esm/config/types.d.ts +12 -0
- package/dist/esm/skills/agents.d.ts +41 -0
- package/dist/esm/skills/agents.js +159 -0
- package/dist/esm/skills/agents.js.map +1 -0
- package/dist/esm/skills/github.d.ts +47 -0
- package/dist/esm/skills/github.js +246 -0
- package/dist/esm/skills/github.js.map +1 -0
- package/dist/esm/skills/index.d.ts +42 -0
- package/dist/esm/skills/index.js +14 -0
- package/dist/esm/skills/index.js.map +1 -0
- package/dist/esm/skills/installer.d.ts +34 -0
- package/dist/esm/skills/installer.js +181 -0
- package/dist/esm/skills/installer.js.map +1 -0
- package/dist/esm/skills/parser.d.ts +39 -0
- package/dist/esm/skills/parser.js +131 -0
- package/dist/esm/skills/parser.js.map +1 -0
- package/dist/esm/skills/types.d.ts +134 -0
- package/dist/esm/skills/types.js +7 -0
- package/dist/esm/skills/types.js.map +1 -0
- package/dist/esm/test-utils/config-isolation.d.ts +2 -0
- package/dist/esm/test-utils/config-isolation.js +41 -0
- package/dist/esm/test-utils/config-isolation.js.map +1 -0
- package/dist/esm/test-utils/index.d.ts +1 -0
- package/dist/esm/test-utils/index.js +7 -0
- package/dist/esm/test-utils/index.js.map +1 -0
- package/package.json +23 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { CachedArtifact, DownloadSkillsOptions, ReleaseInfo, SkillSet } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Get the cache directory for skills.
|
|
4
|
+
* Uses XDG_CACHE_HOME on Linux, ~/.cache otherwise.
|
|
5
|
+
*
|
|
6
|
+
* @returns Absolute path to cache directory
|
|
7
|
+
*/
|
|
8
|
+
export declare function getCacheDir(): string;
|
|
9
|
+
/**
|
|
10
|
+
* Fetch release information from GitHub API.
|
|
11
|
+
*
|
|
12
|
+
* @param version - 'latest' or specific version (e.g., 'v0.1.0')
|
|
13
|
+
* @returns Release information
|
|
14
|
+
* @throws Error if release not found or API request fails
|
|
15
|
+
*/
|
|
16
|
+
export declare function getRelease(version?: string): Promise<ReleaseInfo>;
|
|
17
|
+
/**
|
|
18
|
+
* List available releases with skills artifacts.
|
|
19
|
+
*
|
|
20
|
+
* @param limit - Maximum number of releases to return (default: 10)
|
|
21
|
+
* @returns Array of release information
|
|
22
|
+
*/
|
|
23
|
+
export declare function listReleases(limit?: number): Promise<ReleaseInfo[]>;
|
|
24
|
+
/**
|
|
25
|
+
* Get cached artifact metadata if available.
|
|
26
|
+
*
|
|
27
|
+
* @param version - Release version
|
|
28
|
+
* @param skillSet - Skill set to check
|
|
29
|
+
* @returns Cached artifact info or null if not cached
|
|
30
|
+
*/
|
|
31
|
+
export declare function getCachedArtifact(version: string, skillSet: SkillSet): CachedArtifact | null;
|
|
32
|
+
/**
|
|
33
|
+
* Download and extract skills artifact.
|
|
34
|
+
* Uses direct download URLs to avoid GitHub API rate limits.
|
|
35
|
+
*
|
|
36
|
+
* @param skillSet - Which skill set to download ('b2c' or 'b2c-cli')
|
|
37
|
+
* @param options - Download options
|
|
38
|
+
* @returns Path to extracted skills directory
|
|
39
|
+
* @throws Error if download fails or artifact not available
|
|
40
|
+
*/
|
|
41
|
+
export declare function downloadSkillsArtifact(skillSet: SkillSet, options?: DownloadSkillsOptions): Promise<string>;
|
|
42
|
+
/**
|
|
43
|
+
* Clear the skills cache.
|
|
44
|
+
*
|
|
45
|
+
* @param version - Optional specific version to clear (default: all)
|
|
46
|
+
*/
|
|
47
|
+
export declare function clearCache(version?: string): Promise<void>;
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2
|
|
4
|
+
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from 'node:fs';
|
|
7
|
+
import * as os from 'node:os';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
import JSZip from 'jszip';
|
|
10
|
+
import { getLogger } from '../logging/logger.js';
|
|
11
|
+
const GITHUB_REPO = 'SalesforceCommerceCloud/b2c-developer-tooling';
|
|
12
|
+
const GITHUB_API_BASE = 'https://api.github.com';
|
|
13
|
+
const GITHUB_DOWNLOAD_BASE = 'https://github.com';
|
|
14
|
+
/**
|
|
15
|
+
* Asset filename patterns for skill archives.
|
|
16
|
+
*/
|
|
17
|
+
const ASSET_NAMES = {
|
|
18
|
+
b2c: 'b2c-skills.zip',
|
|
19
|
+
'b2c-cli': 'b2c-cli-skills.zip',
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Build direct download URL for a release asset.
|
|
23
|
+
* These URLs don't require API calls and avoid rate limiting.
|
|
24
|
+
*
|
|
25
|
+
* @param version - 'latest' or specific version tag
|
|
26
|
+
* @param assetName - Name of the asset file
|
|
27
|
+
* @returns Direct download URL
|
|
28
|
+
*/
|
|
29
|
+
function getDirectDownloadUrl(version, assetName) {
|
|
30
|
+
if (version === 'latest') {
|
|
31
|
+
return `${GITHUB_DOWNLOAD_BASE}/${GITHUB_REPO}/releases/latest/download/${assetName}`;
|
|
32
|
+
}
|
|
33
|
+
const tag = version.startsWith('v') ? version : `v${version}`;
|
|
34
|
+
return `${GITHUB_DOWNLOAD_BASE}/${GITHUB_REPO}/releases/download/${tag}/${assetName}`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get the cache directory for skills.
|
|
38
|
+
* Uses XDG_CACHE_HOME on Linux, ~/.cache otherwise.
|
|
39
|
+
*
|
|
40
|
+
* @returns Absolute path to cache directory
|
|
41
|
+
*/
|
|
42
|
+
export function getCacheDir() {
|
|
43
|
+
const xdgCache = process.env.XDG_CACHE_HOME;
|
|
44
|
+
const baseCache = xdgCache || path.join(os.homedir(), '.cache');
|
|
45
|
+
return path.join(baseCache, 'b2c-cli', 'skills');
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Parse GitHub API release response into ReleaseInfo.
|
|
49
|
+
*/
|
|
50
|
+
function parseRelease(release) {
|
|
51
|
+
const b2cAsset = release.assets.find((a) => a.name === ASSET_NAMES['b2c']);
|
|
52
|
+
const b2cCliAsset = release.assets.find((a) => a.name === ASSET_NAMES['b2c-cli']);
|
|
53
|
+
return {
|
|
54
|
+
tagName: release.tag_name,
|
|
55
|
+
version: release.tag_name.replace(/^v/, ''),
|
|
56
|
+
publishedAt: release.published_at,
|
|
57
|
+
b2cSkillsAssetUrl: b2cAsset?.browser_download_url ?? null,
|
|
58
|
+
b2cCliSkillsAssetUrl: b2cCliAsset?.browser_download_url ?? null,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Fetch release information from GitHub API.
|
|
63
|
+
*
|
|
64
|
+
* @param version - 'latest' or specific version (e.g., 'v0.1.0')
|
|
65
|
+
* @returns Release information
|
|
66
|
+
* @throws Error if release not found or API request fails
|
|
67
|
+
*/
|
|
68
|
+
export async function getRelease(version = 'latest') {
|
|
69
|
+
const logger = getLogger();
|
|
70
|
+
const endpoint = version === 'latest'
|
|
71
|
+
? `${GITHUB_API_BASE}/repos/${GITHUB_REPO}/releases/latest`
|
|
72
|
+
: `${GITHUB_API_BASE}/repos/${GITHUB_REPO}/releases/tags/${version.startsWith('v') ? version : `v${version}`}`;
|
|
73
|
+
logger.debug({ endpoint }, 'Fetching release info');
|
|
74
|
+
const response = await fetch(endpoint, {
|
|
75
|
+
headers: {
|
|
76
|
+
Accept: 'application/vnd.github.v3+json',
|
|
77
|
+
'User-Agent': 'b2c-cli',
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
if (!response.ok) {
|
|
81
|
+
if (response.status === 404) {
|
|
82
|
+
throw new Error(`Release not found: ${version}`);
|
|
83
|
+
}
|
|
84
|
+
throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
|
|
85
|
+
}
|
|
86
|
+
const data = (await response.json());
|
|
87
|
+
return parseRelease(data);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* List available releases with skills artifacts.
|
|
91
|
+
*
|
|
92
|
+
* @param limit - Maximum number of releases to return (default: 10)
|
|
93
|
+
* @returns Array of release information
|
|
94
|
+
*/
|
|
95
|
+
export async function listReleases(limit = 10) {
|
|
96
|
+
const logger = getLogger();
|
|
97
|
+
const endpoint = `${GITHUB_API_BASE}/repos/${GITHUB_REPO}/releases?per_page=${limit}`;
|
|
98
|
+
logger.debug({ endpoint }, 'Listing releases');
|
|
99
|
+
const response = await fetch(endpoint, {
|
|
100
|
+
headers: {
|
|
101
|
+
Accept: 'application/vnd.github.v3+json',
|
|
102
|
+
'User-Agent': 'b2c-cli',
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
if (!response.ok) {
|
|
106
|
+
throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
|
|
107
|
+
}
|
|
108
|
+
const data = (await response.json());
|
|
109
|
+
// Only return releases that have at least one skills artifact
|
|
110
|
+
return data.map(parseRelease).filter((r) => r.b2cSkillsAssetUrl || r.b2cCliSkillsAssetUrl);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get cached artifact metadata if available.
|
|
114
|
+
*
|
|
115
|
+
* @param version - Release version
|
|
116
|
+
* @param skillSet - Skill set to check
|
|
117
|
+
* @returns Cached artifact info or null if not cached
|
|
118
|
+
*/
|
|
119
|
+
export function getCachedArtifact(version, skillSet) {
|
|
120
|
+
const cacheDir = getCacheDir();
|
|
121
|
+
const manifestPath = path.join(cacheDir, version, skillSet, 'manifest.json');
|
|
122
|
+
if (!fs.existsSync(manifestPath)) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
const content = fs.readFileSync(manifestPath, 'utf-8');
|
|
127
|
+
return JSON.parse(content);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Extract version tag from a GitHub release download URL.
|
|
135
|
+
* URLs follow pattern: .../releases/download/{tag}/...
|
|
136
|
+
*
|
|
137
|
+
* @param url - The final URL after redirects
|
|
138
|
+
* @returns Version tag or null if not found
|
|
139
|
+
*/
|
|
140
|
+
function extractVersionFromUrl(url) {
|
|
141
|
+
const match = url.match(/\/releases\/download\/([^/]+)\//);
|
|
142
|
+
return match ? match[1] : null;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Download and extract skills artifact.
|
|
146
|
+
* Uses direct download URLs to avoid GitHub API rate limits.
|
|
147
|
+
*
|
|
148
|
+
* @param skillSet - Which skill set to download ('b2c' or 'b2c-cli')
|
|
149
|
+
* @param options - Download options
|
|
150
|
+
* @returns Path to extracted skills directory
|
|
151
|
+
* @throws Error if download fails or artifact not available
|
|
152
|
+
*/
|
|
153
|
+
export async function downloadSkillsArtifact(skillSet, options = {}) {
|
|
154
|
+
const logger = getLogger();
|
|
155
|
+
const { version = 'latest', forceDownload = false } = options;
|
|
156
|
+
const assetName = ASSET_NAMES[skillSet];
|
|
157
|
+
// For specific versions, check cache first (before any network calls)
|
|
158
|
+
if (version !== 'latest' && !forceDownload) {
|
|
159
|
+
const versionTag = version.startsWith('v') ? version : `v${version}`;
|
|
160
|
+
const cached = getCachedArtifact(versionTag, skillSet);
|
|
161
|
+
if (cached && fs.existsSync(cached.path)) {
|
|
162
|
+
logger.debug({ version: versionTag, skillSet, path: cached.path }, 'Using cached skills');
|
|
163
|
+
return cached.path;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Build direct download URL (avoids API rate limits)
|
|
167
|
+
const downloadUrl = getDirectDownloadUrl(version, assetName);
|
|
168
|
+
logger.debug({ url: downloadUrl, skillSet }, 'Downloading skills artifact');
|
|
169
|
+
// Download artifact - GitHub will redirect to the actual file
|
|
170
|
+
const response = await fetch(downloadUrl, {
|
|
171
|
+
headers: {
|
|
172
|
+
'User-Agent': 'b2c-cli',
|
|
173
|
+
},
|
|
174
|
+
redirect: 'follow',
|
|
175
|
+
});
|
|
176
|
+
if (!response.ok) {
|
|
177
|
+
if (response.status === 404) {
|
|
178
|
+
throw new Error(`Skills artifact '${assetName}' not found for ${version === 'latest' ? 'latest release' : `version ${version}`}`);
|
|
179
|
+
}
|
|
180
|
+
throw new Error(`Failed to download skills: ${response.status} ${response.statusText}`);
|
|
181
|
+
}
|
|
182
|
+
// Extract actual version from the final URL (after redirects)
|
|
183
|
+
const actualVersion = extractVersionFromUrl(response.url) || version;
|
|
184
|
+
// Check cache for the resolved version (for 'latest' which we now know)
|
|
185
|
+
if (version === 'latest' && !forceDownload) {
|
|
186
|
+
const cached = getCachedArtifact(actualVersion, skillSet);
|
|
187
|
+
if (cached && fs.existsSync(cached.path)) {
|
|
188
|
+
logger.debug({ version: actualVersion, skillSet, path: cached.path }, 'Using cached skills (resolved latest)');
|
|
189
|
+
return cached.path;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const zipBuffer = Buffer.from(await response.arrayBuffer());
|
|
193
|
+
logger.debug({ size: zipBuffer.length, version: actualVersion }, 'Downloaded skills archive');
|
|
194
|
+
// Extract to cache directory
|
|
195
|
+
const cacheDir = options.cacheDir || getCacheDir();
|
|
196
|
+
const extractDir = path.join(cacheDir, actualVersion, skillSet);
|
|
197
|
+
// Clean existing extraction if present
|
|
198
|
+
if (fs.existsSync(extractDir)) {
|
|
199
|
+
await fs.promises.rm(extractDir, { recursive: true });
|
|
200
|
+
}
|
|
201
|
+
await fs.promises.mkdir(extractDir, { recursive: true });
|
|
202
|
+
// Extract zip contents
|
|
203
|
+
const zip = await JSZip.loadAsync(zipBuffer);
|
|
204
|
+
let extractedCount = 0;
|
|
205
|
+
for (const [relativePath, zipEntry] of Object.entries(zip.files)) {
|
|
206
|
+
if (zipEntry.dir) {
|
|
207
|
+
await fs.promises.mkdir(path.join(extractDir, relativePath), { recursive: true });
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
const targetPath = path.join(extractDir, relativePath);
|
|
211
|
+
const targetDir = path.dirname(targetPath);
|
|
212
|
+
// Ensure parent directory exists
|
|
213
|
+
await fs.promises.mkdir(targetDir, { recursive: true });
|
|
214
|
+
// Write file
|
|
215
|
+
const content = await zipEntry.async('nodebuffer');
|
|
216
|
+
await fs.promises.writeFile(targetPath, content);
|
|
217
|
+
extractedCount++;
|
|
218
|
+
}
|
|
219
|
+
logger.debug({ extractDir, fileCount: extractedCount }, 'Extracted skills');
|
|
220
|
+
// Write cache manifest
|
|
221
|
+
const manifest = {
|
|
222
|
+
version: actualVersion,
|
|
223
|
+
path: extractDir,
|
|
224
|
+
downloadedAt: new Date().toISOString(),
|
|
225
|
+
};
|
|
226
|
+
await fs.promises.writeFile(path.join(extractDir, 'manifest.json'), JSON.stringify(manifest, null, 2));
|
|
227
|
+
return extractDir;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Clear the skills cache.
|
|
231
|
+
*
|
|
232
|
+
* @param version - Optional specific version to clear (default: all)
|
|
233
|
+
*/
|
|
234
|
+
export async function clearCache(version) {
|
|
235
|
+
const cacheDir = getCacheDir();
|
|
236
|
+
if (version) {
|
|
237
|
+
const versionDir = path.join(cacheDir, version);
|
|
238
|
+
if (fs.existsSync(versionDir)) {
|
|
239
|
+
await fs.promises.rm(versionDir, { recursive: true });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
else if (fs.existsSync(cacheDir)) {
|
|
243
|
+
await fs.promises.rm(cacheDir, { recursive: true });
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../../src/skills/github.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills management module for downloading and installing agent skills.
|
|
3
|
+
*
|
|
4
|
+
* This module provides functionality to:
|
|
5
|
+
* - Download skills artifacts from GitHub releases
|
|
6
|
+
* - Detect installed IDEs
|
|
7
|
+
* - Install skills to various IDE configurations
|
|
8
|
+
* - Manage skills cache
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import {
|
|
13
|
+
* downloadSkillsArtifact,
|
|
14
|
+
* scanSkills,
|
|
15
|
+
* installSkills,
|
|
16
|
+
* detectInstalledIdes,
|
|
17
|
+
* } from '@salesforce/b2c-tooling-sdk/skills';
|
|
18
|
+
*
|
|
19
|
+
* // Download and extract skills
|
|
20
|
+
* const skillsDir = await downloadSkillsArtifact('b2c');
|
|
21
|
+
*
|
|
22
|
+
* // Scan for available skills
|
|
23
|
+
* const skills = await scanSkills(skillsDir, 'b2c');
|
|
24
|
+
*
|
|
25
|
+
* // Detect installed IDEs
|
|
26
|
+
* const ides = await detectInstalledIdes();
|
|
27
|
+
*
|
|
28
|
+
* // Install skills
|
|
29
|
+
* const result = await installSkills(skills, skillsDir, {
|
|
30
|
+
* ides: ['cursor'],
|
|
31
|
+
* global: true,
|
|
32
|
+
* update: false,
|
|
33
|
+
* });
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @module skills
|
|
37
|
+
*/
|
|
38
|
+
export type { IdeType, SkillSet, IdePaths, IdeConfig, SkillMetadata, ReleaseInfo, DownloadSkillsOptions, InstallSkillsOptions, SkillInstallation, SkillSkipped, SkillError, InstallSkillsResult, CachedArtifact, } from './types.js';
|
|
39
|
+
export { IDE_CONFIGS, ALL_IDE_TYPES, detectInstalledIdes, getSkillInstallPath, getIdeDisplayName, getIdeDocsUrl, } from './agents.js';
|
|
40
|
+
export { getCacheDir, getRelease, listReleases, getCachedArtifact, downloadSkillsArtifact, clearCache, } from './github.js';
|
|
41
|
+
export { parseSkillFrontmatter, scanSkills, filterSkillsByName, findSkillsByName } from './parser.js';
|
|
42
|
+
export { isSkillInstalled, installSkills, removeSkill } from './installer.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2
|
|
4
|
+
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
|
|
5
|
+
*/
|
|
6
|
+
// Agent/IDE utilities
|
|
7
|
+
export { IDE_CONFIGS, ALL_IDE_TYPES, detectInstalledIdes, getSkillInstallPath, getIdeDisplayName, getIdeDocsUrl, } from './agents.js';
|
|
8
|
+
// GitHub/download utilities
|
|
9
|
+
export { getCacheDir, getRelease, listReleases, getCachedArtifact, downloadSkillsArtifact, clearCache, } from './github.js';
|
|
10
|
+
// Skill parsing
|
|
11
|
+
export { parseSkillFrontmatter, scanSkills, filterSkillsByName, findSkillsByName } from './parser.js';
|
|
12
|
+
// Installation
|
|
13
|
+
export { isSkillInstalled, installSkills, removeSkill } from './installer.js';
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/skills/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAyDH,sBAAsB;AACtB,OAAO,EACL,WAAW,EACX,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,GACd,MAAM,aAAa,CAAC;AAErB,4BAA4B;AAC5B,OAAO,EACL,WAAW,EACX,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,sBAAsB,EACtB,UAAU,GACX,MAAM,aAAa,CAAC;AAErB,gBAAgB;AAChB,OAAO,EAAC,qBAAqB,EAAE,UAAU,EAAE,kBAAkB,EAAE,gBAAgB,EAAC,MAAM,aAAa,CAAC;AAEpG,eAAe;AACf,OAAO,EAAC,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAC,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { IdeType, InstallSkillsOptions, InstallSkillsResult, SkillMetadata } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Check if a skill is already installed.
|
|
4
|
+
*
|
|
5
|
+
* @param skillName - Name of the skill
|
|
6
|
+
* @param ide - Target IDE
|
|
7
|
+
* @param options - Installation options
|
|
8
|
+
* @returns true if skill is installed, false otherwise
|
|
9
|
+
*/
|
|
10
|
+
export declare function isSkillInstalled(skillName: string, ide: IdeType, options: {
|
|
11
|
+
global: boolean;
|
|
12
|
+
projectRoot?: string;
|
|
13
|
+
}): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Install skills to target IDE directories.
|
|
16
|
+
*
|
|
17
|
+
* @param skills - Skills to install
|
|
18
|
+
* @param sourceDir - Directory containing extracted skills
|
|
19
|
+
* @param options - Installation options
|
|
20
|
+
* @returns Installation results
|
|
21
|
+
*/
|
|
22
|
+
export declare function installSkills(skills: SkillMetadata[], sourceDir: string, options: InstallSkillsOptions): Promise<InstallSkillsResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Remove an installed skill.
|
|
25
|
+
*
|
|
26
|
+
* @param skillName - Name of the skill to remove
|
|
27
|
+
* @param ide - Target IDE
|
|
28
|
+
* @param options - Installation options
|
|
29
|
+
* @returns true if removed, false if not found
|
|
30
|
+
*/
|
|
31
|
+
export declare function removeSkill(skillName: string, ide: IdeType, options: {
|
|
32
|
+
global: boolean;
|
|
33
|
+
projectRoot?: string;
|
|
34
|
+
}): Promise<boolean>;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025, Salesforce, Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2
|
|
4
|
+
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from 'node:fs';
|
|
7
|
+
import * as path from 'node:path';
|
|
8
|
+
import { getSkillInstallPath } from './agents.js';
|
|
9
|
+
import { getLogger } from '../logging/logger.js';
|
|
10
|
+
/**
|
|
11
|
+
* Sanitize a skill name to prevent path traversal attacks.
|
|
12
|
+
*
|
|
13
|
+
* @param name - Skill name to sanitize
|
|
14
|
+
* @returns Sanitized name safe for use in file paths
|
|
15
|
+
*/
|
|
16
|
+
function sanitizeName(name) {
|
|
17
|
+
// Remove path separators and null bytes
|
|
18
|
+
let sanitized = name.replace(/[/\\:\0]/g, '');
|
|
19
|
+
// Remove leading/trailing dots and spaces
|
|
20
|
+
sanitized = sanitized.replace(/^[.\s]+|[.\s]+$/g, '');
|
|
21
|
+
// Limit length
|
|
22
|
+
if (sanitized.length > 255) {
|
|
23
|
+
sanitized = sanitized.slice(0, 255);
|
|
24
|
+
}
|
|
25
|
+
return sanitized;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Validate that a path is safely within a base directory.
|
|
29
|
+
*
|
|
30
|
+
* @param targetPath - Path to validate
|
|
31
|
+
* @param baseDir - Base directory that must contain targetPath
|
|
32
|
+
* @returns true if path is safe, false otherwise
|
|
33
|
+
*/
|
|
34
|
+
function isPathSafe(targetPath, baseDir) {
|
|
35
|
+
const resolvedTarget = path.resolve(targetPath);
|
|
36
|
+
const resolvedBase = path.resolve(baseDir);
|
|
37
|
+
// Ensure the target is within the base directory
|
|
38
|
+
return resolvedTarget.startsWith(resolvedBase + path.sep) || resolvedTarget === resolvedBase;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Recursively copy a directory.
|
|
42
|
+
*
|
|
43
|
+
* @param source - Source directory
|
|
44
|
+
* @param target - Target directory
|
|
45
|
+
*/
|
|
46
|
+
async function copyDirectory(source, target) {
|
|
47
|
+
const logger = getLogger();
|
|
48
|
+
let fileCount = 0;
|
|
49
|
+
await fs.promises.mkdir(target, { recursive: true });
|
|
50
|
+
const entries = await fs.promises.readdir(source, { withFileTypes: true });
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
const sourcePath = path.join(source, entry.name);
|
|
53
|
+
const targetPath = path.join(target, entry.name);
|
|
54
|
+
if (entry.isDirectory()) {
|
|
55
|
+
fileCount += await copyDirectory(sourcePath, targetPath);
|
|
56
|
+
}
|
|
57
|
+
else if (entry.isFile()) {
|
|
58
|
+
await fs.promises.copyFile(sourcePath, targetPath);
|
|
59
|
+
fileCount++;
|
|
60
|
+
}
|
|
61
|
+
// Skip symlinks and other special files for security
|
|
62
|
+
}
|
|
63
|
+
logger.debug({ source, target, fileCount }, 'Copied directory');
|
|
64
|
+
return fileCount;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Check if a skill is already installed.
|
|
68
|
+
*
|
|
69
|
+
* @param skillName - Name of the skill
|
|
70
|
+
* @param ide - Target IDE
|
|
71
|
+
* @param options - Installation options
|
|
72
|
+
* @returns true if skill is installed, false otherwise
|
|
73
|
+
*/
|
|
74
|
+
export function isSkillInstalled(skillName, ide, options) {
|
|
75
|
+
const installPath = getSkillInstallPath(ide, skillName, options);
|
|
76
|
+
return fs.existsSync(installPath);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Install skills to target IDE directories.
|
|
80
|
+
*
|
|
81
|
+
* @param skills - Skills to install
|
|
82
|
+
* @param sourceDir - Directory containing extracted skills
|
|
83
|
+
* @param options - Installation options
|
|
84
|
+
* @returns Installation results
|
|
85
|
+
*/
|
|
86
|
+
export async function installSkills(skills, sourceDir, options) {
|
|
87
|
+
const logger = getLogger();
|
|
88
|
+
const result = {
|
|
89
|
+
installed: [],
|
|
90
|
+
skipped: [],
|
|
91
|
+
errors: [],
|
|
92
|
+
};
|
|
93
|
+
for (const skill of skills) {
|
|
94
|
+
const sanitizedName = sanitizeName(skill.name);
|
|
95
|
+
if (sanitizedName !== skill.name) {
|
|
96
|
+
logger.warn({ original: skill.name, sanitized: sanitizedName }, 'Skill name was sanitized');
|
|
97
|
+
}
|
|
98
|
+
// Source path: sourceDir/skills/skill-path/
|
|
99
|
+
const sourcePath = path.join(sourceDir, 'skills', skill.path);
|
|
100
|
+
if (!fs.existsSync(sourcePath)) {
|
|
101
|
+
for (const ide of options.ides) {
|
|
102
|
+
result.errors.push({
|
|
103
|
+
skill: skill.name,
|
|
104
|
+
ide,
|
|
105
|
+
error: `Source directory not found: ${sourcePath}`,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
for (const ide of options.ides) {
|
|
111
|
+
try {
|
|
112
|
+
const targetPath = getSkillInstallPath(ide, sanitizedName, {
|
|
113
|
+
global: options.global,
|
|
114
|
+
projectRoot: options.projectRoot,
|
|
115
|
+
});
|
|
116
|
+
// Get the base directory for path safety validation
|
|
117
|
+
const baseDir = path.dirname(targetPath);
|
|
118
|
+
// Validate path safety
|
|
119
|
+
if (!isPathSafe(targetPath, baseDir)) {
|
|
120
|
+
result.errors.push({
|
|
121
|
+
skill: skill.name,
|
|
122
|
+
ide,
|
|
123
|
+
error: 'Path validation failed: potential directory traversal',
|
|
124
|
+
});
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
// Check if already installed
|
|
128
|
+
if (fs.existsSync(targetPath)) {
|
|
129
|
+
if (!options.update) {
|
|
130
|
+
result.skipped.push({
|
|
131
|
+
skill: skill.name,
|
|
132
|
+
ide,
|
|
133
|
+
reason: 'Already installed (use --update to overwrite)',
|
|
134
|
+
});
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
// Remove existing for update
|
|
138
|
+
await fs.promises.rm(targetPath, { recursive: true });
|
|
139
|
+
}
|
|
140
|
+
// Copy skill directory
|
|
141
|
+
await copyDirectory(sourcePath, targetPath);
|
|
142
|
+
result.installed.push({
|
|
143
|
+
skill: skill.name,
|
|
144
|
+
ide,
|
|
145
|
+
path: targetPath,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
result.errors.push({
|
|
150
|
+
skill: skill.name,
|
|
151
|
+
ide,
|
|
152
|
+
error: error instanceof Error ? error.message : String(error),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
logger.debug({
|
|
158
|
+
installed: result.installed.length,
|
|
159
|
+
skipped: result.skipped.length,
|
|
160
|
+
errors: result.errors.length,
|
|
161
|
+
}, 'Installation complete');
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Remove an installed skill.
|
|
166
|
+
*
|
|
167
|
+
* @param skillName - Name of the skill to remove
|
|
168
|
+
* @param ide - Target IDE
|
|
169
|
+
* @param options - Installation options
|
|
170
|
+
* @returns true if removed, false if not found
|
|
171
|
+
*/
|
|
172
|
+
export async function removeSkill(skillName, ide, options) {
|
|
173
|
+
const sanitizedName = sanitizeName(skillName);
|
|
174
|
+
const installPath = getSkillInstallPath(ide, sanitizedName, options);
|
|
175
|
+
if (!fs.existsSync(installPath)) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
await fs.promises.rm(installPath, { recursive: true });
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=installer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installer.js","sourceRoot":"","sources":["../../../src/skills/installer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { SkillMetadata, SkillSet } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parse simple YAML-like frontmatter from SKILL.md content.
|
|
4
|
+
* Only supports basic key: value pairs (name and description).
|
|
5
|
+
*
|
|
6
|
+
* @param content - File content with frontmatter
|
|
7
|
+
* @returns Parsed frontmatter or null if invalid
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseSkillFrontmatter(content: string): {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
} | null;
|
|
13
|
+
/**
|
|
14
|
+
* Scan a directory for skills and extract their metadata.
|
|
15
|
+
*
|
|
16
|
+
* @param skillsDir - Path to extracted skills directory (e.g., ~/.cache/b2c-cli/skills/v0.1.0/b2c/skills/)
|
|
17
|
+
* @param skillSet - The skill set being scanned ('b2c' or 'b2c-cli')
|
|
18
|
+
* @returns Array of skill metadata
|
|
19
|
+
*/
|
|
20
|
+
export declare function scanSkills(skillsDir: string, skillSet: SkillSet): Promise<SkillMetadata[]>;
|
|
21
|
+
/**
|
|
22
|
+
* Filter skills by name.
|
|
23
|
+
*
|
|
24
|
+
* @param skills - All available skills
|
|
25
|
+
* @param names - Skill names to include (if provided)
|
|
26
|
+
* @returns Filtered skills
|
|
27
|
+
*/
|
|
28
|
+
export declare function filterSkillsByName(skills: SkillMetadata[], names?: string[]): SkillMetadata[];
|
|
29
|
+
/**
|
|
30
|
+
* Find skills that match the given names, returning any that weren't found.
|
|
31
|
+
*
|
|
32
|
+
* @param skills - Available skills
|
|
33
|
+
* @param names - Requested skill names
|
|
34
|
+
* @returns Object with matched skills and names not found
|
|
35
|
+
*/
|
|
36
|
+
export declare function findSkillsByName(skills: SkillMetadata[], names: string[]): {
|
|
37
|
+
found: SkillMetadata[];
|
|
38
|
+
notFound: string[];
|
|
39
|
+
};
|