@emmraan/ai-skills 0.0.1 → 0.0.3

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/README.md CHANGED
@@ -1,24 +1,24 @@
1
- # AI Skills CLI
2
-
3
- Install framework-agnostic `SKILLS.md` files for AI agents.
4
-
5
- ## Usage
6
-
7
- - `npx ai-skills react` - Install React skill
8
- - `npx ai-skills install react` - Install React skill (explicit command)
9
- - `npx ai-skills list` - List available and installed skills
10
- - `npx ai-skills update` - Update all installed skills
11
- - `npx ai-skills remove react` - Remove React skill
12
- - `npx ai-skills generate-local` - Run local backend generator
13
-
14
- ## Publish to npm
15
-
16
- This package is the publishable CLI package for the `ai-skills` command.
17
-
18
- 1. Build from workspace root: `pnpm build`
19
- 2. Login to npm: `npm login`
20
- 3. Publish CLI package: `npm publish --access public` (run inside `packages/cli`)
21
-
22
- After publishing, users can run:
23
-
24
- - `npx ai-skills list`
1
+ # AI Skills CLI
2
+
3
+ Install framework-agnostic `SKILLS.md` files for AI agents.
4
+
5
+ ## Usage
6
+
7
+ - `npx @emmraan/ai-skills react` - Install React skill
8
+ - `npx @emmraan/ai-skills install react` - Install React skill (explicit command)
9
+ - `npx @emmraan/ai-skills list` - List available and installed skills
10
+ - `npx @emmraan/ai-skills update` - Update all installed skills
11
+ - `npx @emmraan/ai-skills remove react` - Remove React skill
12
+ - `npx @emmraan/ai-skills generate-local` - Run local backend generator
13
+
14
+ ## Publish to npm
15
+
16
+ This package is the publishable CLI package for the `ai-skills` command.
17
+
18
+ 1. Build from workspace root: `pnpm build`
19
+ 2. Login to npm: `npm login`
20
+ 3. Publish CLI package: `npm publish --access public` (run inside `packages/cli`)
21
+
22
+ After publishing, users can run:
23
+
24
+ - `npx @emmraan/ai-skills list`
package/bin/skills.js CHANGED
@@ -1,3 +1,3 @@
1
- #!/usr/bin/env node
2
-
3
- import '../dist/bin/skills.js';
1
+ #!/usr/bin/env node
2
+
3
+ import '../dist/bin/skills.js';
package/dist/index.js CHANGED
@@ -57,27 +57,27 @@ export async function main() {
57
57
  }
58
58
  }
