@wowok/skills 1.1.2 → 1.1.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wowok/skills",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "description": "WoWok AI Skills for Claude and other AI assistants - Helping AI use WoWok MCP tools correctly",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -16,6 +16,8 @@
16
16
  "wowok-safety/",
17
17
  "wowok-machine/",
18
18
  "wowok-order/",
19
+ "wowok-messenger/",
20
+ "wowok-output/",
19
21
  "examples/",
20
22
  "scripts/install.js",
21
23
  "README.md"
@@ -2,8 +2,12 @@
2
2
  * WoWok Skills installer
3
3
  *
4
4
  * npm lifecycle integration:
5
- * postinstall → copy SKILL.md folders to ~/.claude/skills/
6
- * preuninstall → remove SKILL.md folders from ~/.claude/skills/
5
+ * postinstall → copy SKILL.md folders to ~/.claude/skills/ (and more via env)
6
+ * preuninstall → remove SKILL.md folders from all installed client dirs
7
+ *
8
+ * Environment variables:
9
+ * WOWOK_SKILLS_TARGETS Comma-separated client targets (claude,agents,codebuddy)
10
+ * Defaults to "claude". Example: "claude,agents"
7
11
  */
8
12
 
9
13
  const fs = require('fs');
@@ -21,7 +25,13 @@ const SKILL_DIRS = [
21
25
  'wowok-safety',
22
26
  ];
23
27
 
24
- const CLAUDE_SKILLS_DIR = path.join(os.homedir(), '.claude', 'skills');
28
+ const CLIENT_DIRS = {
29
+ claude: path.join(os.homedir(), '.claude', 'skills'),
30
+ agents: path.join(os.homedir(), '.agents', 'skills'),
31
+ codebuddy: path.join(os.homedir(), '.codebuddy', 'skills'),
32
+ cursor: path.join(os.homedir(), '.cursor', 'rules'),
33
+ copilot: path.join(os.homedir(), '.github', 'prompts'),
34
+ };
25
35
 
