myskill 1.2.0 → 1.2.2

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/AGENTS.md ADDED
@@ -0,0 +1,102 @@
1
+ # Agent Guide for `myskill`
2
+
3
+ This document is designed to help AI agents (and human developers) understand the architecture, conventions, and workflows of the `myskill` project.
4
+
5
+ ## 1. Project Overview
6
+ `myskill` is a CLI tool built in **Node.js** to unify the creation and management of "Agent Skills" across different AI coding platforms (Claude Code, OpenCode, OpenAI Codex, Gemini CLI).
7
+
8
+ **Core Mission**: Abstract away the differences in YAML frontmatter, directory structures, and configuration files between different AI tools.
9
+
10
+ ## 2. Tech Stack
11
+ - **Runtime**: Node.js (ES Modules)
12
+ - **CLI Framework**: `commander`
13
+ - **Interactivity**: `inquirer`
14
+ - **Validation**: `zod` (Strict schema validation is a core tenet)
15
+ - **File System**: `fs-extra`
16
+ - **Search**: `fuse.js`
17
+ - **Git Integration**: `simple-git`
18
+ - **Path Management**: `env-paths` (for cross-platform config locations)
19
+ - **Formatting**: `prettier` (for generated code)
20
+ - **Testing**: `vitest`
21
+
22
+ ## 3. Architecture
23
+
24
+ ### Directory Structure
25
+ ```text
26
+ myskill/
27
+ ├── bin/
28
+ │ └── myskill.js # CLI Entry point & Command Registration
29
+ ├── src/
30
+ │ ├── commands/ # Individual command logic
31
+ │ │ ├── create.js # Logic for 'myskill create'
32
+ │ │ ├── validate.js # Logic for 'myskill validate'
33
+ │ │ └── ... # All command implementations
34
+ │ ├── platforms/ # Platform Definitions (The "Brain")
35
+ │ │ ├── index.js # Exports all platforms and getPlatformPath
36
+ │ │ ├── claude.js # Claude Code specific config & schema
37
+ │ │ └── ...
38
+ │ ├── templates/ # File generation templates (generateSkill.js)
39
+ │ └── utils/ # Shared utilities (config.js)
40
+ └── test/ # Unit and Integration tests
41
+ ```
42
+
43
+ ### Key Concepts
44
+
45
+ #### Platform Definitions (`src/platforms/*.js`)
46
+ Every supported tool (e.g., Claude, OpenCode) is defined as a module exporting:
47
+ 1. **`id`**: Internal key.
48
+ 2. **`name`**: Display name.
49
+ 3. **`defaultPath`**: Default location where skills live globally on the OS (fallback, now configurable).
50
+ 4. **`schema`**: A **Zod** schema defining valid frontmatter fields.
51
+ 5. **`prompts`**: Inquirer prompt definitions for platform-specific fields.
52
+
53
+ #### Command Pattern
54
+ Commands are defined in `bin/myskill.js` but implemented in `src/commands/*.js`.
55
+ - **Dependency Injection**: Commands should lazily import logic to keep startup fast.
56
+ - **Interactivity**: Commands must support both interactive (Prompts) and non-interactive (Flags) modes.
57
+ - **Error Handling**: Commands throw errors; `bin/myskill.js` catches and handles them.
58
+
59
+ #### Configuration System (`src/utils/config.js`)
60
+ - Uses `env-paths` for cross-platform config directories (e.g., `~/.config/myskill` on Linux/Mac, `%APPDATA%\myskill` on Windows).
61
+ - Platform paths can be overridden via `myskill config set claude.path "/custom/path"`.
62
+ - `getPlatformPath()` in `platforms/index.js` checks config first, falls back to default.
63
+
64
+ #### Current Commands
65
+ - `create`: Generate new skills
66
+ - `validate`: Check skill validity
67
+ - `list`: List installed skills
68
+ - `find`: Fuzzy search skills
69
+ - `install`: Install local skills to global paths
70
+ - `pull`: Clone/pull skills from Git repos
71
+ - `convert`: Convert skills between platforms
72
+ - `uninstall`: Remove skills
73
+ - `run`: Execute skill scripts (experimental)
74
+ - `config`: Manage configuration
75
+ - `doctor`: System health check
76
+
77
+ ## 4. Development Guidelines
78
+
79
+ ### Adding a New Platform
80
+ To add support for a new tool (e.g., "SuperAI"):
81
+ 1. Create `src/platforms/superai.js`.
82
+ 2. Define its Zod schema and default paths.
83
+ 3. Export it in `src/platforms/index.js`.
84
+ 4. Add unit tests in `test/schemas.test.js`.
85
+
86
+ ### Adding a New Command
87
+ 1. Create `src/commands/mycommand.js`.
88
+ 2. Register it in `bin/myskill.js`.
89
+ 3. Ensure it handles `options` for non-interactive usage and throws errors appropriately.
90
+ 4. Add tests in `test/mycommand.test.js`.
91
+
92
+ ### Testing Rules
93
+ - **Run Tests**: `npm test` (uses Vitest).
94
+ - **Mocking**: Use `vi.mock` for `fs-extra`, `inquirer`, `simple-git`, and other I/O libraries to avoid file system side effects during unit tests.
95
+ - **Coverage**: Ensure both success paths and error paths (e.g., invalid YAML, missing files) are tested.
96
+ - **Cross-Platform**: Tests should work on Windows/Linux/macOS; use `path.join` in mocks.
97
+
98
+ ## 5. Common Pitfalls
99
+ - **ESM**: This project uses `"type": "module"`. Use `import/export`, not `require` (unless constructing a `require` via `module`).
100
+ - **Paths**: Always use `path.join` or `path.resolve` for cross-platform compatibility (Windows/Linux/macOS). Config paths use `env-paths`.
101
+ - **Zod Strictness**: When defining schemas, be precise. `myskill validate` relies on these schemas to catch user errors.
102
+ - **Error Propagation**: Commands should throw errors, not call `process.exit`. Let the CLI entry point handle exits.
package/README.md CHANGED
@@ -11,9 +11,11 @@
11
11
  - **Cross-Platform**: Works seamlessly on Windows, macOS, and Linux.
