vibes-plug 2.14.1 → 3.9.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 (151) hide show
  1. package/.claude/rules/vibes-plug-core.md +5 -0
  2. package/.cursor/rules/vibes-plug-core.mdc +7 -2
  3. package/.cursorrules +8 -2
  4. package/AGENTS.md +23 -2
  5. package/CHANGELOG.md +114 -0
  6. package/CLAUDE.md +10 -3
  7. package/README.md +216 -611
  8. package/bin/vibes.mjs +1104 -0
  9. package/package.json +11 -3
  10. package/plugin.json +4 -3
  11. package/scripts/check-anti-slop.mjs +53 -0
  12. package/scripts/install.js +3 -1
  13. package/scripts/update_skills.js +1 -1
  14. package/scripts/update_skills.mjs +86 -0
  15. package/scripts/validate-skills.mjs +111 -0
  16. package/skills/accessibility-testing-expert/SKILL.md +117 -116
  17. package/skills/affective-computing-emotion-ai/SKILL.md +83 -0
  18. package/skills/agentic-coding-workflow-expert/SKILL.md +297 -0
  19. package/skills/agentic-memory-architect/SKILL.md +52 -0
  20. package/skills/agentic-micro-economy-architect/SKILL.md +92 -0
  21. package/skills/ai-llm-integration-expert/SKILL.md +330 -194
  22. package/skills/ai-media-generation-expert/SKILL.md +173 -172
  23. package/skills/ai-prompt-engineering-expert/SKILL.md +204 -134
  24. package/skills/ai-safety-governance-expert/SKILL.md +223 -0
  25. package/skills/angular-expert/SKILL.md +149 -148
  26. package/skills/anti-slop/SKILL.md +134 -133
  27. package/skills/api-design-expert/SKILL.md +4 -3
  28. package/skills/api-gateway-proxy-expert/SKILL.md +3 -2
  29. package/skills/app-analyzer-optimizer/SKILL.md +4 -3
  30. package/skills/apple-ecosystem-expert/SKILL.md +6 -5
  31. package/skills/astro-framework-expert/SKILL.md +201 -200
  32. package/skills/async-queue-temporal-expert/SKILL.md +218 -217
  33. package/skills/authentication-identity-expert/SKILL.md +174 -173
  34. package/skills/autonomous-red-teamer/SKILL.md +338 -203
  35. package/skills/autonomous-tdd-debugger/SKILL.md +6 -5
  36. package/skills/biome-linter-formatter-expert/SKILL.md +90 -89
  37. package/skills/blockchain-web3-expert/SKILL.md +116 -115
  38. package/skills/brainstorming/SKILL.md +392 -377
  39. package/skills/browser-automation-expert/SKILL.md +260 -222
  40. package/skills/bun-runtime-expert/SKILL.md +5 -4
  41. package/skills/chatbot-messaging-expert/SKILL.md +115 -114
  42. package/skills/ci-cd-devops-architect/SKILL.md +3 -2
  43. package/skills/cloud-hosting-expert/SKILL.md +5 -4
  44. package/skills/coderabbit/SKILL.md +5 -4
  45. package/skills/compliance-gdpr-privacy-expert/SKILL.md +3 -2
  46. package/skills/composable-mach-architect/SKILL.md +338 -0
  47. package/skills/cron-scheduler-expert/SKILL.md +5 -4
  48. package/skills/data-pipeline-etl-expert/SKILL.md +3 -2
  49. package/skills/data-telemetry-expert/SKILL.md +5 -4
  50. package/skills/data-visualization-expert/SKILL.md +155 -154
  51. package/skills/database-orm-expert/SKILL.md +166 -165
  52. package/skills/deep-research-analyst/SKILL.md +182 -136
  53. package/skills/dependency-upgrade-migrator/SKILL.md +11 -10
  54. package/skills/design-system-architect/SKILL.md +4 -3
  55. package/skills/desktop-electron-expert/SKILL.md +129 -128
  56. package/skills/documentation-site-expert/SKILL.md +60 -59
  57. package/skills/doku-mcp-server/SKILL.md +5 -4
  58. package/skills/doku-payment-gateway/SKILL.md +250 -232
  59. package/skills/domain-driven-design-expert/SKILL.md +3 -2
  60. package/skills/e2e-testing-expert/SKILL.md +5 -4
  61. package/skills/ecommerce-expert/SKILL.md +88 -87
  62. package/skills/email-notification-expert/SKILL.md +5 -4
  63. package/skills/ephemeral-generative-ui-architect/SKILL.md +88 -0
  64. package/skills/error-resilience-expert/SKILL.md +14 -13
  65. package/skills/event-driven-architect/SKILL.md +5 -4
  66. package/skills/feature-flag-analytics-expert/SKILL.md +3 -2
  67. package/skills/file-upload-media-expert/SKILL.md +5 -4
  68. package/skills/firebase-security-expert/SKILL.md +5 -4
  69. package/skills/form-validation-expert/SKILL.md +7 -6
  70. package/skills/frontier-ai-models-expert/SKILL.md +116 -0
  71. package/skills/fullstack-expert/SKILL.md +185 -184
  72. package/skills/gemini-agent-booster/SKILL.md +248 -172
  73. package/skills/geospatial-maps-expert/SKILL.md +81 -80
  74. package/skills/global-a11y-i18n-expert/SKILL.md +5 -4
  75. package/skills/glsl-shader-expert/SKILL.md +191 -190
  76. package/skills/go-programming-expert/SKILL.md +5 -4
  77. package/skills/graph-rag-knowledge-expert/SKILL.md +201 -200
  78. package/skills/graphql-apollo-expert/SKILL.md +5 -4
  79. package/skills/headless-cms-expert/SKILL.md +182 -181
  80. package/skills/hig/SKILL.md +5 -4
  81. package/skills/js-backend-expert/SKILL.md +219 -218
  82. package/skills/legacy-code-translator/SKILL.md +6 -5
  83. package/skills/llm-finops-router/SKILL.md +52 -0
  84. package/skills/local-slm-edge-ai-expert/SKILL.md +168 -167
  85. package/skills/logging-error-tracking-expert/SKILL.md +5 -4
  86. package/skills/mcp-server-architect/SKILL.md +315 -307
  87. package/skills/micro-frontend-architect/SKILL.md +5 -4
  88. package/skills/mobile-expo-expert/SKILL.md +5 -4
  89. package/skills/modern-css-native-expert/SKILL.md +190 -189
  90. package/skills/monorepo-architect/SKILL.md +5 -4
  91. package/skills/mpa-orchestrator/SKILL.md +41 -4
  92. package/skills/multi-agent-orchestration/SKILL.md +388 -254
  93. package/skills/mvc-expert/SKILL.md +5 -4
  94. package/skills/n8n-automation-expert/SKILL.md +90 -89
  95. package/skills/nextjs-app-router-expert/SKILL.md +3 -2
  96. package/skills/openapi-swagger-codegen-expert/SKILL.md +4 -3
  97. package/skills/payment-gateway-expert/SKILL.md +131 -128
  98. package/skills/pdf-document-generation-expert/SKILL.md +92 -91
  99. package/skills/performance-web-vitals/SKILL.md +5 -4
  100. package/skills/post-quantum-crypto-migrator/SKILL.md +3 -2
  101. package/skills/prd-architect/SKILL.md +183 -182
  102. package/skills/proactive-background-watcher/SKILL.md +5 -4
  103. package/skills/production-ready-hardener/SKILL.md +10 -9
  104. package/skills/pwa-offline-first-expert/SKILL.md +227 -226
  105. package/skills/pydantic-ai-expert/SKILL.md +162 -161
  106. package/skills/python-programming-expert/SKILL.md +5 -4
  107. package/skills/rate-limit-abuse-prevention/SKILL.md +5 -4
  108. package/skills/realtime-collaboration-expert/SKILL.md +3 -2
  109. package/skills/rich-text-editor-expert/SKILL.md +178 -177
  110. package/skills/rust-programming-expert/SKILL.md +5 -4
  111. package/skills/saas-architect/SKILL.md +155 -154
  112. package/skills/saas-billing/SKILL.md +394 -382
  113. package/skills/saas-multi-tenant/SKILL.md +7 -6
  114. package/skills/scalability-clean-code/SKILL.md +5 -4
  115. package/skills/search-engine-expert/SKILL.md +90 -89
  116. package/skills/self-healing-cloud-orchestrator/SKILL.md +3 -2
  117. package/skills/senior-frontend/SKILL.md +14 -9
  118. package/skills/seo/SKILL.md +4 -4
  119. package/skills/session-memory-manager/SKILL.md +129 -128
  120. package/skills/solidjs-expert/SKILL.md +81 -80
  121. package/skills/spa-orchestrator/SKILL.md +5 -4
  122. package/skills/sse-websocket-streaming-expert/SKILL.md +3 -2
  123. package/skills/state-management-expert/SKILL.md +5 -4
  124. package/skills/supabase-security-expert/SKILL.md +5 -4
  125. package/skills/svelte-sveltekit-expert/SKILL.md +92 -91
  126. package/skills/svg-animation-motion-expert/SKILL.md +3 -2
  127. package/skills/synthetic-data-finetuning-expert/SKILL.md +156 -155
  128. package/skills/tailwind-expert/SKILL.md +62 -5
  129. package/skills/tanstack-query-expert/SKILL.md +5 -4
  130. package/skills/tauri-expert/SKILL.md +5 -4
  131. package/skills/typescript-expert/SKILL.md +5 -4
  132. package/skills/ui-ux-pro-max/SKILL.md +7 -6
  133. package/skills/vector-db-rag-expert/SKILL.md +209 -208
  134. package/skills/vercel-ai-sdk-expert/SKILL.md +226 -181
  135. package/skills/voice-ai-realtime-agent/SKILL.md +243 -242
  136. package/skills/vue-frontend-expert/SKILL.md +5 -4
  137. package/skills/wasm-edge-computing-expert/SKILL.md +3 -2
  138. package/skills/web-3d-graphics-expert/SKILL.md +314 -313
  139. package/skills/web-game-engine-expert/SKILL.md +330 -329
  140. package/skills/web-scraper/SKILL.md +158 -157
  141. package/skills/website-design-cloner/SKILL.md +5 -4
  142. package/skills/webxr-ar-vr-expert/SKILL.md +163 -162
  143. package/skills/wordpress-headless-expert/SKILL.md +145 -144
  144. package/skills/zero-tech-debt-auditor/SKILL.md +115 -0
  145. package/skills/zero-to-prod-orchestrator/SKILL.md +281 -229
  146. package/skills/zero-trust-secret-vault/SKILL.md +3 -2
  147. package/BLUEPRINT.md +0 -319
  148. package/skills/bootstrap-to-modern/SKILL.md +0 -94
  149. package/skills/multiple-entry-points/SKILL.md +0 -91
  150. package/skills/secure-fuzz-testing/SKILL.md +0 -207
  151. package/skills/visual-qa-vision-agent/SKILL.md +0 -71
