@wowok/skills 3.0.3 → 3.1.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.
Files changed (47) hide show
  1. package/README.md +146 -122
  2. package/dist/cli.d.ts +6 -0
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +223 -837
  5. package/dist/cli.js.map +1 -1
  6. package/dist/index.d.ts +4 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +24 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/installer.d.ts +121 -0
  11. package/dist/installer.d.ts.map +1 -0
  12. package/dist/installer.js +802 -0
  13. package/dist/installer.js.map +1 -0
  14. package/dist/skills.d.ts +5 -2
  15. package/dist/skills.d.ts.map +1 -1
  16. package/dist/skills.js +86 -62
  17. package/dist/skills.js.map +1 -1
  18. package/dist/targets.d.ts +94 -0
  19. package/dist/targets.d.ts.map +1 -0
  20. package/dist/targets.js +421 -0
  21. package/dist/targets.js.map +1 -0
  22. package/dist/types.d.ts +5 -4
  23. package/dist/types.d.ts.map +1 -1
  24. package/dist/types.js +0 -32
  25. package/dist/types.js.map +1 -1
  26. package/package.json +7 -4
  27. package/scripts/install.js +21 -858
  28. package/wowok-arbitrator/SKILL.md +5 -12
  29. package/wowok-auditor/SKILL.md +5 -17
  30. package/wowok-collaborator/SKILL.md +5 -17
  31. package/wowok-governance/SKILL.md +95 -0
  32. package/wowok-machine/SKILL.md +5 -18
  33. package/wowok-market/SKILL.md +82 -0
  34. package/wowok-messenger/SKILL.md +5 -18
  35. package/wowok-onboard/SKILL.md +5 -22
  36. package/wowok-order/SKILL.md +5 -18
  37. package/wowok-output/SKILL.md +5 -10
  38. package/wowok-planner/SKILL.md +5 -19
  39. package/wowok-provider/SKILL.md +5 -17
  40. package/wowok-supplier/SKILL.md +5 -16
  41. package/examples/Insurance/Insurance.md +0 -1245
  42. package/examples/MyShop/MyShop.md +0 -2003
  43. package/examples/MyShop/myshop_machine_nodes.json +0 -93
  44. package/examples/MyShop_Advanced/MyShop_Advanced.md +0 -2874
  45. package/examples/ThreeBody_Signature/ThreeBody_Signature.md +0 -1831
  46. package/examples/Travel/Travel.md +0 -1849
  47. package/examples/Travel/calc-weather-timestamps.js +0 -12
package/dist/cli.js CHANGED
@@ -1,934 +1,320 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
- if (k2 === undefined) k2 = k;
5
- var desc = Object.getOwnPropertyDescriptor(m, k);
6
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
- desc = { enumerable: true, get: function() { return m[k]; } };
8
- }
9
- Object.defineProperty(o, k2, desc);
10
- }) : (function(o, m, k, k2) {
11
- if (k2 === undefined) k2 = k;
12
- o[k2] = m[k];
13
- }));
14
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
- Object.defineProperty(o, "default", { enumerable: true, value: v });
16
- }) : function(o, v) {
17
- o["default"] = v;
18
- });
19
- var __importStar = (this && this.__importStar) || (function () {
20
- var ownKeys = function(o) {
21
- ownKeys = Object.getOwnPropertyNames || function (o) {
22
- var ar = [];
23
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
- return ar;
25
- };
26
- return ownKeys(o);
27
- };
28
- return function (mod) {
29
- if (mod && mod.__esModule) return mod;
30
- var result = {};
31
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
- __setModuleDefault(result, mod);
33
- return result;
34
- };
35
- })();
36
- Object.defineProperty(exports, "__esModule", { value: true });
37
- const fs = __importStar(require("fs"));
38
- const path = __importStar(require("path"));
39
- const child_process_1 = require("child_process");
40
- const os = __importStar(require("os"));
41
- const skills_1 = require("./skills");
42
- const types_1 = require("./types");
43
3
  /**
44
- * Skill directory names (must match folder names in package)
45
- * Must stay in sync with scripts/install.js SKILL_DIRS
46
- * Ordered by role for clarity:
47
- * - Customer: wowok-order
48
- * - Provider: wowok-provider, wowok-machine
49
- * - Arbitrator: wowok-arbitrator
50
- * - Shared: wowok-messenger, wowok-output
51
- * - Onboarding: wowok-onboard, wowok-planner, wowok-auditor
4
+ * `wowok-skills` CLI.
52
5
  *
53
- * GLM5-31 sink refactor: wowok-guard/tools/safety/scenario were sunk into
54
- * the MCP knowledge layer and are no longer installed (see DEPRECATED_SKILLS).
55
- */
56
- const SKILL_DIRS = [
57
- 'wowok-order',
58
- 'wowok-provider',
59
- 'wowok-machine',
60
- 'wowok-arbitrator',
61
- 'wowok-messenger',
62
- 'wowok-output',
63
- 'wowok-onboard',
64
- 'wowok-planner',
65
- 'wowok-auditor',
66
- 'wowok-supplier',
67
- 'wowok-collaborator',
68
- 'wowok-governance',
69
- ];
70
- /**
71
- * Deprecated skill dirs — never installed, but uninit still removes them
72
- * from legacy installs so users can clean up pre-refactor installations.
73
- */
74
- const LEGACY_SKILL_DIRS = [...skills_1.DEPRECATED_SKILLS];
75
- /**
76
- * Role display names for CLI output
6
+ * All installation/MCP logic lives in src/installer.ts + src/targets.ts so the
7
+ * CLI and the npm postinstall hook can never drift apart again.
77
8
  */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ const skills_1 = require("./skills");
11
+ const targets_1 = require("./targets");
12
+ const installer_1 = require("./installer");
78
13
  const ROLE_DISPLAY = {
79
14
  customer: '👤 Customer',
80
15
  provider: '🏪 Provider',
81
16
  supplier: '📦 Supplier',
82
17
  collaborator: '🤝 Collaborator',
83
18
  arbitrator: '⚖️ Arbitrator',
84
- shared: '🛠️ Shared'
19
+ shared: '🛠️ Shared',
85
20
  };