12
12
  - **Workspace Management**: Initialize skill workspaces and run experimental skills locally.
13
13
  - **Discovery**: Fuzzy find installed skills across all global and local scopes.
14
+ - **Smart Detection**: Automatically identify skills in any directory, including nested platform-specific folders.
14
15
  - **Git Integration**: Pull and update skills directly from remote repositories.
15
- - **Interactive Experience**: Cancel any interactive prompt with **Escape** key or **Ctrl+C**.
16
+ - **Interactive Experience**: Step-by-step guides with **Multi-selection** support for bulk actions.
16
17
  - **Configurable Paths**: Override default platform paths for custom setups.
18
+ - **Onboarding**: Built-in guide for AI agents to understand the codebase.
17
19
 
18
20
  ## 📦 Installation
19
21
 
@@ -41,101 +43,74 @@ myskill create
41
43
  # Cancel anytime with Escape key or Ctrl+C
42
44
  ```
43
45
 
44
- Or use flags for automation:
45
-
46
- ```bash
47
- myskill create \
48
- --name "git-helper" \
49
- --platform claude \
50
- --description "Automates complex git workflows" \
51
- --scope project \
52
- --non-interactive
53
- ```
54
-
55
46
  ### Discovering Skills
56
47
 
57
- List all installed skills for a platform:
58
-
59
- ```bash
60
- myskill list --platform claude
61
- ```
62
-
63
- Find a skill by name or description (supports fuzzy search):
64
-
65
- ```bash
66
- myskill find "deploy"
67
- ```
68
-
69
- Validate a skill's structure and frontmatter:
48
+ Detect skills in the current directory and platform-specific subfolders:
70
49
 
71
50
  ```bash
72
- myskill validate ./git-helper
51
+ myskill detect
73
52
  ```
74
53
 
75
- Run a skill script (experimental):
54
+ List all installed skills for a platform:
76
55
 
77
56
  ```bash
78
- myskill run ./git-helper -- arg1 arg2
57
+ myskill list --platform claude
79
58
  ```
80
59
 
81
60
  ### Sharing Skills
82
61
 
83
- Install a local skill directory to the global platform path:
62
+ Install a local skill directory to the global platform path (supports auto-detection and interactive selection):
84
63
 
85
64
  ```bash
86
- myskill install ./my-local-skill --platform claude
65
+ myskill install
87
66
  ```
88
67
 
89
- Pull (clone/update) a skill from a Git repository:
68
+ Uninstall skills with **multi-selection** support:
90
69
 
91
70
  ```bash
