@salesforce/b2c-tooling-sdk 0.0.0-nightly.20260120023917 → 0.0.0-nightly.20260121023856

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.
Files changed (79) hide show
  1. package/dist/cjs/cli/base-command.d.ts +5 -0
  2. package/dist/cjs/cli/base-command.js +22 -2
  3. package/dist/cjs/cli/base-command.js.map +1 -1
  4. package/dist/cjs/cli/hooks.d.ts +13 -5
  5. package/dist/cjs/cli/hooks.js.map +1 -1
  6. package/dist/cjs/config/resolver.d.ts +2 -1
  7. package/dist/cjs/config/resolver.js +11 -7
  8. package/dist/cjs/config/resolver.js.map +1 -1
  9. package/dist/cjs/config/sources/dw-json-source.d.ts +1 -0
  10. package/dist/cjs/config/sources/dw-json-source.js +1 -0
  11. package/dist/cjs/config/sources/dw-json-source.js.map +1 -1
  12. package/dist/cjs/config/sources/index.d.ts +1 -0
  13. package/dist/cjs/config/sources/index.js +1 -0
  14. package/dist/cjs/config/sources/index.js.map +1 -1
  15. package/dist/cjs/config/sources/mobify-source.d.ts +1 -0
  16. package/dist/cjs/config/sources/mobify-source.js +1 -0
  17. package/dist/cjs/config/sources/mobify-source.js.map +1 -1
  18. package/dist/cjs/config/sources/package-json-source.d.ts +14 -0
  19. package/dist/cjs/config/sources/package-json-source.js +86 -0
  20. package/dist/cjs/config/sources/package-json-source.js.map +1 -0
  21. package/dist/cjs/config/types.d.ts +12 -0
  22. package/dist/cjs/skills/agents.d.ts +41 -0
  23. package/dist/cjs/skills/agents.js +159 -0
  24. package/dist/cjs/skills/agents.js.map +1 -0
  25. package/dist/cjs/skills/github.d.ts +47 -0
  26. package/dist/cjs/skills/github.js +246 -0
  27. package/dist/cjs/skills/github.js.map +1 -0
  28. package/dist/cjs/skills/index.d.ts +42 -0
  29. package/dist/cjs/skills/index.js +14 -0
  30. package/dist/cjs/skills/index.js.map +1 -0
  31. package/dist/cjs/skills/installer.d.ts +34 -0
  32. package/dist/cjs/skills/installer.js +181 -0
  33. package/dist/cjs/skills/installer.js.map +1 -0
  34. package/dist/cjs/skills/parser.d.ts +39 -0
  35. package/dist/cjs/skills/parser.js +131 -0
  36. package/dist/cjs/skills/parser.js.map +1 -0
  37. package/dist/cjs/skills/types.d.ts +134 -0
  38. package/dist/cjs/skills/types.js +7 -0
  39. package/dist/cjs/skills/types.js.map +1 -0
  40. package/dist/esm/cli/base-command.d.ts +5 -0
  41. package/dist/esm/cli/base-command.js +22 -2
  42. package/dist/esm/cli/base-command.js.map +1 -1
  43. package/dist/esm/cli/hooks.d.ts +13 -5
  44. package/dist/esm/cli/hooks.js.map +1 -1
  45. package/dist/esm/config/resolver.d.ts +2 -1
  46. package/dist/esm/config/resolver.js +11 -7
  47. package/dist/esm/config/resolver.js.map +1 -1
  48. package/dist/esm/config/sources/dw-json-source.d.ts +1 -0
  49. package/dist/esm/config/sources/dw-json-source.js +1 -0
  50. package/dist/esm/config/sources/dw-json-source.js.map +1 -1
  51. package/dist/esm/config/sources/index.d.ts +1 -0
  52. package/dist/esm/config/sources/index.js +1 -0
  53. package/dist/esm/config/sources/index.js.map +1 -1
  54. package/dist/esm/config/sources/mobify-source.d.ts +1 -0
  55. package/dist/esm/config/sources/mobify-source.js +1 -0
  56. package/dist/esm/config/sources/mobify-source.js.map +1 -1
  57. package/dist/esm/config/sources/package-json-source.d.ts +14 -0
  58. package/dist/esm/config/sources/package-json-source.js +86 -0
  59. package/dist/esm/config/sources/package-json-source.js.map +1 -0
  60. package/dist/esm/config/types.d.ts +12 -0
  61. package/dist/esm/skills/agents.d.ts +41 -0
  62. package/dist/esm/skills/agents.js +159 -0
  63. package/dist/esm/skills/agents.js.map +1 -0
  64. package/dist/esm/skills/github.d.ts +47 -0
  65. package/dist/esm/skills/github.js +246 -0
  66. package/dist/esm/skills/github.js.map +1 -0
  67. package/dist/esm/skills/index.d.ts +42 -0
  68. package/dist/esm/skills/index.js +14 -0
  69. package/dist/esm/skills/index.js.map +1 -0
  70. package/dist/esm/skills/installer.d.ts +34 -0
  71. package/dist/esm/skills/installer.js +181 -0
  72. package/dist/esm/skills/installer.js.map +1 -0
  73. package/dist/esm/skills/parser.d.ts +39 -0
  74. package/dist/esm/skills/parser.js +131 -0
  75. package/dist/esm/skills/parser.js.map +1 -0
  76. package/dist/esm/skills/types.d.ts +134 -0
  77. package/dist/esm/skills/types.js +7 -0
  78. package/dist/esm/skills/types.js.map +1 -0
  79. package/package.json +12 -1