package/bin/vibes.mjs ADDED
@@ -0,0 +1,1104 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs/promises';
4
+ import path from 'path';
5
+ import readline from 'readline';
6
+ import { fileURLToPath } from 'url';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+ const PLUGIN_ROOT = path.join(__dirname, '..');
11
+
12
+ const args = process.argv.slice(2);
13
+ const command = args[0];
14
+
15
+ const rl = readline.createInterface({
16
+ input: process.stdin,
17
+ output: process.stdout
18
+ });
19
+
20
+ const question = (query) => new Promise((resolve) => rl.question(query, resolve));
21
+
22
+ async function runInit(projectName) {
23
+ if (!projectName) {
24
+ console.error('āŒ Error: Project name is required.');
25
+ console.log('Usage: vibes init <project-name>');
26
+ process.exit(1);
27
+ }
28
+
29
+ const targetDir = path.join(process.cwd(), projectName);
30
+
31
+ try {
32
+ await fs.mkdir(targetDir);
33
+ console.log(`\nšŸ“‚ Created project directory: ${projectName}`);
34
+
35
+ // Create standard Zero-To-Prod boilerplate
36
+ const filesToCreate = {
37
+ 'README.md': `# ${projectName}\n\nProject initialized with Vibes-Plug Swarm Orchestrator.\n\n## Next Steps\nAsk your AI agent to begin **Phase 1: Discovery** using the \`zero-to-prod-orchestrator\` skill.`,
38
+ 'PROGRESS.md': `# šŸš€ Zero to Prod - Progress Tracker\n\n- [ ] Phase 1: Discovery & PRD\n- [ ] Phase 2: Foundation & Monorepo\n- [ ] Phase 3: Database & Auth\n- [ ] Phase 4: Backend & APIs\n- [ ] Phase 5: Frontend & UI\n- [ ] Phase 6: Testing & Security\n- [ ] Phase 7: DevOps & Monitoring\n- [ ] Phase 8: Launch`,
39
+ 'BLUEPRINT.md': `# šŸ“ System Blueprint\n\n(Auto-generated architectural decisions will be logged here by the AI agent)`,
40
+ 'PRD.md': `# šŸ“‹ Product Requirements Document\n\n(To be filled by the deep-research-analyst agent)`
41
+ };
42
+
43
+ for (const [filename, content] of Object.entries(filesToCreate)) {
44
+ await fs.writeFile(path.join(targetDir, filename), content, 'utf8');
45
+ console.log(` šŸ“„ Created ${filename}`);
46
+ }
47
+
48
+ console.log('\nšŸŽ‰ Project scaffolded successfully!');
49
+ console.log('\nTo get started:');
50
+ console.log(` cd ${projectName}`);
51
+ console.log(' Ask your AI (Claude/Cursor/Antigravity): "Begin phase 1 using zero-to-prod-orchestrator"');
52
+
53
+ } catch (err) {
54
+ console.error(`\nāŒ Error creating project: ${err.message}`);
55
+ } finally {
56
+ rl.close();
57
+ }
58
+ }
59
+
60
+ async function runBootstrap(templateName, projectName) {
61
+ if (!templateName || !projectName) {
62
+ console.error('āŒ Error: Template name and Project name are required.');
63
+ console.log('Usage: vibes bootstrap <template> <project-name>');
64
+ console.log('Available templates: saas, ecommerce');
65
+ process.exit(1);
66
+ }
67
+
68
+ const validTemplates = ['saas', 'ecommerce', 'mobile', 'api', 'fullstack'];
69
+ if (!validTemplates.includes(templateName)) {
70
+ console.error(`āŒ Error: Invalid template '${templateName}'. Valid options: ${validTemplates.join(', ')}`);
71
+ process.exit(1);
72
+ }
73
+
74
+ const targetDir = path.join(process.cwd(), projectName);
75
+
76
+ try {
77
+ const exists = await fs.access(targetDir).then(() => true).catch(() => false);
78
+ if (exists) {
79
+ console.error(`āŒ Error: Directory '${projectName}' already exists.`);
80
+ process.exit(1);
81
+ }
82
+
83
+ // Resolve template-specific config first
84
+ let scaffoldCmd = null;
85
+ let prdTitle = projectName;
86
+ let specificSkills = [];
87
+
88
+ if (templateName === 'saas') {
89
+ prdTitle = 'Multi-Tenant SaaS';
90
+ scaffoldCmd = `npx create-next-app@latest ${projectName} --ts --tailwind --eslint --app --src-dir --import-alias "@/*" --use-npm --yes`;
91
+ specificSkills = ['saas-architect', 'saas-multi-tenant', 'saas-billing', 'payment-gateway-expert', 'supabase-security-expert'];
92
+ } else if (templateName === 'ecommerce') {
93
+ prdTitle = 'E-Commerce Platform';
94
+ scaffoldCmd = `npx create-next-app@latest ${projectName} --ts --tailwind --eslint --app --src-dir --import-alias "@/*" --use-npm --yes`;
95
+ specificSkills = ['ecommerce-expert', 'payment-gateway-expert', 'database-orm-expert', 'doku-payment-gateway'];
96
+ } else if (templateName === 'mobile') {
97
+ prdTitle = 'Mobile App (Expo)';
98
+ scaffoldCmd = `npx create-expo-app@latest ${projectName} --template blank-typescript --yes`;
99
+ specificSkills = ['mobile-expo-expert', 'authentication-identity-expert', 'api-design-expert', 'state-management-expert'];
100
+ } else if (templateName === 'api') {
101
+ prdTitle = 'Backend API (Hono/Node.js)';
102
+ scaffoldCmd = `npx create-hono@latest ${projectName} --template nodejs --pm npm --install`;
103
+ specificSkills = ['js-backend-expert', 'api-design-expert', 'database-orm-expert', 'authentication-identity-expert', 'logging-error-tracking-expert'];
104
+ } else if (templateName === 'fullstack') {
105
+ prdTitle = 'Full-Stack T3 App';
106
+ scaffoldCmd = `npx create-t3-app@latest ${projectName} --CI --noGit --appRouter --tailwind --trpc --prisma --nextAuth`;
107
+ specificSkills = ['nextjs-app-router-expert', 'saas-architect', 'database-orm-expert', 'authentication-identity-expert', 'tailwind-expert'];
108
+ }
109
+
110
+ console.log(`\n\ud83d\ude80 Bootstrapping ${prdTitle} project: ${projectName}...`);
111
+ console.log('\u23f3 This may take a minute or two as npm installs dependencies...\n');
112
+
113
+ const { execSync } = await import('child_process');
114
+ execSync(scaffoldCmd, { stdio: 'inherit' });
115
+
116
+ console.log(`\nšŸ“‚ Project scaffolded. Injecting AI skills for ${templateName}...`);
117
+
118
+ // Core skills for all templates
119
+ const coreSkills = [
120
+ 'zero-to-prod-orchestrator',
121
+ 'senior-frontend',
122
+ 'tailwind-expert',
123
+ 'anti-slop',
124
+ 'session-memory-manager'
125
+ ];
126
+
127
+ const allSkills = [...coreSkills, ...specificSkills];
128
+ const targetAgentsDir = path.join(targetDir, '.agents', 'skills');
129
+ await fs.mkdir(targetAgentsDir, { recursive: true });
130
+
131
+ for (const skill of allSkills) {
132
+ const sourceDir = path.join(PLUGIN_ROOT, 'skills', skill);
133
+ const skillTargetDir = path.join(targetAgentsDir, skill);
134
+
135
+ const skillExists = await fs.access(sourceDir).then(() => true).catch(() => false);
136
+ if (skillExists) {
137
+ await fs.cp(sourceDir, skillTargetDir, { recursive: true });
138
+ console.log(` āž• Injected skill: ${skill}`);
139
+ } else {
140
+ console.warn(` āš ļø Warning: Skill '${skill}' not found in global registry.`);
141
+ }
142
+ }
143
+
144
+ // Overwrite README and PRD
145
+ const filesToCreate = {
146
+ 'README.md': `# ${projectName}\n\nProject initialized with Vibes-Plug Swarm Orchestrator (${templateName.toUpperCase()} template).\n\n## Next Steps\nAsk your AI agent to begin **Phase 1: Discovery** using the \`zero-to-prod-orchestrator\` skill.`,
147
+ 'PRD.md': `# šŸ“‹ ${prdTitle} - Product Requirements Document\n\n(To be filled by the deep-research-analyst agent based on the ${templateName} template)`
148
+ };
149
+
150
+ for (const [filename, content] of Object.entries(filesToCreate)) {
151
+ await fs.writeFile(path.join(targetDir, filename), content, 'utf8');
152
+ console.log(` šŸ“„ Created ${filename}`);
153
+ }
154
+
155
+ console.log(`\nšŸŽ‰ Super-Scaffolding complete for ${projectName}!`);
156
+ console.log('\nTo get started:');
157
+ console.log(` cd ${projectName}`);
158
+ console.log(' Ask your AI (Claude/Cursor/Antigravity): "Begin phase 1 using zero-to-prod-orchestrator"');
159
+
160
+ } catch (err) {
161
+ console.error(`\nāŒ Error during bootstrap: ${err.message}`);
162
+ } finally {
163
+ rl.close();
164
+ }
165
+ }
166
+
167
+ async function runValidate() {
168
+ console.log('Running ecosystem validation...\n');
169
+ try {
170
+ const { execSync } = await import('child_process');
171
+ execSync('node ' + path.join(PLUGIN_ROOT, 'scripts', 'validate-skills.mjs'), { stdio: 'inherit' });
172
+ } catch (err) {
173
+ // Error is already printed by the child process
174
+ }
175
+ rl.close();
176
+ }
177
+
178
+ async function runAudit() {
179
+ console.log('Running Anti-AI Slop Audit...\n');
180
+ try {
181
+ const { execSync } = await import('child_process');
182
+ execSync('node ' + path.join(PLUGIN_ROOT, 'scripts', 'check-anti-slop.mjs'), { stdio: 'inherit' });
183
+ } catch (err) {
184
+ // Error is already printed by the child process
185
+ }
186
+ rl.close();
187
+ }
188
+
189
+ async function runCreateSkill(skillName) {
190
+ if (!skillName) {
191
+ console.error('āŒ Error: Skill name is required.');
192
+ console.log('Usage: vibes create-skill <skill-name>');
193
+ process.exit(1);
194
+ }
195
+
196
+ const kebabCaseRegex = /^[a-z0-9]+(-[a-z0-9]+)*$/;
197
+ if (!kebabCaseRegex.test(skillName)) {
198
+ console.error('āŒ Error: Skill name must be in kebab-case (e.g., my-new-skill).');
199
+ process.exit(1);
200
+ }
201
+
202
+ const targetDir = path.join(PLUGIN_ROOT, 'skills', skillName);
203
+ const templatePath = path.join(PLUGIN_ROOT, 'templates', 'SKILL_TEMPLATE.md');
204
+
205
+ try {
206
+ const exists = await fs.access(targetDir).then(() => true).catch(() => false);
207
+ if (exists) {
208
+ console.error(`āŒ Error: Skill directory '${skillName}' already exists.`);
209
+ process.exit(1);
210
+ }
211
+
212
+ await fs.mkdir(targetDir, { recursive: true });
213
+
214
+ let templateContent = await fs.readFile(templatePath, 'utf8');
215
+
216
+ // Basic string replacements
217
+ templateContent = templateContent.replace(/skill-baru/g, skillName);
218
+ templateContent = templateContent.replace(/\[Skill Name\]/g, skillName);
219
+
220
+ await fs.writeFile(path.join(targetDir, 'SKILL.md'), templateContent, 'utf8');
221
+
222
+ console.log(`\nšŸŽ‰ Scaffolded new skill: ${skillName}`);
223
+ console.log(`šŸ“‚ Location: skills/${skillName}/SKILL.md`);
224
+ console.log('\nNext steps:');
225
+ console.log(' 1. Open the file and follow the checklist at the bottom.');
226
+ console.log(' 2. Replace all [...] placeholders with actual content.');
227
+ console.log(' 3. Register your new skill in brainstorming/SKILL.md');
228
+
229
+ } catch (err) {
230
+ console.error(`\nāŒ Error creating skill: ${err.message}`);
231
+ } finally {
232
+ rl.close();
233
+ }
234
+ }
235
+
236
+ async function runCreateMcp(serverName) {
237
+ if (!serverName) {
238
+ console.error('āŒ Error: MCP Server name is required.');
239
+ console.log('Usage: vibes create-mcp <server-name>');
240
+ process.exit(1);
241
+ }
242
+
243
+ const targetDir = path.join(process.cwd(), serverName);
244
+
245
+ try {
246
+ const exists = await fs.access(targetDir).then(() => true).catch(() => false);
247
+ if (exists) {
248
+ console.error(`āŒ Error: Directory '${serverName}' already exists.`);
249
+ process.exit(1);
250
+ }
251
+
252
+ await fs.mkdir(targetDir, { recursive: true });
253
+ await fs.mkdir(path.join(targetDir, 'src'), { recursive: true });
254
+
255
+ const filesToCreate = {
256
+ 'package.json': `{
257
+ "name": "${serverName}",
258
+ "version": "1.0.0",
259
+ "description": "MCP Server generated by vibes-plug",
260
+ "type": "module",
261
+ "bin": {
262
+ "${serverName}": "./build/index.js"
263
+ },
264
+ "scripts": {
265
+ "build": "tsc",
266
+ "start": "node build/index.js"
267
+ },
268
+ "dependencies": {
269
+ "@modelcontextprotocol/sdk": "latest",
270
+ "zod": "^3.23.8"
271
+ },
272
+ "devDependencies": {
273
+ "@types/node": "^22.0.0",
274
+ "typescript": "^5.5.4"
275
+ }
276
+ }`,
277
+ 'tsconfig.json': `{
278
+ "compilerOptions": {
279
+ "target": "ES2022",
280
+ "module": "NodeNext",
281
+ "moduleResolution": "NodeNext",
282
+ "outDir": "./build",
283
+ "rootDir": "./src",
284
+ "strict": true,
285
+ "esModuleInterop": true,
286
+ "skipLibCheck": true,
287
+ "forceConsistentCasingInFileNames": true
288
+ },
289
+ "include": ["src/**/*"]
290
+ }`,
291
+ 'src/index.ts': `#!/usr/bin/env node
292
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
293
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
294
+ import {
295
+ CallToolRequestSchema,
296
+ ErrorCode,
297
+ ListToolsRequestSchema,
298
+ McpError,
299
+ } from "@modelcontextprotocol/sdk/types.js";
300
+
301
+ class ${serverName.replace(/[^a-zA-Z0-9]/g, '')}Server {
302
+ private server: Server;
303
+
304
+ constructor() {
305
+ this.server = new Server(
306
+ {
307
+ name: "${serverName}",
308
+ version: "1.0.0",
309
+ },
310
+ {
311
+ capabilities: {
312
+ tools: {},
313
+ },
314
+ }
315
+ );
316
+
317
+ this.setupToolHandlers();
318
+
319
+ // Error handling
320
+ this.server.onerror = (error) => console.error('[MCP Error]', error);
321
+ process.on('SIGINT', async () => {
322
+ await this.server.close();
323
+ process.exit(0);
324
+ });
325
+ }
326
+
327
+ private setupToolHandlers() {
328
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
329
+ tools: [
330
+ {
331
+ name: "hello_world",
332
+ description: "A simple hello world tool",
333
+ inputSchema: {
334
+ type: "object",
335
+ properties: {
336
+ name: {
337
+ type: "string",
338
+ description: "Name to greet",
339
+ },
340
+ },
341
+ required: ["name"],
342
+ },
343
+ },
344
+ ],
345
+ }));
346
+
347
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
348
+ if (request.params.name !== "hello_world") {
349
+ throw new McpError(
350
+ ErrorCode.MethodNotFound,
351
+ \`Unknown tool: \${request.params.name}\`
352
+ );
353
+ }
354
+
355
+ const args = request.params.arguments as { name: string };
356
+
357
+ return {
358
+ content: [
359
+ {
360
+ type: "text",
361
+ text: \`Hello, \${args.name}! Welcome to your new MCP server.\`,
362
+ },
363
+ ],
364
+ };
365
+ });
366
+ }
367
+
368
+ async run() {
369
+ const transport = new StdioServerTransport();
370
+ await this.server.connect(transport);
371
+ console.error('${serverName} MCP server running on stdio');
372
+ }
373
+ }
374
+
375
+ const server = new ${serverName.replace(/[^a-zA-Z0-9]/g, '')}Server();
376
+ server.run().catch(console.error);
377
+ `
378
+ };
379
+
380
+ for (const [filename, content] of Object.entries(filesToCreate)) {
381
+ await fs.writeFile(path.join(targetDir, filename), content, 'utf8');
382
+ console.log(` šŸ“„ Created ${filename}`);
383
+ }
384
+
385
+ console.log(`\nšŸŽ‰ MCP Server scaffolded successfully in ./${serverName}`);
386
+ console.log('\nNext steps:');
387
+ console.log(` cd ${serverName}`);
388
+ console.log(' npm install');
389
+ console.log(' npm run build');
390
+ console.log('\nTo use with Claude Desktop or Cursor, add this to your config:');
391
+ console.log(`
392
+ {
393
+ "mcpServers": {
394
+ "${serverName}": {
395
+ "command": "node",
396
+ "args": ["${path.join(process.cwd(), serverName, 'build', 'index.js')}"]
397
+ }
398
+ }
399
+ }`);
400
+ } catch (err) {
401
+ console.error(`\nāŒ Error creating MCP Server: ${err.message}`);
402
+ } finally {
403
+ rl.close();
404
+ }
405
+ }
406
+
407
+ async function runAddSkill(skillName) {
408
+ if (!skillName) {
409
+ console.error('āŒ Error: Skill name is required.');
410
+ console.log('Usage: vibes add <skill-name>');
411
+ process.exit(1);
412
+ }
413
+
414
+ const sourceDir = path.join(PLUGIN_ROOT, 'skills', skillName);
415
+
416
+ try {
417
+ const exists = await fs.access(sourceDir).then(() => true).catch(() => false);
418
+ if (!exists) {
419
+ console.error(`āŒ Error: Skill '${skillName}' not found in vibes-plug global registry.`);
420
+ process.exit(1);
421
+ }
422
+
423
+ // Default to .agents/skills for local project injection
424
+ const targetBaseDir = path.join(process.cwd(), '.agents', 'skills');
425
+ const targetDir = path.join(targetBaseDir, skillName);
426
+
427
+ await fs.mkdir(targetBaseDir, { recursive: true });
428
+
429
+ // Node v16.7.0+ required for fs.cp
430
+ await fs.cp(sourceDir, targetDir, { recursive: true });
431
+
432
+ console.log(`\nšŸŽ‰ Successfully added '${skillName}' to your local project!`);
433
+ console.log(`šŸ“‚ Location: .agents/skills/${skillName}/SKILL.md`);
434
+ console.log('\nYour AI agents will now automatically load this skill when working in this repository.');
435
+ } catch (err) {
436
+ console.error(`\nāŒ Error adding skill: ${err.message}`);
437
+ } finally {
438
+ rl.close();
439
+ }
440
+ }
441
+
442
+ async function runUi() {
443
+ let checkbox;
444
+ try {
445
+ const prompts = await import('@inquirer/prompts');
446
+ checkbox = prompts.checkbox;
447
+ } catch (err) {
448
+ console.error('āŒ Error: The Interactive TUI requires the @inquirer/prompts package.');
449
+ console.error('Please run "npm install" inside the vibes-plug directory first:');
450
+ console.error(` cd ${PLUGIN_ROOT}`);
451
+ console.error(' npm install');
452
+ process.exit(1);
453
+ }
454
+
455
+ // Close the global readline so inquirer can take over stdin
456
+ rl.close();
457
+
458
+ try {
459
+ const skillsDir = path.join(PLUGIN_ROOT, 'skills');
460
+ const entries = await fs.readdir(skillsDir, { withFileTypes: true });
461
+ const skills = entries
462
+ .filter(dirent => dirent.isDirectory())
463
+ .map(dirent => dirent.name)
464
+ .sort();
465
+
466
+ const choices = skills.map(skill => ({ name: skill, value: skill }));
467
+
468
+ console.log(`\n🌊 Vibes-Plug Interactive TUI`);
469
+ const selectedSkills = await checkbox({
470
+ message: 'Select the AI skills to install into this project:',
471
+ choices: choices,
472
+ loop: false,
473
+ pageSize: 15
474
+ });
475
+
476
+ if (!selectedSkills || selectedSkills.length === 0) {
477
+ console.log('No skills selected. Exiting.');
478
+ return;
479
+ }
480
+
481
+ const targetBaseDir = path.join(process.cwd(), '.agents', 'skills');
482
+ await fs.mkdir(targetBaseDir, { recursive: true });
483
+
484
+ let count = 0;
485
+ for (const skill of selectedSkills) {
486
+ const sourceDir = path.join(skillsDir, skill);
487
+ const targetDir = path.join(targetBaseDir, skill);
488
+
489
+ const exists = await fs.access(targetDir).then(() => true).catch(() => false);
490
+ if (!exists) {
491
+ await fs.cp(sourceDir, targetDir, { recursive: true });
492
+ console.log(` āž• Added: ${skill}`);
493
+ count++;
494
+ } else {
495
+ console.log(` ā­ļø Skipped (already exists): ${skill}`);
496
+ }
497
+ }
498
+
499
+ console.log(`\nšŸŽ‰ Successfully installed ${count} skill(s) into .agents/skills/`);
500
+ console.log('Your AI agents will now automatically load these skills when working in this repository.');
501
+
502
+ } catch (err) {
503
+ if (err.name === 'ExitPromptError') {
504
+ console.log('Interactive prompt cancelled.');
505
+ } else {
506
+ console.error(`\nāŒ Error: ${err.message}`);
507
+ }
508
+ }
509
+ }
510
+
511
+ async function runRemoveSkill(skillName) {
512
+ if (!skillName) {
513
+ console.error('āŒ Error: Skill name is required.');
514
+ console.log('Usage: vibes remove <skill-name>');
515
+ process.exit(1);
516
+ }
517
+
518
+ const targetDir = path.join(process.cwd(), '.agents', 'skills', skillName);
519
+
520
+ try {
521
+ const exists = await fs.access(targetDir).then(() => true).catch(() => false);
522
+ if (!exists) {
523
+ console.error(`āŒ Skill '${skillName}' is not installed in this project.`);
524
+ console.log('Run "vibes list" to see available skills or "vibes ui" to manage them.');
525
+ process.exit(1);
526
+ }
527
+
528
+ await fs.rm(targetDir, { recursive: true, force: true });
529
+ console.log(`\nāœ… Successfully removed '${skillName}' from your local project.`);
530
+ console.log('šŸ’” Run "vibes add" or "vibes ui" to re-install skills anytime.');
531
+
532
+ } catch (err) {
533
+ console.error(`\nāŒ Error removing skill: ${err.message}`);
534
+ } finally {
535
+ rl.close();
536
+ }
537
+ }
538
+
539
+ async function runListSkills(filter) {
540
+ try {
541
+ const skillsDir = path.join(PLUGIN_ROOT, 'skills');
542
+ const entries = await fs.readdir(skillsDir, { withFileTypes: true });
543
+ const allSkills = entries
544
+ .filter(dirent => dirent.isDirectory())
545
+ .map(dirent => dirent.name)
546
+ .sort();
547
+
548
+ // Check which skills are already installed locally
549
+ const localAgentsDir = path.join(process.cwd(), '.agents', 'skills');
550
+ let localSkills = new Set();
551
+ const localExists = await fs.access(localAgentsDir).then(() => true).catch(() => false);
552
+ if (localExists) {
553
+ const localEntries = await fs.readdir(localAgentsDir, { withFileTypes: true });
554
+ localEntries
555
+ .filter(d => d.isDirectory())
556
+ .forEach(d => localSkills.add(d.name));
557
+ }
558
+
559
+ // Apply filter if provided
560
+ const filtered = filter
561
+ ? allSkills.filter(s => s.includes(filter.toLowerCase()))
562
+ : allSkills;
563
+
564
+ if (filtered.length === 0) {
565
+ console.log(`āŒ No skills found matching "${filter}".`);
566
+ rl.close();
567
+ return;
568
+ }
569
+
570
+ const title = filter ? `Skills matching "${filter}"` : 'All Available Skills';
571
+ console.log(`\n🌊 Vibes-Plug Registry — ${title}`);
572
+ console.log(`šŸ“Š ${filtered.length} skill(s) found | āœ… = installed locally\n`);
573
+
574
+ // Group by domain prefix for readability
575
+ filtered.forEach(skill => {
576
+ const installed = localSkills.has(skill) ? ' āœ…' : '';
577
+ console.log(` • ${skill}${installed}`);
578
+ });
579
+
580
+ console.log(`
581
+ šŸ’” Commands:`);
582
+ console.log(' vibes add <skill-name> — Install a skill into this project');
583
+ console.log(' vibes remove <skill-name> — Remove a skill from this project');
584
+ console.log(' vibes ui — Interactive multiselect menu');
585
+
586
+ } catch (err) {
587
+ console.error(`\nāŒ Error listing skills: ${err.message}`);
588
+ } finally {
589
+ rl.close();
590
+ }
591
+ }
592
+
593
+ async function runVersion(action, type) {
594
+ const pkgPath = path.join(PLUGIN_ROOT, 'package.json');
595
+ const pluginJsonPath = path.join(PLUGIN_ROOT, 'plugin.json');
596
+ const changelogPath = path.join(PLUGIN_ROOT, 'CHANGELOG.md');
597
+ const vivesMjsPath = path.join(PLUGIN_ROOT, 'bin', 'vibes.mjs');
598
+
599
+ try {
600
+ const pkgRaw = await fs.readFile(pkgPath, 'utf8');
601
+ const pkg = JSON.parse(pkgRaw);
602
+ const current = pkg.version;
603
+ const [major, minor, patch] = current.split('.').map(Number);
604
+
605
+ if (!action || action === 'current') {
606
+ console.log(`šŸ“¦ Current version: v${current}`);
607
+ rl.close();
608
+ return;
609
+ }
610
+
611
+ if (action !== 'bump') {
612
+ console.error('āŒ Usage: vibes version current OR vibes version bump <major|minor|patch>');
613
+ process.exit(1);
614
+ }
615
+
616
+ let next;
617
+ if (type === 'major') next = `${major + 1}.0.0`;
618
+ else if (type === 'minor') next = `${major}.${minor + 1}.0`;
619
+ else if (type === 'patch') next = `${major}.${minor}.${patch + 1}`;
620
+ else {
621
+ console.error('āŒ Bump type must be: major | minor | patch');
622
+ process.exit(1);
623
+ }
624
+
625
+ const files = [
626
+ { path: pkgPath, from: `"version": "${current}"`, to: `"version": "${next}"` },
627
+ { path: pluginJsonPath, from: `"version": "${current}"`, to: `"version": "${next}"` },
628
+ { path: vivesMjsPath, from: `CLI (v${current})`, to: `CLI (v${next})` },
629
+ ];
630
+
631
+ for (const { path: filePath, from, to } of files) {
632
+ const raw = await fs.readFile(filePath, 'utf8');
633
+ if (raw.includes(from)) {
634
+ await fs.writeFile(filePath, raw.replaceAll(from, to), 'utf8');
635
+ console.log(` āœ… Updated: ${path.basename(filePath)} ${current} → ${next}`);
636
+ } else {
637
+ console.log(` ā­ļø Skipped (pattern not found): ${path.basename(filePath)}`);
638
+ }
639
+ }
640
+
641
+ // Prepend a new changelog entry
642
+ const today = new Date().toISOString().split('T')[0];
643
+ const entry = `## [${next}] - ${today}\n\n### Changed\n- Version bumped from ${current} to ${next}\n\n---\n\n`;
644
+ const changelog = await fs.readFile(changelogPath, 'utf8');
645
+ const insertIdx = changelog.indexOf('## [');
646
+ const updated = changelog.slice(0, insertIdx) + entry + changelog.slice(insertIdx);
647
+ await fs.writeFile(changelogPath, updated, 'utf8');
648
+ console.log(` āœ… Updated: CHANGELOG.md added [${next}] entry`);
649
+
650
+ console.log(`
651
+ šŸŽ‰ Version bumped: v${current} → v${next}`);
652
+ console.log('šŸ’” Don\'t forget to commit and tag: git tag v' + next);
653
+
654
+ } catch (err) {
655
+ console.error(`āŒ Error: ${err.message}`);
656
+ } finally {
657
+ rl.close();
658
+ }
659
+ }
660
+
661
+ async function runDoctor() {
662
+ console.log('\n🧬 Vibes-Plug Doctor — Running diagnostics...\n');
663
+ const checks = [];
664
+
665
+ // 1. Node.js version
666
+ const nodeVersion = process.versions.node;
667
+ const nodeMajor = parseInt(nodeVersion.split('.')[0], 10);
668
+ checks.push(nodeMajor >= 18
669
+ ? `āœ… Node.js v${nodeVersion} (>= 18 required)`
670
+ : `āŒ Node.js v${nodeVersion} is too old. Please upgrade to v18+`);
671
+
672
+ // 2. npx available
673
+ try {
674
+ const { execSync } = await import('child_process');
675
+ execSync('npx --version', { stdio: 'pipe' });
676
+ checks.push('āœ… npx is available');
677
+ } catch {
678
+ checks.push('āŒ npx not found. Install Node.js from https://nodejs.org');
679
+ }
680
+
681
+ // 3. Global skills directory
682
+ const skillsDir = path.join(PLUGIN_ROOT, 'skills');
683
+ try {
684
+ const entries = await fs.readdir(skillsDir, { withFileTypes: true });
685
+ const count = entries.filter(d => d.isDirectory()).length;
686
+ checks.push(`āœ… Global skills registry: ${count} skills found`);
687
+ } catch {
688
+ checks.push('āŒ Skills directory missing! Run: npm install -g vibes-plug');
689
+ }
690
+
691
+ // 4. @inquirer/prompts installed
692
+ try {
693
+ await import('@inquirer/prompts');
694
+ checks.push('āœ… @inquirer/prompts is installed (vibes ui works)');
695
+ } catch {
696
+ checks.push(`āš ļø @inquirer/prompts not found. Run: cd ${PLUGIN_ROOT} && npm install`);
697
+ }
698
+
699
+ // 5. Local project .agents/skills
700
+ const localAgentsDir = path.join(process.cwd(), '.agents', 'skills');
701
+ const localExists = await fs.access(localAgentsDir).then(() => true).catch(() => false);
702
+ if (localExists) {
703
+ const localEntries = await fs.readdir(localAgentsDir, { withFileTypes: true });
704
+ const localCount = localEntries.filter(d => d.isDirectory()).length;
705
+ checks.push(`āœ… Local project: ${localCount} skill(s) installed in .agents/skills/`);
706
+ } else {
707
+ checks.push('ā„¹ļø No local .agents/skills/ found (run vibes add or vibes ui to install skills)');
708
+ }
709
+
710
+ // 6. Package version
711
+ const pkgPath = path.join(PLUGIN_ROOT, 'package.json');
712
+ const pkgRaw = await fs.readFile(pkgPath, 'utf8');
713
+ const pkg = JSON.parse(pkgRaw);
714
+ checks.push(`šŸ“¦ vibes-plug version: v${pkg.version}`);
715
+
716
+ checks.forEach(c => console.log(' ' + c));
717
+
718
+ const failed = checks.filter(c => c.startsWith(' āŒ')).length;
719
+ console.log(failed > 0
720
+ ? `\n🚨 ${failed} issue(s) found. Fix them above and re-run: vibes doctor`
721
+ : '\nšŸŽ‰ All checks passed! Your Vibes-Plug environment is healthy.');
722
+
723
+ rl.close();
724
+ }
725
+
726
+ async function runSkillInfo(skillName) {
727
+ if (!skillName) {
728
+ console.error('āŒ Error: Skill name is required.');
729
+ console.log('Usage: vibes skill info <skill-name>');
730
+ process.exit(1);
731
+ }
732
+
733
+ const skillPath = path.join(PLUGIN_ROOT, 'skills', skillName, 'SKILL.md');
734
+ try {
735
+ const content = await fs.readFile(skillPath, 'utf8');
736
+
737
+ // Parse frontmatter
738
+ const fmMatch = content.match(/---[\r\n]+([\s\S]*?)[\r\n]+---/);
739
+ if (!fmMatch) {
740
+ console.error(`āŒ Skill '${skillName}' has no frontmatter.`);
741
+ process.exit(1);
742
+ }
743
+
744
+ const fm = fmMatch[1];
745
+ const get = (key) => { const m = fm.match(new RegExp(`${key}:\\s*["']?([^"'\\n]+)["']?`)); return m ? m[1].trim() : 'N/A'; };
746
+
747
+ const name = get('name');
748
+ const version = get('version');
749
+ const description = get('description');
750
+ const author = get('author');
751
+
752
+ // Extract orchestration section
753
+ const orchMatch = content.match(/## (?:Orchestration & Integration|Integrasi Orkestrasi)[\r\n]+([\s\S]*?)(?=\n##|$)/);
754
+ const orchText = orchMatch ? orchMatch[1].trim().split('\n').slice(0, 5).join('\n') : 'N/A';
755
+
756
+ // Check local installation status
757
+ const localPath = path.join(process.cwd(), '.agents', 'skills', skillName);
758
+ const isLocal = await fs.access(localPath).then(() => true).catch(() => false);
759
+
760
+ console.log(`\nšŸ“– ${name} (v${version})`);
761
+ console.log(`šŸ“ ${description}`);
762
+ console.log(`šŸ‘¤ Author : ${author}`);
763
+ console.log(`šŸ“ Status : ${isLocal ? 'āœ… Installed locally (.agents/skills/)' : 'āŒ Not installed in this project'}`);
764
+ console.log(`\nšŸ”— Orchestration:`);
765
+ console.log(orchText);
766
+ console.log(`\nšŸ’” To install: vibes add ${skillName}`);
767
+
768
+ } catch {
769
+ console.error(`āŒ Skill '${skillName}' not found in the global registry.`);
770
+ console.log('Run "vibes list" to see all available skills.');
771
+ } finally {
772
+ rl.close();
773
+ }
774
+ }
775
+
776
+ async function runHooks(action) {
777
+ const gitDir = path.join(process.cwd(), '.git');
778
+ const hookPath = path.join(gitDir, 'hooks', 'pre-commit');
779
+
780
+ const gitExists = await fs.access(gitDir).then(() => true).catch(() => false);
781
+ if (!gitExists) {
782
+ console.error('āŒ No .git directory found. Run this command inside a git repository.');
783
+ process.exit(1);
784
+ }
785
+
786
+ try {
787
+ if (!action || action === 'install') {
788
+ const hookContent = `#!/bin/sh
789
+ # Installed by vibes-plug — Anti-AI Slop pre-commit gate
790
+ echo "šŸ” Running Vibes Anti-Slop Audit..."
791
+ node "${path.join(PLUGIN_ROOT, 'scripts', 'check-anti-slop.mjs')}" || exit 1
792
+ `;
793
+ await fs.mkdir(path.join(gitDir, 'hooks'), { recursive: true });
794
+ await fs.writeFile(hookPath, hookContent, { mode: 0o755 });
795
+ console.log('\n\u2705 Git pre-commit hook installed!');
796
+ console.log('šŸ›”ļø Anti-Slop Audit will now run automatically before every commit.');
797
+ console.log(`šŸ“‚ Hook location: ${hookPath}`);
798
+
799
+ } else if (action === 'remove') {
800
+ const exists = await fs.access(hookPath).then(() => true).catch(() => false);
801
+ if (!exists) {
802
+ console.log('ā„¹ļø No vibes pre-commit hook found to remove.');
803
+ } else {
804
+ await fs.rm(hookPath, { force: true });
805
+ console.log('āœ… Git pre-commit hook removed.');
806
+ }
807
+ } else {
808
+ console.error('āŒ Usage: vibes hooks install OR vibes hooks remove');
809
+ process.exit(1);
810
+ }
811
+ } catch (err) {
812
+ console.error(`āŒ Error managing hooks: ${err.message}`);
813
+ } finally {
814
+ rl.close();
815
+ }
816
+ }
817
+
818
+ // Built-in skill recipes (curated bundles)
819
+ const RECIPES = {
820
+ 'ai-stack': {
821
+ description: 'Full AI/LLM integration stack with RAG, vector DB, and agent orchestration',
822
+ skills: ['ai-llm-integration-expert', 'vector-db-rag-expert', 'vercel-ai-sdk-expert', 'ai-prompt-engineering-expert', 'multi-agent-orchestration']
823
+ },
824
+ 'fullstack-pro': {
825
+ description: 'Production-grade fullstack: Next.js 15, auth, DB, payments, testing',
826
+ skills: ['nextjs-app-router-expert', 'authentication-identity-expert', 'database-orm-expert', 'payment-gateway-expert', 'e2e-testing-expert', 'error-resilience-expert']
827
+ },
828
+ 'security-hardened': {
829
+ description: 'Security-first stack: zero-trust, rate limiting, auth, GDPR compliance',
830
+ skills: ['zero-trust-secret-vault', 'rate-limit-abuse-prevention', 'authentication-identity-expert', 'compliance-gdpr-privacy-expert', 'autonomous-red-teamer', 'supabase-security-expert']
831
+ },
832
+ 'realtime-app': {
833
+ description: 'Real-time collaboration: WebSockets, SSE, CRDTs, streaming',
834
+ skills: ['realtime-collaboration-expert', 'sse-websocket-streaming-expert', 'state-management-expert', 'error-resilience-expert']
835
+ },
836
+ 'mobile-first': {
837
+ description: 'Mobile app stack: Expo, offline-first PWA, push notifications',
838
+ skills: ['mobile-expo-expert', 'pwa-offline-first-expert', 'authentication-identity-expert', 'api-design-expert', 'email-notification-expert']
839
+ },
840
+ 'data-platform': {
841
+ description: 'Data engineering: ETL pipelines, visualization, telemetry, analytics',
842
+ skills: ['data-pipeline-etl-expert', 'data-visualization-expert', 'data-telemetry-expert', 'search-engine-expert']
843
+ }
844
+ };
845
+
846
+ async function runRecipe(action, recipeName) {
847
+ if (!action || action === 'list') {
848
+ console.log('\n\ud83e\uddc9 Available Vibes-Plug Recipes:\n');
849
+ for (const [name, { description, skills }] of Object.entries(RECIPES)) {
850
+ console.log(` \x1b[36m${name}\x1b[0m`);
851
+ console.log(` ${description}`);
852
+ console.log(` Skills (${skills.length}): ${skills.join(', ')}\n`);
853
+ }
854
+ console.log('Usage: vibes recipe apply <recipe-name>');
855
+ rl.close();
856
+ return;
857
+ }
858
+
859
+ if (action === 'apply') {
860
+ if (!recipeName) {
861
+ console.error('\u274c Error: Recipe name required.');
862
+ console.log('Usage: vibes recipe apply <recipe-name>');
863
+ console.log('Run "vibes recipe list" to see available recipes.');
864
+ process.exit(1);
865
+ }
866
+
867
+ const recipe = RECIPES[recipeName];
868
+ if (!recipe) {
869
+ console.error(`\u274c Recipe '${recipeName}' not found.`);
870
+ console.log(`Available: ${Object.keys(RECIPES).join(', ')}`);
871
+ process.exit(1);
872
+ }
873
+
874
+ console.log(`\n\ud83e\uddc9 Applying recipe: ${recipeName}`);
875
+ console.log(`\ud83d\udcdd ${recipe.description}\n`);
876
+
877
+ const targetAgentsDir = path.join(process.cwd(), '.agents', 'skills');
878
+ await fs.mkdir(targetAgentsDir, { recursive: true });
879
+
880
+ let installed = 0, skipped = 0;
881
+ for (const skill of recipe.skills) {
882
+ const sourceDir = path.join(PLUGIN_ROOT, 'skills', skill);
883
+ const targetDir = path.join(targetAgentsDir, skill);
884
+ const alreadyInstalled = await fs.access(targetDir).then(() => true).catch(() => false);
885
+ if (alreadyInstalled) {
886
+ console.log(` \u23ed\ufe0f Already installed: ${skill}`);
887
+ skipped++;
888
+ } else {
889
+ const exists = await fs.access(sourceDir).then(() => true).catch(() => false);
890
+ if (exists) {
891
+ await fs.cp(sourceDir, targetDir, { recursive: true });
892
+ console.log(` \u2705 Installed: ${skill}`);
893
+ installed++;
894
+ } else {
895
+ console.warn(` \u26a0\ufe0f Not found in registry: ${skill}`);
896
+ }
897
+ }
898
+ }
899
+
900
+ console.log(`\n\ud83c\udf89 Recipe '${recipeName}' applied! ${installed} new, ${skipped} already installed.`);
901
+ console.log('\ud83d\udca1 Ask your AI agent to read the injected skills and begin development.');
902
+
903
+ } else {
904
+ console.error('\u274c Usage: vibes recipe list OR vibes recipe apply <name>');
905
+ process.exit(1);
906
+ }
907
+
908
+ rl.close();
909
+ }
910
+
911
+ async function runSearch(query) {
912
+ if (!query) {
913
+ console.error('\u274c Error: Search query required.');
914
+ console.log('Usage: vibes search <query>');
915
+ process.exit(1);
916
+ }
917
+
918
+ const skillsDir = path.join(PLUGIN_ROOT, 'skills');
919
+ const entries = await fs.readdir(skillsDir, { withFileTypes: true });
920
+ const skills = entries.filter(d => d.isDirectory()).map(d => d.name);
921
+
922
+ const q = query.toLowerCase();
923
+ const results = [];
924
+
925
+ for (const skill of skills) {
926
+ const skillMdPath = path.join(skillsDir, skill, 'SKILL.md');
927
+ try {
928
+ const content = await fs.readFile(skillMdPath, 'utf8');
929
+ const lower = content.toLowerCase();
930
+ // Score by keyword frequency
931
+ const score = (lower.match(new RegExp(q, 'g')) || []).length;
932
+ if (score > 0) {
933
+ // Extract description from frontmatter
934
+ const descMatch = content.match(/description:\s*["']?([^"'\n]{10,120})/);
935
+ const desc = descMatch ? descMatch[1].trim() : '';
936
+ results.push({ skill, score, desc });
937
+ }
938
+ } catch { /* skip unreadable */ }
939
+ }
940
+
941
+ results.sort((a, b) => b.score - a.score);
942
+
943
+ if (results.length === 0) {
944
+ console.log(`\n\ud83d\udd0d No skills found matching "${query}".`);
945
+ console.log('Try: vibes list to browse all 125 skills.');
946
+ } else {
947
+ console.log(`\n\ud83d\udd0d Found ${results.length} skill(s) matching "${query}":\n`);
948
+ results.slice(0, 10).forEach(({ skill, score, desc }) => {
949
+ console.log(` \x1b[36m${skill}\x1b[0m (relevance: ${score})`);
950
+ if (desc) console.log(` ${desc.slice(0, 100)}`);
951
+ });
952
+ if (results.length > 10) console.log(` ... and ${results.length - 10} more. Use "vibes list" to see all.`);
953
+ }
954
+
955
+ rl.close();
956
+ }
957
+
958
+ async function runSync() {
959
+ console.log('\nšŸ”„ Vibes-Plug Master Synchronizer (Pemicu Utama)...');
960
+ console.log('Verifying primary trigger configuration and cross-skill synchronization...\n');
961
+
962
+ const skillsDir = path.join(PLUGIN_ROOT, 'skills');
963
+ let skillCount = 0;
964
+ try {
965
+ const entries = await fs.readdir(skillsDir, { withFileTypes: true });
966
+ skillCount = entries.filter(e => e.isDirectory()).length;
967
+ } catch (e) {
968
+ console.error(`āŒ Could not read skills dir: ${e.message}`);
969
+ }
970
+
971
+ console.log(` āœ… Global Registry: ${skillCount} skills detected.`);
972
+
973
+ // Check platforms entry points
974
+ const checkFiles = [
975
+ { name: 'Antigravity (AGENTS.md)', file: path.join(PLUGIN_ROOT, 'AGENTS.md') },
976
+ { name: 'Claude Code (CLAUDE.md)', file: path.join(PLUGIN_ROOT, 'CLAUDE.md') },
977
+ { name: 'Cursor IDE (.cursorrules)', file: path.join(PLUGIN_ROOT, '.cursorrules') },
978
+ { name: 'Cursor Rules (.cursor/rules/vibes-plug-core.mdc)', file: path.join(PLUGIN_ROOT, '.cursor', 'rules', 'vibes-plug-core.mdc') },
979
+ { name: 'Claude Rules (.claude/rules/vibes-plug-core.md)', file: path.join(PLUGIN_ROOT, '.claude', 'rules', 'vibes-plug-core.md') }
980
+ ];
981
+
982
+ for (const item of checkFiles) {
983
+ try {
984
+ const content = await fs.readFile(item.file, 'utf8');
985
+ const hasTrigger = content.includes('PRIMARY TRIGGER') || content.includes('Pemicu Utama');
986
+ if (hasTrigger) {
987
+ console.log(` āœ… ${item.name}: Primary Trigger active & configured.`);
988
+ } else {
989
+ console.log(` āš ļø ${item.name}: Missing Primary Trigger directive.`);
990
+ }
991
+ } catch {
992
+ console.log(` ā„¹ļø ${item.name}: Not found.`);
993
+ }
994
+ }
995
+
996
+ // Check master orchestrators
997
+ const brainPath = path.join(skillsDir, 'brainstorming', 'SKILL.md');
998
+ const ztpPath = path.join(skillsDir, 'zero-to-prod-orchestrator', 'SKILL.md');
999
+ const hasBrain = await fs.access(brainPath).then(() => true).catch(() => false);
1000
+ const hasZtp = await fs.access(ztpPath).then(() => true).catch(() => false);
1001
+
1002
+ if (hasBrain && hasZtp) {
1003
+ console.log(` āœ… Master Orchestrators: brainstorming & zero-to-prod-orchestrator synchronized.`);
1004
+ } else {
1005
+ console.log(` āš ļø Master Orchestrators: check missing files.`);
1006
+ }
1007
+
1008
+ console.log('\n⚔ Vibes-Plug is operational as the PRIMARY TRIGGER (Pemicu Utama).');
1009
+ console.log(' All 127+ skills automatically synchronize when the user submits any coding prompt.\n');
1010
+ rl.close();
1011
+ }
1012
+
1013
+ function showHelp() {
1014
+ console.log(`
1015
+ 🌊 Vibes-Plug CLI (v3.9.0)
1016
+ The ultimate AI Swarm Orchestrator tool.
1017
+
1018
+ Usage:
1019
+ vibes <command> [options]
1020
+
1021
+ Commands:
1022
+ sync Verify and synchronize primary trigger & cross-skill orchestration
1023
+ init <project-name> Scaffold a new zero-to-prod 8-Phase project structure
1024
+ bootstrap <type> <name> Super-scaffold a project + AI Skills (saas | ecommerce | mobile | api | fullstack)
1025
+ ui Launch the interactive TUI to visually select and install skills
1026
+ list [filter] List all available skills (optional: filter by keyword)
1027
+ search <query> Search all 131 skills by keyword (ranked by relevance)
1028
+ add <skill-name> Inject a skill from the global registry into your local project
1029
+ remove <skill-name> Remove an installed skill from your local project (.agents/skills)
1030
+ skill info <skill-name> Show metadata, description, and orchestration info for a skill
1031
+ recipe list List all built-in skill bundles/recipes
1032
+ recipe apply <name> Apply a recipe bundle to your project (ai-stack, fullstack-pro, ...)
1033
+ create-skill <skill-name> Scaffold a new skill using the standard template (kebab-case)
1034
+ create-mcp <server-name> Scaffold a new Model Context Protocol (MCP) server
1035
+ version current Show current version
1036
+ version bump <type> Bump version across all files (type: major | minor | patch)
1037
+ hooks install Install Git pre-commit Anti-Slop gate
1038
+ hooks remove Remove the Git pre-commit hook
1039
+ doctor Run environment health diagnostics
1040
+ audit Run the strict Anti-AI Slop quality gate check
1041
+ validate Run the strict skill ecosystem validation check
1042
+ help Show this help menu
1043
+ `);
1044
+ rl.close();
1045
+ }
1046
+
1047
+ // Main Router
1048
+ switch (command) {
1049
+ case 'sync':
1050
+ runSync();
1051
+ break;
1052
+ case 'init':
1053
+ runInit(args[1]);
1054
+ break;
1055
+ case 'bootstrap':
1056
+ runBootstrap(args[1], args[2]);
1057
+ break;
1058
+ case 'ui':
1059
+ runUi();
1060
+ break;
1061
+ case 'list':
1062
+ runListSkills(args[1]);
1063
+ break;
1064
+ case 'search':
1065
+ runSearch(args[1]);
1066
+ break;
1067
+ case 'add':
1068
+ runAddSkill(args[1]);
1069
+ break;
1070
+ case 'remove':
1071
+ runRemoveSkill(args[1]);
1072
+ break;
1073
+ case 'recipe':
1074
+ runRecipe(args[1], args[2]);
1075
+ break;
1076
+ case 'version':
1077
+ runVersion(args[1], args[2]);
1078
+ break;
1079
+ case 'doctor':
1080
+ runDoctor();
1081
+ break;
1082
+ case 'skill':
1083
+ runSkillInfo(args[2]);
1084
+ break;
1085
+ case 'hooks':
1086
+ runHooks(args[1]);
1087
+ break;
1088
+ case 'create-skill':
1089
+ runCreateSkill(args[1]);
1090
+ break;
1091
+ case 'create-mcp':
1092
+ runCreateMcp(args[1]);
1093
+ break;
1094
+ case 'audit':
1095
+ runAudit();
1096
+ break;
1097
+ case 'validate':
1098
+ runValidate();
1099
+ break;
1100
+ default:
1101
+ showHelp();
1102
+ break;
1103
+ }
1104
+