@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
package/src/core/installer.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { writeFile, mkdir, readFile, rm } from 'fs/promises';
|
|
2
2
|
import { dirname } from 'path';
|
|
3
|
-
import { getSkillInstallPaths, getSkillMetadataPaths } from './config.js';
|
|
3
|
+
import { getSkillInstallPaths, getSkillMetadataPaths, type InstallOptions } from './config.js';
|
|
4
4
|
import { sha256 } from '../utils/hash.js';
|
|
5
5
|
import { info, warn } from '../utils/logger.js';
|
|
6
6
|
|
|
7
|
-
export async function installSkill(
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
export async function installSkill(
|
|
8
|
+
skillName: string,
|
|
9
|
+
skillContent: string,
|
|
10
|
+
options: InstallOptions = {}
|
|
11
|
+
): Promise<string[]> {
|
|
12
|
+
const installPaths = getSkillInstallPaths(skillName, options);
|
|
13
|
+
const metadataPaths = getSkillMetadataPaths(skillName, options);
|
|
10
14
|
const installedPaths: string[] = [];
|
|
11
15
|
const installedMetadataPaths: string[] = [];
|
|
12
16
|
const hash = sha256(skillContent);
|
|
@@ -50,21 +54,26 @@ export async function installSkill(skillName: string, skillContent: string): Pro
|
|
|
50
54
|
return installedPaths;
|
|
51
55
|
}
|
|
52
56
|
|
|
53
|
-
export async function removeSkill(
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
export async function removeSkill(
|
|
58
|
+
skillName: string,
|
|
59
|
+
options: InstallOptions = {}
|
|
60
|
+
): Promise<string[]> {
|
|
61
|
+
const installPaths = getSkillInstallPaths(skillName, options);
|
|
62
|
+
const metadataPaths = getSkillMetadataPaths(skillName, options);
|
|
56
63
|
const removedPaths: string[] = [];
|
|
57
64
|
|
|
58
65
|
for (let i = 0; i < installPaths.length; i++) {
|
|
59
66
|
const skillPath = installPaths[i];
|
|
60
67
|
const metadataPath = metadataPaths[i];
|
|
68
|
+
const skillDir = dirname(skillPath);
|
|
61
69
|
try {
|
|
62
70
|
await rm(skillPath, { force: true });
|
|
63
71
|
await rm(metadataPath, { force: true });
|
|
72
|
+
await rm(skillDir, { recursive: true, force: true });
|
|
64
73
|
removedPaths.push(skillPath);
|
|
65
|
-
info(`Removed ${
|
|
74
|
+
info(`Removed ${skillDir}`);
|
|
66
75
|
} catch (err) {
|
|
67
|
-
warn(`Failed to remove ${
|
|
76
|
+
warn(`Failed to remove ${skillDir}: ${err instanceof Error ? err.message : String(err)}`);
|
|
68
77
|
}
|
|
69
78
|
}
|
|
70
79
|
|
package/src/core/lockfile.ts
CHANGED
|
@@ -59,6 +59,21 @@ export async function removeSkillFromLockfile(skillName: string): Promise<void>
|
|
|
59
59
|
await writeLockfile(lockfile);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
export async function updateSkillInstallPathsInLockfile(
|
|
63
|
+
skillName: string,
|
|
64
|
+
installPaths: string[]
|
|
65
|
+
): Promise<void> {
|
|
66
|
+
const lockfile = await readLockfile();
|
|
67
|
+
const entry = lockfile.installedSkills[skillName];
|
|
68
|
+
if (!entry) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
entry.installPaths = installPaths;
|
|
73
|
+
entry.timestamp = new Date().toISOString();
|
|
74
|
+
await writeLockfile(lockfile);
|
|
75
|
+
}
|
|
76
|
+
|
|
62
77
|
export async function getInstalledSkills(): Promise<LockfileEntry[]> {
|
|
63
78
|
const lockfile = await readLockfile();
|
|
64
79
|
return Object.values(lockfile.installedSkills);
|
package/src/index.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
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
|
|
|
8
9
|
const args = process.argv.slice(2);
|
|
9
10
|
|
|
10
11
|
export async function main(): Promise<void> {
|
|
12
|
+
ui.printBanner();
|
|
13
|
+
|
|
11
14
|
if (args.length === 0) {
|
|
12
15
|
showHelp();
|
|
13
16
|
return;
|
|
@@ -18,11 +21,15 @@ export async function main(): Promise<void> {
|
|
|
18
21
|
try {
|
|
19
22
|
if (command === 'install' && args.length >= 2) {
|
|
20
23
|
const skill = args[1];
|
|
21
|
-
const
|
|
24
|
+
const flags = parseInstallFlags(args.slice(2));
|
|
25
|
+
const options = await resolveInstallOptionsFromFlags(flags, true);
|
|
26
|
+
const success = await install(skill, options);
|
|
22
27
|
process.exit(success ? 0 : 1);
|
|
23
28
|
} else if (command === 'remove' && args.length >= 2) {
|
|
24
29
|
const skill = args[1];
|
|
25
|
-
const
|
|
30
|
+
const flags = parseRemoveFlags(args.slice(2));
|
|
31
|
+
const options = await resolveRemoveOptionsFromFlags(flags, true);
|
|
32
|
+
const success = await remove(skill, options);
|
|
26
33
|
process.exit(success ? 0 : 1);
|
|
27
34
|
} else if (command === 'list') {
|
|
28
35
|
const jsonFlag = args.includes('--json');
|
|
@@ -43,7 +50,9 @@ export async function main(): Promise<void> {
|
|
|
43
50
|
process.exit(success ? 0 : 1);
|
|
44
51
|
} else if (!command.startsWith('-')) {
|
|
45
52
|
// Default behavior: treat first arg as skill name to install
|
|
46
|
-
const
|
|
53
|
+
const flags = parseInstallFlags(args.slice(1));
|
|
54
|
+
const options = await resolveInstallOptionsFromFlags(flags, true);
|
|
55
|
+
const success = await install(command, options);
|
|
47
56
|
process.exit(success ? 0 : 1);
|
|
48
57
|
} else {
|
|
49
58
|
showHelp();
|
|
@@ -59,16 +68,30 @@ function showHelp() {
|
|
|
59
68
|
AI Skills CLI - Install framework-agnostic SKILLS.md files
|
|
60
69
|
|
|
61
70
|
Usage:
|
|
62
|
-
ai-skills <skill> Install a skill
|
|
63
|
-
ai-skills install <skill> Install a skill
|
|
71
|
+
ai-skills <skill> [options] Install a skill
|
|
72
|
+
ai-skills install <skill> [options] Install a skill
|
|
64
73
|
ai-skills list [--json] List installed and available skills
|
|
65
|
-
ai-skills remove <skill>
|
|
74
|
+
ai-skills remove <skill> [options] Remove an installed skill
|
|
66
75
|
ai-skills update [--force] Update all installed skills
|
|
67
76
|
[--skill <name>] Update a specific skill
|
|
68
77
|
ai-skills generate-local [skill] Run local backend generator
|
|
69
78
|
|
|
79
|
+
Install options:
|
|
80
|
+
--local Install in current project (.ai-skills/skills)
|
|
81
|
+
--global Install in home agent folders
|
|
82
|
+
--all Install to all global platforms
|
|
83
|
+
--platform <a,b,c> Install to selected global platforms
|
|
84
|
+
|
|
85
|
+
Remove options:
|
|
86
|
+
--local Remove from current project platforms
|
|
87
|
+
--global Remove from home agent platforms
|
|
88
|
+
--all Remove from all platforms for selected scope
|
|
89
|
+
--platform <a,b,c> Remove from selected platforms for selected scope
|
|
90
|
+
|
|
70
91
|
Examples:
|
|
71
92
|
ai-skills react
|
|
93
|
+
ai-skills react --local
|
|
94
|
+
ai-skills react --platform claude,gemini,opencode,vscode,codex,agents
|
|
72
95
|
ai-skills install typescript
|
|
73
96
|
ai-skills list
|
|
74
97
|
ai-skills remove python
|
package/src/utils/logger.ts
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
|
|
3
5
|
export function log(message: string) {
|
|
4
6
|
console.log(message);
|
|
5
7
|
}
|
|
6
8
|
|
|
7
9
|
export function info(message: string) {
|
|
8
|
-
console.log(
|
|
10
|
+
console.log(`${chalk.cyan('ℹ')} ${chalk.gray(message)}`);
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
export function success(message: string) {
|
|
12
|
-
console.log(
|
|
14
|
+
console.log(`${chalk.green('✓')} ${chalk.green(message)}`);
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
export function error(message: string) {
|
|
16
|
-
console.error(
|
|
18
|
+
console.error(`${chalk.red('✗')} ${chalk.red(message)}`);
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
export function warn(message: string) {
|
|
20
|
-
console.warn(
|
|
22
|
+
console.warn(`${chalk.yellow('⚠')} ${chalk.yellow(message)}`);
|
|
21
23
|
}
|
package/src/utils/ui.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora, { type Ora } from 'ora';
|
|
3
|
+
import { info } from '../utils/logger.js';
|
|
4
|
+
|
|
5
|
+
let activeSpinner: Ora | null = null;
|
|
6
|
+
|
|
7
|
+
export const ui = {
|
|
8
|
+
bannerShown: false,
|
|
9
|
+
|
|
10
|
+
printBanner(): void {
|
|
11
|
+
if (this.bannerShown || !process.stdout.isTTY) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const title = chalk.bold.cyan('AI Skills CLI');
|
|
16
|
+
const subtitle = chalk.gray('Install framework-agnostic SKILLS.md files');
|
|
17
|
+
// Subtle, single-line banner to keep npx output concise
|
|
18
|
+
info(`${title} ${chalk.gray('•')} ${subtitle}`);
|
|
19
|
+
this.bannerShown = true;
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
startSpinner(text: string): void {
|
|
23
|
+
if (!process.stdout.isTTY) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (activeSpinner) {
|
|
28
|
+
activeSpinner.stop();
|
|
29
|
+
}
|
|
30
|
+
activeSpinner = ora({ text, spinner: 'dots' }).start();
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
stopSpinnerSuccess(text?: string): void {
|
|
34
|
+
if (!activeSpinner) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
activeSpinner.succeed(text);
|
|
38
|
+
activeSpinner = null;
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
stopSpinnerFail(text?: string): void {
|
|
42
|
+
if (!activeSpinner) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
activeSpinner.fail(text);
|
|
46
|
+
activeSpinner = null;
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
stopSpinner(): void {
|
|
50
|
+
if (!activeSpinner) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
activeSpinner.stop();
|
|
54
|
+
activeSpinner = null;
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|