59
59
  function showHelp() {
60
- info(`
61
- AI Skills CLI - Install framework-agnostic SKILLS.md files
62
-
63
- Usage:
64
- ai-skills <skill> Install a skill
65
- ai-skills install <skill> Install a skill
66
- ai-skills list [--json] List installed and available skills
67
- ai-skills remove <skill> Remove an installed skill
68
- ai-skills update [--force] Update all installed skills
69
- [--skill <name>] Update a specific skill
70
- ai-skills generate-local [skill] Run local backend generator
71
-
72
- Examples:
73
- ai-skills react
74
- ai-skills install typescript
75
- ai-skills list
76
- ai-skills remove python
77
- ai-skills update --force
78
- ai-skills update --skill react
79
- ai-skills generate-local
80
- ai-skills generate-local react
60
+ info(`
61
+ AI Skills CLI - Install framework-agnostic SKILLS.md files
62
+
63
+ Usage:
64
+ ai-skills <skill> Install a skill
65
+ ai-skills install <skill> Install a skill
66
+ ai-skills list [--json] List installed and available skills
67
+ ai-skills remove <skill> Remove an installed skill
68
+ ai-skills update [--force] Update all installed skills
69
+ [--skill <name>] Update a specific skill
70
+ ai-skills generate-local [skill] Run local backend generator
71
+
72
+ Examples:
73
+ ai-skills react
74
+ ai-skills install typescript
75
+ ai-skills list
76
+ ai-skills remove python
77
+ ai-skills update --force
78
+ ai-skills update --skill react
79
+ ai-skills generate-local
80
+ ai-skills generate-local react
81
81
  `);
82
82
  }
83
83
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,34 +1,32 @@
1
- {
2
- "name": "@emmraan/ai-skills",
3
- "version": "0.0.1",
4
- "description": "CLI tool for installing AI Skills across agent platforms",
5
- "type": "module",
6
- "bin": {
7
- "ai-skills": "bin/skills.js",
8
- "skills": "bin/skills.js"
9
- },
10
- "main": "./dist/index.js",
11
- "types": "./dist/index.d.ts",
12
- "exports": {
13
- ".": {
14
- "import": "./dist/index.js",
15
- "types": "./dist/index.d.ts"
16
- }
17
- },
18
- "scripts": {
19
- "build": "tsc --project tsconfig.json",
20
- "dev": "tsx src/bin/skills.ts",
21
- "test": "vitest run",
22
- "lint": "node -e \"process.exit(0)\"",
23
- "typecheck": "tsc --noEmit --project tsconfig.json",
24
- "clean": "rm -rf dist"
25
- },
26
- "dependencies": {
27
- "@ai-skills/shared-types": "workspace:*"
28
- },
29
- "devDependencies": {
30
- "@types/node": "^20.10.0",
31
- "tsx": "^4.7.0",
32
- "vitest": "^1.1.0"
33
- }
34
- }
1
+ {
2
+ "name": "@emmraan/ai-skills",
3
+ "version": "0.0.3",
4
+ "description": "CLI tool for installing AI Skills across agent platforms",
5
+ "type": "module",
6
+ "bin": {
7
+ "ai-skills": "bin/skills.js",
8
+ "skills": "bin/skills.js"
9
+ },
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "import": "./dist/index.js",
15
+ "types": "./dist/index.d.ts"
16
+ }
17
+ },
18
+ "scripts": {
19
+ "build": "tsc --project tsconfig.json",
20
+ "dev": "tsx src/bin/skills.ts",
21
+ "test": "vitest run",
22
+ "lint": "node -e \"process.exit(0)\"",
23
+ "typecheck": "tsc --noEmit --project tsconfig.json",
24
+ "clean": "rm -rf dist"
25
+ },
26
+ "devDependencies": {
27
+ "@ai-skills/shared-types": "workspace:*",
28
+ "@types/node": "^20.10.0",
29
+ "tsx": "^4.7.0",
30
+ "vitest": "^1.1.0"
31
+ }
32
+ }
package/src/bin/skills.ts CHANGED
@@ -1,8 +1,8 @@
1
- #!/usr/bin/env node
2
-
3
- import { main } from '../index.js';
4
-
5
- main().catch((err) => {
6
- console.error('Fatal error:', err);
7
- process.exit(1);
8
- });
1
+ #!/usr/bin/env node
2
+
3
+ import { main } from '../index.js';
4
+
5
+ main().catch((err) => {
6
+ console.error('Fatal error:', err);
7
+ process.exit(1);
8
+ });
@@ -1,49 +1,49 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
-
3
- vi.mock('../../core/downloader', () => ({
4
- fetchSkill: vi.fn(),
5
- fetchRegistryIndex: vi.fn(),
6
- }));
7
-
8
- vi.mock('../../core/installer', () => ({
9
- installSkill: vi.fn(),
10
- }));
11
-
12
- vi.mock('../../core/lockfile', () => ({
13
- addSkillToLockfile: vi.fn(),
14
- }));
15
-
16
- import { install } from '../../commands/install';
17
-
18
- describe('install command', () => {
19
- beforeEach(() => {
20
- vi.clearAllMocks();
21
- });
22
-
23
- it('uses registry index version when writing lockfile', async () => {
24
- const downloader = await import('../../core/downloader');
25
- const installer = await import('../../core/installer');
26
- const lockfile = await import('../../core/lockfile');
27
-
28
- vi.mocked(downloader.fetchSkill).mockResolvedValue('# React Skill');
29
- vi.mocked(downloader.fetchRegistryIndex).mockResolvedValue({
30
- skills: {
31
- react: {
32
- version: '18.2.0',
33
- domains: ['frontend'],
34
- lastGenerated: '2026-02-06T00:00:00Z',
35
- },
36
- },
37
- });
38
- vi.mocked(installer.installSkill).mockResolvedValue(['/tmp/.agents/skills/react/SKILLS.md']);
39
-
40
- const ok = await install('react');
41
- expect(ok).toBe(true);
42
- expect(lockfile.addSkillToLockfile).toHaveBeenCalledWith(
43
- 'react',
44
- '18.2.0',
45
- expect.stringMatching(/^[a-f0-9]{64}$/),
46
- ['/tmp/.agents/skills/react/SKILLS.md']
47
- );
48
- });
49
- });
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+
3
+ vi.mock('../../core/downloader', () => ({
4
+ fetchSkill: vi.fn(),
5
+ fetchRegistryIndex: vi.fn(),
6
+ }));
7
+
8
+ vi.mock('../../core/installer', () => ({
9
+ installSkill: vi.fn(),
10
+ }));
11
+
12
+ vi.mock('../../core/lockfile', () => ({
13
+ addSkillToLockfile: vi.fn(),
14
+ }));
15
+
16
+ import { install } from '../../commands/install';
17
+
18
+ describe('install command', () => {
19
+ beforeEach(() => {
20
+ vi.clearAllMocks();
21
+ });
22
+
23
+ it('uses registry index version when writing lockfile', async () => {
24
+ const downloader = await import('../../core/downloader');
25
+ const installer = await import('../../core/installer');
26
+ const lockfile = await import('../../core/lockfile');
27
+
28
+ vi.mocked(downloader.fetchSkill).mockResolvedValue('# React Skill');
29
+ vi.mocked(downloader.fetchRegistryIndex).mockResolvedValue({
30
+ skills: {
31
+ react: {
32
+ version: '18.2.0',
33
+ domains: ['frontend'],
34
+ lastGenerated: '2026-02-06T00:00:00Z',
35
+ },
36
+ },
37
+ });
38
+ vi.mocked(installer.installSkill).mockResolvedValue(['/tmp/.agents/skills/react/SKILLS.md']);
39
+
40
+ const ok = await install('react');
41
+ expect(ok).toBe(true);
42
+ expect(lockfile.addSkillToLockfile).toHaveBeenCalledWith(
43
+ 'react',
44
+ '18.2.0',
45
+ expect.stringMatching(/^[a-f0-9]{64}$/),
46
+ ['/tmp/.agents/skills/react/SKILLS.md']
47
+ );
48
+ });
49
+ });
@@ -1,38 +1,38 @@
1
- import { spawn } from 'child_process';
2
- import { resolve } from 'path';
3
- import { error, info, success } from '../utils/logger.js';
4
-
5
- export async function generateLocal(skill?: string): Promise<boolean> {
6
- const backendDir = resolve(process.cwd(), 'backend');
7
- const command = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm';
8
- const args = ['run', 'generate'];
9
-
10
- if (skill) {
11
- args.push('--', '--skill', skill);
12
- }
13
-
14
- info(`Running local generator in ${backendDir}...`);
15
-
16
- return new Promise((resolvePromise) => {
17
- const child = spawn(command, args, {
18
- cwd: backendDir,
19
- stdio: 'inherit',
20
- shell: false,
21
- });
22
-
23
- child.on('error', (err) => {
24
- error(`Failed to start local generator: ${err.message}`);
25
- resolvePromise(false);
26
- });
27
-
28
- child.on('exit', (code) => {
29
- if (code === 0) {
30
- success('Local generation completed successfully');
31
- resolvePromise(true);
32
- } else {
33
- error(`Local generation failed with exit code ${code ?? -1}`);
34
- resolvePromise(false);
35
- }
36
- });
37
- });
38
- }
1
+ import { spawn } from 'child_process';
2
+ import { resolve } from 'path';
3
+ import { error, info, success } from '../utils/logger.js';
4
+
5
+ export async function generateLocal(skill?: string): Promise<boolean> {
6
+ const backendDir = resolve(process.cwd(), 'backend');
7
+ const command = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm';
8
+ const args = ['run', 'generate'];
9
+
10
+ if (skill) {
11
+ args.push('--', '--skill', skill);
12
+ }
13
+
14
+ info(`Running local generator in ${backendDir}...`);
15
+
16
+ return new Promise((resolvePromise) => {
17
+ const child = spawn(command, args, {
18
+ cwd: backendDir,
19
+ stdio: 'inherit',
20
+ shell: false,
21
+ });
22
+
23
+ child.on('error', (err) => {
24
+ error(`Failed to start local generator: ${err.message}`);
25
+ resolvePromise(false);
26
+ });
27
+
28
+ child.on('exit', (code) => {
29
+ if (code === 0) {
30
+ success('Local generation completed successfully');
31
+ resolvePromise(true);
32
+ } else {
33
+ error(`Local generation failed with exit code ${code ?? -1}`);
34
+ resolvePromise(false);
35
+ }
36
+ });
37
+ });
38
+ }
@@ -1,31 +1,31 @@
1
- import { fetchSkill, fetchRegistryIndex } from '../core/downloader.js';
2
- import { installSkill } from '../core/installer.js';
3
- import { addSkillToLockfile } from '../core/lockfile.js';
4
- import { sha256 } from '../utils/hash.js';
5
- import { error, success, info } from '../utils/logger.js';
6
-
7
- export async function install(skillName: string): Promise<boolean> {
8
- try {
9
- info(`Fetching ${skillName}...`);
10
- const skillContent = await fetchSkill(skillName);
11
- const hash = sha256(skillContent);
12
-
13
- info(`Installing ${skillName}...`);
14
- const installPaths = await installSkill(skillName, skillContent);
15
-
16
- if (installPaths.length === 0) {
17
- error(`Failed to install ${skillName} to any location`);
18
- return false;
19
- }
20
-
21
- const index = await fetchRegistryIndex();
22
- const skillVersion = index.skills[skillName]?.version || 'unknown';
23
-
24
- await addSkillToLockfile(skillName, skillVersion, hash, installPaths);
25
- success(`Installed ${skillName} (${skillVersion}) to ${installPaths.length} location(s)`);
26
- return true;
27
- } catch (err) {
28
- error(`Failed to install ${skillName}: ${err instanceof Error ? err.message : String(err)}`);
29
- return false;
30
- }
31
- }
1
+ import { fetchSkill, fetchRegistryIndex } from '../core/downloader.js';
2
+ import { installSkill } from '../core/installer.js';
3
+ import { addSkillToLockfile } from '../core/lockfile.js';
4
+ import { sha256 } from '../utils/hash.js';
5
+ import { error, success, info } from '../utils/logger.js';
6
+
7
+ export async function install(skillName: string): Promise<boolean> {
8
+ try {
9
+ info(`Fetching ${skillName}...`);
10
+ const skillContent = await fetchSkill(skillName);
11
+ const hash = sha256(skillContent);
12
+
13
+ info(`Installing ${skillName}...`);
14
+ const installPaths = await installSkill(skillName, skillContent);
15
+
16
+ if (installPaths.length === 0) {
17
+ error(`Failed to install ${skillName} to any location`);
18
+ return false;
19
+ }
20
+
21
+ const index = await fetchRegistryIndex();
22
+ const skillVersion = index.skills[skillName]?.version || 'unknown';
23
+
24
+ await addSkillToLockfile(skillName, skillVersion, hash, installPaths);
25
+ success(`Installed ${skillName} (${skillVersion}) to ${installPaths.length} location(s)`);
26
+ return true;
27
+ } catch (err) {
28
+ error(`Failed to install ${skillName}: ${err instanceof Error ? err.message : String(err)}`);
29
+ return false;
30
+ }
31
+ }
@@ -1,41 +1,41 @@
1
- import { getAvailableSkills } from '../core/downloader.js';
2
- import { getInstalledSkills } from '../core/lockfile.js';
3
- import { log } from '../utils/logger.js';
4
-
5
- export async function list(json: boolean = false): Promise<void> {
6
- const installedSkills = await getInstalledSkills();
7
- const availableSkills = await getAvailableSkills();
8
-
9
- const installed = installedSkills.map((s) => s.name);
10
-
11
- if (json) {
12
- const output = {
13
- installed,
14
- available: availableSkills,
15
- summary: {
16
- installedCount: installed.length,
17
- availableCount: availableSkills.length,
18
- },
19
- };
20
- log(JSON.stringify(output, null, 2));
21
- } else {
22
- log('\nšŸ“¦ Installed Skills:');
23
- if (installed.length === 0) {
24
- log(' (none)');
25
- } else {
26
- installed.forEach((name) => {
27
- const entry = installedSkills.find((s) => s.name === name);
28
- log(` • ${name} (v${entry?.version || 'unknown'})`);
29
- });
30
- }
31
-
32
- log('\n🌐 Available Skills:');
33
- availableSkills.forEach((name) => {
34
- const isInstalled = installed.includes(name);
35
- const status = isInstalled ? ' [installed]' : '';
36
- log(` • ${name}${status}`);
37
- });
38
-
39
- log(`\nTotal: ${installed.length} installed, ${availableSkills.length} available\n`);
40
- }
41
- }
1
+ import { getAvailableSkills } from '../core/downloader.js';
2
+ import { getInstalledSkills } from '../core/lockfile.js';
3
+ import { log } from '../utils/logger.js';
4
+
5
+ export async function list(json: boolean = false): Promise<void> {
6
+ const installedSkills = await getInstalledSkills();
7
+ const availableSkills = await getAvailableSkills();
8
+
9
+ const installed = installedSkills.map((s) => s.name);
10
+
11
+ if (json) {
12
+ const output = {
13
+ installed,
14
+ available: availableSkills,
15
+ summary: {
16
+ installedCount: installed.length,
17
+ availableCount: availableSkills.length,
18
+ },
19
+ };
20
+ log(JSON.stringify(output, null, 2));
21
+ } else {
22
+ log('\nšŸ“¦ Installed Skills:');
23
+ if (installed.length === 0) {
24
+ log(' (none)');
25
+ } else {
26
+ installed.forEach((name) => {
27
+ const entry = installedSkills.find((s) => s.name === name);
28
+ log(` • ${name} (v${entry?.version || 'unknown'})`);
29
+ });
30
+ }
31
+
32
+ log('\n🌐 Available Skills:');
33
+ availableSkills.forEach((name) => {
34
+ const isInstalled = installed.includes(name);
35
+ const status = isInstalled ? ' [installed]' : '';
36
+ log(` • ${name}${status}`);
37
+ });
38
+
39
+ log(`\nTotal: ${installed.length} installed, ${availableSkills.length} available\n`);
40
+ }
41
+ }
@@ -1,22 +1,22 @@
1
- import { removeSkill } from '../core/installer.js';
2
- import { removeSkillFromLockfile, getSkillEntry } from '../core/lockfile.js';
3
- import { error, success, info } from '../utils/logger.js';
4
-
5
- export async function remove(skillName: string): Promise<boolean> {
6
- try {
7
- const entry = await getSkillEntry(skillName);
8
- if (!entry) {
9
- info(`${skillName} is not installed`);
10
- return true;
11
- }
12
-
13
- info(`Removing ${skillName}...`);
14
- await removeSkill(skillName);
15
- await removeSkillFromLockfile(skillName);
16
- success(`Removed ${skillName}`);
17
- return true;
18
- } catch (err) {
19
- error(`Failed to remove ${skillName}: ${err instanceof Error ? err.message : String(err)}`);
20
- return false;
21
- }
22
- }
1
+ import { removeSkill } from '../core/installer.js';
2
+ import { removeSkillFromLockfile, getSkillEntry } from '../core/lockfile.js';
3
+ import { error, success, info } from '../utils/logger.js';
4
+
5
+ export async function remove(skillName: string): Promise<boolean> {
6
+ try {
7
+ const entry = await getSkillEntry(skillName);
8
+ if (!entry) {
9
+ info(`${skillName} is not installed`);
10
+ return true;
11
+ }
12
+
13
+ info(`Removing ${skillName}...`);
14
+ await removeSkill(skillName);
15
+ await removeSkillFromLockfile(skillName);
16
+ success(`Removed ${skillName}`);
17
+ return true;
18
+ } catch (err) {
19
+ error(`Failed to remove ${skillName}: ${err instanceof Error ? err.message : String(err)}`);
20
+ return false;
21
+ }
22
+ }