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 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
- ## Install
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 };
@@ -0,0 +1,3 @@
1
+ import { t as add } from "../add-CmzBK4br.mjs";
2
+
3
+ export { add };
@@ -1,63 +1,27 @@
1
- import fs from "node:fs/promises";
2
- import path from "node:path";
3
- import process from "node:process";
4
- import { loadConfig } from "c12";
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.2.1";
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: "install",
15
+ name: "skills-manifest",
16
16
  version,
17
- description: "Install skills"
17
+ description: "A lightweight manifest manager for skills"
18
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 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,6 @@
1
+ import * as citty1 from "citty";
2
+
3
+ //#region src/cli/init.d.ts
4
+ declare const init: citty1.CommandDef<citty1.ArgsDef>;
5
+ //#endregion
6
+ export { init };
@@ -0,0 +1,3 @@
1
+ import { t as init } from "../init-4enI_4o6.mjs";
2
+
3
+ export { init };
@@ -0,0 +1,6 @@
1
+ import * as citty0 from "citty";
2
+
3
+ //#region src/cli/install.d.ts
4
+ declare const install: citty0.CommandDef<citty0.ArgsDef>;
5
+ //#endregion
6
+ export { install };
@@ -0,0 +1,3 @@
1
+ import { t as install } from "../install-CmdQl0XL.mjs";
2
+
3
+ export { install };
@@ -0,0 +1,5 @@
1
+ //#region src/cli/patch.d.ts
2
+ /** Replace node_modules/skills/bin/cli.mjs with wrapper (add/remove sync with skills-manifest.json, add --skip-manifest) */
3
+ declare function patchSkillsCli(): Promise<void>;
4
+ //#endregion
5
+ export { patchSkillsCli };
@@ -0,0 +1,3 @@
1
+ import { t as patchSkillsCli } from "../patch-C3hgBcHP.mjs";
2
+
3
+ export { patchSkillsCli };
@@ -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 };
@@ -0,0 +1,3 @@
1
+ import { t as remove } from "../remove-ByCBLakw.mjs";
2
+
3
+ export { remove };
@@ -0,0 +1,6 @@
1
+ import * as citty4 from "citty";
2
+
3
+ //#region src/cli/sync.d.ts
4
+ declare const sync: citty4.CommandDef<citty4.ArgsDef>;
5
+ //#endregion
6
+ export { sync };
@@ -0,0 +1,3 @@
1
+ import { t as sync } from "../sync-1OE33hei.mjs";
2
+
3
+ export { sync };
package/dist/index.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { n as Skills, r as SkillsManifest, t as Repo } from "./index-OGqMIJuf.mjs";
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 };
@@ -1,2 +1,2 @@
1
- import { n as Skills, r as SkillsManifest, t as Repo } from "../index-OGqMIJuf.mjs";
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,3 @@
1
+ import { t as syncFromSkills } from "../utils-m5dGqHGZ.mjs";
2
+
3
+ export { 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.2.1",
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.2.0"
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.2.0",
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.2.1"
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);