@emmraan/ai-skills 0.0.3 → 1.0.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 +41 -0
- package/dist/commands/install.d.ts +10 -1
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +123 -5
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/remove.d.ts +10 -1
- package/dist/commands/remove.d.ts.map +1 -1
- package/dist/commands/remove.js +126 -6
- package/dist/commands/remove.js.map +1 -1
- package/dist/core/config.d.ts +13 -2
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +28 -4
- package/dist/core/config.js.map +1 -1
- package/dist/core/installer.d.ts +3 -2
- package/dist/core/installer.d.ts.map +1 -1
- package/dist/core/installer.js +10 -8
- package/dist/core/installer.js.map +1 -1
- package/dist/core/lockfile.d.ts +1 -0
- package/dist/core/lockfile.d.ts.map +1 -1
- package/dist/core/lockfile.js +10 -0
- package/dist/core/lockfile.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -8
- package/dist/index.js.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +5 -4
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/ui.d.ts +9 -0
- package/dist/utils/ui.d.ts.map +1 -0
- package/dist/utils/ui.js +48 -0
- package/dist/utils/ui.js.map +1 -0
- package/package.json +6 -1
- package/src/commands/install.ts +149 -5
- package/src/commands/remove.ts +156 -6
- package/src/core/config.ts +50 -4
- package/src/core/installer.ts +18 -9
- package/src/core/lockfile.ts +15 -0
- package/src/index.ts +31 -8
- package/src/utils/logger.ts +6 -4
- package/src/utils/ui.ts +57 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lockfile.js","sourceRoot":"","sources":["../../src/core/lockfile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAe9C,MAAM,gBAAgB,GAAa;IACjC,OAAO,EAAE,CAAC;IACV,eAAe,EAAE,EAAE;CACpB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;IAC/B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,gBAAgB,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAkB;IACpD,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;IAC/B,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,SAAiB,EACjB,OAAe,EACf,IAAY,EACZ,YAAsB;IAEtB,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;IACtC,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC,GAAG;QACpC,IAAI,EAAE,SAAS;QACf,OAAO;QACP,IAAI;QACJ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,YAAY;KACb,CAAC;IACF,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,SAAiB;IAC7D,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;IACtC,OAAO,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;IAC3C,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;IACtC,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,SAAiB;IACnD,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;IACtC,OAAO,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;AACrD,CAAC"}
|
|
1
|
+
{"version":3,"file":"lockfile.js","sourceRoot":"","sources":["../../src/core/lockfile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAe9C,MAAM,gBAAgB,GAAa;IACjC,OAAO,EAAE,CAAC;IACV,eAAe,EAAE,EAAE;CACpB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;IAC/B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,gBAAgB,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAkB;IACpD,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;IAC/B,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,SAAiB,EACjB,OAAe,EACf,IAAY,EACZ,YAAsB;IAEtB,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;IACtC,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC,GAAG;QACpC,IAAI,EAAE,SAAS;QACf,OAAO;QACP,IAAI;QACJ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,YAAY;KACb,CAAC;IACF,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,SAAiB;IAC7D,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;IACtC,OAAO,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;IAC3C,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iCAAiC,CACrD,SAAiB,EACjB,YAAsB;IAEtB,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;IACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;IAClD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;IACT,CAAC;IAED,KAAK,CAAC,YAAY,GAAG,YAAY,CAAC;IAClC,KAAK,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;IACtC,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,SAAiB;IACnD,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;IACtC,OAAO,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;AACrD,CAAC"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAqD1C"}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { install } from './commands/install.js';
|
|
2
|
-
import { remove } from './commands/remove.js';
|
|
1
|
+
import { install, parseInstallFlags, resolveInstallOptionsFromFlags } from './commands/install.js';
|
|
2
|
+
import { remove, parseRemoveFlags, resolveRemoveOptionsFromFlags } from './commands/remove.js';
|
|
3
3
|
import { list } from './commands/list.js';
|
|
4
4
|
import { update } from './commands/update.js';
|
|
5
5
|
import { generateLocal } from './commands/generate-local.js';
|
|
6
6
|
import { error, info } from './utils/logger.js';
|
|
7
|
+
import { ui } from './utils/ui.js';
|
|
7
8
|
const args = process.argv.slice(2);
|
|
8
9
|
export async function main() {
|
|
10
|
+
ui.printBanner();
|
|
9
11
|
if (args.length === 0) {
|
|
10
12
|
showHelp();
|
|
11
13
|
return;
|
|
@@ -14,12 +16,16 @@ export async function main() {
|
|
|
14
16
|
try {
|
|
15
17
|
if (command === 'install' && args.length >= 2) {
|
|
16
18
|
const skill = args[1];
|
|
17
|
-
const
|
|
19
|
+
const flags = parseInstallFlags(args.slice(2));
|
|
20
|
+
const options = await resolveInstallOptionsFromFlags(flags, true);
|
|
21
|
+
const success = await install(skill, options);
|
|
18
22
|
process.exit(success ? 0 : 1);
|
|
19
23
|
}
|
|
20
24
|
else if (command === 'remove' && args.length >= 2) {
|
|
21
25
|
const skill = args[1];
|
|
22
|
-
const
|
|
26
|
+
const flags = parseRemoveFlags(args.slice(2));
|
|
27
|
+
const options = await resolveRemoveOptionsFromFlags(flags, true);
|
|
28
|
+
const success = await remove(skill, options);
|
|
23
29
|
process.exit(success ? 0 : 1);
|
|
24
30
|
}
|
|
25
31
|
else if (command === 'list') {
|
|
@@ -44,7 +50,9 @@ export async function main() {
|
|
|
44
50
|
}
|
|
45
51
|
else if (!command.startsWith('-')) {
|
|
46
52
|
// Default behavior: treat first arg as skill name to install
|
|
47
|
-
const
|
|
53
|
+
const flags = parseInstallFlags(args.slice(1));
|
|
54
|
+
const options = await resolveInstallOptionsFromFlags(flags, true);
|
|
55
|
+
const success = await install(command, options);
|
|
48
56
|
process.exit(success ? 0 : 1);
|
|
49
57
|
}
|
|
50
58
|
else {
|
|
@@ -61,16 +69,30 @@ function showHelp() {
|
|
|
61
69
|
AI Skills CLI - Install framework-agnostic SKILLS.md files
|
|
62
70
|
|
|
63
71
|
Usage:
|
|
64
|
-
ai-skills <skill> Install a skill
|
|
65
|
-
ai-skills install <skill> Install a skill
|
|
72
|
+
ai-skills <skill> [options] Install a skill
|
|
73
|
+
ai-skills install <skill> [options] Install a skill
|
|
66
74
|
ai-skills list [--json] List installed and available skills
|
|
67
|
-
ai-skills remove <skill>
|
|
75
|
+
ai-skills remove <skill> [options] Remove an installed skill
|
|
68
76
|
ai-skills update [--force] Update all installed skills
|
|
69
77
|
[--skill <name>] Update a specific skill
|
|
70
78
|
ai-skills generate-local [skill] Run local backend generator
|
|
71
79
|
|
|
80
|
+
Install options:
|
|
81
|
+
--local Install in current project (.ai-skills/skills)
|
|
82
|
+
--global Install in home agent folders
|
|
83
|
+
--all Install to all global platforms
|
|
84
|
+
--platform <a,b,c> Install to selected global platforms
|
|
85
|
+
|
|
86
|
+
Remove options:
|
|
87
|
+
--local Remove from current project platforms
|
|
88
|
+
--global Remove from home agent platforms
|
|
89
|
+
--all Remove from all platforms for selected scope
|
|
90
|
+
--platform <a,b,c> Remove from selected platforms for selected scope
|
|
91
|
+
|
|
72
92
|
Examples:
|
|
73
93
|
ai-skills react
|
|
94
|
+
ai-skills react --local
|
|
95
|
+
ai-skills react --platform claude,gemini,opencode,vscode,codex,agents
|
|
74
96
|
ai-skills install typescript
|
|
75
97
|
ai-skills list
|
|
76
98
|
ai-skills remove python
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAIA,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,QAElC;AAED,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,QAEnC;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,QAEtC;AAED,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,QAEpC;AAED,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,QAEnC"}
|
package/dist/utils/logger.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
+
import chalk from 'chalk';
|
|
2
3
|
export function log(message) {
|
|
3
4
|
console.log(message);
|
|
4
5
|
}
|
|
5
6
|
export function info(message) {
|
|
6
|
-
console.log(
|
|
7
|
+
console.log(`${chalk.cyan('ℹ')} ${chalk.gray(message)}`);
|
|
7
8
|
}
|
|
8
9
|
export function success(message) {
|
|
9
|
-
console.log(
|
|
10
|
+
console.log(`${chalk.green('✓')} ${chalk.green(message)}`);
|
|
10
11
|
}
|
|
11
12
|
export function error(message) {
|
|
12
|
-
console.error(
|
|
13
|
+
console.error(`${chalk.red('✗')} ${chalk.red(message)}`);
|
|
13
14
|
}
|
|
14
15
|
export function warn(message) {
|
|
15
|
-
console.warn(
|
|
16
|
+
console.warn(`${chalk.yellow('⚠')} ${chalk.yellow(message)}`);
|
|
16
17
|
}
|
|
17
18
|
//# sourceMappingURL=logger.js.map
|
package/dist/utils/logger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAE/B,MAAM,UAAU,GAAG,CAAC,OAAe;IACjC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,OAAe;IAClC,OAAO,CAAC,GAAG,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAE/B,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,UAAU,GAAG,CAAC,OAAe;IACjC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,OAAe;IAClC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,OAAe;IACrC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,OAAe;IACnC,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,OAAe;IAClC,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/utils/ui.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,EAAE;;mBAGE,IAAI;uBAYA,MAAM,GAAG,IAAI;8BAWN,MAAM,GAAG,IAAI;2BAQhB,MAAM,GAAG,IAAI;mBAQrB,IAAI;CAOpB,CAAC"}
|
package/dist/utils/ui.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { info } from '../utils/logger.js';
|
|
4
|
+
let activeSpinner = null;
|
|
5
|
+
export const ui = {
|
|
6
|
+
bannerShown: false,
|
|
7
|
+
printBanner() {
|
|
8
|
+
if (this.bannerShown || !process.stdout.isTTY) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const title = chalk.bold.cyan('AI Skills CLI');
|
|
12
|
+
const subtitle = chalk.gray('Install framework-agnostic SKILLS.md files');
|
|
13
|
+
// Subtle, single-line banner to keep npx output concise
|
|
14
|
+
info(`${title} ${chalk.gray('•')} ${subtitle}`);
|
|
15
|
+
this.bannerShown = true;
|
|
16
|
+
},
|
|
17
|
+
startSpinner(text) {
|
|
18
|
+
if (!process.stdout.isTTY) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (activeSpinner) {
|
|
22
|
+
activeSpinner.stop();
|
|
23
|
+
}
|
|
24
|
+
activeSpinner = ora({ text, spinner: 'dots' }).start();
|
|
25
|
+
},
|
|
26
|
+
stopSpinnerSuccess(text) {
|
|
27
|
+
if (!activeSpinner) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
activeSpinner.succeed(text);
|
|
31
|
+
activeSpinner = null;
|
|
32
|
+
},
|
|
33
|
+
stopSpinnerFail(text) {
|
|
34
|
+
if (!activeSpinner) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
activeSpinner.fail(text);
|
|
38
|
+
activeSpinner = null;
|
|
39
|
+
},
|
|
40
|
+
stopSpinner() {
|
|
41
|
+
if (!activeSpinner) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
activeSpinner.stop();
|
|
45
|
+
activeSpinner = null;
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=ui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/utils/ui.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAiB,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE1C,IAAI,aAAa,GAAe,IAAI,CAAC;AAErC,MAAM,CAAC,MAAM,EAAE,GAAG;IAChB,WAAW,EAAE,KAAK;IAElB,WAAW;QACT,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAC9C,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QAC1E,wDAAwD;QACxD,IAAI,CAAC,GAAG,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED,YAAY,CAAC,IAAY;QACvB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAC1B,OAAO;QACT,CAAC;QAED,IAAI,aAAa,EAAE,CAAC;YAClB,aAAa,CAAC,IAAI,EAAE,CAAC;QACvB,CAAC;QACD,aAAa,GAAG,GAAG,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;IACzD,CAAC;IAED,kBAAkB,CAAC,IAAa;QAC9B,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,OAAO;QACT,CAAC;QACD,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5B,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC;IAED,eAAe,CAAC,IAAa;QAC3B,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,OAAO;QACT,CAAC;QACD,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC;IAED,WAAW;QACT,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,OAAO;QACT,CAAC;QACD,aAAa,CAAC,IAAI,EAAE,CAAC;QACrB,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC;CACF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@emmraan/ai-skills",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "CLI tool for installing AI Skills across agent platforms",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,6 +23,11 @@
|
|
|
23
23
|
"typecheck": "tsc --noEmit --project tsconfig.json",
|
|
24
24
|
"clean": "rm -rf dist"
|
|
25
25
|
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"chalk": "^5.4.1",
|
|
28
|
+
"inquirer": "^12.9.6",
|
|
29
|
+
"ora": "^8.2.0"
|
|
30
|
+
},
|
|
26
31
|
"devDependencies": {
|
|
27
32
|
"@ai-skills/shared-types": "workspace:*",
|
|
28
33
|
"@types/node": "^20.10.0",
|
package/src/commands/install.ts
CHANGED
|
@@ -1,30 +1,174 @@
|
|
|
1
1
|
import { fetchSkill, fetchRegistryIndex } from '../core/downloader.js';
|
|
2
2
|
import { installSkill } from '../core/installer.js';
|
|
3
3
|
import { addSkillToLockfile } from '../core/lockfile.js';
|
|
4
|
+
import { AGENT_PLATFORMS, type InstallOptions, type InstallLocation } from '../core/config.js';
|
|
4
5
|
import { sha256 } from '../utils/hash.js';
|
|
5
|
-
import { error, success
|
|
6
|
+
import { error, success } from '../utils/logger.js';
|
|
7
|
+
import inquirer from 'inquirer';
|
|
8
|
+
import { ui } from '../utils/ui.js';
|
|
6
9
|
|
|
7
|
-
export
|
|
10
|
+
export interface CliInstallFlags {
|
|
11
|
+
local?: boolean;
|
|
12
|
+
global?: boolean;
|
|
13
|
+
all?: boolean;
|
|
14
|
+
platforms?: string[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function parseInstallFlags(args: string[]): CliInstallFlags {
|
|
18
|
+
const flags: CliInstallFlags = {};
|
|
19
|
+
|
|
20
|
+
for (let i = 0; i < args.length; i++) {
|
|
21
|
+
const arg = args[i];
|
|
22
|
+
if (arg === '--local') {
|
|
23
|
+
flags.local = true;
|
|
24
|
+
} else if (arg === '--global') {
|
|
25
|
+
flags.global = true;
|
|
26
|
+
} else if (arg === '--all') {
|
|
27
|
+
flags.all = true;
|
|
28
|
+
} else if (arg === '--platform') {
|
|
29
|
+
const value = args[i + 1];
|
|
30
|
+
if (!value || value.startsWith('--')) {
|
|
31
|
+
throw new Error('Missing value for --platform. Example: --platform claude,gemini');
|
|
32
|
+
}
|
|
33
|
+
i++;
|
|
34
|
+
const parsed = value
|
|
35
|
+
.split(',')
|
|
36
|
+
.map((p) => p.trim())
|
|
37
|
+
.filter(Boolean);
|
|
38
|
+
flags.platforms = [...(flags.platforms ?? []), ...parsed];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return flags;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function resolveInstallOptionsFromFlags(
|
|
46
|
+
flags: CliInstallFlags,
|
|
47
|
+
interactive: boolean
|
|
48
|
+
): Promise<InstallOptions> {
|
|
49
|
+
if (flags.local && flags.global) {
|
|
50
|
+
throw new Error('Use only one of --local or --global');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const hasAnyFlag = Boolean(
|
|
54
|
+
flags.local || flags.global || flags.all || (flags.platforms ?? []).length
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
if (flags.local) {
|
|
58
|
+
return {
|
|
59
|
+
location: 'local',
|
|
60
|
+
all: flags.all || !flags.platforms || flags.platforms.length === 0,
|
|
61
|
+
platforms: flags.platforms,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (flags.global) {
|
|
66
|
+
return {
|
|
67
|
+
location: 'global',
|
|
68
|
+
all: flags.all || !flags.platforms || flags.platforms.length === 0,
|
|
69
|
+
platforms: flags.platforms,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if ((flags.platforms ?? []).length > 0 || flags.all) {
|
|
74
|
+
return {
|
|
75
|
+
location: 'global',
|
|
76
|
+
all: flags.all,
|
|
77
|
+
platforms: flags.platforms,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!hasAnyFlag) {
|
|
82
|
+
if (interactive && process.stdin.isTTY && process.stdout.isTTY) {
|
|
83
|
+
return promptInstallOptions();
|
|
84
|
+
}
|
|
85
|
+
return { location: 'global', all: true };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return { location: 'global', all: true };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function promptInstallOptions(): Promise<InstallOptions> {
|
|
92
|
+
const { location } = await inquirer.prompt<{ location: InstallLocation }>([
|
|
93
|
+
{
|
|
94
|
+
type: 'list',
|
|
95
|
+
name: 'location',
|
|
96
|
+
message: 'Install location',
|
|
97
|
+
choices: [
|
|
98
|
+
{ name: 'Local (current project)', value: 'local' },
|
|
99
|
+
{ name: 'Global (agent platforms)', value: 'global' },
|
|
100
|
+
],
|
|
101
|
+
default: 'global',
|
|
102
|
+
},
|
|
103
|
+
]);
|
|
104
|
+
|
|
105
|
+
const { target } = await inquirer.prompt<{ target: 'all' | 'specific' }>([
|
|
106
|
+
{
|
|
107
|
+
type: 'list',
|
|
108
|
+
name: 'target',
|
|
109
|
+
message: `${location === 'local' ? 'Local' : 'Global'} install target`,
|
|
110
|
+
choices: [
|
|
111
|
+
{ name: 'All platforms', value: 'all' },
|
|
112
|
+
{ name: 'Specific platforms', value: 'specific' },
|
|
113
|
+
],
|
|
114
|
+
default: 'all',
|
|
115
|
+
},
|
|
116
|
+
]);
|
|
117
|
+
|
|
118
|
+
if (target === 'all') {
|
|
119
|
+
return { location, all: true };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const platformChoices = AGENT_PLATFORMS.map((platform) => {
|
|
123
|
+
const value = platform.replace(/^\./, '');
|
|
124
|
+
return { name: value, value };
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const { platforms } = await inquirer.prompt<{ platforms: string[] }>([
|
|
128
|
+
{
|
|
129
|
+
type: 'checkbox',
|
|
130
|
+
name: 'platforms',
|
|
131
|
+
message: 'Select target platforms',
|
|
132
|
+
choices: platformChoices,
|
|
133
|
+
pageSize: 10,
|
|
134
|
+
validate: (value: string[]) =>
|
|
135
|
+
value.length > 0 ? true : 'Please select at least one platform.',
|
|
136
|
+
},
|
|
137
|
+
]);
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
location,
|
|
141
|
+
all: false,
|
|
142
|
+
platforms,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export async function install(skillName: string, options: InstallOptions = {}): Promise<boolean> {
|
|
8
147
|
try {
|
|
9
|
-
|
|
148
|
+
ui.startSpinner(`Fetching ${skillName}...`);
|
|
10
149
|
const skillContent = await fetchSkill(skillName);
|
|
150
|
+
ui.stopSpinnerSuccess(`Fetched ${skillName}`);
|
|
11
151
|
const hash = sha256(skillContent);
|
|
12
152
|
|
|
13
|
-
|
|
14
|
-
const installPaths = await installSkill(skillName, skillContent);
|
|
153
|
+
ui.startSpinner(`Installing ${skillName}...`);
|
|
154
|
+
const installPaths = await installSkill(skillName, skillContent, options);
|
|
155
|
+
ui.stopSpinnerSuccess(`Installed files for ${skillName}`);
|
|
15
156
|
|
|
16
157
|
if (installPaths.length === 0) {
|
|
17
158
|
error(`Failed to install ${skillName} to any location`);
|
|
18
159
|
return false;
|
|
19
160
|
}
|
|
20
161
|
|
|
162
|
+
ui.startSpinner(`Updating lockfile for ${skillName}...`);
|
|
21
163
|
const index = await fetchRegistryIndex();
|
|
22
164
|
const skillVersion = index.skills[skillName]?.version || 'unknown';
|
|
23
165
|
|
|
24
166
|
await addSkillToLockfile(skillName, skillVersion, hash, installPaths);
|
|
167
|
+
ui.stopSpinnerSuccess(`Updated lockfile for ${skillName}`);
|
|
25
168
|
success(`Installed ${skillName} (${skillVersion}) to ${installPaths.length} location(s)`);
|
|
26
169
|
return true;
|
|
27
170
|
} catch (err) {
|
|
171
|
+
ui.stopSpinner();
|
|
28
172
|
error(`Failed to install ${skillName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
29
173
|
return false;
|
|
30
174
|
}
|
package/src/commands/remove.ts
CHANGED
|
@@ -1,8 +1,149 @@
|
|
|
1
1
|
import { removeSkill } from '../core/installer.js';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
removeSkillFromLockfile,
|
|
4
|
+
getSkillEntry,
|
|
5
|
+
updateSkillInstallPathsInLockfile,
|
|
6
|
+
} from '../core/lockfile.js';
|
|
7
|
+
import { AGENT_PLATFORMS, type InstallLocation, type InstallOptions } from '../core/config.js';
|
|
3
8
|
import { error, success, info } from '../utils/logger.js';
|
|
9
|
+
import { ui } from '../utils/ui.js';
|
|
10
|
+
import inquirer from 'inquirer';
|
|
4
11
|
|
|
5
|
-
export
|
|
12
|
+
export interface CliRemoveFlags {
|
|
13
|
+
local?: boolean;
|
|
14
|
+
global?: boolean;
|
|
15
|
+
all?: boolean;
|
|
16
|
+
platforms?: string[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function parseRemoveFlags(args: string[]): CliRemoveFlags {
|
|
20
|
+
const flags: CliRemoveFlags = {};
|
|
21
|
+
|
|
22
|
+
for (let i = 0; i < args.length; i++) {
|
|
23
|
+
const arg = args[i];
|
|
24
|
+
if (arg === '--local') {
|
|
25
|
+
flags.local = true;
|
|
26
|
+
} else if (arg === '--global') {
|
|
27
|
+
flags.global = true;
|
|
28
|
+
} else if (arg === '--all') {
|
|
29
|
+
flags.all = true;
|
|
30
|
+
} else if (arg === '--platform') {
|
|
31
|
+
const value = args[i + 1];
|
|
32
|
+
if (!value || value.startsWith('--')) {
|
|
33
|
+
throw new Error('Missing value for --platform. Example: --platform claude,gemini');
|
|
34
|
+
}
|
|
35
|
+
i++;
|
|
36
|
+
const parsed = value
|
|
37
|
+
.split(',')
|
|
38
|
+
.map((p) => p.trim())
|
|
39
|
+
.filter(Boolean);
|
|
40
|
+
flags.platforms = [...(flags.platforms ?? []), ...parsed];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return flags;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function resolveRemoveOptionsFromFlags(
|
|
48
|
+
flags: CliRemoveFlags,
|
|
49
|
+
interactive: boolean
|
|
50
|
+
): Promise<InstallOptions> {
|
|
51
|
+
if (flags.local && flags.global) {
|
|
52
|
+
throw new Error('Use only one of --local or --global');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const hasAnyFlag = Boolean(
|
|
56
|
+
flags.local || flags.global || flags.all || (flags.platforms ?? []).length
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
if (flags.local) {
|
|
60
|
+
return {
|
|
61
|
+
location: 'local',
|
|
62
|
+
all: flags.all || !flags.platforms || flags.platforms.length === 0,
|
|
63
|
+
platforms: flags.platforms,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (flags.global) {
|
|
68
|
+
return {
|
|
69
|
+
location: 'global',
|
|
70
|
+
all: flags.all || !flags.platforms || flags.platforms.length === 0,
|
|
71
|
+
platforms: flags.platforms,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if ((flags.platforms ?? []).length > 0 || flags.all) {
|
|
76
|
+
return {
|
|
77
|
+
location: 'global',
|
|
78
|
+
all: flags.all,
|
|
79
|
+
platforms: flags.platforms,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!hasAnyFlag) {
|
|
84
|
+
if (interactive && process.stdin.isTTY && process.stdout.isTTY) {
|
|
85
|
+
return promptRemoveOptions();
|
|
86
|
+
}
|
|
87
|
+
return { location: 'global', all: true };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return { location: 'global', all: true };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function promptRemoveOptions(): Promise<InstallOptions> {
|
|
94
|
+
const { location } = await inquirer.prompt<{ location: InstallLocation }>([
|
|
95
|
+
{
|
|
96
|
+
type: 'list',
|
|
97
|
+
name: 'location',
|
|
98
|
+
message: 'Remove from location',
|
|
99
|
+
choices: [
|
|
100
|
+
{ name: 'Local (current project)', value: 'local' },
|
|
101
|
+
{ name: 'Global (agent platforms)', value: 'global' },
|
|
102
|
+
],
|
|
103
|
+
default: 'global',
|
|
104
|
+
},
|
|
105
|
+
]);
|
|
106
|
+
|
|
107
|
+
const { target } = await inquirer.prompt<{ target: 'all' | 'specific' }>([
|
|
108
|
+
{
|
|
109
|
+
type: 'list',
|
|
110
|
+
name: 'target',
|
|
111
|
+
message: `${location === 'local' ? 'Local' : 'Global'} remove target`,
|
|
112
|
+
choices: [
|
|
113
|
+
{ name: 'All platforms', value: 'all' },
|
|
114
|
+
{ name: 'Specific platforms', value: 'specific' },
|
|
115
|
+
],
|
|
116
|
+
default: 'all',
|
|
117
|
+
},
|
|
118
|
+
]);
|
|
119
|
+
|
|
120
|
+
if (target === 'all') {
|
|
121
|
+
return { location, all: true };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const platformChoices = AGENT_PLATFORMS.map((platform) => {
|
|
125
|
+
const value = platform.replace(/^\./, '');
|
|
126
|
+
return { name: value, value };
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const { platforms } = await inquirer.prompt<{ platforms: string[] }>([
|
|
130
|
+
{
|
|
131
|
+
type: 'checkbox',
|
|
132
|
+
name: 'platforms',
|
|
133
|
+
message: 'Select target platforms',
|
|
134
|
+
choices: platformChoices,
|
|
135
|
+
pageSize: 10,
|
|
136
|
+
},
|
|
137
|
+
]);
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
location,
|
|
141
|
+
all: platforms.length === 0,
|
|
142
|
+
platforms,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export async function remove(skillName: string, options: InstallOptions = {}): Promise<boolean> {
|
|
6
147
|
try {
|
|
7
148
|
const entry = await getSkillEntry(skillName);
|
|
8
149
|
if (!entry) {
|
|
@@ -10,12 +151,21 @@ export async function remove(skillName: string): Promise<boolean> {
|
|
|
10
151
|
return true;
|
|
11
152
|
}
|
|
12
153
|
|
|
13
|
-
|
|
14
|
-
await removeSkill(skillName);
|
|
15
|
-
|
|
16
|
-
|
|
154
|
+
ui.startSpinner(`Removing ${skillName}...`);
|
|
155
|
+
const removedPaths = await removeSkill(skillName, options);
|
|
156
|
+
|
|
157
|
+
const remaining = entry.installPaths.filter((p) => !removedPaths.includes(p));
|
|
158
|
+
if (remaining.length === 0) {
|
|
159
|
+
await removeSkillFromLockfile(skillName);
|
|
160
|
+
} else {
|
|
161
|
+
await updateSkillInstallPathsInLockfile(skillName, remaining);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
ui.stopSpinnerSuccess(`Removed files for ${skillName}`);
|
|
165
|
+
success(`Removed ${skillName} from ${removedPaths.length} location(s)`);
|
|
17
166
|
return true;
|
|
18
167
|
} catch (err) {
|
|
168
|
+
ui.stopSpinner();
|
|
19
169
|
error(`Failed to remove ${skillName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
20
170
|
return false;
|
|
21
171
|
}
|
package/src/core/config.ts
CHANGED
|
@@ -8,22 +8,68 @@ export const REGISTRY_INDEX_URL = `${REGISTRY_URL}/skills/.index.json`;
|
|
|
8
8
|
|
|
9
9
|
export const AGENT_PLATFORMS = ['.claude', '.gemini', '.vscode', '.opencode', '.codex', '.agents'];
|
|
10
10
|
|
|
11
|
+
export type InstallLocation = 'local' | 'global';
|
|
12
|
+
|
|
13
|
+
export interface InstallOptions {
|
|
14
|
+
location?: InstallLocation;
|
|
15
|
+
platforms?: string[];
|
|
16
|
+
all?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ResolvedInstallOptions {
|
|
20
|
+
location: InstallLocation;
|
|
21
|
+
platforms: string[];
|
|
22
|
+
}
|
|
23
|
+
|
|
11
24
|
export function getAgentPlatformDirs(): string[] {
|
|
12
25
|
const home = homedir();
|
|
13
26
|
return AGENT_PLATFORMS.map((p) => join(home, p, 'skills'));
|
|
14
27
|
}
|
|
15
28
|
|
|
29
|
+
export function resolveInstallOptions(options: InstallOptions = {}): ResolvedInstallOptions {
|
|
30
|
+
const location: InstallLocation = options.location ?? 'global';
|
|
31
|
+
|
|
32
|
+
const normalized = (options.platforms ?? []).map((p) => normalizePlatformName(p));
|
|
33
|
+
const unique = [...new Set(normalized)];
|
|
34
|
+
|
|
35
|
+
if (options.all || unique.length === 0) {
|
|
36
|
+
return { location, platforms: [...AGENT_PLATFORMS] };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
for (const p of unique) {
|
|
40
|
+
if (!AGENT_PLATFORMS.includes(p)) {
|
|
41
|
+
throw new Error(`Unknown platform: ${p}. Supported: ${AGENT_PLATFORMS.join(', ')}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return { location, platforms: unique };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function normalizePlatformName(name: string): string {
|
|
49
|
+
const trimmed = name.trim();
|
|
50
|
+
return trimmed.startsWith('.') ? trimmed : `.${trimmed}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getSelectedPlatformDirs(resolved: ResolvedInstallOptions): string[] {
|
|
54
|
+
const baseDir = resolved.location === 'local' ? process.cwd() : homedir();
|
|
55
|
+
return resolved.platforms.map((p) => join(baseDir, p, 'skills'));
|
|
56
|
+
}
|
|
57
|
+
|
|
16
58
|
export function getLockfilePath(): string {
|
|
17
59
|
const home = homedir();
|
|
18
60
|
return join(home, '.ai-skills', '.skill-lock.json');
|
|
19
61
|
}
|
|
20
62
|
|
|
21
|
-
export function getSkillInstallPaths(skillName: string): string[] {
|
|
22
|
-
|
|
63
|
+
export function getSkillInstallPaths(skillName: string, options: InstallOptions = {}): string[] {
|
|
64
|
+
const resolved = resolveInstallOptions(options);
|
|
65
|
+
return getSelectedPlatformDirs(resolved).map((dir) => join(dir, skillName, 'SKILLS.md'));
|
|
23
66
|
}
|
|
24
67
|
|
|
25
|
-
export function getSkillMetadataPaths(skillName: string): string[] {
|
|
26
|
-
|
|
68
|
+
export function getSkillMetadataPaths(skillName: string, options: InstallOptions = {}): string[] {
|
|
69
|
+
const resolved = resolveInstallOptions(options);
|
|
70
|
+
return getSelectedPlatformDirs(resolved).map((dir) =>
|
|
71
|
+
join(dir, skillName, '.skill-metadata.json')
|
|
72
|
+
);
|
|
27
73
|
}
|
|
28
74
|
|
|
29
75
|
export const IS_WINDOWS = platform() === 'win32';
|