86
- function getPackageRoot() {
87
- return path.resolve(__dirname, '..');
88
- }
89
- function copyDir(src, dest) {
90
- if (!fs.existsSync(src))
91
- return false;
92
- fs.mkdirSync(dest, { recursive: true });
93
- const entries = fs.readdirSync(src, { withFileTypes: true });
94
- for (const entry of entries) {
95
- const srcPath = path.join(src, entry.name);
96
- const destPath = path.join(dest, entry.name);
97
- if (entry.isDirectory()) {
98
- copyDir(srcPath, destPath);
99
- }
100
- else {
101
- fs.copyFileSync(srcPath, destPath);
102
- }
103
- }
104
- return true;
105
- }
106
- function removeDir(dir) {
107
- if (!fs.existsSync(dir))
108
- return;
109
- const entries = fs.readdirSync(dir, { withFileTypes: true });
110
- for (const entry of entries) {
111
- const fullPath = path.join(dir, entry.name);
112
- if (entry.isDirectory()) {
113
- removeDir(fullPath);
114
- }
115
- else {
116
- fs.unlinkSync(fullPath);
117
- }
118
- }
119
- fs.rmdirSync(dir);
120
- }
121
- function parseFrontmatter(content) {
122
- const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
123
- if (!match)
124
- return null;
125
- const frontmatterStr = match[1];
126
- const body = match[2];
127
- const frontmatter = {};
128
- let currentKey = null;
129
- let currentValue = '';
130
- for (const line of frontmatterStr.split('\n')) {
131
- const kvMatch = line.match(/^(\w[\w-]*)\s*:\s*(.*)$/);
132
- if (kvMatch) {
133
- if (currentKey) {
134
- frontmatter[currentKey] = currentValue.trim();
135
- }
136
- currentKey = kvMatch[1];
137
- currentValue = kvMatch[2];
138
- }
139
- else if (currentKey) {
140
- currentValue += '\n' + line;
141
- }
142
- }
143
- if (currentKey) {
144
- frontmatter[currentKey] = currentValue.trim();
145
- }
146
- return { frontmatter, body };
147
- }
148
- function convertToCursor(content, skillDir) {
149
- const parsed = parseFrontmatter(content);
150
- if (!parsed)
151
- return content;
152
- const { frontmatter, body } = parsed;
153
- let description = frontmatter.description || frontmatter.name || skillDir;
154
- if (typeof description === 'string') {
155
- description = description.replace(/\n/g, ' ');
156
- }
157
- const isAlways = frontmatter.loading === 'always' || frontmatter.always === true || frontmatter.always === 'true';
158
- const alwaysApply = isAlways ? 'true' : 'false';
159
- const newFrontmatter = [
160
- '---',
161
- `description: "${description}"`,
162
- `alwaysApply: ${alwaysApply}`,
163
- '---',
164
- ].join('\n');
165
- return newFrontmatter + '\n' + body;
166
- }
167
- function convertToCopilot(content) {
168
- const parsed = parseFrontmatter(content);
169
- if (!parsed)
170
- return content;
171
- return parsed.body;
172
- }
173
- function convertSkillContent(content, target, skillDir) {
174
- if (target === 'cursor')
175
- return convertToCursor(content, skillDir);
176
- if (target === 'copilot')
177
- return convertToCopilot(content);
178
- return content;
179
- }
180
21
  // =========================================================================
181
- // MCP Server Management — shared by postinstall and `wowok-skills init`
22
+ // Informational commands
182
23
  // =========================================================================
