skills-manifest 0.2.1 → 0.3.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/README.md +50 -3
- package/dist/add-CmzBK4br.mjs +32 -0
- package/dist/cli/add.d.mts +12 -0
- package/dist/cli/add.mjs +3 -0
- package/dist/cli/index.mjs +14 -50
- package/dist/cli/init.d.mts +6 -0
- package/dist/cli/init.mjs +3 -0
- package/dist/cli/install.d.mts +6 -0
- package/dist/cli/install.mjs +3 -0
- package/dist/cli/patch.d.mts +5 -0
- package/dist/cli/patch.mjs +3 -0
- package/dist/cli/remove.d.mts +12 -0
- package/dist/cli/remove.mjs +3 -0
- package/dist/cli/sync.d.mts +6 -0
- package/dist/cli/sync.mjs +3 -0
- package/dist/index.d.mts +1 -1
- package/dist/init-4enI_4o6.mjs +48 -0
- package/dist/install-CmdQl0XL.mjs +62 -0
- package/dist/patch-C3hgBcHP.mjs +34 -0
- package/dist/remove-ByCBLakw.mjs +42 -0
- package/dist/sync-1OE33hei.mjs +18 -0
- package/dist/types/index.d.mts +1 -1
- package/dist/utils/index.d.mts +8 -0
- package/dist/utils/index.mjs +3 -0
- package/dist/utils-m5dGqHGZ.mjs +58 -0
- package/package.json +7 -5
- package/patches/skills-cli.mjs +27 -0
- /package/dist/{index-OGqMIJuf.d.mts → index-DeyN5X2A.d.mts} +0 -0
package/README.md
CHANGED
|
@@ -9,10 +9,47 @@
|
|
|
9
9
|
A lightweight manifest manager for [skills](https://github.com/vercel-labs/skills), enabling project-level skill synchronization and collaborative configuration.
|
|
10
10
|
|
|
11
11
|
> [!IMPORTANT]
|
|
12
|
-
> The `skills add <args>` command will not automatically update the `skills-manifest.json` file
|
|
13
|
-
> Since [skills](https://github.com/vercel-labs/skills) does not currently support project-level lock files, this project serves as a temporary solution for sharing and persisting skills across collaborative environments
|
|
12
|
+
> ~~The `skills add <args>` command will not automatically update the `skills-manifest.json` file.~~
|
|
13
|
+
> ~~Since [skills](https://github.com/vercel-labs/skills) does not currently support project-level lock files, this project serves as a temporary solution for sharing and persisting skills across collaborative environments.~~
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
> Now you can use `skills add` to add skills to the manifest.
|
|
16
|
+
|
|
17
|
+
## Init & sync with skills
|
|
18
|
+
|
|
19
|
+
Run once in your project:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx skills-manifest init
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This will:
|
|
26
|
+
|
|
27
|
+
- Install `skills` and `skills-manifest` as dev dependencies
|
|
28
|
+
- Create `skills-manifest.json` and add a `prepare` script that runs `skills-manifest install`
|
|
29
|
+
- Add `skills` to `.gitignore`
|
|
30
|
+
|
|
31
|
+
Then run:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
skills-manifest install
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`install` syncs skills from the manifest and **injects a wrapper** into `node_modules/skills` so that:
|
|
38
|
+
|
|
39
|
+
| When you run | skills-manifest also runs |
|
|
40
|
+
|--------------|---------------------------|
|
|
41
|
+
| `skills add <repo> [--skill ...]` | `skills-manifest add <repo> [...]` — the repo and skills are written to `skills-manifest.json` |
|
|
42
|
+
| `skills remove <skills...>` | `skills-manifest remove` for each repo that had those skills |
|
|
43
|
+
|
|
44
|
+
To add a skill **without** updating the manifest (e.g. one-off try), use:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
skills add <repo> --skip-manifest
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Install (manual)
|
|
51
|
+
|
|
52
|
+
Alternatively, install without `init`:
|
|
16
53
|
|
|
17
54
|
```bash
|
|
18
55
|
pnpm add skills skills-manifest -D
|
|
@@ -52,6 +89,16 @@ skills
|
|
|
52
89
|
}
|
|
53
90
|
```
|
|
54
91
|
|
|
92
|
+
## AGENTS.md for AI Agents
|
|
93
|
+
|
|
94
|
+
After you have configured `skills-manifest.json` and run `skills-manifest install` to generate the skills tree, we recommend using [OpenSkills](https://github.com/numman-ali/openskills) to produce an `AGENTS.md` that AI agents can consume:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npx openskills sync
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
This keeps your installed skills in sync with an `AGENTS.md` (or custom output path) so agents that read it (e.g. Claude Code, Cursor, Windsurf) can discover and use the same skills. See [OpenSkills](https://github.com/numman-ali/openskills) for options such as `--universal` and `-o <path>`.
|
|
101
|
+
|
|
55
102
|
## License
|
|
56
103
|
|
|
57
104
|
[MIT](./LICENSE) License © [Hairyf](https://github.com/hairyf)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { loadConfig } from "c12";
|
|
3
|
+
import { defineCommand } from "citty";
|
|
4
|
+
|
|
5
|
+
//#region src/cli/add.ts
|
|
6
|
+
const add = defineCommand({
|
|
7
|
+
meta: {
|
|
8
|
+
name: "add",
|
|
9
|
+
description: "Add repo and skills to manifest"
|
|
10
|
+
},
|
|
11
|
+
args: { repo: {
|
|
12
|
+
type: "positional",
|
|
13
|
+
description: "Repository (e.g. owner/repo or full URL)",
|
|
14
|
+
required: true
|
|
15
|
+
} },
|
|
16
|
+
async run({ args }) {
|
|
17
|
+
const { config, configFile } = await loadConfig({ configFile: "skills-manifest" });
|
|
18
|
+
if (!configFile) throw new Error("skills-manifest.json not found. Run `skills-manifest init` first.");
|
|
19
|
+
const repo = args.repo;
|
|
20
|
+
const skills = (args._ ?? []).slice(1);
|
|
21
|
+
const existing = config.skills[repo];
|
|
22
|
+
const existingList = Array.isArray(existing) ? existing : typeof existing === "object" && existing !== null ? Object.keys(existing).filter((k) => existing[k]) : [];
|
|
23
|
+
const skillsToAdd = [...new Set([...existingList, ...skills])];
|
|
24
|
+
config.skills[repo] = skillsToAdd;
|
|
25
|
+
const content = JSON.stringify(config, null, 2);
|
|
26
|
+
await fs.writeFile(configFile, content);
|
|
27
|
+
console.log(`Added ${repo} to skills-manifest.json`);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
export { add as t };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as citty6 from "citty";
|
|
2
|
+
|
|
3
|
+
//#region src/cli/add.d.ts
|
|
4
|
+
declare const add: citty6.CommandDef<{
|
|
5
|
+
readonly repo: {
|
|
6
|
+
readonly type: "positional";
|
|
7
|
+
readonly description: "Repository (e.g. owner/repo or full URL)";
|
|
8
|
+
readonly required: true;
|
|
9
|
+
};
|
|
10
|
+
}>;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { add };
|
package/dist/cli/add.mjs
ADDED
package/dist/cli/index.mjs
CHANGED
|
@@ -1,63 +1,27 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
1
|
+
import { t as add } from "../add-CmzBK4br.mjs";
|
|
2
|
+
import { t as init } from "../init-4enI_4o6.mjs";
|
|
3
|
+
import { t as install } from "../install-CmdQl0XL.mjs";
|
|
4
|
+
import { t as remove } from "../remove-ByCBLakw.mjs";
|
|
5
|
+
import { t as sync } from "../sync-1OE33hei.mjs";
|
|
5
6
|
import { defineCommand, runMain } from "citty";
|
|
6
|
-
import { x } from "tinyexec";
|
|
7
7
|
|
|
8
8
|
//#region package.json
|
|
9
|
-
var version = "0.
|
|
9
|
+
var version = "0.3.1";
|
|
10
10
|
|
|
11
11
|
//#endregion
|
|
12
12
|
//#region src/cli/index.ts
|
|
13
13
|
runMain(defineCommand({
|
|
14
14
|
meta: {
|
|
15
|
-
name: "
|
|
15
|
+
name: "skills-manifest",
|
|
16
16
|
version,
|
|
17
|
-
description: "
|
|
17
|
+
description: "A lightweight manifest manager for skills"
|
|
18
18
|
},
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"add",
|
|
26
|
-
repo,
|
|
27
|
-
"--agent",
|
|
28
|
-
...config.agents,
|
|
29
|
-
"--all",
|
|
30
|
-
"--yes"
|
|
31
|
-
], { nodeOptions: { stdio: "inherit" } });
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
await x("skills", [
|
|
35
|
-
"add",
|
|
36
|
-
repo,
|
|
37
|
-
"--skill",
|
|
38
|
-
...Array.isArray(config.skills[repo]) ? config.skills[repo] : Object.keys(config.skills[repo]).filter((skill) => config.skills[repo][skill] === true),
|
|
39
|
-
"--agent",
|
|
40
|
-
...config.agents,
|
|
41
|
-
"--yes"
|
|
42
|
-
], { nodeOptions: { stdio: "inherit" } });
|
|
43
|
-
}
|
|
44
|
-
const TARGET_MAP = {
|
|
45
|
-
cursor: ".cursor",
|
|
46
|
-
opencode: ".opencode"
|
|
47
|
-
};
|
|
48
|
-
const agents = path.join(process.cwd(), ".agents");
|
|
49
|
-
const fixedAgents = config.agents.filter((a) => a in TARGET_MAP);
|
|
50
|
-
for (const agent of fixedAgents) {
|
|
51
|
-
const dest = path.join(process.cwd(), TARGET_MAP[agent]);
|
|
52
|
-
await fs.rm(dest, {
|
|
53
|
-
recursive: true,
|
|
54
|
-
force: true
|
|
55
|
-
});
|
|
56
|
-
await fs.cp(agents, dest, {
|
|
57
|
-
recursive: true,
|
|
58
|
-
verbatimSymlinks: false
|
|
59
|
-
});
|
|
60
|
-
}
|
|
19
|
+
subCommands: {
|
|
20
|
+
add,
|
|
21
|
+
init,
|
|
22
|
+
install,
|
|
23
|
+
remove,
|
|
24
|
+
sync
|
|
61
25
|
}
|
|
62
26
|
}));
|
|
63
27
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as citty3 from "citty";
|
|
2
|
+
|
|
3
|
+
//#region src/cli/remove.d.ts
|
|
4
|
+
declare const remove: citty3.CommandDef<{
|
|
5
|
+
readonly repo: {
|
|
6
|
+
readonly type: "positional";
|
|
7
|
+
readonly description: "Repository (e.g. owner/repo or full URL)";
|
|
8
|
+
readonly required: true;
|
|
9
|
+
};
|
|
10
|
+
}>;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { remove };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as Skills, r as SkillsManifest, t as Repo } from "./index-
|
|
1
|
+
import { n as Skills, r as SkillsManifest, t as Repo } from "./index-DeyN5X2A.mjs";
|
|
2
2
|
export { Repo, Skills, SkillsManifest };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { t as patchSkillsCli } from "./patch-C3hgBcHP.mjs";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import { defineCommand } from "citty";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import process from "node:process";
|
|
6
|
+
import { addDevDependency, installDependencies } from "nypm";
|
|
7
|
+
|
|
8
|
+
//#region src/cli/init.ts
|
|
9
|
+
const DEFAULT_MANIFEST = {
|
|
10
|
+
agents: ["cursor", "claude-code"],
|
|
11
|
+
skills: {}
|
|
12
|
+
};
|
|
13
|
+
const init = defineCommand({
|
|
14
|
+
meta: {
|
|
15
|
+
name: "init",
|
|
16
|
+
description: "Initialize skills configuration"
|
|
17
|
+
},
|
|
18
|
+
async run() {
|
|
19
|
+
const cwd = process.cwd();
|
|
20
|
+
await addDevDependency(["skills", "skills-manifest"], { cwd });
|
|
21
|
+
await installDependencies({ cwd });
|
|
22
|
+
await patchSkillsCli();
|
|
23
|
+
const manifestPath = path.join(cwd, "skills-manifest.json");
|
|
24
|
+
if (!await fs.stat(manifestPath).catch(() => null)) {
|
|
25
|
+
const content = {
|
|
26
|
+
$schema: "https://raw.githubusercontent.com/hairyf/skills-manifest/main/skills-manifest.schema.json",
|
|
27
|
+
...DEFAULT_MANIFEST
|
|
28
|
+
};
|
|
29
|
+
await fs.writeFile(manifestPath, JSON.stringify(content, null, 2));
|
|
30
|
+
}
|
|
31
|
+
const gitignorePath = path.join(cwd, ".gitignore");
|
|
32
|
+
const gitignore = await fs.readFile(gitignorePath, "utf-8").catch(() => "");
|
|
33
|
+
if (!gitignore.split("\n").includes("skills")) await fs.appendFile(gitignorePath, gitignore.endsWith("\n") ? "skills\n" : "\nskills\n");
|
|
34
|
+
const pkgPath = path.join(cwd, "package.json");
|
|
35
|
+
const pkg = JSON.parse(await fs.readFile(pkgPath, "utf-8"));
|
|
36
|
+
const prepare = pkg.scripts?.prepare;
|
|
37
|
+
const cmd = "skills-manifest install";
|
|
38
|
+
if (!prepare) pkg.scripts = {
|
|
39
|
+
...pkg.scripts,
|
|
40
|
+
prepare: cmd
|
|
41
|
+
};
|
|
42
|
+
else if (!prepare.includes(cmd)) pkg.scripts.prepare = `${prepare} && ${cmd}`;
|
|
43
|
+
await fs.writeFile(pkgPath, JSON.stringify(pkg, null, 2));
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
//#endregion
|
|
48
|
+
export { init as t };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { t as patchSkillsCli } from "./patch-C3hgBcHP.mjs";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import { loadConfig } from "c12";
|
|
4
|
+
import { defineCommand } from "citty";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import process from "node:process";
|
|
7
|
+
import { x } from "tinyexec";
|
|
8
|
+
|
|
9
|
+
//#region src/cli/install.ts
|
|
10
|
+
const TARGET_MAP = {
|
|
11
|
+
cursor: ".cursor",
|
|
12
|
+
opencode: ".opencode"
|
|
13
|
+
};
|
|
14
|
+
const install = defineCommand({
|
|
15
|
+
meta: {
|
|
16
|
+
name: "install",
|
|
17
|
+
description: "Install skills"
|
|
18
|
+
},
|
|
19
|
+
async run() {
|
|
20
|
+
const { config } = await loadConfig({ configFile: "skills-manifest" });
|
|
21
|
+
const repos = Object.keys(config.skills);
|
|
22
|
+
for (const repo of repos) {
|
|
23
|
+
if (typeof config.skills[repo] === "boolean") {
|
|
24
|
+
await x("skills", [
|
|
25
|
+
"add",
|
|
26
|
+
repo,
|
|
27
|
+
"--agent",
|
|
28
|
+
...config.agents,
|
|
29
|
+
"--all",
|
|
30
|
+
"--yes"
|
|
31
|
+
], { nodeOptions: { stdio: "inherit" } });
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
await x("skills", [
|
|
35
|
+
"add",
|
|
36
|
+
repo,
|
|
37
|
+
"--skill",
|
|
38
|
+
...Array.isArray(config.skills[repo]) ? config.skills[repo] : Object.keys(config.skills[repo]).filter((skill) => config.skills[repo][skill] === true),
|
|
39
|
+
"--agent",
|
|
40
|
+
...config.agents,
|
|
41
|
+
"--yes"
|
|
42
|
+
], { nodeOptions: { stdio: "inherit" } });
|
|
43
|
+
}
|
|
44
|
+
const agents = path.join(process.cwd(), ".agents");
|
|
45
|
+
const fixedAgents = config.agents.filter((a) => a in TARGET_MAP);
|
|
46
|
+
for (const agent of fixedAgents) {
|
|
47
|
+
const dest = path.join(process.cwd(), TARGET_MAP[agent]);
|
|
48
|
+
await fs.rm(dest, {
|
|
49
|
+
recursive: true,
|
|
50
|
+
force: true
|
|
51
|
+
});
|
|
52
|
+
await fs.cp(agents, dest, {
|
|
53
|
+
recursive: true,
|
|
54
|
+
verbatimSymlinks: false
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
await patchSkillsCli();
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
//#endregion
|
|
62
|
+
export { install as t };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
|
|
6
|
+
//#region src/cli/patch.ts
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
/** Replace node_modules/skills/bin/cli.mjs with wrapper (add/remove sync with skills-manifest.json, add --skip-manifest) */
|
|
9
|
+
async function patchSkillsCli() {
|
|
10
|
+
const cwd = process.cwd();
|
|
11
|
+
const cliPath = path.join(cwd, "node_modules", "skills", "bin", "cli.mjs");
|
|
12
|
+
try {
|
|
13
|
+
if (!(await fs.stat(cliPath)).isFile()) return;
|
|
14
|
+
} catch {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if ((await fs.readFile(cliPath, "utf-8").catch(() => "")).includes("Injected by skills-manifest")) return;
|
|
18
|
+
let wrapperPath;
|
|
19
|
+
try {
|
|
20
|
+
const pkgJsonPath = require.resolve("skills-manifest/package.json");
|
|
21
|
+
wrapperPath = path.join(path.dirname(pkgJsonPath), "patches", "skills-cli.mjs");
|
|
22
|
+
} catch {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const wrapper = await fs.readFile(wrapperPath, "utf-8");
|
|
27
|
+
await fs.writeFile(cliPath, wrapper, "utf-8");
|
|
28
|
+
} catch {
|
|
29
|
+
console.warn("skills-manifest: failed to inject wrapper. Sync add/remove with manifest will not run.");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
export { patchSkillsCli as t };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { loadConfig } from "c12";
|
|
3
|
+
import { defineCommand } from "citty";
|
|
4
|
+
|
|
5
|
+
//#region src/cli/remove.ts
|
|
6
|
+
const remove = defineCommand({
|
|
7
|
+
meta: {
|
|
8
|
+
name: "remove",
|
|
9
|
+
description: "Remove repo or skills from manifest"
|
|
10
|
+
},
|
|
11
|
+
args: { repo: {
|
|
12
|
+
type: "positional",
|
|
13
|
+
description: "Repository (e.g. owner/repo or full URL)",
|
|
14
|
+
required: true
|
|
15
|
+
} },
|
|
16
|
+
async run({ args }) {
|
|
17
|
+
const { config, configFile } = await loadConfig({ configFile: "skills-manifest" });
|
|
18
|
+
if (!configFile) throw new Error("skills-manifest.json not found. Run `skills-manifest init` first.");
|
|
19
|
+
const repo = args.repo;
|
|
20
|
+
const skillsToRemove = (args._ ?? []).slice(1);
|
|
21
|
+
if (!(repo in config.skills)) throw new Error(`Repo ${repo} not found in manifest`);
|
|
22
|
+
if (skillsToRemove.length === 0) {
|
|
23
|
+
delete config.skills[repo];
|
|
24
|
+
console.log(`Removed ${repo} from skills-manifest.json`);
|
|
25
|
+
} else {
|
|
26
|
+
const existing = config.skills[repo];
|
|
27
|
+
const skillsToKeep = (Array.isArray(existing) ? existing : typeof existing === "object" && existing !== null ? Object.keys(existing).filter((k) => existing[k]) : []).filter((s) => !skillsToRemove.includes(s));
|
|
28
|
+
if (skillsToKeep.length === 0) {
|
|
29
|
+
delete config.skills[repo];
|
|
30
|
+
console.log(`Removed ${repo} from skills-manifest.json`);
|
|
31
|
+
} else {
|
|
32
|
+
config.skills[repo] = skillsToKeep;
|
|
33
|
+
console.log(`Removed skills from ${repo} in skills-manifest.json`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const content = JSON.stringify(config, null, 2);
|
|
37
|
+
await fs.writeFile(configFile, content);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
export { remove as t };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { t as syncFromSkills } from "./utils-m5dGqHGZ.mjs";
|
|
2
|
+
import { defineCommand } from "citty";
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
|
|
5
|
+
//#region src/cli/sync.ts
|
|
6
|
+
const sync = defineCommand({
|
|
7
|
+
meta: {
|
|
8
|
+
name: "sync",
|
|
9
|
+
description: "Sync manifest from skills CLI argv (internal)"
|
|
10
|
+
},
|
|
11
|
+
async run() {
|
|
12
|
+
const idx = process.argv.indexOf("sync");
|
|
13
|
+
await syncFromSkills(idx < 0 ? [] : process.argv.slice(idx + 1));
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
export { sync as t };
|
package/dist/types/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as Skills, r as SkillsManifest, t as Repo } from "../index-
|
|
1
|
+
import { n as Skills, r as SkillsManifest, t as Repo } from "../index-DeyN5X2A.mjs";
|
|
2
2
|
export { Repo, Skills, SkillsManifest };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/utils/index.d.ts
|
|
2
|
+
interface SyncFromSkillsOptions {
|
|
3
|
+
cwd?: string;
|
|
4
|
+
}
|
|
5
|
+
/** Parse skills CLI-style argv and sync manifest (used by skills-cli patch). */
|
|
6
|
+
declare function syncFromSkills(argv: string[], options?: SyncFromSkillsOptions): Promise<void>;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { SyncFromSkillsOptions, syncFromSkills };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { loadConfig } from "c12";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
|
|
6
|
+
//#region src/utils/index.ts
|
|
7
|
+
/** Parse skills CLI-style argv and sync manifest (used by skills-cli patch). */
|
|
8
|
+
async function syncFromSkills(argv, options = {}) {
|
|
9
|
+
const cmd = argv[0];
|
|
10
|
+
if (cmd !== "add" && cmd !== "remove") return;
|
|
11
|
+
const cwd = options.cwd ?? process.cwd();
|
|
12
|
+
const configPath = path.join(cwd, "skills-manifest.json");
|
|
13
|
+
try {
|
|
14
|
+
await fs.access(configPath);
|
|
15
|
+
} catch {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const { config, configFile } = await loadConfig({
|
|
19
|
+
configFile: "skills-manifest",
|
|
20
|
+
cwd
|
|
21
|
+
});
|
|
22
|
+
if (!configFile) return;
|
|
23
|
+
if (cmd === "add") {
|
|
24
|
+
const rest = argv.slice(1);
|
|
25
|
+
let repo = "";
|
|
26
|
+
const skills = [];
|
|
27
|
+
for (let i = 0; i < rest.length; i++) {
|
|
28
|
+
if (rest[i] === "--skill" && rest[i + 1]) {
|
|
29
|
+
skills.push(rest[i + 1]);
|
|
30
|
+
i++;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (!rest[i].startsWith("-") && !repo) {
|
|
34
|
+
repo = rest[i];
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!repo) return;
|
|
39
|
+
const existing = config.skills[repo];
|
|
40
|
+
const existingList = Array.isArray(existing) ? existing : typeof existing === "object" && existing !== null ? Object.keys(existing).filter((k) => existing[k]) : [];
|
|
41
|
+
config.skills[repo] = [...new Set([...existingList, ...skills])];
|
|
42
|
+
} else {
|
|
43
|
+
const skillNames = argv.slice(1).filter((a) => !a.startsWith("-"));
|
|
44
|
+
if (skillNames.length === 0) return;
|
|
45
|
+
for (const [repo, list] of Object.entries(config.skills)) {
|
|
46
|
+
const arr = Array.isArray(list) ? list : typeof list === "object" && list !== null ? Object.keys(list).filter((k) => list[k]) : [];
|
|
47
|
+
const toRemove = skillNames.filter((s) => arr.includes(s));
|
|
48
|
+
if (toRemove.length === 0) continue;
|
|
49
|
+
const kept = arr.filter((s) => !toRemove.includes(s));
|
|
50
|
+
if (kept.length === 0) delete config.skills[repo];
|
|
51
|
+
else config.skills[repo] = kept;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
await fs.writeFile(configFile, JSON.stringify(config, null, 2));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
58
|
+
export { syncFromSkills as t };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skills-manifest",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.1",
|
|
5
5
|
"description": "A lightweight manifest manager for skills, enabling project-level skill synchronization and collaborative configuration.",
|
|
6
6
|
"author": "Hairyf <wwu710632@gmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -28,14 +28,16 @@
|
|
|
28
28
|
},
|
|
29
29
|
"files": [
|
|
30
30
|
"bin",
|
|
31
|
-
"dist"
|
|
31
|
+
"dist",
|
|
32
|
+
"patches"
|
|
32
33
|
],
|
|
33
34
|
"peerDependencies": {
|
|
34
|
-
"skills": "^1.
|
|
35
|
+
"skills": "^1.3.4"
|
|
35
36
|
},
|
|
36
37
|
"dependencies": {
|
|
37
38
|
"c12": "^3.3.3",
|
|
38
39
|
"citty": "^0.2.0",
|
|
40
|
+
"nypm": "^0.6.4",
|
|
39
41
|
"tinyexec": "^1.0.2"
|
|
40
42
|
},
|
|
41
43
|
"devDependencies": {
|
|
@@ -48,7 +50,7 @@
|
|
|
48
50
|
"lint-staged": "^16.2.7",
|
|
49
51
|
"publint": "^0.3.16",
|
|
50
52
|
"simple-git-hooks": "^2.13.1",
|
|
51
|
-
"skills": "^1.
|
|
53
|
+
"skills": "^1.3.4",
|
|
52
54
|
"tsdown": "^0.17.3",
|
|
53
55
|
"tsx": "^4.21.0",
|
|
54
56
|
"typescript": "^5.9.3",
|
|
@@ -56,7 +58,7 @@
|
|
|
56
58
|
"vitest": "^4.0.15",
|
|
57
59
|
"vitest-package-exports": "^0.1.1",
|
|
58
60
|
"yaml": "^2.8.2",
|
|
59
|
-
"skills-manifest": "0.
|
|
61
|
+
"skills-manifest": "0.3.1"
|
|
60
62
|
},
|
|
61
63
|
"simple-git-hooks": {
|
|
62
64
|
"pre-commit": "pnpm i --frozen-lockfile --ignore-scripts --offline && npx lint-staged"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { join, dirname } from 'node:path';
|
|
6
|
+
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
|
|
10
|
+
const argv = process.argv.slice(2);
|
|
11
|
+
const skipManifest = argv.includes('--skip-manifest');
|
|
12
|
+
const forwardArgs = argv.filter(arg => arg !== '--skip-manifest');
|
|
13
|
+
const [cmd] = forwardArgs;
|
|
14
|
+
|
|
15
|
+
// 1. 执行主 CLI 程序
|
|
16
|
+
const mainResult = spawnSync(process.execPath, [join(__dirname, '../dist/cli.mjs'), ...forwardArgs], { stdio: 'inherit' });
|
|
17
|
+
|
|
18
|
+
if (mainResult.status === 0 && !skipManifest && ['add', 'remove'].includes(cmd)) {
|
|
19
|
+
try {
|
|
20
|
+
const binPath = require.resolve('skills-manifest/bin/skills-manifest', { paths: [process.cwd()] });
|
|
21
|
+
spawnSync(process.execPath, [binPath, 'sync', ...forwardArgs], { stdio: 'inherit' });
|
|
22
|
+
} catch {
|
|
23
|
+
console.warn('skills-manifest: failed to sync from skills. Sync add/remove with manifest will not run.')
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
process.exit(mainResult.status ?? 1);
|
|
File without changes
|