skmr 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 +87 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +5 -0
- package/dist/commands/add.d.ts +1 -0
- package/dist/commands/add.js +106 -0
- package/dist/commands/help.d.ts +1 -0
- package/dist/commands/help.js +31 -0
- package/dist/commands/install.d.ts +1 -0
- package/dist/commands/install.js +76 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +29 -0
- package/dist/lib/runner.d.ts +6 -0
- package/dist/lib/runner.js +30 -0
- package/dist/lib/skills-json.d.ts +4 -0
- package/dist/lib/skills-json.js +47 -0
- package/dist/lib/types.d.ts +11 -0
- package/dist/lib/types.js +2 -0
- package/package.json +26 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Minwei Shen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# skmr
|
|
2
|
+
|
|
3
|
+
A CLI tool to manage AI agent skills using a `skills.json` manifest file. Think of it as `package.json` for [skills](https://skills.sh/).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g skmr
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or use directly with `npx`:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx skmr <command>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
### Add a skill
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
skmr add <source> --skill <name> -a <agent> [-a <agent>...] [-g|-p]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The `-a` flag is required and repeatable. This wraps `npx skills add` and updates your `skills.json`.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Add a skill for claude-code and cursor, project-level
|
|
29
|
+
skmr add https://github.com/vercel-labs/agent-skills --skill vercel-react-best-practices -a claude-code -a cursor -p
|
|
30
|
+
|
|
31
|
+
# Add a skill globally
|
|
32
|
+
skmr add https://github.com/anthropics/skills --skill skill-creator -a claude-code -g
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Install all skills
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Install from ./skills.json
|
|
39
|
+
skmr install
|
|
40
|
+
|
|
41
|
+
# Install from a custom path
|
|
42
|
+
skmr install -c path/to/skills.json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Reads `skills.json` and installs all skills in parallel.
|
|
46
|
+
|
|
47
|
+
### Help
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
skmr help
|
|
51
|
+
skmr -h
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## skills.json
|
|
55
|
+
|
|
56
|
+
The `skills.json` file tracks your installed skills:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"version": "0.0.1",
|
|
61
|
+
"command": "npx",
|
|
62
|
+
"skills": [
|
|
63
|
+
{
|
|
64
|
+
"source": "https://github.com/vercel-labs/agent-skills",
|
|
65
|
+
"name": "vercel-react-best-practices",
|
|
66
|
+
"agents": ["claude-code", "cursor"],
|
|
67
|
+
"location": "project"
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
| Field | Maps to |
|
|
74
|
+
|-------|---------|
|
|
75
|
+
| `source` | `<source>` positional arg |
|
|
76
|
+
| `name` | `--skill <name>` |
|
|
77
|
+
| `agents` | `--agent <agent1> <agent2>` |
|
|
78
|
+
| `location: "global"` | `-g` |
|
|
79
|
+
| `location: "project"` | (default) |
|
|
80
|
+
|
|
81
|
+
## Supported Agents
|
|
82
|
+
|
|
83
|
+
claude-code, cursor, windsurf, cline, copilot, codex, gemini-cli, roo-code, kilo-code, trae, goose, opencode, continue, junie, kiro-cli, qwen-code, pochi, amp
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
MIT
|
package/dist/bin.d.ts
ADDED
package/dist/bin.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function addCommand(args: string[]): Promise<void>;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addCommand = addCommand;
|
|
4
|
+
const runner_js_1 = require("../lib/runner.js");
|
|
5
|
+
const skills_json_js_1 = require("../lib/skills-json.js");
|
|
6
|
+
function parseAddArgs(args) {
|
|
7
|
+
const result = {
|
|
8
|
+
source: "",
|
|
9
|
+
skill: "",
|
|
10
|
+
agents: [],
|
|
11
|
+
location: undefined,
|
|
12
|
+
};
|
|
13
|
+
let i = 0;
|
|
14
|
+
// First positional arg is the source
|
|
15
|
+
if (args.length > 0 && !args[0].startsWith("-")) {
|
|
16
|
+
result.source = args[0];
|
|
17
|
+
i = 1;
|
|
18
|
+
}
|
|
19
|
+
while (i < args.length) {
|
|
20
|
+
const arg = args[i];
|
|
21
|
+
if (arg === "--skill" && i + 1 < args.length) {
|
|
22
|
+
result.skill = args[++i];
|
|
23
|
+
}
|
|
24
|
+
else if (arg === "-a" && i + 1 < args.length) {
|
|
25
|
+
result.agents.push(args[++i]);
|
|
26
|
+
}
|
|
27
|
+
else if (arg === "-g") {
|
|
28
|
+
result.location = "global";
|
|
29
|
+
}
|
|
30
|
+
else if (arg === "-p") {
|
|
31
|
+
result.location = "project";
|
|
32
|
+
}
|
|
33
|
+
i++;
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
function buildSkillsArgs(parsed) {
|
|
38
|
+
const args = ["add", parsed.source, "--skill", parsed.skill];
|
|
39
|
+
if (parsed.agents.length > 0) {
|
|
40
|
+
args.push("--agent", ...parsed.agents);
|
|
41
|
+
}
|
|
42
|
+
if (parsed.location === "global") {
|
|
43
|
+
args.push("-g");
|
|
44
|
+
}
|
|
45
|
+
args.push("-y");
|
|
46
|
+
return args;
|
|
47
|
+
}
|
|
48
|
+
const KNOWN_AGENTS = [
|
|
49
|
+
"claude-code",
|
|
50
|
+
"cursor",
|
|
51
|
+
"windsurf",
|
|
52
|
+
"cline",
|
|
53
|
+
"copilot",
|
|
54
|
+
"codex",
|
|
55
|
+
"gemini-cli",
|
|
56
|
+
"roo-code",
|
|
57
|
+
"kilo-code",
|
|
58
|
+
"trae",
|
|
59
|
+
"goose",
|
|
60
|
+
"opencode",
|
|
61
|
+
"continue",
|
|
62
|
+
"junie",
|
|
63
|
+
"kiro-cli",
|
|
64
|
+
"qwen-code",
|
|
65
|
+
"pochi",
|
|
66
|
+
"amp",
|
|
67
|
+
];
|
|
68
|
+
async function addCommand(args) {
|
|
69
|
+
const parsed = parseAddArgs(args);
|
|
70
|
+
if (!parsed.source || !parsed.skill) {
|
|
71
|
+
console.error("Error: source and --skill are required.");
|
|
72
|
+
console.error("Usage: skmr add [source] --skill [name] -a [agent]... [-g|-p]");
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
if (parsed.agents.length === 0) {
|
|
76
|
+
console.error("Error: at least one agent is required via -a flag.\n");
|
|
77
|
+
console.error("Available agents:");
|
|
78
|
+
for (const agent of KNOWN_AGENTS) {
|
|
79
|
+
console.error(` ${agent}`);
|
|
80
|
+
}
|
|
81
|
+
console.error("\nUsage: skmr add [source] --skill [name] -a [agent]... [-g|-p]");
|
|
82
|
+
console.error("Example: skmr add https://github.com/org/repo --skill my-skill -a claude-code -a cursor -p");
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
// Read the manifest to get the command
|
|
86
|
+
const manifest = await (0, skills_json_js_1.readSkillsJson)();
|
|
87
|
+
const baseCommand = manifest.command || "npx";
|
|
88
|
+
// Build and run the skills command
|
|
89
|
+
const skillsArgs = ["skills", ...buildSkillsArgs(parsed)];
|
|
90
|
+
console.log(`Running: ${baseCommand} ${skillsArgs.join(" ")}`);
|
|
91
|
+
const result = await (0, runner_js_1.runSkillsCommand)(baseCommand, skillsArgs);
|
|
92
|
+
if (result.exitCode !== 0) {
|
|
93
|
+
console.error(`\nskills command failed with exit code ${result.exitCode}`);
|
|
94
|
+
process.exit(result.exitCode);
|
|
95
|
+
}
|
|
96
|
+
// Update skills.json
|
|
97
|
+
const entry = {
|
|
98
|
+
source: parsed.source,
|
|
99
|
+
name: parsed.skill,
|
|
100
|
+
agents: parsed.agents,
|
|
101
|
+
location: parsed.location ?? "project",
|
|
102
|
+
};
|
|
103
|
+
const updated = (0, skills_json_js_1.upsertSkill)(manifest, entry);
|
|
104
|
+
await (0, skills_json_js_1.writeSkillsJson)(updated);
|
|
105
|
+
console.log(`\nUpdated skills.json with "${entry.name}"`);
|
|
106
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function helpCommand(): void;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.helpCommand = helpCommand;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
function helpCommand() {
|
|
7
|
+
const pkgPath = (0, node_path_1.join)(__dirname, "..", "..", "package.json");
|
|
8
|
+
const pkg = JSON.parse((0, node_fs_1.readFileSync)(pkgPath, "utf-8"));
|
|
9
|
+
console.log(`
|
|
10
|
+
skmr v${pkg.version} - AI skill manager
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
skmr <command> [options]
|
|
14
|
+
|
|
15
|
+
Commands:
|
|
16
|
+
add [source] --skill [name] Add a skill and update skills.json
|
|
17
|
+
-a <agent> Target agent (required, repeatable, e.g. -a claude-code -a cursor)
|
|
18
|
+
-g Install globally
|
|
19
|
+
-p Install for project
|
|
20
|
+
|
|
21
|
+
install Install all skills from skills.json in parallel
|
|
22
|
+
-c <path> Path to skills.json (default: ./skills.json)
|
|
23
|
+
|
|
24
|
+
help Show this help message
|
|
25
|
+
|
|
26
|
+
Examples:
|
|
27
|
+
skmr add https://github.com/vercel-labs/agent-skills --skill vercel-react-best-practices -a claude-code -p
|
|
28
|
+
skmr install
|
|
29
|
+
skmr install -c config/skills.json
|
|
30
|
+
`.trim());
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function installCommand(args: string[]): Promise<void>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.installCommand = installCommand;
|
|
4
|
+
const skills_json_js_1 = require("../lib/skills-json.js");
|
|
5
|
+
const runner_js_1 = require("../lib/runner.js");
|
|
6
|
+
function buildSkillsArgs(skill) {
|
|
7
|
+
const args = ["skills", "add", skill.source, "--skill", skill.name];
|
|
8
|
+
if (skill.agents.length > 0) {
|
|
9
|
+
args.push("--agent", ...skill.agents);
|
|
10
|
+
}
|
|
11
|
+
if (skill.location === "global") {
|
|
12
|
+
args.push("-g");
|
|
13
|
+
}
|
|
14
|
+
args.push("-y");
|
|
15
|
+
return args;
|
|
16
|
+
}
|
|
17
|
+
function parseInstallArgs(args) {
|
|
18
|
+
for (let i = 0; i < args.length; i++) {
|
|
19
|
+
if (args[i] === "-c" && i + 1 < args.length) {
|
|
20
|
+
return { configPath: args[i + 1] };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return {};
|
|
24
|
+
}
|
|
25
|
+
async function installCommand(args) {
|
|
26
|
+
const { configPath } = parseInstallArgs(args);
|
|
27
|
+
let manifest;
|
|
28
|
+
try {
|
|
29
|
+
manifest = await (0, skills_json_js_1.readSkillsJson)(configPath);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
if (err.code === "ENOENT") {
|
|
33
|
+
console.error(`Error: skills.json not found at ${configPath ?? "skills.json"}`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
if (err instanceof SyntaxError) {
|
|
37
|
+
console.error(`Error: Invalid JSON in ${configPath ?? "skills.json"}: ${err.message}`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
42
|
+
if (manifest.skills.length === 0) {
|
|
43
|
+
console.log("No skills to install.");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const baseCommand = manifest.command || "npx";
|
|
47
|
+
console.log(`Installing ${manifest.skills.length} skill(s) in parallel...\n`);
|
|
48
|
+
const results = await Promise.allSettled(manifest.skills.map(async (skill) => {
|
|
49
|
+
const skillArgs = buildSkillsArgs(skill);
|
|
50
|
+
console.log(`[${skill.name}] Running: ${baseCommand} ${skillArgs.join(" ")}`);
|
|
51
|
+
const result = await (0, runner_js_1.runSkillsCommand)(baseCommand, skillArgs);
|
|
52
|
+
return { skill, result };
|
|
53
|
+
}));
|
|
54
|
+
// Summary
|
|
55
|
+
let succeeded = 0;
|
|
56
|
+
let failed = 0;
|
|
57
|
+
console.log("\n--- Installation Summary ---");
|
|
58
|
+
for (const r of results) {
|
|
59
|
+
if (r.status === "fulfilled" && r.value.result.exitCode === 0) {
|
|
60
|
+
console.log(` OK: ${r.value.skill.name}`);
|
|
61
|
+
succeeded++;
|
|
62
|
+
}
|
|
63
|
+
else if (r.status === "fulfilled") {
|
|
64
|
+
console.log(` FAIL: ${r.value.skill.name} (exit code ${r.value.result.exitCode})`);
|
|
65
|
+
failed++;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
console.log(` FAIL: ${r.reason}`);
|
|
69
|
+
failed++;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
console.log(`\n${succeeded} succeeded, ${failed} failed`);
|
|
73
|
+
if (failed > 0) {
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function main(): Promise<void>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = main;
|
|
4
|
+
const help_js_1 = require("./commands/help.js");
|
|
5
|
+
const add_js_1 = require("./commands/add.js");
|
|
6
|
+
const install_js_1 = require("./commands/install.js");
|
|
7
|
+
async function main() {
|
|
8
|
+
const args = process.argv.slice(2);
|
|
9
|
+
const command = args[0];
|
|
10
|
+
const commandArgs = args.slice(1);
|
|
11
|
+
switch (command) {
|
|
12
|
+
case "add":
|
|
13
|
+
await (0, add_js_1.addCommand)(commandArgs);
|
|
14
|
+
break;
|
|
15
|
+
case "install":
|
|
16
|
+
await (0, install_js_1.installCommand)(commandArgs);
|
|
17
|
+
break;
|
|
18
|
+
case "help":
|
|
19
|
+
case "-h":
|
|
20
|
+
case "--help":
|
|
21
|
+
case undefined:
|
|
22
|
+
(0, help_js_1.helpCommand)();
|
|
23
|
+
break;
|
|
24
|
+
default:
|
|
25
|
+
console.error(`Unknown command: ${command}`);
|
|
26
|
+
(0, help_js_1.helpCommand)();
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runSkillsCommand = runSkillsCommand;
|
|
4
|
+
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
function runSkillsCommand(command, args) {
|
|
6
|
+
return new Promise((resolve) => {
|
|
7
|
+
const child = (0, node_child_process_1.spawn)(command, args, {
|
|
8
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
9
|
+
});
|
|
10
|
+
let stdout = "";
|
|
11
|
+
let stderr = "";
|
|
12
|
+
child.stdout.on("data", (data) => {
|
|
13
|
+
const text = data.toString();
|
|
14
|
+
stdout += text;
|
|
15
|
+
process.stdout.write(text);
|
|
16
|
+
});
|
|
17
|
+
child.stderr.on("data", (data) => {
|
|
18
|
+
const text = data.toString();
|
|
19
|
+
stderr += text;
|
|
20
|
+
process.stderr.write(text);
|
|
21
|
+
});
|
|
22
|
+
child.on("close", (code) => {
|
|
23
|
+
resolve({ exitCode: code ?? 1, stdout, stderr });
|
|
24
|
+
});
|
|
25
|
+
child.on("error", (err) => {
|
|
26
|
+
stderr += err.message;
|
|
27
|
+
resolve({ exitCode: 1, stdout, stderr });
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { SkillEntry, SkillsManifest } from "./types.js";
|
|
2
|
+
export declare function readSkillsJson(path?: string): Promise<SkillsManifest>;
|
|
3
|
+
export declare function writeSkillsJson(manifest: SkillsManifest, path?: string): Promise<void>;
|
|
4
|
+
export declare function upsertSkill(manifest: SkillsManifest, entry: SkillEntry): SkillsManifest;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readSkillsJson = readSkillsJson;
|
|
4
|
+
exports.writeSkillsJson = writeSkillsJson;
|
|
5
|
+
exports.upsertSkill = upsertSkill;
|
|
6
|
+
const promises_1 = require("node:fs/promises");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
const DEFAULT_PATH = "skills.json";
|
|
9
|
+
function createDefaultManifest() {
|
|
10
|
+
return {
|
|
11
|
+
version: "0.0.1",
|
|
12
|
+
command: "npx",
|
|
13
|
+
skills: [],
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
async function readSkillsJson(path) {
|
|
17
|
+
const filePath = (0, node_path_1.resolve)(path ?? DEFAULT_PATH);
|
|
18
|
+
let content;
|
|
19
|
+
try {
|
|
20
|
+
content = await (0, promises_1.readFile)(filePath, "utf-8");
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
if (err.code === "ENOENT") {
|
|
24
|
+
return createDefaultManifest();
|
|
25
|
+
}
|
|
26
|
+
throw err;
|
|
27
|
+
}
|
|
28
|
+
const data = JSON.parse(content);
|
|
29
|
+
if (!Array.isArray(data.skills)) {
|
|
30
|
+
throw new Error(`Invalid skills.json: "skills" must be an array`);
|
|
31
|
+
}
|
|
32
|
+
return data;
|
|
33
|
+
}
|
|
34
|
+
async function writeSkillsJson(manifest, path) {
|
|
35
|
+
const filePath = (0, node_path_1.resolve)(path ?? DEFAULT_PATH);
|
|
36
|
+
await (0, promises_1.writeFile)(filePath, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
|
|
37
|
+
}
|
|
38
|
+
function upsertSkill(manifest, entry) {
|
|
39
|
+
const idx = manifest.skills.findIndex((s) => s.source === entry.source && s.name === entry.name);
|
|
40
|
+
if (idx >= 0) {
|
|
41
|
+
manifest.skills[idx] = entry;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
manifest.skills.push(entry);
|
|
45
|
+
}
|
|
46
|
+
return manifest;
|
|
47
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "skmr",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"bin": {
|
|
7
|
+
"skmr": "dist/bin.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"dev": "tsc --watch",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [],
|
|
18
|
+
"homepage": "https://github.com/MinweiShen/skill-manager",
|
|
19
|
+
"author": "Minwei Shen",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"description": "A cli tool to manage your AI skills with skills.json",
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^25.2.3",
|
|
24
|
+
"typescript": "^5.0.0"
|
|
25
|
+
}
|
|
26
|
+
}
|