@skillsmanager/cli 0.0.1
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 +84 -0
- package/dist/auth.d.ts +5 -0
- package/dist/auth.js +68 -0
- package/dist/backends/gdrive.d.ts +24 -0
- package/dist/backends/gdrive.js +371 -0
- package/dist/backends/interface.d.ts +14 -0
- package/dist/backends/interface.js +1 -0
- package/dist/backends/local.d.ts +20 -0
- package/dist/backends/local.js +159 -0
- package/dist/bm25.d.ts +20 -0
- package/dist/bm25.js +65 -0
- package/dist/cache.d.ts +21 -0
- package/dist/cache.js +59 -0
- package/dist/commands/add.d.ts +3 -0
- package/dist/commands/add.js +62 -0
- package/dist/commands/collection.d.ts +1 -0
- package/dist/commands/collection.js +42 -0
- package/dist/commands/fetch.d.ts +5 -0
- package/dist/commands/fetch.js +46 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +45 -0
- package/dist/commands/install.d.ts +8 -0
- package/dist/commands/install.js +89 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.js +38 -0
- package/dist/commands/refresh.d.ts +1 -0
- package/dist/commands/refresh.js +46 -0
- package/dist/commands/registry.d.ts +14 -0
- package/dist/commands/registry.js +258 -0
- package/dist/commands/search.d.ts +1 -0
- package/dist/commands/search.js +37 -0
- package/dist/commands/setup/google.d.ts +1 -0
- package/dist/commands/setup/google.js +281 -0
- package/dist/commands/update.d.ts +3 -0
- package/dist/commands/update.js +83 -0
- package/dist/config.d.ts +28 -0
- package/dist/config.js +136 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +128 -0
- package/dist/ready.d.ts +15 -0
- package/dist/ready.js +39 -0
- package/dist/registry.d.ts +10 -0
- package/dist/registry.js +58 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.js +13 -0
- package/package.json +56 -0
- package/skills/skillsmanager/SKILL.md +139 -0
package/dist/ready.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { OAuth2Client } from "google-auth-library";
|
|
2
|
+
import { GDriveBackend } from "./backends/gdrive.js";
|
|
3
|
+
import type { Config } from "./types.js";
|
|
4
|
+
export interface ReadyContext {
|
|
5
|
+
auth: OAuth2Client;
|
|
6
|
+
config: Config;
|
|
7
|
+
backend: GDriveBackend;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Ensures the user is authenticated and has at least one collection configured.
|
|
11
|
+
* - If not authenticated: launches OAuth flow automatically.
|
|
12
|
+
* - If no config or empty collections: auto-discovers from Google Drive.
|
|
13
|
+
* Call this at the start of any command that needs Drive access.
|
|
14
|
+
*/
|
|
15
|
+
export declare function ensureReady(): Promise<ReadyContext>;
|
package/dist/ready.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { ensureAuth } from "./auth.js";
|
|
3
|
+
import { readConfig, writeConfig, mergeCollections, CONFIG_PATH } from "./config.js";
|
|
4
|
+
import { GDriveBackend } from "./backends/gdrive.js";
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
/**
|
|
7
|
+
* Ensures the user is authenticated and has at least one collection configured.
|
|
8
|
+
* - If not authenticated: launches OAuth flow automatically.
|
|
9
|
+
* - If no config or empty collections: auto-discovers from Google Drive.
|
|
10
|
+
* Call this at the start of any command that needs Drive access.
|
|
11
|
+
*/
|
|
12
|
+
export async function ensureReady() {
|
|
13
|
+
const auth = await ensureAuth();
|
|
14
|
+
const backend = new GDriveBackend(auth);
|
|
15
|
+
// Try to load config
|
|
16
|
+
let config = null;
|
|
17
|
+
if (fs.existsSync(CONFIG_PATH)) {
|
|
18
|
+
try {
|
|
19
|
+
config = readConfig();
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
config = null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// Auto-discover if no config or no collections
|
|
26
|
+
if (!config || config.collections.length === 0) {
|
|
27
|
+
process.stdout.write(chalk.dim("Discovering collections... "));
|
|
28
|
+
const fresh = await backend.discoverCollections();
|
|
29
|
+
const collections = mergeCollections(fresh, config?.collections ?? []);
|
|
30
|
+
config = { registries: config?.registries ?? [], collections, skills: config?.skills ?? {}, discoveredAt: new Date().toISOString() };
|
|
31
|
+
writeConfig(config);
|
|
32
|
+
if (collections.length === 0) {
|
|
33
|
+
process.stdout.write("\n");
|
|
34
|
+
throw new Error("No collections found. Run: skillsmanager collection create <name>");
|
|
35
|
+
}
|
|
36
|
+
process.stdout.write(chalk.green(`found ${collections.length}.\n`));
|
|
37
|
+
}
|
|
38
|
+
return { auth, config: config, backend };
|
|
39
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CollectionFile, RegistryFile } from "./types.js";
|
|
2
|
+
export declare const REGISTRY_FILENAME = "SKILLS_REGISTRY.yaml";
|
|
3
|
+
export declare const COLLECTION_FILENAME = "SKILLS_COLLECTION.yaml";
|
|
4
|
+
export declare const LEGACY_COLLECTION_FILENAME = "SKILLS_SYNC.yaml";
|
|
5
|
+
export declare function parseCollection(content: string): CollectionFile;
|
|
6
|
+
export declare function serializeCollection(collection: CollectionFile): string;
|
|
7
|
+
export declare const parseRegistry: typeof parseCollection;
|
|
8
|
+
export declare const serializeRegistry: typeof serializeCollection;
|
|
9
|
+
export declare function parseRegistryFile(content: string): RegistryFile;
|
|
10
|
+
export declare function serializeRegistryFile(registry: RegistryFile): string;
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import YAML from "yaml";
|
|
2
|
+
// ── Filename constants ───────────────────────────────────────────────────────
|
|
3
|
+
export const REGISTRY_FILENAME = "SKILLS_REGISTRY.yaml";
|
|
4
|
+
export const COLLECTION_FILENAME = "SKILLS_COLLECTION.yaml";
|
|
5
|
+
export const LEGACY_COLLECTION_FILENAME = "SKILLS_SYNC.yaml";
|
|
6
|
+
// ── Collection (formerly "registry") parsing ─────────────────────────────────
|
|
7
|
+
export function parseCollection(content) {
|
|
8
|
+
const data = YAML.parse(content);
|
|
9
|
+
return {
|
|
10
|
+
name: data.name ?? "",
|
|
11
|
+
owner: data.owner ?? "",
|
|
12
|
+
skills: (data.skills ?? []).map((s) => ({
|
|
13
|
+
name: s.name,
|
|
14
|
+
path: s.path ?? `${s.name}/`,
|
|
15
|
+
description: s.description ?? "",
|
|
16
|
+
})),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function serializeCollection(collection) {
|
|
20
|
+
return YAML.stringify({
|
|
21
|
+
name: collection.name,
|
|
22
|
+
owner: collection.owner,
|
|
23
|
+
skills: collection.skills.map((s) => ({
|
|
24
|
+
name: s.name,
|
|
25
|
+
path: s.path,
|
|
26
|
+
description: s.description,
|
|
27
|
+
})),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
// Backwards-compat aliases
|
|
31
|
+
export const parseRegistry = parseCollection;
|
|
32
|
+
export const serializeRegistry = serializeCollection;
|
|
33
|
+
// ── Registry file parsing ────────────────────────────────────────────────────
|
|
34
|
+
export function parseRegistryFile(content) {
|
|
35
|
+
const data = YAML.parse(content);
|
|
36
|
+
return {
|
|
37
|
+
name: data.name ?? "",
|
|
38
|
+
owner: data.owner ?? "",
|
|
39
|
+
source: data.source ?? "local",
|
|
40
|
+
collections: (data.collections ?? []).map((c) => ({
|
|
41
|
+
name: c.name,
|
|
42
|
+
backend: c.backend ?? "local",
|
|
43
|
+
ref: c.ref ?? c.name,
|
|
44
|
+
})),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export function serializeRegistryFile(registry) {
|
|
48
|
+
return YAML.stringify({
|
|
49
|
+
name: registry.name,
|
|
50
|
+
owner: registry.owner,
|
|
51
|
+
source: registry.source,
|
|
52
|
+
collections: registry.collections.map((c) => ({
|
|
53
|
+
name: c.name,
|
|
54
|
+
backend: c.backend,
|
|
55
|
+
ref: c.ref,
|
|
56
|
+
})),
|
|
57
|
+
});
|
|
58
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export interface SkillEntry {
|
|
2
|
+
name: string;
|
|
3
|
+
path: string;
|
|
4
|
+
description: string;
|
|
5
|
+
}
|
|
6
|
+
export interface CollectionFile {
|
|
7
|
+
name: string;
|
|
8
|
+
owner: string;
|
|
9
|
+
skills: SkillEntry[];
|
|
10
|
+
}
|
|
11
|
+
export interface CollectionInfo {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
backend: string;
|
|
15
|
+
folderId: string;
|
|
16
|
+
registryFileId?: string;
|
|
17
|
+
sourceRegistryId?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface RegistryCollectionRef {
|
|
20
|
+
name: string;
|
|
21
|
+
backend: string;
|
|
22
|
+
ref: string;
|
|
23
|
+
}
|
|
24
|
+
export interface RegistryFile {
|
|
25
|
+
name: string;
|
|
26
|
+
owner: string;
|
|
27
|
+
source: string;
|
|
28
|
+
collections: RegistryCollectionRef[];
|
|
29
|
+
}
|
|
30
|
+
export interface RegistryInfo {
|
|
31
|
+
id: string;
|
|
32
|
+
name: string;
|
|
33
|
+
backend: string;
|
|
34
|
+
folderId: string;
|
|
35
|
+
fileId?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface SkillLocation {
|
|
38
|
+
collectionId: string;
|
|
39
|
+
installedAt: string[];
|
|
40
|
+
}
|
|
41
|
+
export interface SkillIndex {
|
|
42
|
+
[skillName: string]: SkillLocation[];
|
|
43
|
+
}
|
|
44
|
+
export interface Config {
|
|
45
|
+
registries: RegistryInfo[];
|
|
46
|
+
collections: CollectionInfo[];
|
|
47
|
+
skills: SkillIndex;
|
|
48
|
+
discoveredAt: string;
|
|
49
|
+
}
|
|
50
|
+
export interface ResolvedSkill {
|
|
51
|
+
entry: SkillEntry;
|
|
52
|
+
collection: CollectionInfo;
|
|
53
|
+
}
|
|
54
|
+
export declare const AGENT_PATHS: Record<string, string>;
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import os from "os";
|
|
2
|
+
import path from "path";
|
|
3
|
+
// Agent name → user-level skills directory path
|
|
4
|
+
export const AGENT_PATHS = {
|
|
5
|
+
claude: path.join(os.homedir(), ".claude", "skills"),
|
|
6
|
+
codex: path.join(os.homedir(), ".codex", "skills"),
|
|
7
|
+
agents: path.join(os.homedir(), ".agents", "skills"),
|
|
8
|
+
cursor: path.join(os.homedir(), ".cursor", "skills"),
|
|
9
|
+
windsurf: path.join(os.homedir(), ".codeium", "windsurf", "skills"),
|
|
10
|
+
copilot: path.join(os.homedir(), ".copilot", "skills"),
|
|
11
|
+
gemini: path.join(os.homedir(), ".gemini", "skills"),
|
|
12
|
+
roo: path.join(os.homedir(), ".roo", "skills"),
|
|
13
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@skillsmanager/cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Discover, fetch, and manage agent skills from local or remote storage",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"skillsmanager": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/",
|
|
11
|
+
"!dist/tests/",
|
|
12
|
+
"skills/"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"prepublishOnly": "npm run build",
|
|
17
|
+
"dev": "node --loader ts-node/esm src/index.ts",
|
|
18
|
+
"test": "vitest run",
|
|
19
|
+
"test:watch": "vitest"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"ai",
|
|
23
|
+
"agent",
|
|
24
|
+
"skills",
|
|
25
|
+
"claude",
|
|
26
|
+
"codex",
|
|
27
|
+
"cursor",
|
|
28
|
+
"copilot",
|
|
29
|
+
"gemini",
|
|
30
|
+
"registry",
|
|
31
|
+
"sync"
|
|
32
|
+
],
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/talktoajayprakash/skillsmanager.git"
|
|
36
|
+
},
|
|
37
|
+
"author": "Ajay Prakash",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"homepage": "https://github.com/talktoajayprakash/skillsmanager#readme",
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"chalk": "^4.1.2",
|
|
42
|
+
"commander": "^12.0.0",
|
|
43
|
+
"googleapis": "^144.0.0",
|
|
44
|
+
"ora": "^5.4.1",
|
|
45
|
+
"yaml": "^2.4.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^20.0.0",
|
|
49
|
+
"ts-node": "^10.9.2",
|
|
50
|
+
"typescript": "^5.4.0",
|
|
51
|
+
"vitest": "^4.1.0"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=18"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skillsmanager
|
|
3
|
+
description: Discover, fetch, add, and update agent skills from local or remote storage using the skillsmanager CLI
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Skills Manager
|
|
7
|
+
|
|
8
|
+
Skills Manager is a CLI tool for managing agent skills stored locally or in remote storage (Google Drive). Use it to find, install, share, and update skills. Works offline by default — no setup needed for local use.
|
|
9
|
+
|
|
10
|
+
## Prerequisites
|
|
11
|
+
|
|
12
|
+
- Local storage works out of the box — no setup needed.
|
|
13
|
+
- For Google Drive: a human must run `skillsmanager setup google` once to configure credentials.
|
|
14
|
+
- All commands except `setup google` are non-interactive and designed for agent use.
|
|
15
|
+
|
|
16
|
+
## Commands
|
|
17
|
+
|
|
18
|
+
### Find and install a skill
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Search by name or description (BM25 ranked — partial/reordered terms work)
|
|
22
|
+
skillsmanager search <query>
|
|
23
|
+
|
|
24
|
+
# Download and install for this agent
|
|
25
|
+
skillsmanager fetch <name> --agent <agent>
|
|
26
|
+
|
|
27
|
+
# Install to current project only (instead of global)
|
|
28
|
+
skillsmanager fetch <name> --agent <agent> --scope project
|
|
29
|
+
|
|
30
|
+
# List all available skills across all collections
|
|
31
|
+
skillsmanager list
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Supported agents: `claude`, `codex`, `agents`, `cursor`, `windsurf`, `copilot`, `gemini`, `roo`
|
|
35
|
+
|
|
36
|
+
### Share a skill
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Upload a local skill directory to a collection
|
|
40
|
+
# The directory must contain a SKILL.md with name and description in YAML frontmatter
|
|
41
|
+
skillsmanager add <path>
|
|
42
|
+
|
|
43
|
+
# Upload to a specific collection
|
|
44
|
+
skillsmanager add <path> --collection <name>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Update a skill
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Push local edits back to storage
|
|
51
|
+
# The skill must have been fetched on this machine first
|
|
52
|
+
skillsmanager update <path>
|
|
53
|
+
|
|
54
|
+
# If the skill exists in multiple collections, specify which one
|
|
55
|
+
skillsmanager update <path> --collection <name>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
After updating, the local cache is refreshed so all symlinks on this machine reflect the change immediately.
|
|
59
|
+
|
|
60
|
+
### Registry and collection management
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Create a local registry (auto-created on first use)
|
|
64
|
+
skillsmanager registry create
|
|
65
|
+
|
|
66
|
+
# Create a registry in Google Drive
|
|
67
|
+
skillsmanager registry create --backend gdrive
|
|
68
|
+
|
|
69
|
+
# Show all registries and their collection references
|
|
70
|
+
skillsmanager registry list
|
|
71
|
+
|
|
72
|
+
# Search a backend for registries owned by the current user
|
|
73
|
+
skillsmanager registry discover --backend gdrive
|
|
74
|
+
|
|
75
|
+
# Add a collection reference to the registry
|
|
76
|
+
skillsmanager registry add-collection <name>
|
|
77
|
+
|
|
78
|
+
# Push local registry and collections to Google Drive
|
|
79
|
+
skillsmanager registry push --backend gdrive
|
|
80
|
+
|
|
81
|
+
# Create a new collection
|
|
82
|
+
skillsmanager collection create [name]
|
|
83
|
+
|
|
84
|
+
# Re-discover collections from storage
|
|
85
|
+
skillsmanager refresh
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Install the skillsmanager skill for agents
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Install to all agent directories
|
|
92
|
+
skillsmanager install
|
|
93
|
+
|
|
94
|
+
# Install to specific agents
|
|
95
|
+
skillsmanager install --agent claude,codex
|
|
96
|
+
|
|
97
|
+
# Install to a custom path
|
|
98
|
+
skillsmanager install --path <dir>
|
|
99
|
+
|
|
100
|
+
# Remove from all agents
|
|
101
|
+
skillsmanager uninstall
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Common Workflows
|
|
105
|
+
|
|
106
|
+
**User asks to find a skill:**
|
|
107
|
+
1. `skillsmanager search <relevant terms>`
|
|
108
|
+
2. `skillsmanager fetch <skill-name> --agent claude`
|
|
109
|
+
|
|
110
|
+
**User asks to share a skill they created:**
|
|
111
|
+
1. Ensure the skill directory has a `SKILL.md` with `name` and `description` in YAML frontmatter
|
|
112
|
+
2. `skillsmanager add <path-to-skill-directory>`
|
|
113
|
+
|
|
114
|
+
**User asks to update a skill:**
|
|
115
|
+
1. Edit the skill files locally
|
|
116
|
+
2. `skillsmanager update <path-to-skill-directory>`
|
|
117
|
+
|
|
118
|
+
**User asks to install a skill for this project only:**
|
|
119
|
+
1. `skillsmanager fetch <name> --agent claude --scope project`
|
|
120
|
+
|
|
121
|
+
**User wants to back up local skills to Google Drive:**
|
|
122
|
+
1. `skillsmanager setup google` (one-time, human-only)
|
|
123
|
+
2. `skillsmanager registry push --backend gdrive`
|
|
124
|
+
|
|
125
|
+
**User wants to see what registries and collections exist:**
|
|
126
|
+
1. `skillsmanager registry list`
|
|
127
|
+
|
|
128
|
+
## Architecture
|
|
129
|
+
|
|
130
|
+
- **Registry** (`SKILLS_REGISTRY.yaml`): root index pointing to all collections across backends
|
|
131
|
+
- **Collection** (`SKILLS_COLLECTION.yaml`): folder of skills with an index file
|
|
132
|
+
- **Backends**: `local` (default, `~/.skillsmanager/`) and `gdrive` (Google Drive)
|
|
133
|
+
- **Cache**: skills are cached at `~/.skillsmanager/cache/<uuid>/` and symlinked to agent directories
|
|
134
|
+
- **Symlinks**: all agents share one cached copy — updating the cache updates all agents
|
|
135
|
+
|
|
136
|
+
## Scope
|
|
137
|
+
|
|
138
|
+
- `--scope global` (default): installs to `~/.agent/skills/` — available across all projects
|
|
139
|
+
- `--scope project`: installs to `./.agent/skills/` in the current working directory — this project only
|