26
36
  function getPackageRoot() {
27
37
  return path.resolve(__dirname, '..');
@@ -57,26 +67,91 @@ function removeDir(dir) {
57
67
  fs.rmdirSync(dir);
58
68
  }
59
69
 
60
- function installSkills(targetDir) {
70
+ function getFileExt(target) {
71
+ const exts = { claude: '.md', agents: '.md', codebuddy: '.md', cursor: '.mdc', copilot: '.prompt.md' };
72
+ return exts[target] || '.md';
73
+ }
74
+
75
+ function parseFrontmatter(content) {
76
+ const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
77
+ if (!match) return null;
78
+ const frontmatterStr = match[1];
79
+ const body = match[2];
80
+ const frontmatter = {};
81
+ let currentKey = null;
82
+ let currentValue = '';
83
+ for (const line of frontmatterStr.split('\n')) {
84
+ const kvMatch = line.match(/^(\w[\w-]*)\s*:\s*(.*)$/);
85
+ if (kvMatch) {
86
+ if (currentKey) {
87
+ frontmatter[currentKey] = currentValue.trim();
88
+ }
89
+ currentKey = kvMatch[1];
90
+ currentValue = kvMatch[2];
91
+ } else if (currentKey) {
92
+ currentValue += '\n' + line;
93
+ }
94
+ }
95
+ if (currentKey) {
96
+ frontmatter[currentKey] = currentValue.trim();
97
+ }
98
+ return { frontmatter, body };
99
+ }
100
+
101
+ function convertSkill(content, target, skillDir) {
102
+ if (target === 'cursor') {
103
+ const parsed = parseFrontmatter(content);
104
+ if (!parsed) return content;
105
+ const { frontmatter, body } = parsed;
106
+ let description = (frontmatter.description || frontmatter.name || skillDir);
107
+ if (typeof description === 'string') {
108
+ description = description.replace(/\n/g, ' ');
109
+ }
110
+ const isAlways = frontmatter.loading === 'always' || frontmatter.always === true;
111
+ const alwaysApply = isAlways ? 'true' : 'false';
112
+ const newFrontmatter = [
113
+ '---',
114
+ `description: "${description}"`,
115
+ `alwaysApply: ${alwaysApply}`,
116
+ '---',
117
+ ].join('\n');
118
+ return newFrontmatter + '\n' + body;
119
+ }
120
+ if (target === 'copilot') {
121
+ const parsed = parseFrontmatter(content);
122
+ if (!parsed) return content;
123
+ return parsed.body;
124
+ }
125
+ return content;
126
+ }
127
+
128
+ function installSkills(targetDir, target) {
61
129
  const pkgRoot = getPackageRoot();
130
+ const ext = getFileExt(target);
62
131
  let count = 0;
63
132
 
64
133
  fs.mkdirSync(targetDir, { recursive: true });
65
134
 
66
135
  for (const dir of SKILL_DIRS) {
67
136
  const src = path.join(pkgRoot, dir, 'SKILL.md');
68
- const destDir = path.join(targetDir, dir);
69
- const dest = path.join(destDir, 'SKILL.md');
70
137
 
71
138
  if (!fs.existsSync(src)) {
72
139
  console.warn(`[wowok-skills] WARN: SKILL.md not found for ${dir}`);
73
140
  continue;
74
141
  }
75
142
 
143
+ const content = fs.readFileSync(src, 'utf-8');
144
+ const converted = convertSkill(content, target, dir);
145
+ const basename = (target === 'cursor' || target === 'copilot')
146
+ ? `wowok-${dir.replace('wowok-', '')}${ext}`
147
+ : 'SKILL.md';
148
+ const destDir = path.join(targetDir, dir);
149
+ const dest = path.join(destDir, basename);
150
+
76
151
  fs.mkdirSync(destDir, { recursive: true });
77
- fs.copyFileSync(src, dest);
152
+ fs.writeFileSync(dest, converted, 'utf-8');
78
153
  count++;
79
- console.log(`[wowok-skills] installed: ${dir} → ${destDir}`);
154
+ console.log(`[wowok-skills] installed: ${dir} → ${dest}`);
80
155
  }
81
156
 
82
157
  return count;
@@ -97,19 +172,55 @@ function uninstallSkills(targetDir) {
97
172
  return count;
98
173
  }
99
174
 
175
+ function getTargets() {
176
+ const envTargets = process.env.WOWOK_SKILLS_TARGETS;
177
+ if (!envTargets) {
178
+ return ['claude'];
179
+ }
180
+ return envTargets.split(',').map(t => t.trim()).filter(t => CLIENT_DIRS[t]);
181
+ }
182
+
100
183
  function main() {
101
184
  const event = process.env.npm_lifecycle_event || '';
102
185
 
103
186
  if (event === 'postinstall') {
104
- console.log('[wowok-skills] Installing skills to ~/.claude/skills/ ...');
105
- const count = installSkills(CLAUDE_SKILLS_DIR);
106
- console.log(`[wowok-skills] Done — ${count} skills installed.`);
107
- console.log('[wowok-skills] Skills will be available in your next Claude Code session.');
187
+ const targets = getTargets();
188
+ console.log(`[wowok-skills] Installing skills to ${targets.length} client(s)...`);
189
+
190
+ let total = 0;
191
+ for (const target of targets) {
192
+ const dir = CLIENT_DIRS[target];
193
+ console.log(`[wowok-skills] → ${dir}`);
194
+ const count = installSkills(dir, target);
195
+ total += count;
196
+ }
197
+
198
+ console.log(`[wowok-skills] Done — ${total} skills installed across ${targets.length} client(s).`);
108
199
  } else if (event === 'preuninstall') {
109
- console.log('[wowok-skills] Removing skills from ~/.claude/skills/ ...');
110
- const count = uninstallSkills(CLAUDE_SKILLS_DIR);
111
- console.log(`[wowok-skills] Done — ${count} skills removed.`);
200
+ const targets = Object.keys(CLIENT_DIRS);
201
+ console.log('[wowok-skills] Removing skills from all client dirs...');
202
+
203
+ let total = 0;
204
+ for (const target of targets) {
205
+ const dir = CLIENT_DIRS[target];
206
+ if (countExisting(dir) > 0) {
207
+ console.log(`[wowok-skills] → ${dir}`);
208
+ total += uninstallSkills(dir);
209
+ }
210
+ }
211
+
212
+ console.log(`[wowok-skills] Done — ${total} skills removed.`);
112
213
  }
113
214
  }
114
215
 
216
+ function countExisting(targetDir) {
217
+ let count = 0;
218
+ for (const dir of SKILL_DIRS) {
219
+ if (fs.existsSync(path.join(targetDir, dir))) {
220
+ count++;
221
+ }
222
+ }
223
+ return count;
224
+ }
225
+
115
226
  main();