skill-tags 1.2.1 → 1.3.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/README.md CHANGED
@@ -16,6 +16,7 @@ If you're interested in contributing to Cursor Kits, please let me know!
16
16
  - [Agent Setup Prompt](#agent-setup-prompt)
17
17
  - [Install Options](#install-options)
18
18
  - [How It Works](#how-it-works)
19
+ - [Project-Level Install](#project-level-install)
19
20
  - [CLI Reference](#cli-reference)
20
21
  - [Manual Sync](#manual-sync)
21
22
  - [Skill Sources Scanned](#skill-sources-scanned)
@@ -29,23 +30,38 @@ If you're interested in contributing to Cursor Kits, please let me know!
29
30
 
30
31
  ## Quick Start
31
32
 
33
+ ### Global (recommended for most users)
34
+
35
+ 1. **Install:** `npm install skill-tags -g`
36
+ 2. **Setup:** `skill-tags --setup` → choose **Global** → `source ~/.zshrc`
37
+ 3. **Sync:** `skill-tags` (generates the command file)
38
+ 4. **Use:** Reference `@skill-tags.md` in any Cursor chat
39
+
32
40
  ```bash
33
- # Install
34
41
  npm install skill-tags -g
35
-
36
- # Add the shell auto-trigger wrapper
37
- skill-tags --setup
42
+ skill-tags --setup # choose: Global
38
43
  source ~/.zshrc
39
-
40
- # Initial sync (generate command file)
41
44
  skill-tags
42
45
  ```
43
46
 
47
+ ### Project-level
48
+
49
+ 1. **Install:** `npm install skill-tags --save-dev`
50
+ 2. **Setup:** `npx skill-tags --setup` → choose **Project**
51
+ 3. **Use:** Reference `@project-skill-tags.md` in Cursor chat
52
+
53
+ ```bash
54
+ npm install skill-tags --save-dev
55
+ npx skill-tags --setup # choose: Project — adds "skills" script to package.json
56
+
57
+ npm run skills add owner/repo/skill-name # adds skill + auto-syncs
58
+ ```
59
+
44
60
  ## Usage
45
61
 
46
62
  In any Cursor chat, attach the full index of your skills by referencing the generated command file:
47
63
 
48
- - `@skill-tags.md`
64
+ - `@skill-tags.md` (global) or `@project-skill-tags.md` (local, from `skill-tags --local`)
49
65
 
50
66
  Example:
51
67
 
@@ -94,9 +110,9 @@ Use a terminal that runs outside the sandbox with full permissions to avoid perm
94
110
 
95
111
  Steps to perform:
96
112
  1. Install the package: `npm install skill-tags -g`
97
- 2. Run `skill-tags --setup` to install the `skills()` shell wrapper in my rc file (~/.zshrc or ~/.bash_profile)
98
- 3. Run `skill-tags` to perform an initial sync of all installed skills
99
- 4. Source my shell rc file or instruct me to do so manually
113
+ 2. Run `skill-tags --setup` when prompted, choose Global and Auto (recommended)
114
+ 3. Source my shell rc file or instruct me to do so manually
115
+ 4. Run `skill-tags` to perform an initial sync of all installed skills
100
116
 
101
117
  When complete, output a summary that includes:
102
118
  - Where the command file was generated (~/.cursor/commands/skill-tags.md)
@@ -113,14 +129,23 @@ When complete, output a summary that includes:
113
129
 
114
130
  ## Install Options
115
131
 
116
- ### Install via npm
132
+ ### Global install (npm)
117
133
 
118
134
  ```bash
119
135
  npm install skill-tags -g
120
- skill-tags --setup
136
+ skill-tags --setup # choose: Global
121
137
  source ~/.zshrc
122
138
  ```
123
139
 
140
+ ### Project install (npm)
141
+
142
+ ```bash
143
+ npm install skill-tags --save-dev
144
+ npx skill-tags --setup # choose: Project
145
+ ```
146
+
147
+ Adds `"skills": "st-skills"` to `package.json`. Use `npm run skills add <pkg>` to add project skills — auto-syncs `.cursor/commands/project-skill-tags.md` on every change.
148
+
124
149
  ### One-off run (no install)
125
150
 
126
151
  ```bash
@@ -141,31 +166,74 @@ source ~/.zshrc # or ~/.bash_profile / ~/.bashrc
141
166
 
142
167
  ## How It Works
143
168
 
144
- After setup, the `skills` command wraps `npx skills` and automatically runs a sync after every `skills add` or `skills remove`:
169
+ After global setup, the `skills` command wraps `npx skills` and automatically runs a sync after every `skills add` or `skills remove`:
145
170
 
146
171
  ```bash
147
172
  # Install (or remove) a skill — sync runs automatically
148
173
  skills add vercel-labs/agent-skills/vercel-react-best-practices
149
174
 
150
- # The single command file is updated:
175
+ # The command file is updated:
151
176
  # ~/.cursor/commands/skill-tags.md
152
177
 
153
178
  # Use it in Cursor chat:
154
179
  # @skill-tags.md
155
180
  ```
156
181
 
182
+ ## Project-Level Install
183
+
184
+ Install skill-tags as a dev dependency to manage project-specific skills without touching your global shell config. The `--setup` wizard adds a `"skills"` npm script backed by the bundled `st-skills` binary.
185
+
186
+ ```bash
187
+ npm install skill-tags --save-dev
188
+ npx skill-tags --setup # choose: Project
189
+ ```
190
+
191
+ After setup, `package.json` will include:
192
+
193
+ ```json
194
+ "scripts": {
195
+ "skills": "st-skills"
196
+ }
197
+ ```
198
+
199
+ Use `npm run skills` to add, remove, or update project skills:
200
+
201
+ ```bash
202
+ npm run skills add owner/repo/skill-name # adds skill + auto-syncs
203
+ npm run skills remove owner/repo/skill-name # removes skill + auto-syncs
204
+ npm run skills update owner/repo/skill-name # updates skill + auto-syncs
205
+
206
+ # Manual re-sync:
207
+ skill-tags --local
208
+
209
+ # Use in Cursor chat:
210
+ # @project-skill-tags.md
211
+ ```
212
+
213
+ The `st-skills` binary (from this package) wraps `npx skills`, then automatically runs `skill-tags --local` on every successful `add`, `remove`, or `update`, writing the index to `.cursor/commands/project-skill-tags.md`.
214
+
157
215
  ## CLI Reference
158
216
 
159
217
  ```bash
160
218
  skill-tags # sync all skills, generate/update the command file
161
219
  skill-tags --categories # open interactive category wizard (CRUD)
162
- skill-tags --setup # install skills() shell wrapper in ~/.zshrc
163
- skill-tags --global-only # skip project-level skills (.agents/skills in CWD)
164
- skill-tags --project-only # scan only .agents/skills in CWD; write to .cursor/commands/skill-tags.md
220
+ skill-tags --setup # interactive setup: choose Global (shell profile) or Project (package.json)
221
+ skill-tags --global # skip local skills (.agents/skills in CWD); scan global sources only
222
+ skill-tags --local # scan only .agents/skills in CWD; write to .cursor/commands/project-skill-tags.md
165
223
  skill-tags --version # print version
166
224
  skill-tags --help # show usage
167
225
  ```
168
226
 
227
+ ### `st-skills` (project binary)
228
+
229
+ ```bash
230
+ npm run skills add <pkg> # install a project skill + auto-sync
231
+ npm run skills remove <pkg> # remove a project skill + auto-sync
232
+ npm run skills update <pkg> # update a project skill + auto-sync
233
+ ```
234
+
235
+ `st-skills` is registered in `package.json` by `skill-tags --setup` (local mode). It wraps `npx skills` and calls `skill-tags --local` after every mutating command.
236
+
169
237
  ## Manual Sync
170
238
 
171
239
  Run at any time to regenerate the command file:
@@ -192,7 +260,7 @@ Skills are discovered from all of these locations automatically. When the same s
192
260
 
193
261
  ## Generated File Format
194
262
 
195
- The `~/.cursor/commands/skill-tags.md` contains:
263
+ The `~/.cursor/commands/skill-tags.md` (global) and `./.cursor/commands/project-skill-tags.md` (local) contain:
196
264
 
197
265
  - An opening instruction for the agent to assess all skills and apply them autonomously.
198
266
  - Instructions for the agent on how to plan with skills when in Plan Mode.
package/bin/categories.js CHANGED
@@ -212,11 +212,6 @@ function toTitleCase(str) {
212
212
  return str.replace(/[-_]/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
213
213
  }
214
214
 
215
- function truncate(str, len) {
216
- if (!str || str.length <= len) return str || '';
217
- return str.slice(0, len - 1) + '…';
218
- }
219
-
220
215
  // ─── Wizard actions ──────────────────────────────────────────────────────────
221
216
 
222
217
  async function addCategories(skills, config) {
@@ -256,25 +251,9 @@ async function addCategories(skills, config) {
256
251
  }
257
252
 
258
253
  for (const cat of selected) {
259
- const skillChoices = skills.map(s => {
260
- const match = matchKeywords(s, cat);
261
- const hint = match ? ` ${match.reason}` : '';
262
- return {
263
- name: `${s.name}${hint}`,
264
- value: s.name,
265
- checked: !!match,
266
- description: truncate(s.description, 60),
267
- };
268
- });
269
-
270
- const selectedSkills = await checkbox({
271
- message: `Select skills for "${cat}" (space to toggle)`,
272
- choices: skillChoices,
273
- pageSize: 15,
274
- });
275
-
276
- config[cat] = selectedSkills;
277
- console.log(` ✓ ${toTitleCase(cat)}: ${selectedSkills.length} skill(s)\n`);
254
+ const matched = skills.filter(s => matchKeywords(s, cat));
255
+ config[cat] = matched.map(s => s.name);
256
+ console.log(` ${toTitleCase(cat)}: ${matched.length} skill(s) auto-assigned\n`);
278
257
  }
279
258
  }
280
259
 
@@ -293,26 +272,9 @@ async function editCategory(skills, config) {
293
272
  })),
294
273
  });
295
274
 
296
- const currentSet = new Set(config[cat] || []);
297
- const skillChoices = skills.map(s => {
298
- const match = matchKeywords(s, cat);
299
- const hint = match ? ` — ${match.reason}` : '';
300
- return {
301
- name: `${s.name}${hint}`,
302
- value: s.name,
303
- checked: currentSet.has(s.name),
304
- description: truncate(s.description, 60),
305
- };
306
- });
307
-
308
- const selectedSkills = await checkbox({
309
- message: `Select skills for "${cat}" (space to toggle)`,
310
- choices: skillChoices,
311
- pageSize: 15,
312
- });
313
-
314
- config[cat] = selectedSkills;
315
- console.log(` ✓ Updated ${toTitleCase(cat)}: ${selectedSkills.length} skill(s)\n`);
275
+ const matched = skills.filter(s => matchKeywords(s, cat));
276
+ config[cat] = matched.map(s => s.name);
277
+ console.log(` ✓ Re-generated ${toTitleCase(cat)}: ${matched.length} skill(s) auto-assigned\n`);
316
278
  }
317
279
 
318
280
  async function deleteCategory(config) {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // bin/postinstall.js
3
- // Runs automatically after `npm install -g skill-tags`.
4
- // Performs an initial sync of any already-installed skills.
3
+ // Runs automatically after `npm install skill-tags`.
4
+ // Global installs: perform initial sync. Local installs: print setup guidance.
5
5
  // Never throws — a failed postinstall should never break npm install.
6
6
 
7
7
  'use strict';
@@ -15,12 +15,18 @@ if (process.platform === 'win32') {
15
15
  process.exit(0);
16
16
  }
17
17
 
18
- // Skip on local (non-global) installs to avoid running on every `npm install`
19
- // in a project. npm sets npm_config_global=true for -g installs.
20
- if (process.env.npm_config_global !== 'true') {
18
+ const isGlobal = process.env.npm_config_global === 'true';
19
+
20
+ if (!isGlobal) {
21
+ // Project (local) install — print setup guidance and exit cleanly
22
+ console.log('\n skill-tags installed as a project dependency.');
23
+ console.log(' Run setup to add the "skills" npm script to your package.json:\n');
24
+ console.log(' npx skill-tags --setup\n');
21
25
  process.exit(0);
22
26
  }
23
27
 
28
+ // ─── Global install: run initial sync ────────────────────────────────────────
29
+
24
30
  const syncScript = path.join(__dirname, '..', 'sync.sh');
25
31
 
26
32
  if (!fs.existsSync(syncScript)) {
package/bin/setup.js ADDED
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env node
2
+ // bin/setup.js
3
+ // Interactive setup wizard: global/project install mode + auto/manual sync preference.
4
+
5
+ 'use strict';
6
+
7
+ const { spawnSync } = require('child_process');
8
+ const path = require('path');
9
+ const fs = require('fs');
10
+ const os = require('os');
11
+
12
+ const HOME = os.homedir();
13
+ const SYNC_SCRIPT = path.join(__dirname, '..', 'sync.sh');
14
+ const WRAPPER_MARKER = '# ─── skill-tags / Cursor Skill Command Sync';
15
+
16
+ module.exports = async function runSetup() {
17
+ const { select, confirm } = require('@inquirer/prompts');
18
+
19
+ console.log('\n skill-tags: setup\n');
20
+
21
+ const isGlobal = process.env.npm_config_global === 'true';
22
+
23
+ const mode = await select({
24
+ message: 'How are you using skill-tags?',
25
+ choices: [
26
+ {
27
+ name: 'Global — add skills() wrapper to shell profile (recommended for most users)',
28
+ value: 'global',
29
+ },
30
+ {
31
+ name: 'Project — add "skills" npm script to this project\'s package.json',
32
+ value: 'project',
33
+ },
34
+ ],
35
+ default: isGlobal ? 'global' : 'project',
36
+ });
37
+
38
+ const syncMode = await select({
39
+ message: 'How should skill-tags sync?',
40
+ choices: [
41
+ {
42
+ name: 'Auto (recommended) — sync automatically whenever you add or remove a skill',
43
+ value: 'auto',
44
+ },
45
+ {
46
+ name: 'Manual — run skill-tags yourself to sync when needed',
47
+ value: 'manual',
48
+ },
49
+ ],
50
+ default: 'auto',
51
+ });
52
+
53
+ if (mode === 'global') {
54
+ await setupGlobal(confirm, syncMode);
55
+ } else {
56
+ await setupProject(confirm, syncMode);
57
+ }
58
+ };
59
+
60
+ // ─── Global setup ─────────────────────────────────────────────────────────────
61
+
62
+ async function setupGlobal(confirm, syncMode) {
63
+ const shellName = path.basename(process.env.SHELL || 'bash');
64
+ let rcFile;
65
+ if (shellName === 'zsh') rcFile = path.join(HOME, '.zshrc');
66
+ else if (process.platform === 'darwin') rcFile = path.join(HOME, '.bash_profile');
67
+ else rcFile = path.join(HOME, '.bashrc');
68
+
69
+ const displayRc = rcFile.replace(HOME, '~');
70
+
71
+ if (syncMode === 'manual') {
72
+ console.log('\n Manual sync selected.');
73
+ console.log(' Run skill-tags at any time to regenerate ~/.cursor/commands/skill-tags.md\n');
74
+ console.log(' Running initial sync...\n');
75
+ spawnSync('bash', [SYNC_SCRIPT], { stdio: 'inherit' });
76
+ console.log(`\n Done! Run skill-tags manually to re-sync.\n`);
77
+ return;
78
+ }
79
+
80
+ // Auto sync: add shell wrapper
81
+ let alreadyInstalled = false;
82
+ try {
83
+ const content = fs.readFileSync(rcFile, 'utf-8');
84
+ if (content.includes(WRAPPER_MARKER)) alreadyInstalled = true;
85
+ } catch {}
86
+
87
+ if (alreadyInstalled) {
88
+ console.log(`\n ✓ Shell wrapper already installed in ${displayRc}\n`);
89
+ process.exit(0);
90
+ }
91
+
92
+ console.log(`\n This will add a skills() shell wrapper to ${displayRc}`);
93
+ console.log(` It auto-syncs skill-tags.md after every skills add/remove.\n`);
94
+
95
+ const yes = await confirm({
96
+ message: `Add the wrapper to ${displayRc}?`,
97
+ default: true,
98
+ });
99
+
100
+ if (!yes) {
101
+ console.log('\n Skipped.\n');
102
+ process.exit(0);
103
+ }
104
+
105
+ const syncPath = fs.existsSync(path.join(HOME, '.cursor', 'sync-skill-commands.sh'))
106
+ ? path.join(HOME, '.cursor', 'sync-skill-commands.sh')
107
+ : SYNC_SCRIPT;
108
+
109
+ const wrapper = `
110
+ ${WRAPPER_MARKER} ────────────────────────────────────────────────
111
+ # Wraps \`npx skills\` to auto-generate skill-tags.md after install/removal.
112
+ # Run manually: skill-tags (or: bash ${syncPath})
113
+ function skills() {
114
+ npx skills "$@"
115
+ local exit_code=$?
116
+ if [[ "$1" == "add" || "$1" == "remove" ]] && [[ $exit_code -eq 0 ]]; then
117
+ bash "${syncPath}"
118
+ fi
119
+ return $exit_code
120
+ }
121
+ # ─────────────────────────────────────────────────────────────────────────────
122
+ `;
123
+
124
+ try {
125
+ fs.appendFileSync(rcFile, wrapper);
126
+ } catch (err) {
127
+ console.error(`\n Failed to write to ${displayRc}: ${err.message}\n`);
128
+ process.exit(1);
129
+ }
130
+
131
+ console.log(`\n ✓ Added skills() wrapper to ${displayRc}`);
132
+ console.log(` Reload with: source ${displayRc}\n`);
133
+ }
134
+
135
+ // ─── Project setup ────────────────────────────────────────────────────────────
136
+
137
+ async function setupProject(confirm, syncMode) {
138
+ const pkgPath = path.join(process.cwd(), 'package.json');
139
+
140
+ if (!fs.existsSync(pkgPath)) {
141
+ console.error('\n No package.json found in current directory.');
142
+ console.error(' Run skill-tags --setup from your project root.\n');
143
+ process.exit(1);
144
+ }
145
+
146
+ let pkg;
147
+ try {
148
+ pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
149
+ } catch (err) {
150
+ console.error(`\n Failed to read package.json: ${err.message}\n`);
151
+ process.exit(1);
152
+ }
153
+
154
+ const scripts = pkg.scripts || {};
155
+
156
+ if (syncMode === 'manual') {
157
+ console.log('\n Manual sync selected.');
158
+ console.log(' Run skill-tags --local at any time to regenerate .cursor/commands/project-skill-tags.md\n');
159
+ console.log(' Running initial project sync...\n');
160
+ spawnSync(
161
+ 'node',
162
+ [path.join(__dirname, 'skill-tags.js'), '--local'],
163
+ { stdio: 'inherit', cwd: process.cwd() }
164
+ );
165
+ console.log(`\n Done! Run skill-tags --local manually to re-sync.\n`);
166
+ return;
167
+ }
168
+
169
+ // Auto sync: add "skills" npm script
170
+ if (scripts.skills === 'st-skills') {
171
+ console.log('\n ✓ Already configured — "skills": "st-skills" is in package.json\n');
172
+ console.log(' Add a skill: npm run skills add <owner/repo/skill-name>');
173
+ console.log(' Remove: npm run skills remove <owner/repo/skill-name>\n');
174
+ process.exit(0);
175
+ }
176
+
177
+ console.log('\n This will add a "skills" script to your package.json:');
178
+ console.log(' "scripts": { "skills": "st-skills" }');
179
+ console.log('\n Then use: npm run skills add <owner/repo/skill-name>');
180
+ console.log(' Auto-syncs .cursor/commands/project-skill-tags.md after every add/remove.\n');
181
+
182
+ const yes = await confirm({
183
+ message: 'Add the "skills" script to package.json?',
184
+ default: true,
185
+ });
186
+
187
+ if (!yes) {
188
+ console.log('\n Skipped.\n');
189
+ process.exit(0);
190
+ }
191
+
192
+ pkg.scripts = { ...scripts, skills: 'st-skills' };
193
+
194
+ try {
195
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
196
+ } catch (err) {
197
+ console.error(`\n Failed to write package.json: ${err.message}\n`);
198
+ process.exit(1);
199
+ }
200
+
201
+ console.log('\n ✓ Added "skills": "st-skills" to package.json');
202
+ console.log('\n Running initial project sync...\n');
203
+
204
+ const result = spawnSync(
205
+ 'node',
206
+ [path.join(__dirname, 'skill-tags.js'), '--local'],
207
+ { stdio: 'inherit', cwd: process.cwd() }
208
+ );
209
+
210
+ if (result.error) {
211
+ console.error(`\n Warning: initial sync failed — ${result.error.message}`);
212
+ }
213
+
214
+ console.log('\n Setup complete!\n');
215
+ console.log(' Add a skill: npm run skills add <owner/repo/skill-name>');
216
+ console.log(' Remove: npm run skills remove <owner/repo/skill-name>');
217
+ console.log(' Manual sync: skill-tags --local\n');
218
+ }
package/bin/skill-tags.js CHANGED
@@ -7,12 +7,9 @@
7
7
  const { spawnSync } = require('child_process');
8
8
  const path = require('path');
9
9
  const fs = require('fs');
10
- const os = require('os');
11
10
 
12
11
  const VERSION = require('../package.json').version;
13
- const HOME = os.homedir();
14
12
  const SYNC_SCRIPT = path.join(__dirname, '..', 'sync.sh');
15
- const WRAPPER_MARKER = '# ─── skill-tags / Cursor Skill Command Sync';
16
13
 
17
14
  // ─── --version ───────────────────────────────────────────────────────────────
18
15
 
@@ -40,9 +37,9 @@ if (process.argv.includes('--help') || process.argv.includes('-h')) {
40
37
  Options:
41
38
  (none) Scan all skill sources and generate skill-tags.md
42
39
  --categories Interactive category wizard (arrow keys + space to toggle)
43
- --global-only Skip project-level skills (.agents/skills in CWD)
44
- --project-only Scan only .agents/skills in CWD; write to .cursor/commands/skill-tags.md
45
- --setup Install the skills() shell wrapper in your shell rc
40
+ --global Skip local skills (.agents/skills in CWD); scan global sources only
41
+ --local Scan only .agents/skills in CWD; write to .cursor/commands/project-skill-tags.md
42
+ --setup Interactive setup: choose Global (shell profile) or Project (package.json)
46
43
  --version, -v Print version
47
44
  --help, -h Show this help
48
45
 
@@ -55,12 +52,21 @@ if (process.argv.includes('--help') || process.argv.includes('-h')) {
55
52
  ./.agents/skills/ project-level skills (current directory)
56
53
 
57
54
  Output:
58
- ~/.cursor/commands/skill-tags.md full index of all skills
59
- ~/.cursor/commands/skills-<category>.md generated by --categories
60
- ./.cursor/commands/skill-tags.md generated by --project-only
55
+ ~/.cursor/commands/skill-tags.md full index of all skills (global)
56
+ ~/.cursor/commands/skills-<category>.md generated by --categories
57
+ ./.cursor/commands/project-skill-tags.md generated by --local
61
58
 
62
59
  Config:
63
60
  ~/.cursor/skill-tags-categories.conf
61
+
62
+ Setup modes:
63
+ Global Adds skills() wrapper to ~/.zshrc — use: skills add <pkg>
64
+ Project Adds "skills": "st-skills" to package.json — use: npm run skills add <pkg>
65
+
66
+ Project binary (st-skills):
67
+ st-skills add <pkg> Install a project skill and auto-sync
68
+ st-skills remove <pkg> Remove a project skill and auto-sync
69
+ st-skills update <pkg> Update a project skill and auto-sync
64
70
  `);
65
71
  process.exit(0);
66
72
  }
@@ -74,6 +80,7 @@ if (process.argv.includes('--categories')) {
74
80
  // ─── --setup ─────────────────────────────────────────────────────────────────
75
81
 
76
82
  else if (process.argv.includes('--setup')) {
83
+ const runSetup = require('./setup');
77
84
  runSetup().catch(err => {
78
85
  if (err.name === 'ExitPromptError') { console.log(); process.exit(0); }
79
86
  console.error(' Error:', err.message);
@@ -100,72 +107,3 @@ else {
100
107
 
101
108
  process.exit(result.status ?? 0);
102
109
  }
103
-
104
- // ─── Setup implementation ────────────────────────────────────────────────────
105
-
106
- async function runSetup() {
107
- const { confirm } = require('@inquirer/prompts');
108
-
109
- const shellName = path.basename(process.env.SHELL || 'bash');
110
- let rcFile;
111
- if (shellName === 'zsh') rcFile = path.join(HOME, '.zshrc');
112
- else if (process.platform === 'darwin') rcFile = path.join(HOME, '.bash_profile');
113
- else rcFile = path.join(HOME, '.bashrc');
114
-
115
- const displayRc = rcFile.replace(HOME, '~');
116
-
117
- console.log(`\n skill-tags: shell setup\n`);
118
-
119
- let alreadyInstalled = false;
120
- try {
121
- const content = fs.readFileSync(rcFile, 'utf-8');
122
- if (content.includes(WRAPPER_MARKER)) alreadyInstalled = true;
123
- } catch {}
124
-
125
- if (alreadyInstalled) {
126
- console.log(` ✓ Shell wrapper already installed in ${displayRc}\n`);
127
- process.exit(0);
128
- }
129
-
130
- console.log(` This will add a skills() shell wrapper to ${displayRc}`);
131
- console.log(` It auto-syncs skill-tags.md after every skills add/remove.\n`);
132
-
133
- const yes = await confirm({
134
- message: `Add the wrapper to ${displayRc}?`,
135
- default: true,
136
- });
137
-
138
- if (!yes) {
139
- console.log('\n Skipped.\n');
140
- process.exit(0);
141
- }
142
-
143
- const syncPath = fs.existsSync(path.join(HOME, '.cursor', 'sync-skill-commands.sh'))
144
- ? path.join(HOME, '.cursor', 'sync-skill-commands.sh')
145
- : SYNC_SCRIPT;
146
-
147
- const wrapper = `
148
- ${WRAPPER_MARKER} ────────────────────────────────────────────────
149
- # Wraps \`npx skills\` to auto-generate skill-tags.md after install/removal.
150
- # Run manually: skill-tags (or: bash ${syncPath})
151
- function skills() {
152
- npx skills "$@"
153
- local exit_code=$?
154
- if [[ "$1" == "add" || "$1" == "remove" ]] && [[ $exit_code -eq 0 ]]; then
155
- bash "${syncPath}"
156
- fi
157
- return $exit_code
158
- }
159
- # ─────────────────────────────────────────────────────────────────────────────
160
- `;
161
-
162
- try {
163
- fs.appendFileSync(rcFile, wrapper);
164
- } catch (err) {
165
- console.error(`\n Failed to write to ${displayRc}: ${err.message}\n`);
166
- process.exit(1);
167
- }
168
-
169
- console.log(`\n ✓ Added skills() wrapper to ${displayRc}`);
170
- console.log(` Reload with: source ${displayRc}\n`);
171
- }
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ // bin/st-skills.js
3
+ // Project-level skills wrapper: runs npx skills and auto-syncs project-skill-tags.md on add/remove/update.
4
+
5
+ 'use strict';
6
+
7
+ const { spawnSync } = require('child_process');
8
+ const path = require('path');
9
+
10
+ const args = process.argv.slice(2);
11
+ const subcommand = args[0];
12
+
13
+ // Run npx skills with all forwarded arguments
14
+ const result = spawnSync('npx', ['skills', ...args], { stdio: 'inherit', shell: false });
15
+
16
+ if (result.error) {
17
+ console.error(`\n st-skills: failed to run npx skills — ${result.error.message}\n`);
18
+ process.exit(1);
19
+ }
20
+
21
+ const exitCode = result.status ?? 1;
22
+
23
+ // Auto-sync project-skill-tags.md on successful mutating subcommands
24
+ if (['add', 'remove', 'update'].includes(subcommand) && exitCode === 0) {
25
+ const syncResult = spawnSync(
26
+ 'node',
27
+ [path.join(__dirname, 'skill-tags.js'), '--local'],
28
+ { stdio: 'inherit', cwd: process.cwd() }
29
+ );
30
+
31
+ if (syncResult.error) {
32
+ console.error(`\n st-skills: sync failed — ${syncResult.error.message}\n`);
33
+ }
34
+ }
35
+
36
+ process.exit(exitCode);
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "skill-tags",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "Generates consolidated command files (@skill-tags.md and custom @skills-<category>.md indexes) for all installed Cursor skills.",
5
5
  "bin": {
6
- "skill-tags": "bin/skill-tags.js"
6
+ "skill-tags": "bin/skill-tags.js",
7
+ "st-skills": "bin/st-skills.js"
7
8
  },
8
9
  "scripts": {
9
10
  "postinstall": "node ./bin/postinstall.js"
package/sync.sh CHANGED
@@ -7,13 +7,13 @@
7
7
 
8
8
  set -euo pipefail
9
9
 
10
- VERSION="1.2.1"
10
+ VERSION="1.3.0"
11
11
 
12
12
  GLOBAL_COMMANDS_DIR="${HOME}/.cursor/commands"
13
13
  OUTPUT_FILE="${GLOBAL_COMMANDS_DIR}/skill-tags.md"
14
14
  CATEGORIES_CONFIG="${HOME}/.cursor/skill-tags-categories.conf"
15
15
  PROJECT_COMMANDS_DIR="$(pwd)/.cursor/commands"
16
- PROJECT_OUTPUT_FILE="${PROJECT_COMMANDS_DIR}/skill-tags.md"
16
+ PROJECT_OUTPUT_FILE="${PROJECT_COMMANDS_DIR}/project-skill-tags.md"
17
17
 
18
18
  # ─── Priority-ordered skill source directories ─────────────────────────────────
19
19
  # Earlier entries take priority when the same skill name exists in multiple locations.
@@ -39,8 +39,8 @@ PROJECT_ONLY=false
39
39
 
40
40
  for arg in "$@"; do
41
41
  case "$arg" in
42
- --global-only) GLOBAL_ONLY=true ;;
43
- --project-only) PROJECT_ONLY=true ;;
42
+ --global) GLOBAL_ONLY=true ;;
43
+ --local) PROJECT_ONLY=true ;;
44
44
  esac
45
45
  done
46
46
 
@@ -259,7 +259,7 @@ EOF
259
259
  printf "\n skill-tags v%s — syncing skills\n\n" "$VERSION"
260
260
 
261
261
  if [[ "$PROJECT_ONLY" == "true" ]]; then
262
- # ─── --project-only: scan only .agents/skills in CWD ────────────────────────
262
+ # ─── --local: scan only .agents/skills in CWD ───────────────────────────────
263
263
  PROJECT_SKILLS_DIR="$(pwd)/.agents/skills"
264
264
 
265
265
  if [[ ! -d "$PROJECT_SKILLS_DIR" ]]; then
@@ -299,12 +299,12 @@ EOF
299
299
 
300
300
  printf "\n"
301
301
  if [[ "$is_update" == "true" ]]; then
302
- printf " ✓ Updated: .cursor/commands/skill-tags.md\n"
302
+ printf " ✓ Updated: .cursor/commands/project-skill-tags.md\n"
303
303
  else
304
- printf " ✓ Generated: .cursor/commands/skill-tags.md\n"
304
+ printf " ✓ Generated: .cursor/commands/project-skill-tags.md\n"
305
305
  fi
306
306
  printf " Skills: %d indexed\n" "$count_found"
307
- printf "\n Tip: type @skill-tags.md in Cursor chat to load the project skills reference.\n\n"
307
+ printf "\n Tip: type @project-skill-tags.md in Cursor chat to load the project skills reference.\n\n"
308
308
 
309
309
  else
310
310
  # ─── Default: scan all sources ───────────────────────────────────────────────