@@ -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
+ };
@@ -0,0 +1,131 @@
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 { getLogger } from '../logging/logger.js';
9
+ /**
10
+ * Parse simple YAML-like frontmatter from SKILL.md content.
11
+ * Only supports basic key: value pairs (name and description).
12
+ *
13
+ * @param content - File content with frontmatter
14
+ * @returns Parsed frontmatter or null if invalid
15
+ */
16
+ export function parseSkillFrontmatter(content) {
17
+ // Match frontmatter between --- delimiters
18
+ const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
19
+ if (!match) {
20
+ return null;
21
+ }
22
+ const frontmatter = match[1];
23
+ const result = {};
24
+ // Parse simple key: value lines
25
+ for (const line of frontmatter.split('\n')) {
26
+ const keyValueMatch = line.match(/^(\w+):\s*(.+)$/);
27
+ if (keyValueMatch) {
28
+ const [, key, value] = keyValueMatch;
29
+ if (key === 'name') {
30
+ result.name = value.trim();
31
+ }
32
+ else if (key === 'description') {
33
+ result.description = value.trim();
34
+ }
35
+ }
36
+ }
37
+ if (!result.name || !result.description) {
38
+ return null;
39
+ }
40
+ return { name: result.name, description: result.description };
41
+ }
42
+ /**
43
+ * Scan a directory for skills and extract their metadata.
44
+ *
45
+ * @param skillsDir - Path to extracted skills directory (e.g., ~/.cache/b2c-cli/skills/v0.1.0/b2c/skills/)
46
+ * @param skillSet - The skill set being scanned ('b2c' or 'b2c-cli')
47
+ * @returns Array of skill metadata
48
+ */
49
+ export async function scanSkills(skillsDir, skillSet) {
50
+ const logger = getLogger();
51
+ const skills = [];
52
+ // The extracted structure should be: skillsDir/skills/skill-name/SKILL.md
53
+ // Find the skills subdirectory
54
+ const skillsSubdir = path.join(skillsDir, 'skills');
55
+ if (!fs.existsSync(skillsSubdir)) {
56
+ logger.debug({ skillsDir, skillsSubdir }, 'Skills subdirectory not found');
57
+ return skills;
58
+ }
59
+ const entries = await fs.promises.readdir(skillsSubdir, { withFileTypes: true });
60
+ for (const entry of entries) {
61
+ if (!entry.isDirectory()) {
62
+ continue;
63
+ }
64
+ const skillDir = path.join(skillsSubdir, entry.name);
65
+ const skillPath = path.join(skillDir, 'SKILL.md');
66
+ if (!fs.existsSync(skillPath)) {
67
+ logger.debug({ skillDir }, 'No SKILL.md found, skipping');
68
+ continue;
69
+ }
70
+ try {
71
+ const content = await fs.promises.readFile(skillPath, 'utf-8');
72
+ const frontmatter = parseSkillFrontmatter(content);
73
+ if (!frontmatter) {
74
+ logger.warn({ skillPath }, 'Invalid frontmatter in SKILL.md');
75
+ continue;
76
+ }
77
+ // Check for references directory
78
+ const referencesDir = path.join(skillDir, 'references');
79
+ const hasReferences = fs.existsSync(referencesDir);
80
+ skills.push({
81
+ name: frontmatter.name,
82
+ description: frontmatter.description,
83
+ skillSet,
84
+ path: entry.name, // Relative path within skills directory
85
+ hasReferences,
86
+ });
87
+ }
88
+ catch (error) {
89
+ logger.warn({ skillPath, error }, 'Failed to parse SKILL.md');
90
+ }
91
+ }
92
+ logger.debug({ count: skills.length, skillSet }, 'Scanned skills');
93
+ return skills;
94
+ }
95
+ /**
96
+ * Filter skills by name.
97
+ *
98
+ * @param skills - All available skills
99
+ * @param names - Skill names to include (if provided)
100
+ * @returns Filtered skills
101
+ */
102
+ export function filterSkillsByName(skills, names) {
103
+ if (!names || names.length === 0) {
104
+ return skills;
105
+ }
106
+ const nameSet = new Set(names);
107
+ return skills.filter((skill) => nameSet.has(skill.name));
108
+ }
109
+ /**
110
+ * Find skills that match the given names, returning any that weren't found.
111
+ *
112
+ * @param skills - Available skills
113
+ * @param names - Requested skill names
114
+ * @returns Object with matched skills and names not found
115
+ */
116
+ export function findSkillsByName(skills, names) {
117
+ const skillMap = new Map(skills.map((s) => [s.name, s]));
118
+ const found = [];
119
+ const notFound = [];
120
+ for (const name of names) {
121
+ const skill = skillMap.get(name);
122
+ if (skill) {
123
+ found.push(skill);
124
+ }
125
+ else {
126
+ notFound.push(name);
127
+ }
128
+ }
129
+ return { found, notFound };
130
+ }
131
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../../src/skills/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Supported IDE types for skill installation.
3
+ */
4
+ export type IdeType = 'claude-code' | 'cursor' | 'windsurf' | 'vscode' | 'codex' | 'opencode' | 'manual';
5
+ /**
6
+ * Skill set categories matching the plugins directory structure.
7
+ */
8
+ export type SkillSet = 'b2c' | 'b2c-cli';
9
+ /**
10
+ * IDE path configuration for skill installation.
11
+ */
12
+ export interface IdePaths {
13
+ /** Relative path for project-level installation (e.g., '.claude/skills') */
14
+ projectDir: string;
15
+ /** Absolute path for global/user-level installation (e.g., '~/.claude/skills') */
16
+ globalDir: string;
17
+ }
18
+ /**
19
+ * IDE configuration including paths and display name.
20
+ */
21
+ export interface IdeConfig {
22
+ /** IDE identifier */
23
+ id: IdeType;
24
+ /** Human-readable display name */
25
+ displayName: string;
26
+ /** Installation paths */
27
+ paths: IdePaths;
28
+ /** Function to detect if IDE is installed */
29
+ detectInstalled: () => Promise<boolean>;
30
+ /** Optional documentation URL for skill configuration */
31
+ docsUrl?: string;
32
+ }
33
+ /**
34
+ * Skill metadata extracted from SKILL.md frontmatter.
35
+ */
36
+ export interface SkillMetadata {
37
+ /** Skill identifier from frontmatter name field */
38
+ name: string;
39
+ /** Skill description from frontmatter */
40
+ description: string;
41
+ /** Skill set this skill belongs to (b2c or b2c-cli) */
42
+ skillSet: SkillSet;
43
+ /** Relative path within the skills archive */
44
+ path: string;
45
+ /** Whether this skill has a references/ subdirectory */
46
+ hasReferences: boolean;
47
+ }
48
+ /**
49
+ * GitHub release information.
50
+ */
51
+ export interface ReleaseInfo {
52
+ /** Git tag name (e.g., 'v0.1.0') */
53
+ tagName: string;
54
+ /** Version number without 'v' prefix */
55
+ version: string;
56
+ /** ISO date string when release was published */
57
+ publishedAt: string;
58
+ /** Download URL for b2c-skills.zip asset, or null if not present */
59
+ b2cSkillsAssetUrl: string | null;
60
+ /** Download URL for b2c-cli-skills.zip asset, or null if not present */
61
+ b2cCliSkillsAssetUrl: string | null;
62
+ }
63
+ /**
64
+ * Options for downloading skills artifacts.
65
+ */
66
+ export interface DownloadSkillsOptions {
67
+ /** Specific release version to download (default: 'latest') */
68
+ version?: string;
69
+ /** Custom cache directory (default: ~/.cache/b2c-cli/skills/) */
70
+ cacheDir?: string;
71
+ /** Force re-download even if cached */
72
+ forceDownload?: boolean;
73
+ }
74
+ /**
75
+ * Options for installing skills.
76
+ */
77
+ export interface InstallSkillsOptions {
78
+ /** Specific skill names to install (default: all skills in skillset) */
79
+ skills?: string[];
80
+ /** Target IDEs to install to */
81
+ ides: IdeType[];
82
+ /** Install to global/user directory instead of project */
83
+ global: boolean;
84
+ /** Overwrite existing skills */
85
+ update: boolean;
86
+ /** Project root for project-level installations */
87
+ projectRoot?: string;
88
+ }
89
+ /**
90
+ * Result of a single skill installation.
91
+ */
92
+ export interface SkillInstallation {
93
+ skill: string;
94
+ ide: IdeType;
95
+ path: string;
96
+ }
97
+ /**
98
+ * Reason for skipping a skill installation.
99
+ */
100
+ export interface SkillSkipped {
101
+ skill: string;
102
+ ide: IdeType;
103
+ reason: string;
104
+ }
105
+ /**
106
+ * Error during skill installation.
107
+ */
108
+ export interface SkillError {
109
+ skill: string;
110
+ ide: IdeType;
111
+ error: string;
112
+ }
113
+ /**
114
+ * Result of installing skills.
115
+ */
116
+ export interface InstallSkillsResult {
117
+ /** Successfully installed skills */
118
+ installed: SkillInstallation[];
119
+ /** Skipped skills (already exist, no update flag) */
120
+ skipped: SkillSkipped[];
121
+ /** Failed installations */
122
+ errors: SkillError[];
123
+ }
124
+ /**
125
+ * Cached artifact metadata stored in manifest.json.
126
+ */
127
+ export interface CachedArtifact {
128
+ /** Version of the cached artifact */
129
+ version: string;
130
+ /** Path to the extracted skills directory */
131
+ path: string;
132
+ /** ISO date string when artifact was downloaded */
133
+ downloadedAt: string;
134
+ }
@@ -0,0 +1,7 @@
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
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/skills/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/b2c-tooling-sdk",
3
- "version": "0.0.0-nightly.20260120023917",
3
+ "version": "0.0.0-nightly.20260121023856",
4
4
  "description": "Core tooling library for Salesforce Commerce Cloud B2C CLI",
5
5
  "author": "Charles Lavery",
6
6
  "license": "Apache-2.0",
@@ -199,6 +199,17 @@
199
199
  "types": "./dist/cjs/discovery/index.d.ts",
200
200
  "default": "./dist/cjs/discovery/index.js"
201
201
  }
202
+ },
203
+ "./skills": {
204
+ "development": "./src/skills/index.ts",
205
+ "import": {
206
+ "types": "./dist/esm/skills/index.d.ts",
207
+ "default": "./dist/esm/skills/index.js"
208
+ },
209
+ "require": {
210
+ "types": "./dist/cjs/skills/index.d.ts",
211
+ "default": "./dist/cjs/skills/index.js"
212
+ }
202
213
  }
203
214
  },
204
215
  "main": "./dist/cjs/index.js",