183
- const MCP_PACKAGE = '@wowok/agent-mcp';
184
- /**
185
- * Resolve CodeBuddy MCP config file according to its official priority rules.
186
- * Reference: https://www.codebuddy.ai/docs/cli/mcp#configuration-file-locations
187
- *
188
- * USER scope priority (highest → lowest):
189
- * 1. ~/.codebuddy/.mcp.json (recommended)
190
- * 2. ~/.codebuddy/mcp.json (deprecated)
191
- * 3. ~/.codebuddy.json (legacy)
192
- *
193
- * Read rule : pick the FIRST existing candidate.
194
- * Write rule: if any file exists, merge into that first existing file;
195
- * if none exist, create the highest-priority one (.mcp.json).
196
- */
197
- function resolveCodeBuddyMcpFile() {
198
- const home = os.homedir();
199
- const candidates = [
200
- path.join(home, '.codebuddy', '.mcp.json'), // 1. recommended
201
- path.join(home, '.codebuddy', 'mcp.json'), // 2. deprecated
202
- path.join(home, '.codebuddy.json'), // 3. legacy
203
- ];
204
- const existing = candidates.find((p) => fs.existsSync(p));
205
- return existing || candidates[0];
206
- }
207
- /**
208
- * Resolve VS Code globalStorage MCP settings files for a given extension ID.
209
- * See install.js resolveVscodeGlobalStorageFiles for full path references.
210
- */
211
- function resolveVscodeGlobalStorageFiles(extensionId, fileName) {
212
- const home = os.homedir();
213
- const vsBaseDirs = (() => {
214
- switch (process.platform) {
215
- case 'darwin':
216
- return [path.join(home, 'Library', 'Application Support')];
217
- case 'win32':
218
- return [process.env.APPDATA || path.join(home, 'AppData', 'Roaming')];
219
- default:
220
- return [process.env.XDG_CONFIG_HOME || path.join(home, '.config')];
221
- }
222
- })();
223
- const results = [];
224
- const vsVariants = ['Code', 'Code - Insiders', 'VSCodium', 'Cursor'];
225
- for (const base of vsBaseDirs) {
226
- for (const variant of vsVariants) {
227
- const vsUserDir = path.join(base, variant, 'User');
228
- if (fs.existsSync(vsUserDir)) {
229
- results.push(path.join(vsUserDir, 'globalStorage', extensionId, 'settings', fileName));
230
- }
24
+ function cmdList() {
25
+ console.log('Available WoWok Skills (by role):\n');
26
+ for (const group of (0, skills_1.getRoleSkills)()) {
27
+ console.log(ROLE_DISPLAY[group.role]);
28
+ console.log(` ${group.description}`);
29
+ for (const skill of group.skills) {
30
+ const loading = skill.loading === 'always' ? '[always]' : '[on-demand]';
31
+ console.log(` • ${skill.name} ${loading}`);
32
+ console.log(` ${skill.description}`);
231
33
  }
34
+ console.log('');
232
35
  }
233
- return results;
234
- }
235
- /**
236
- * Resolve ALL Roo Code MCP config files that should receive the wowok entry.
237
- * Covers both Standalone CLI config and VS Code extension globalStorage
238
- * entries for every detected VS Code variant (Code, Insiders, VSCodium, Cursor).
239
- *
240
- * See detailed references in install.js resolveRooMcpFiles comments.
241
- */
242
- function resolveRooMcpFiles() {
243
- const results = [];
244
- // (A) Standalone CLI config
245
- results.push(path.join(os.homedir(), '.roo', 'mcp_settings.json'));
246
- // (B) VS Code extension globalStorage entries
247
- results.push(...resolveVscodeGlobalStorageFiles('rooveterinaryinc.roo-cline', 'cline_mcp_settings.json'));
248
- return results;
249
- }
250
- /**
251
- * Resolve ALL Cline (VS Code) MCP config files.
252
- * Cline stores MCP settings in VS Code globalStorage under its extension ID
253
- * (saoudrizwan.claude-dev), filename cline_mcp_settings.json.
254
- * Reference: https://www.skillmd.ai/skills/mcp-installer-1/
255
- */
256
- function resolveClineMcpFiles() {
257
- return resolveVscodeGlobalStorageFiles('saoudrizwan.claude-dev', 'cline_mcp_settings.json');
258
36
  }
259
- /**
260
- * Resolve ALL Kilo Code MCP config files.
261
- * Kilo Code reads MCP settings from two separate places (documented by Kilo):
262
- * (A) VS Code extension → globalStorage/kilocode.kilo-code/settings/mcp_settings.json
263
- * (B) CLI → ~/.kilocode/cli/global/settings/mcp_settings.json
264
- * References:
265
- * - https://kilo.ai/docs/features/mcp/using-mcp-in-cli
266
- * - https://github.com/Kilo-Org/kilocode/blob/main/docs/file-locations.md
267
- */
268
- function resolveKiloMcpFiles() {
269
- const results = [];
270
- results.push(...resolveVscodeGlobalStorageFiles('kilocode.kilo-code', 'mcp_settings.json'));
271
- results.push(path.join(os.homedir(), '.kilocode', 'cli', 'global', 'settings', 'mcp_settings.json'));
272
- return results;
37
+ function cmdGet(name) {
38
+ const skill = (0, skills_1.getSkillByName)(name);
39
+ if (!skill) {
40
+ console.error(`Skill not found: ${name}`);
41
+ process.exit(1);
42
+ }
43
+ console.log(`Name: ${skill.name}`);
44
+ console.log(`Role: ${ROLE_DISPLAY[skill.role]}`);
45
+ console.log(`Loading: ${skill.loading}`);
46
+ console.log(`Version: ${skill.version}`);
47
+ console.log(`Description: ${skill.description}`);
48
+ if (skill.related?.length)
49
+ console.log(`Related: ${skill.related.join(', ')}`);
273
50
  }
274
- const MCP_TARGET_CONFIGS = {
275
- claude: {
276
- configPath: path.join(os.homedir(), '.claude', 'settings.json'),
277
- merge: (config) => {
278
- config.mcpServers = config.mcpServers || {};
279
- config.mcpServers.wowok = { command: 'npx', args: ['-y', '@wowok/agent-mcp'] };
280
- return config;
281
- },
282
- },
283
- codebuddy: {
284
- resolveConfigPaths: () => [resolveCodeBuddyMcpFile()],
285
- merge: (config) => {
286
- config.mcpServers = config.mcpServers || {};
287
- config.mcpServers.wowok = { command: 'npx', args: ['-y', '@wowok/agent-mcp'] };
288
- return config;
289
- },
290
- },
291
- windsurf: {
292
- configPath: path.join(os.homedir(), '.codeium', 'windsurf', 'mcp_config.json'),
293
- merge: (config) => {
294
- config.mcpServers = config.mcpServers || {};
295
- config.mcpServers.wowok = { command: 'npx', args: ['-y', '@wowok/agent-mcp'] };
296
- return config;
297
- },
298
- },
299
- qoder: {
300
- configPath: (() => {
301
- if (process.platform === 'win32') {
302
- return path.join(process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming'), 'Qoder', 'mcp-settings.json');
303
- }
304
- if (process.platform === 'darwin') {
305
- return path.join(os.homedir(), 'Library', 'Application Support', 'Qoder', 'mcp-settings.json');
306
- }
307
- return path.join(process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'), 'qoder', 'mcp-settings.json');
308
- })(),
309
- merge: (config) => {
310
- config.mcpServers = config.mcpServers || {};
311
- config.mcpServers.wowok = { command: 'npx', args: ['-y', '@wowok/agent-mcp'] };
312
- return config;
313
- },
314
- },
315
- roo: {
316
- resolveConfigPaths: () => resolveRooMcpFiles(),
317
- merge: (config) => {
318
- config.mcpServers = config.mcpServers || {};
319
- config.mcpServers.wowok = { command: 'npx', args: ['-y', '@wowok/agent-mcp'] };
320
- return config;
321
- },
322
- },
323
- cline: {
324
- resolveConfigPaths: () => resolveClineMcpFiles(),
325
- merge: (config) => {
326
- config.mcpServers = config.mcpServers || {};
327
- config.mcpServers.wowok = { command: 'npx', args: ['-y', '@wowok/agent-mcp'] };
328
- return config;
329
- },
330
- },
331
- kilo: {
332
- resolveConfigPaths: () => resolveKiloMcpFiles(),
333
- merge: (config) => {
334
- config.mcpServers = config.mcpServers || {};
335
- config.mcpServers.wowok = { command: 'npx', args: ['-y', '@wowok/agent-mcp'] };
336
- return config;
337
- },
338
- },
339
- // trae / agents: IDE-managed MCP via ~/.trae-cn/mcps/ directory structure
340
- trae: null,
341
- agents: null,
342
- // cursor: project-level only
343
- cursor: null,
344
- // copilot: user-level MCP config (Copilot CLI)
345
- copilot: {
346
- configPath: path.join(os.homedir(), '.copilot', 'mcp-config.json'),
347
- merge: (config) => {
348
- config.mcpServers = config.mcpServers || {};
349
- config.mcpServers.wowok = { type: 'local', command: 'npx', args: ['-y', '@wowok/agent-mcp'] };
350
- return config;
351
- },
352
- },
353
- // codex: global TOML config (~/.codex/config.toml)
354
- codex: {
355
- configPath: path.join(os.homedir(), '.codex', 'config.toml'),
356
- format: 'toml',
357
- },
358
- };
359
- /** Project-level MCP configs (written relative to cwd). */
360
- const MCP_PROJECT_CONFIGS = {
361
- cursor: {
362
- configPath: '.cursor/mcp.json',
363
- merge: (config) => {
364
- config.mcpServers = config.mcpServers || {};
365
- config.mcpServers.wowok = { command: 'npx', args: ['-y', '@wowok/agent-mcp'] };
366
- return config;
367
- },
368
- },
369
- windsurf: {
370
- configPath: '.windsurf/mcp.json',
371
- merge: (config) => {
372
- config.mcpServers = config.mcpServers || {};
373
- config.mcpServers.wowok = { command: 'npx', args: ['-y', '@wowok/agent-mcp'] };
374
- return config;
375
- },
376
- },
377
- trae: {
378
- configPath: '.trae/mcp.json',
379
- merge: (config) => {
380
- config.mcpServers = config.mcpServers || {};
381
- config.mcpServers.wowok = { command: 'npx', args: ['-y', '@wowok/agent-mcp'] };
382
- return config;
383
- },
384
- },
385
- agents: {
386
- configPath: '.trae/mcp.json',
387
- merge: (config) => {
388
- config.mcpServers = config.mcpServers || {};
389
- config.mcpServers.wowok = { command: 'npx', args: ['-y', '@wowok/agent-mcp'] };
390
- return config;
391
- },
392
- },
393
- qoder: {
394
- configPath: '.qoder/mcp.json',
395
- merge: (config) => {
396
- config.mcpServers = config.mcpServers || {};
397
- config.mcpServers.wowok = { command: 'npx', args: ['-y', '@wowok/agent-mcp'] };
398
- return config;
399
- },
400
- },
401
- roo: {
402
- configPath: '.roo/mcp.json',
403
- merge: (config) => {
404
- config.mcpServers = config.mcpServers || {};
405
- config.mcpServers.wowok = { command: 'npx', args: ['-y', '@wowok/agent-mcp'] };
406
- return config;
407
- },
408
- },
409
- kilo: {
410
- configPath: '.kilocode/mcp.json',
411
- merge: (config) => {
412
- config.mcpServers = config.mcpServers || {};
413
- config.mcpServers.wowok = { command: 'npx', args: ['-y', '@wowok/agent-mcp'] };
414
- return config;
415
- },
416
- },
417
- };
418
- function getInstalledMcpVersion() {
419
- try {
420
- const output = (0, child_process_1.execSync)(`npm ls -g ${MCP_PACKAGE} --depth=0 --json`, {
421
- encoding: 'utf-8',
422
- stdio: 'pipe',
423
- timeout: 15000,
424
- });
425
- const parsed = JSON.parse(output);
426
- const pkg = parsed.dependencies?.[MCP_PACKAGE] || parsed[MCP_PACKAGE];
427
- return pkg?.version || null;
51
+ function cmdRole(role) {
52
+ const roles = ['customer', 'provider', 'supplier', 'collaborator', 'arbitrator', 'shared'];
53
+ if (!roles.includes(role)) {
54
+ console.error(`Invalid role: ${role}`);
55
+ console.error(`Valid roles: ${roles.join(' | ')}`);
56
+ process.exit(1);
428
57
  }
429
- catch {
430
- return null;
58
+ console.log(`${ROLE_DISPLAY[role]} Skills:\n`);
59
+ for (const skill of (0, skills_1.getSkillsByRole)(role)) {
60
+ const loading = skill.loading === 'always' ? '[always]' : '[on-demand]';
61
+ console.log(` • ${skill.name} ${loading}`);
62
+ console.log(` ${skill.description}`);
431
63
  }
432
64
  }
433
- function getLatestMcpVersion() {
434
- try {
435
- // --prefer-online forces npm to bypass local cache so we don't get
436
- // stale version numbers. See project memory (components.mjs fix).
437
- const output = (0, child_process_1.execSync)(`npm view --prefer-online ${MCP_PACKAGE} version`, {
438
- encoding: 'utf-8',
439
- stdio: 'pipe',
440
- timeout: 15000,
441
- });
442
- return output.trim();
65
+ function cmdRecommend(intent) {
66
+ var _a;
67
+ const recommended = (0, skills_1.recommendSkills)(intent);
68
+ console.log(`Recommended skills for: "${intent}"\n`);
69
+ if (recommended.length === 0) {
70
+ console.log(' (no skill matches — this knowledge is served by the MCP server directly)');
71
+ return;
443
72
  }
444
- catch {
445
- return null;
73
+ const byRole = {};
74
+ for (const skill of recommended)
75
+ (byRole[_a = skill.role] || (byRole[_a] = [])).push(skill.name);
76
+ for (const [role, names] of Object.entries(byRole)) {
77
+ console.log(`${ROLE_DISPLAY[role]}:`);
78
+ for (const name of names)
79
+ console.log(` • ${name}`);
80
+ console.log('');
446
81
  }
447
82
  }
448
- function semverMajor(version) {
449
- if (!version)
450
- return 0;
451
- const parts = version.split('.');
452
- return parseInt(parts[0], 10) || 0;
453
- }
454
- function npmInstallGlobal(pkg, retries = 2) {
455
- for (let attempt = 1; attempt <= retries; attempt++) {
456
- try {
457
- (0, child_process_1.execSync)(`npm install -g ${pkg}`, { stdio: 'inherit', timeout: 120000 });
458
- return true;
459
- }
460
- catch (err) {
461
- if (attempt < retries) {
462
- console.log(`[wowok-skills] npm install attempt ${attempt} failed, retrying...`);
463
- const waitCmd = process.platform === 'win32'
464
- ? 'ping -n 3 127.0.0.1 >nul'
465
- : 'sleep 2';
466
- (0, child_process_1.execSync)(waitCmd, { stdio: 'pipe', timeout: 5000 });
467
- }
468
- else {
469
- console.error(`[wowok-skills] npm install failed after ${retries} attempts: ${err.message}`);
470
- return false;
471
- }
83
+ function parseInitArgs(args) {
84
+ const parsed = { noMcp: false, force: false, user: false, project: false };
85
+ for (let i = 0; i < args.length; i++) {
86
+ const arg = args[i];
87
+ if (arg === '--target' || arg === '-t') {
88
+ const value = args[++i];
89
+ if (value)
90
+ parsed.targets = value.split(',').map((t) => t.trim()).filter(Boolean);
472
91
  }
473
- }
474
- return false;
475
- }
476
- function ensureMcpServer() {
477
- const currentVersion = getInstalledMcpVersion();
478
- const latestVersion = getLatestMcpVersion();
479
- if (currentVersion) {
480
- console.log(`[wowok-skills] MCP server ${MCP_PACKAGE} v${currentVersion} found.`);
481
- if (!latestVersion) {
482
- console.log(`[wowok-skills] Cannot check latest version (offline or registry unreachable). Keeping v${currentVersion}.`);
483
- return false;
92
+ else if (arg === '--no-mcp') {
93
+ parsed.noMcp = true;
484
94
  }
485
- if (currentVersion === latestVersion) {
486
- console.log(`[wowok-skills] MCP server is up to date (v${currentVersion}).`);
487
- return false;
95
+ else if (arg === '--force') {
96
+ parsed.force = true;
488
97
  }
489
- const currentMajor = semverMajor(currentVersion);
490
- const latestMajor = semverMajor(latestVersion);
491
- if (latestMajor > currentMajor) {
492
- console.warn(`[wowok-skills] ⚠ WARNING: Major version bump detected v${currentVersion} → v${latestVersion}.`);
493
- console.warn(`[wowok-skills] Skipping auto-upgrade to avoid breaking changes.`);
494
- console.warn(`[wowok-skills] To upgrade manually: npm install -g ${MCP_PACKAGE}@latest`);
495
- return false;
98
+ else if (arg === '--user') {
99
+ parsed.user = true;
496
100
  }
497
- console.log(`[wowok-skills] Upgrading MCP server v${currentVersion} → v${latestVersion}...`);
498
- if (npmInstallGlobal(`${MCP_PACKAGE}@latest`)) {
499
- console.log(`[wowok-skills] MCP server upgraded to v${latestVersion}.`);
500
- return true;
101
+ else if (arg === '--project') {
102
+ parsed.project = true;
501
103
  }
502
- console.error(`[wowok-skills] MCP server upgrade FAILED. Keeping v${currentVersion}.`);
503
- return false;
504
- }
505
- console.log(`[wowok-skills] Installing MCP server ${MCP_PACKAGE}...`);
506
- if (npmInstallGlobal(MCP_PACKAGE)) {
507
- console.log(`[wowok-skills] MCP server installed.`);
508
- return true;
509
- }
510
- console.error(`[wowok-skills] MCP server installation FAILED.`);
511
- return false;
512
- }
513
- function writeMcpConfig(target, configMap, cwd) {
514
- const cfg = configMap[target];
515
- if (!cfg) {
516
- console.log(`[wowok-skills] MCP config: ${target} does not support external MCP registration (skipped).`);
517
- return false;
518
- }
519
- // Expand to an array of concrete paths. Project-level configs always use
520
- // `configPath` (single file); global configs for CodeBuddy / Roo / Cline /
521
- // Kilo use `resolveConfigPaths()` to yield one or more paths.
522
- const rawPaths = cfg.resolveConfigPaths
523
- ? cfg.resolveConfigPaths(cwd)
524
- : [cfg.configPath];
525
- const configPaths = cwd && !cfg.resolveConfigPaths
526
- ? rawPaths.map((p) => path.join(cwd, p))
527
- : rawPaths;
528
- if (configPaths.length === 0) {
529
- console.log(`[wowok-skills] MCP config: no config file detected for ${target} (client not installed) — skipped.`);
530
- return false;
531
- }
532
- let anyWritten = false;
533
- for (const configPath of configPaths) {
534
- try {
535
- // ── TOML format (Codex CLI uses ~/.codex/config.toml) ──────────────
536
- if (cfg.format === 'toml') {
537
- const tomlEntry = '\n[mcp_servers.wowok]\ncommand = "npx"\nargs = ["-y", "@wowok/agent-mcp"]\n';
538
- let content = '';
539
- if (fs.existsSync(configPath)) {
540
- content = fs.readFileSync(configPath, 'utf-8');
541
- }
542
- // Line-level regex: avoid matches inside comments or string literals.
543
- if (/^\s*\[mcp_servers\.wowok\]\s*$/m.test(content)) {
544
- console.log(`[wowok-skills] MCP config already up to date: ${configPath}`);
545
- continue;
546
- }
547
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
548
- fs.writeFileSync(configPath, content + tomlEntry, 'utf-8');
549
- console.log(`[wowok-skills] MCP config written: ${configPath}`);
550
- anyWritten = true;
551
- continue;
552
- }
553
- // ── JSON format (all other clients) ────────────────────────────────
554
- let config = {};
555
- if (fs.existsSync(configPath)) {
556
- config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
557
- }
558
- const before = JSON.stringify(config);
559
- config = cfg.merge(config);
560
- const after = JSON.stringify(config);
561
- if (before !== after) {
562
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
563
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
564
- console.log(`[wowok-skills] MCP config written: ${configPath}`);
565
- anyWritten = true;
566
- }
567
- else {
568
- console.log(`[wowok-skills] MCP config already up to date: ${configPath}`);
569
- }
104
+ else if (arg === '--referrer') {
105
+ parsed.referrer = args[++i]?.trim() || undefined;
570
106
  }
571
- catch (err) {
572
- console.error(`[wowok-skills] ERROR writing MCP config for ${target} at ${configPath}: ${err.message}`);
107
+ else if (!arg.startsWith('-') && targets_1.DEFAULT_TARGET_IDS.includes(arg)) {
108
+ parsed.targets = [arg];
573
109
  }
574
110
  }
575
- return anyWritten;
111
+ return parsed;
576
112
  }
577
- function restartMcpServer() {
578
- try {
579
- if (process.platform === 'win32') {
580
- const psScript = 'Get-CimInstance Win32_Process -Filter "Name=\'node.exe\' AND CommandLine LIKE \'%wowok%agent-mcp%\'" | ' +
581
- 'ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }';
582
- const encoded = Buffer.from(psScript, 'utf16le').toString('base64');
583
- (0, child_process_1.execSync)(`powershell -NoProfile -EncodedCommand ${encoded}`, { stdio: 'pipe', timeout: 10000 });
584
- }
585
- else {
586
- (0, child_process_1.execSync)('pkill -f "wowok.*agent-mcp" 2>/dev/null || true', { stdio: 'pipe', timeout: 5000 });
587
- }
588
- console.log('[wowok-skills] MCP server process terminated (IDE will auto-restart).');
589
- }
590
- catch {
591
- console.log('[wowok-skills] No running MCP server process found. Start your IDE to launch it.');
113
+ function printTargets() {
114
+ console.log('Targets (--target <t> — repeatable, comma-separated; omit for all):');
115
+ for (const target of targets_1.CLIENT_TARGETS) {
116
+ const roots = target.projectSkillDirs.join(', ');
117
+ console.log(` ${target.id.padEnd(10)} project: ${roots.padEnd(20)} ${target.label}`);
592
118
  }
119
+ console.log(` ${'all'.padEnd(10)} every target above (default)`);
593
120
  }
594
- function getTargets(targetArg) {
595
- if (!targetArg || targetArg === 'all') {
596
- return [...types_1.ALL_CLIENT_TARGETS];
597
- }
598
- if (types_1.ALL_CLIENT_TARGETS.includes(targetArg)) {
599
- return [targetArg];
121
+ function cmdInit(parsed) {
122
+ const { targets, unknown } = (0, installer_1.resolveTargets)(parsed.targets);
123
+ if (unknown.length > 0) {
124
+ console.error(`Unknown target(s): ${unknown.join(', ')}`);
125
+ console.error('');
126
+ printTargets();
127
+ process.exit(1);
600
128
  }
601
- console.error(`Invalid target: "${targetArg}"`);
602
- console.error('');
603
- console.error('Supported targets:');
604
- console.error(' claude .claude/skills/ (Claude Code)');
605
- console.error(' cursor .cursor/rules/ (Cursor IDE)');
606
- console.error(' windsurf .windsurf/skills/ (Windsurf / Codeium)');
607
- console.error(' codebuddy .codebuddy/skills/ (CodeBuddy)');
608
- console.error(' codex .codex/skills/ (OpenAI Codex / ChatGPT Desktop Codex Mode)');
609
- console.error(' trae .agents/skills/ (Trae CN & Trae Work)');
610
- console.error(' qoder .qoder/skills/ (Qoder / Qoder CN)');
611
- console.error(' roo .roo/skills/ (Roo Code)');
612
- console.error(' cline .cline/skills/ (Cline - VS Code)');
613
- console.error(' kilo .kilo/skills/ (Kilo Code)');
614
- console.error(' copilot .github/prompts/ (GitHub Copilot)');
615
- console.error(' all All of the above (default)');
616
- process.exit(1);
617
- }
618
- function cmdInit(targetArg, withMcp, referrer) {
129
+ const scopes = parsed.user || parsed.project
130
+ ? [...(parsed.user ? ['user'] : []), ...(parsed.project ? ['project'] : [])]
131
+ : ['user', 'project'];
132
+ // Project scope always targets the current working directory.
619
133
  const cwd = process.cwd();
620
- const pkgRoot = getPackageRoot();
621
- const targets = getTargets(targetArg);
622
- let totalCount = 0;
623
- for (const target of targets) {
624
- const skillsDir = types_1.CLIENT_SKILL_DIRS[target];
625
- const targetDir = path.join(cwd, skillsDir);
626
- const ext = types_1.CLIENT_FILE_EXT[target];
627
- let count = 0;
628
- fs.mkdirSync(targetDir, { recursive: true });
629
- for (const dir of SKILL_DIRS) {
630
- const src = path.join(pkgRoot, dir, 'SKILL.md');
631
- if (!fs.existsSync(src)) {
632
- console.warn(`[wowok-skills] WARN: SKILL.md not found for ${dir}`);
633
- continue;
634
- }
635
- const content = fs.readFileSync(src, 'utf-8');
636
- const converted = convertSkillContent(content, target, dir);
637
- const basename = target === 'cursor' || target === 'copilot'
638
- ? `wowok-${dir.replace('wowok-', '')}${ext}`
639
- : 'SKILL.md';
640
- const destDir = path.join(targetDir, dir);
641
- const dest = path.join(destDir, basename);
642
- fs.mkdirSync(destDir, { recursive: true });
643
- fs.writeFileSync(dest, converted, 'utf-8');
644
- count++;
645
- console.log(`[wowok-skills] installed: ${dest}`);
646
- }
647
- totalCount += count;
648
- console.log(`[wowok-skills] Done — ${count} skills installed to ${targetDir}`);
649
- // GLM5-31 §3.2: detect stale pre-refactor skills and print migration hint.
650
- const legacyFound = LEGACY_SKILL_DIRS.filter((dir) => fs.existsSync(path.join(targetDir, dir)));
651
- if (legacyFound.length > 0) {
652
- const migration = (0, skills_1.checkSkillMigration)(legacyFound);
653
- console.warn(`\n[wowok-skills] ⚠ ${migration.message}`);
654
- console.warn('[wowok-skills] Remove them with: wowok-skills uninit\n');
655
- }
656
- }
657
- if (targets.length > 1) {
658
- console.log(`[wowok-skills] Total: ${totalCount} skills across ${targets.length} clients.`);
659
- }
660
- // ─── MCP setup (default: enabled, use --no-mcp to skip) ────────────
661
- if (withMcp) {
134
+ console.log(`[wowok-skills] Installing skills (${scopes.join(' + ')}) for ${targets.length} target(s)...`);
135
+ const results = (0, installer_1.installSkillsForTargets)(targets, scopes, cwd, { force: parsed.force });
136
+ for (const r of results) {
137
+ console.log(` → ${r.root}\n ${r.written} written · ${r.unchanged} up to date · ${r.pruned} pruned · ${r.legacyRemoved} deprecated removed`);
138
+ for (const err of r.errors)
139
+ console.error(` ERROR: ${err}`);
140
+ }
141
+ if (!parsed.noMcp) {
662
142
  console.log('');
663
- console.log('[wowok-skills] Setting up MCP server (use --no-mcp to skip)...');
664
- const mcpChanged = ensureMcpServer();
665
- console.log('[wowok-skills] Registering MCP server in client config...');
666
- for (const target of targets) {
667
- // Global-level config (Claude, CodeBuddy, Windsurf, Qoder, Roo)
668
- writeMcpConfig(target, MCP_TARGET_CONFIGS);
669
- // Project-level config (Cursor, Windsurf, Trae, Qoder, Roo)
670
- writeMcpConfig(target, MCP_PROJECT_CONFIGS, cwd);
671
- }
672
- if (mcpChanged) {
673
- console.log('[wowok-skills] Restarting MCP server...');
674
- restartMcpServer();
675
- }
676
- console.log('[wowok-skills] MCP server setup complete.');
143
+ console.log('[wowok-skills] Checking MCP server...');
144
+ const changed = (0, installer_1.ensureMcpServer)();
145
+ const launch = (0, installer_1.resolveMcpLaunch)();
146
+ console.log(`[wowok-skills] launcher: ${launch.command} ${launch.args.join(' ')}`);
147
+ const mcpScopes = parsed.project
148
+ ? ['project']
149
+ : parsed.user
150
+ ? ['user']
151
+ : ['user', 'project'];
152
+ console.log('[wowok-skills] Registering MCP server...');
153
+ for (const r of (0, installer_1.registerMcpForTargets)(targets, mcpScopes, cwd)) {
154
+ console.log(` ${r.status.padEnd(9)} ${r.path}${r.detail ? ` (${r.detail})` : ''}`);
155
+ }
156
+ if (changed)
157
+ (0, installer_1.restartMcpServer)();
677
158
  }
678
159
  else {
679
- console.log('');
680
- console.log('[wowok-skills] --no-mcp: MCP server setup skipped (skills only).');
681
- }
682
- // ─── Airdrop referrer (--referrer <addr|name>) ─────────────────────
683
- // Persist it in the MCP data dir; the MCP auto-injects it into every call,
684
- // so it is recorded on-chain at the user's first real on-chain interaction.
685
- // No manual "tell your AI" step needed.
686
- if (referrer) {
687
- saveReferrer(referrer);
160
+ console.log('[wowok-skills] --no-mcp: MCP setup skipped.');
688
161
  }
689
- }
690
- function cmdUninit(targetArg) {
691
- const cwd = process.cwd();
692
- const targets = getTargets(targetArg);
693
- let totalCount = 0;
694
- for (const target of targets) {
695
- const skillsDir = types_1.CLIENT_SKILL_DIRS[target];
696
- const targetDir = path.join(cwd, skillsDir);
697
- let count = 0;
698
- // Remove both retained and legacy (deprecated) skills — legacy dirs may
699
- // still exist from pre-refactor installs and must be cleaned up.
700
- for (const dir of [...SKILL_DIRS, ...LEGACY_SKILL_DIRS]) {
701
- const dirPath = path.join(targetDir, dir);
702
- if (fs.existsSync(dirPath)) {
703
- removeDir(dirPath);
704
- count++;
705
- console.log(`[wowok-skills] removed: ${dirPath}`);
706
- }
707
- }
708
- totalCount += count;
709
- if (count === 0) {
710
- console.log(`[wowok-skills] No skills found in ${targetDir}. Nothing to remove.`);
711
- }
712
- else {
713
- console.log(`[wowok-skills] Done — ${count} skills removed from ${targetDir}`);
714
- }
715
- }
716
- if (targets.length > 1 && totalCount > 0) {
717
- console.log(`[wowok-skills] Total: ${totalCount} skills across ${targets.length} clients.`);
718
- }
719
- }
720
- function cmdList() {
721
- console.log('Available WoWok Skills (organized by role):\n');
722
- const roleSkills = (0, skills_1.getRoleSkills)();
723
- for (const roleGroup of roleSkills) {
724
- console.log(`${ROLE_DISPLAY[roleGroup.role]}`);
725
- console.log(` ${roleGroup.description}`);
726
- for (const skill of roleGroup.skills) {
727
- const loading = skill.loading === 'always' ? '[always]' : '[on-demand]';
728
- console.log(` • ${skill.name} ${loading}`);
729
- console.log(` ${skill.description}`);
730
- }
162
+ if (parsed.referrer) {
731
163
  console.log('');
164
+ (0, installer_1.saveReferrer)(parsed.referrer);
732
165
  }
166
+ console.log('');
167
+ console.log('[wowok-skills] Done. Verify with: wowok-skills doctor');
733
168
  }
734
- function cmdGet(name) {
735
- const skill = (0, skills_1.getSkillByName)(name);
736
- if (skill) {
737
- console.log(`Name: ${skill.name}`);
738
- console.log(`Role: ${ROLE_DISPLAY[skill.role]}`);
739
- console.log(`Loading: ${skill.loading}`);
740
- console.log(`Version: ${skill.version}`);
741
- console.log(`Description: ${skill.description}`);
742
- if (skill.related && skill.related.length > 0) {
743
- console.log(`Related: ${skill.related.join(', ')}`);
744
- }
745
- }
746
- else {
747
- console.error(`Skill not found: ${name}`);
169
+ function cmdUninit(parsed) {
170
+ const { targets, unknown } = (0, installer_1.resolveTargets)(parsed.targets);
171
+ if (unknown.length > 0) {
172
+ console.error(`Unknown target(s): ${unknown.join(', ')}`);
748
173
  process.exit(1);
749
174
  }
175
+ const scopes = parsed.user || parsed.project
176
+ ? [...(parsed.user ? ['user'] : []), ...(parsed.project ? ['project'] : [])]
177
+ : ['user', 'project'];
178
+ const removed = (0, installer_1.uninstallSkillsForTargets)(targets, scopes, process.cwd());
179
+ console.log(`[wowok-skills] Removed ${removed} skill director${removed === 1 ? 'y' : 'ies'}.`);
180
+ console.log('[wowok-skills] MCP config entries are left in place — delete the "wowok" entry manually if unwanted.');
750
181
  }
751
- function cmdRecommend(intent) {
752
- const recommended = (0, skills_1.recommendSkills)(intent);
753
- console.log(`Recommended skills for: "${intent}"\n`);
754
- // Group by role
755
- const byRole = {};
756
- for (const skill of recommended) {
757
- if (!byRole[skill.role])
758
- byRole[skill.role] = [];
759
- byRole[skill.role].push(skill);
760
- }
761
- for (const [role, skills] of Object.entries(byRole)) {
762
- console.log(`${ROLE_DISPLAY[role]}:`);
763
- for (const skill of skills) {
764
- console.log(` • ${skill.name}`);
182
+ function cmdDoctor() {
183
+ const cwd = process.cwd();
184
+ const { targets } = (0, installer_1.resolveTargets)(undefined);
185
+ console.log(`WoWok Skills doctor · CLI v${(0, installer_1.packageVersion)()}`);
186
+ console.log(`Dirs: home=${(0, targets_1.expandHome)('~')} cwd=${cwd}\n`);
187
+ const launch = (0, installer_1.resolveMcpLaunch)();
188
+ console.log(`MCP launcher: ${launch.command} ${launch.args.join(' ')}`);
189
+ console.log(launch.command === 'node'
190
+ ? ' ✔ version-pinned to the verified global install, Windows-safe\n'
191
+ : ' ⚠ falling back to npx (global install not found) — run: npm install -g @wowok/agent-mcp\n');
192
+ const statuses = (0, installer_1.statusForTargets)(targets, cwd);
193
+ for (const status of statuses) {
194
+ console.log(`${status.label} [${status.id}]`);
195
+ const sections = [
196
+ ['user ', status.userRoots],
197
+ ['project', status.projectRoots],
198
+ ];
199
+ for (const [label, roots] of sections) {
200
+ for (const root of roots) {
201
+ if (!root.present) {
202
+ // Project roots only matter inside a project — report quietly.
203
+ console.log(` ${label} ✗ not installed ${root.root}`);
204
+ continue;
205
+ }
206
+ const total = root.fresh + root.stale + root.missing;
207
+ const marker = total === 13 && root.stale === 0 && root.missing === 0 ? '✔' : '⚠';
208
+ console.log(` ${label} ${marker} ${root.fresh} current / ${root.stale} stale / ${root.missing} missing` +
209
+ `${root.legacy > 0 ? ` / ${root.legacy} deprecated` : ''}` +
210
+ ` ${root.root}${root.manifestVersion ? ` (installed by v${root.manifestVersion})` : ''}`);
211
+ }
765
212
  }
213
+ for (const mcp of status.mcp) {
214
+ if (!mcp.present) {
215
+ console.log(` mcp ○ no config file ${mcp.path}`);
216
+ continue;
217
+ }
218
+ console.log(` mcp ${mcp.registered ? '✔' : '✗'} ${mcp.path}${mcp.detail ? `\n ↳ ${mcp.detail}` : ''}`);
219
+ }
220
+ for (const note of status.notes)
221
+ console.log(` note ↳ ${note}`);
766
222
  console.log('');
767
223
  }
224
+ const problems = statuses.filter((s) => [...s.userRoots, ...s.projectRoots].some((r) => r.present && (r.stale > 0 || r.missing > 0 || r.legacy > 0)));
225
+ console.log('-----------------------------------------------------------');
226
+ console.log(`Manifest file written per root: ${targets_1.MANIFEST_FILE}`);
227
+ console.log(problems.length === 0
228
+ ? '✅ No stale installs detected.'
229
+ : `⚠ ${problems.length} root(s) need a refresh — run: wowok-skills init --force`);
230
+ console.log('Tip: `wowok-skills init` inside a project adds project-scoped copies (team sharing via git).');
768
231
  }
769
- function cmdRole(role) {
770
- if (!['customer', 'provider', 'supplier', 'collaborator', 'arbitrator', 'shared'].includes(role)) {
771
- console.error(`Invalid role: ${role}`);
772
- console.error('Valid roles: customer, provider, supplier, collaborator, arbitrator, shared');
773
- process.exit(1);
774
- }
775
- const skills = (0, skills_1.getSkillsByRole)(role);
776
- console.log(`${ROLE_DISPLAY[role]} Skills:\n`);
777
- for (const skill of skills) {
778
- const loading = skill.loading === 'always' ? '[always]' : '[on-demand]';
779
- console.log(` • ${skill.name} ${loading}`);
780
- console.log(` ${skill.description}`);
781
- }
782
- }
232
+ // =========================================================================
233
+ // Help
234
+ // =========================================================================
783
235
  function printUsage() {
784
236
  console.log('WoWok Skills CLI');
785
- console.log('Usage: wowok-skills <command> [args]');
786
- console.log('');
237
+ console.log('Usage: wowok-skills <command> [options]\n');
787
238
  console.log('Commands:');
788
- console.log(' list List all available skills (by role)');
789
- console.log(' get <name> Show skill details');
790
- console.log(' role <role> List skills for a role (customer|provider|supplier|collaborator|arbitrator|shared)');
791
- console.log(' recommend <intent> Recommend skills based on user intent');
792
- console.log(' init [--target <t>] [--no-mcp] [--referrer <addr|name>] Install skills to project (default: ALL clients with MCP)');
793
- console.log(' --no-mcp Skip MCP server setup (skills only)');
794
- console.log(' --referrer Save the airdrop referrer; auto-recorded on first on-chain interaction');
795
- console.log(' referrer <addr|name> Save the airdrop referrer GLOBALLY (no project needed)');
796
- console.log(' uninit [--target <t>] Remove skills from project (default: ALL clients)');
797
- console.log('');
798
- console.log('Targets (--target <t> — omit to install all clients):');
799
- console.log(' claude .claude/skills/ (Claude Code)');
800
- console.log(' cursor .cursor/rules/ (Cursor IDE)');
801
- console.log(' windsurf .windsurf/skills/ (Windsurf / Codeium)');
802
- console.log(' codebuddy .codebuddy/skills/ (CodeBuddy)');
803
- console.log(' codex .codex/skills/ (OpenAI Codex / ChatGPT Desktop Codex Mode)');
804
- console.log(' trae .agents/skills/ (Trae CN & Trae Work)');
805
- console.log(' qoder .qoder/skills/ (Qoder / Qoder CN)');
806
- console.log(' roo .roo/skills/ (Roo Code)');
807
- console.log(' cline .cline/skills/ (Cline - VS Code)');
808
- console.log(' kilo .kilo/skills/ (Kilo Code)');
809
- console.log(' copilot .github/prompts/ (GitHub Copilot)');
810
- console.log(' all All of the above (default)');
811
- console.log('');
812
- console.log('Examples:');
813
- console.log(' wowok-skills list');
814
- console.log(' wowok-skills get wowok-provider');
815
- console.log(' wowok-skills role provider');
816
- console.log(' wowok-skills recommend "create a service"');
817
- console.log(' wowok-skills init # All clients (default)');
818
- console.log(' wowok-skills init --target claude # One client only');
819
- console.log(' wowok-skills init --no-mcp');
820
- console.log(' wowok-skills uninit # All clients (default)');
239
+ console.log(' list List all skills (by role)');
240
+ console.log(' get <name> Show skill details');
241
+ console.log(' role <role> List skills for a role');
242
+ console.log(' recommend <intent> Recommend skills from a user intent');
243
+ console.log(' init [options] Install skills + register MCP (default: user + project, all targets)');
244
+ console.log(' uninit [options] Remove installed skills (MCP entries are left alone)');
245
+ console.log(' doctor Show per-client install + MCP registration state');
246
+ console.log(' referrer <addr|name> Save the airdrop referrer globally\n');
247
+ console.log('Options:');
248
+ console.log(' --target <t> Target(s), comma separated (default: all)');
249
+ console.log(' --user / --project Restrict the scope (default: both for init)');
250
+ console.log(' --force Rewrite every file even when unchanged');
251
+ console.log(' --no-mcp Skip MCP server install/registration');
252
+ console.log(' --referrer <addr|name> Save the airdrop referrer during init\n');
253
+ printTargets();
254
+ console.log('\nExamples:');
255
+ console.log(' wowok-skills init # all targets, user + project');
256
+ console.log(' wowok-skills init --target claude,cursor --project');
257
+ console.log(' wowok-skills doctor');
258
+ console.log(' wowok-skills uninit --target codex');
821
259
  }
822
260
  function main() {
823
261
  const args = process.argv.slice(2);
824
- if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
262
+ const command = args[0];
263
+ if (!command || command === '--help' || command === '-h' || command === 'help') {
825
264
  printUsage();
826
265
  process.exit(0);
827
266
  }
828
- const command = args[0];
829
267
  switch (command) {
830
268
  case 'list':
831
269
  cmdList();
832
270
  break;
833
271
  case 'get':
834
- if (args.length < 2) {
835
- console.error('Error: Skill name required');
272
+ if (!args[1]) {
273
+ console.error('Error: skill name required');
836
274
  process.exit(1);
837
275
  }
838
276
  cmdGet(args[1]);
839
277
  break;
840
278
  case 'role':
841
- if (args.length < 2) {
842
- console.error('Error: Role required (customer|provider|arbitrator|shared)');
279
+ if (!args[1]) {
280
+ console.error('Error: role required (customer|provider|supplier|collaborator|arbitrator|shared)');
843
281
  process.exit(1);
844
282
  }
845
283
  cmdRole(args[1]);
846
284
  break;
847
285
  case 'recommend':
848
286
  if (args.length < 2) {
849
- console.error('Error: Intent description required');
287
+ console.error('Error: intent description required');
850
288
  process.exit(1);
851
289
  }
852
290
  cmdRecommend(args.slice(1).join(' '));
853
291
  break;
854
- case 'init': {
855
- const rest = args.slice(1);
856
- const withMcp = !rest.includes('--no-mcp');
857
- const referrer = parseReferrerArg(rest);
858
- cmdInit(parseTargetArg(rest), withMcp, referrer);
292
+ case 'init':
293
+ cmdInit(parseInitArgs(args.slice(1)));
859
294
  break;
860
- }
861
295
  case 'uninit':
862
- cmdUninit(parseTargetArg(args.slice(1)));
296
+ cmdUninit(parseInitArgs(args.slice(1)));
297
+ break;
298
+ case 'doctor':
299
+ cmdDoctor();
863
300
  break;
864
301
  case 'referrer': {
865
302
  const value = args[1];
866
303
  if (!value || value.startsWith('--')) {
867
- console.error('Error: Referrer address or name required — wowok-skills referrer <addr|name>');
304
+ console.error('Error: referrer address or name required — wowok-skills referrer <addr|name>');
868
305
  process.exit(1);
869
306
  }
870
- saveReferrer(value);
307
+ (0, installer_1.saveReferrer)(value);
871
308
  break;
872
309
  }
310
+ case 'targets':
311
+ printTargets();
312
+ break;
873
313
  default:
874
- console.error(`Unknown command: ${command}`);
314
+ console.error(`Unknown command: ${command}\n`);
875
315
  printUsage();
876
316
  process.exit(1);
877
317
  }
878
318
  }
879
- function parseTargetArg(rest) {
880
- // Check for --target <value> first
881
- const idx = rest.indexOf('--target');
882
- if (idx !== -1 && idx + 1 < rest.length) {
883
- return rest[idx + 1];
884
- }
885
- // Check for positional argument (first non-flag arg)
886
- const positional = rest.find(a => !a.startsWith('--'));
887
- if (positional && types_1.ALL_CLIENT_TARGETS.includes(positional)) {
888
- return positional;
889
- }
890
- return undefined;
891
- }
892
- function parseReferrerArg(rest) {
893
- const idx = rest.indexOf('--referrer');
894
- if (idx !== -1 && idx + 1 < rest.length) {
895
- const v = rest[idx + 1].trim();
896
- return v || undefined;
897
- }
898
- return undefined;
899
- }
900
- /** Wow MCP data dir — mirrors @wowok/wowok getWowMcpDir(): dirname(wowDir)/mcp. */
901
- function wowMcpDir() {
902
- const home = os.homedir();
903
- let wowDir;
904
- if (process.env.WOWOK_DATA_DIR) {
905
- wowDir = process.env.WOWOK_DATA_DIR;
906
- }
907
- else if (process.platform === 'win32') {
908
- wowDir = path.join(home, '.wow', 'V1');
909
- }
910
- else if (process.platform === 'darwin') {
911
- wowDir = path.join(home, 'Library', 'Application Support', '.wow', 'V1');
912
- }
913
- else {
914
- const xdgConfig = process.env.XDG_CONFIG_HOME;
915
- if (xdgConfig) {
916
- wowDir = path.join(xdgConfig, '.wow', 'V1');
917
- }
918
- else {
919
- const xdgData = process.env.XDG_DATA_HOME;
920
- wowDir = xdgData ? path.join(xdgData, '.wow', 'V1') : path.join(home, '.wow', 'V1');
921
- }
922
- }
923
- return path.join(path.dirname(wowDir), 'mcp');
924
- }
925
- /** Persist the airdrop referrer so the MCP auto-injects it on every call. */
926
- function saveReferrer(referrer) {
927
- const dir = wowMcpDir();
928
- fs.mkdirSync(dir, { recursive: true });
929
- fs.writeFileSync(path.join(dir, 'referrer'), referrer.trim() + '\n', 'utf-8');
930
- console.log(`[wowok-skills] airdrop referrer saved: ${referrer.trim()}`);
931
- console.log('[wowok-skills] it is auto-recorded on your first on-chain interaction.');
932
- }
933
319
  main();
934
320
  //# sourceMappingURL=cli.js.map