92
- myskill pull https://github.com/username/awesome-skill.git --platform opencode
71
+ myskill uninstall
93
72
  ```
94
73
 
95
- Convert a skill from one platform format to another:
74
+ ### Configuration & Help
75
+
76
+ List documentation URLs for all platforms:
96
77
 
97
78
  ```bash
98
- myskill convert ./claude-skill --to opencode
79
+ myskill docs
99
80
  ```
100
81
 
101
- Uninstall a skill:
82
+ Display onboarding guide for AI agents:
102
83
 
103
84
  ```bash
104
- myskill uninstall git-helper --platform claude
85
+ myskill onboard
105
86
  ```
106
87
 
107
- ### Configuration & Health
108
-
109
- Override default paths (useful for custom setups):
88
+ Override default paths:
110
89
 
111
90
  ```bash
112
91
  myskill config set claude.path "/custom/path/to/skills"
113
92
  myskill config list
114
93
  ```
115
94
 
116
- Check system health (Git, permissions, paths):
117
-
118
- ```bash
119
- myskill doctor
120
- ```
121
-
122
95
  ## 🔧 Command Reference
123
96
 
124
- | Command | Description | Usage | Options |
125
- | ----------- | ---------------------------------------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
126
- | `create` | Create a new skill interactively or via flags. | `myskill create [options]` | `-n, --name <name>`: Skill name (lowercase alphanumeric with hyphens)<br>`-p, --platform <platform>`: Target platform (claude, opencode, codex, gemini)<br>`-d, --description <description>`: Skill description<br>`-s, --scope <scope>`: Scope (global, project). Default: project<br>`--non-interactive`: Run without interactive prompts |
127
- | `list` | List all installed skills for a platform. | `myskill list [options]` | `-p, --platform <platform>`: Filter by platform |
128
- | `platforms` | List all supported platforms. | `myskill platforms` | None |
129
- | `detect` | Detect skills in directory and identify their platforms. | `myskill detect [path]` | `[path]`: Path to directory to scan (default: current directory) |
130
- | `find` | Find skills by name or description with fuzzy search. | `myskill find [query] [options]` | `[query]`: Search query (supports fuzzy matching)<br>`-p, --platform <platform>`: Filter by platform |
131
- | `validate` | Validate a skill's structure and frontmatter against platform schemas. | `myskill validate [path] [options]` | `[path]`: Path to skill directory. Default: current directory<br>`-p, --platform <platform>`: Validate against specific platform |
132
- | `run` | Run a skill script (experimental). | `myskill run <skill> [args...]` | `<skill>`: Skill name or path<br>`[args...]`: Arguments to pass to the skill script |
133
- | `install` | Install a local skill directory to the global platform path. | `myskill install <path> [options]` | `<path>`: Path to skill directory<br>`-p, --platform <platform>`: Target platform<br>`-f, --force`: Force overwrite if already installed<br>`--non-interactive`: Run without interactive prompts |
134
- | `pull` | Pull (clone/update) a skill from a Git repository. | `myskill pull <repoUrl> [options]` | `<repoUrl>`: Repository URL<br>`-p, --platform <platform>`: Target platform<br>`-n, --name <name>`: Custom skill name<br>`--non-interactive`: Skip prompts |
135
- | `convert` | Convert a skill from one platform format to another. | `myskill convert <path> [options]` | `<path>`: Path to source skill<br>`-t, --to <platform>`: Target platform<br>`-f, --force`: Force overwrite if output exists<br>`--non-interactive`: Reserved for future interactive features |
136
- | `uninstall` | Uninstall a skill from global or local paths. | `myskill uninstall [name] [options]` | `[name]`: Skill name<br>`-p, --platform <platform>`: Platform context<br>`--non-interactive`: Skip confirmation |
137
- | `config` | Manage configuration settings (e.g., custom paths). | `myskill config <action> [key] [value]` | `<action>`: Action (get, set, list)<br>`[key]`: Config key (e.g., claude.path)<br>`[value]`: Config value (for set) |
138
- | `doctor` | Check system health (Git, permissions, paths). | `myskill doctor` | None |
97
+ | Command | Description | Usage | Options |
98
+ | ----------- | ---------------------------------------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
99
+ | `create` | Create a new skill interactively or via flags. | `myskill create [options]` | `-n, --name <name>`: Skill name<br>`-p, --platform <platform>`: Target platform<br>`-d, --description <description>`: Skill description<br>`-s, --scope <scope>`: Scope (global, project). Default: project<br>`--non-interactive`: Run without interactive prompts |
100
+ | `list` | List all installed skills for a platform. | `myskill list [options]` | `-p, --platform <platform>`: Filter by platform |
101
+ | `platforms` | List all supported platforms. | `myskill platforms` | None |
102
+ | `detect` | Detect skills in directory and platform folders. | `myskill detect [path]` | `[path]`: Path to directory to scan (default: current directory) |
103
+ | `docs` | List documentation URLs for all platforms. | `myskill docs` | None |
104
+ | `onboard` | Display onboarding guide for AI agents. | `myskill onboard` | None |
105
+ | `find` | Find skills by name or description with fuzzy search. | `myskill find [query] [options]` | `[query]`: Search query<br>`-p, --platform <platform>`: Filter by platform |
106
+ | `validate` | Validate a skill's structure and frontmatter against platform schemas. | `myskill validate [path] [options]` | `[path]`: Path to skill directory. Default: current directory<br>`-p, --platform <platform>`: Validate against specific platform |
107
+ | `run` | Run a skill script (experimental). | `myskill run <skill> [args...]` | `<skill>`: Skill name or path<br>`[args...]`: Arguments to pass to the skill script |
108
+ | `install` | Install a local skill to the global platform path. | `myskill install [path] [options]` | `[path]`: Path to skill directory (optional - auto-detects if omitted)<br>`-p, --platform <platform>`: Target platform<br>`-f, --force`: Force overwrite<br>`--non-interactive`: Run without prompts |
109
+ | `pull` | Pull (clone/update) a skill from a Git repository. | `myskill pull <repoUrl> [options]` | `<repoUrl>`: Repository URL<br>`-p, --platform <platform>`: Target platform<br>`-n, --name <name>`: Custom skill name<br>`--non-interactive`: Skip prompts |
110
+ | `convert` | Convert a skill from one platform format to another. | `myskill convert <path> [options]` | `<path>`: Path to source skill<br>`-t, --to <platform>`: Target platform<br>`-f, --force`: Force overwrite<br>`--non-interactive`: Fail if output exists |
111
+ | `uninstall` | Uninstall one or more skills from global or local paths. | `myskill uninstall [name] [options]` | `[name]`: Skill name (optional - triggers multi-select if omitted)<br>`-p, --platform <platform>`: Platform context<br>`--non-interactive`: Skip confirmation |
112
+ | `config` | Manage configuration settings (e.g., custom paths). | `myskill config <action> [key] [value]` | `<action>`: Action (get, set, list)<br>`[key]`: Config key (e.g., claude.path)<br>`[value]`: Config value (for set) |
113
+ | `doctor` | Check system health (Git, permissions, paths). | `myskill doctor` | None |
139
114
 
140
115
  ## 🗺️ Roadmap
141
116
 
package/bin/myskill.js CHANGED
@@ -152,4 +152,20 @@ program
152
152
  detect(pathStr);
153
153
  });
154
154
 
155
+ program
156
+ .command("docs")
157
+ .description("List documentation URLs for all platforms")
158
+ .action(async () => {
159
+ const { docs } = await import("../src/commands/docs.js");
160
+ docs();
161
+ });
162
+
163
+ program
164
+ .command("onboard")
165
+ .description("Display onboarding guide for AI agents")
166
+ .action(async () => {
167
+ const { onboard } = await import("../src/commands/onboard.js");
168
+ await onboard();
169
+ });
170
+
155
171
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myskill",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "CLI tool for creating and managing AI agent skills",
5
5
  "author": "Sarfraz Ahmed <sarfraznawaz2005@gmail.com>",
6
6
  "license": "MIT",
@@ -19,7 +19,8 @@
19
19
  "bin",
20
20
  "src",
21
21
  "README.md",
22
- "LICENSE"
22
+ "LICENSE",
23
+ "AGENTS.md"
23
24
  ],
24
25
  "main": "./bin/myskill.js",
25
26
  "bin": {
@@ -40,6 +41,7 @@
40
41
  ],
41
42
  "dependencies": {
42
43
  "chalk": "^5.4.1",
44
+ "cli-table3": "^0.6.5",
43
45
  "commander": "^13.1.0",
44
46
  "env-paths": "^3.0.0",
45
47
  "fs-extra": "^11.3.0",
@@ -194,7 +194,6 @@ export async function create(options = {}) {
194
194
  try {
195
195
  await fs.ensureDir(targetDir);
196
196
  await fs.writeFile(path.join(targetDir, "SKILL.md"), fileContent);
197
- await fs.ensureDir(path.join(targetDir, "scripts"));
198
197
  console.log(chalk.green(`Skill created successfully at ${targetDir}`));
199
198
  } catch (error) {
200
199
  console.error(chalk.red(`Error creating skill: ${error.message}`));
@@ -2,6 +2,7 @@ import fs from "fs-extra";
2
2
  import path from "path";
3
3
  import chalk from "chalk";
4
4
  import { findSkills } from "../utils/skills.js";
5
+ import { platforms } from "../platforms/index.js";
5
6
 
6
7
  export async function detect(pathStr = ".", options = {}) {
7
8
  const targetDir = pathStr === "." ? process.cwd() : path.resolve(pathStr);
@@ -9,14 +10,31 @@ export async function detect(pathStr = ".", options = {}) {
9
10
  console.log(chalk.blue(`Detecting skills in: ${targetDir}\n`));
10
11
 
11
12
  try {
12
- const skills = await findSkills(targetDir);
13
+ let allSkills = await findSkills(targetDir);
13
14
 
14
- if (skills.length === 0) {
15
+ for (const platform of Object.values(platforms)) {
16
+ const localBase =
17
+ platform.id === "opencode"
18
+ ? ".opencode/skill"
19
+ : `.${platform.id}/skills`;
20
+ const platformDir = path.join(targetDir, localBase);
21
+
22
+ if (await fs.pathExists(platformDir)) {
23
+ const platformSkills = await findSkills(platformDir);
24
+ for (const skill of platformSkills) {
25
+ if (!allSkills.some((s) => s.path === skill.path)) {
26
+ allSkills.push(skill);
27
+ }
28
+ }
29
+ }
30
+ }
31
+
32
+ if (allSkills.length === 0) {
15
33
  console.log(chalk.yellow("No skills detected in current directory."));
16
34
  return;
17
35
  }
18
36
 
19
- for (const skill of skills) {
37
+ for (const skill of allSkills) {
20
38
  if (skill.error) {
21
39
  console.log(`${chalk.bold(skill.name)}: ${chalk.red(skill.error)}`);
22
40
  continue;
@@ -25,6 +43,7 @@ export async function detect(pathStr = ".", options = {}) {
25
43
  `${chalk.bold(skill.name)}: ${chalk.green(skill.platform.name)} (${skill.platform.id})`,
26
44
  );
27
45
  console.log(` Description: ${skill.description}`);
46
+ console.log(` Path: ${path.relative(targetDir, skill.path)}`);
28
47
  }
29
48
  } catch (e) {
30
49
  console.error(chalk.red(`Error scanning directory: ${e.message}`));
@@ -0,0 +1,12 @@
1
+ import chalk from "chalk";
2
+ import { platforms } from "../platforms/index.js";
3
+
4
+ export async function docs() {
5
+ console.log(chalk.blue("=== Platform Documentation ===\n"));
6
+
7
+ for (const platform of Object.values(platforms)) {
8
+ console.log(`${chalk.bold(platform.name)}:`);
9
+ console.log(` ${chalk.cyan(platform.docsUrl)}`);
10
+ console.log();
11
+ }
12
+ }
@@ -2,6 +2,7 @@ import fs from "fs-extra";
2
2
  import path from "path";
3
3
  import chalk from "chalk";
4
4
  import yaml from "js-yaml";
5
+ import Table from "cli-table3";
5
6
  import { platforms, getPlatformPath } from "../platforms/index.js";
6
7
 
7
8
  export async function list(options = {}) {
@@ -17,9 +18,9 @@ export async function list(options = {}) {
17
18
  targetPlatforms = Object.values(platforms);
18
19
  }
19
20
 
20
- for (const platform of targetPlatforms) {
21
- console.log(chalk.blue(`\n=== ${platform.name} Skills ===`));
21
+ const skillMap = {};
22
22
 
23
+ for (const platform of targetPlatforms) {
23
24
  const globalPath = await getPlatformPath(platform.id);
24
25
  const locations = [{ name: "Global", path: globalPath }];
25
26
 
@@ -42,14 +43,20 @@ export async function list(options = {}) {
42
43
  const match = content.match(/^---\n([\s\S]*?)\n---/);
43
44
  if (match) {
44
45
  const fm = yaml.load(match[1]);
45
- console.log(
46
- `- ${chalk.bold(fm.name)} (${loc.name}): ${fm.description || "No description"}`,
47
- );
48
- } else {
49
- console.log(`- ${item.name} (${loc.name}): [Invalid Format]`);
46
+ const skillName = fm.name;
47
+ if (!skillMap[skillName]) {
48
+ skillMap[skillName] = {
49
+ description: fm.description || "No description",
50
+ platforms: [],
51
+ location: loc.name,
52
+ };
53
+ }
54
+ if (!skillMap[skillName].platforms.includes(platform.name)) {
55
+ skillMap[skillName].platforms.push(platform.name);
56
+ }
50
57
  }
51
58
  } catch (e) {
52
- console.log(`- ${item.name} (${loc.name}): [Read Error]`);
59
+ // Intentionally skip errors to avoid cluttering output
53
60
  }
54
61
  }
55
62
  }
@@ -57,4 +64,28 @@ export async function list(options = {}) {
57
64
  }
58
65
  }
59
66
  }
67
+
68
+ const table = new Table({
69
+ head: [
70
+ chalk.bold("Skill Name"),
71
+ chalk.bold("Platforms"),
72
+ chalk.bold("Location"),
73
+ chalk.bold("Description"),
74
+ ],
75
+ colWidths: [20, 40, 10, 50],
76
+ wordWrap: true,
77
+ });
78
+
79
+ for (const [skillName, data] of Object.entries(skillMap)) {
80
+ const platformsStr = chalk.cyan(data.platforms.join(", "));
81
+ table.push([
82
+ chalk.bold(skillName),
83
+ platformsStr,
84
+ data.location,
85
+ data.description,
86
+ ]);
87
+ }
88
+
89
+ console.log(chalk.bold("Skill Listing:"));
90
+ console.log(table.toString());
60
91
  }
@@ -0,0 +1,32 @@
1
+ import fs from "fs-extra";
2
+ import path from "path";
3
+ import { fileURLToPath } from "url";
4
+ import chalk from "chalk";
5
+
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
+
8
+ export async function onboard() {
9
+ const agentsMdPath = path.join(__dirname, "..", "..", "AGENTS.md");
10
+
11
+ try {
12
+ if (await fs.pathExists(agentsMdPath)) {
13
+ const content = await fs.readFile(agentsMdPath, "utf8");
14
+ console.log(content);
15
+ } else {
16
+ console.error(chalk.red("Error: AGENTS.md not found."));
17
+ if (process.env.NODE_ENV === "test") {
18
+ throw new Error("AGENTS_MD_NOT_FOUND");
19
+ }
20
+ process.exit(1);
21
+ }
22
+ } catch (error) {
23
+ if (error.message === "AGENTS_MD_NOT_FOUND") throw error;
24
+ console.error(
25
+ chalk.red(`Error reading onboarding guide: ${error.message}`),
26
+ );
27
+ if (process.env.NODE_ENV === "test") {
28
+ throw error;
29
+ }
30
+ process.exit(1);
31
+ }
32
+ }
@@ -30,6 +30,7 @@ try {
30
30
  export const claude = {
31
31
  id: "claude",
32
32
  name: "Claude Code",
33
+ docsUrl: "https://code.claude.com/docs/en/skills",
33
34
  defaultPath: path.join(os.homedir(), ".claude", "skills"),
34
35
  schema: z.object({
35
36
  name: z
@@ -5,6 +5,7 @@ import os from "os";
5
5
  export const codex = {
6
6
  id: "codex",
7
7
  name: "OpenAI Codex",
8
+ docsUrl: "https://developers.openai.com/codex/skills",
8
9
  defaultPath: path.join(os.homedir(), ".codex", "skills"),
9
10
  schema: z.object({
10
11
  name: z.string().min(1),
@@ -5,6 +5,7 @@ import os from "os";
5
5
  export const gemini = {
6
6
  id: "gemini",
7
7
  name: "Gemini CLI",
8
+ docsUrl: "https://geminicli.com/docs/cli/skills",
8
9
  defaultPath: path.join(os.homedir(), ".gemini", "skills"),
9
10
  schema: z.object({
10
11
  name: z
@@ -5,6 +5,7 @@ import os from "os";
5
5
  export const opencode = {
6
6
  id: "opencode",
7
7
  name: "OpenCode",
8
+ docsUrl: "https://opencode.ai/docs/skills",
8
9
  defaultPath: path.join(os.homedir(), ".config", "opencode", "skill"),
9
10
  schema: z.object({
10
11
  name: z