@trieungoctam/vibekit 1.0.2 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/vibekit.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { program } from 'commander';
3
3
  import { initCommand } from '../src/commands/init.js';
4
+ import { updateCommand } from '../src/commands/update.js';
4
5
 
5
6
  program
6
7
  .name('vibekit')
@@ -15,4 +16,9 @@ program
15
16
  .option('--force', 'Overwrite existing files')
16
17
  .action(initCommand);
17
18
 
19
+ program
20
+ .command('update')
21
+ .description('Update VibeKit to latest version')
22
+ .action(updateCommand);
23
+
18
24
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trieungoctam/vibekit",
3
- "version": "1.0.2",
3
+ "version": "1.0.5",
4
4
  "description": "Unified IDE configuration - setup rules/skills directly in your repo",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,9 +13,9 @@
13
13
  * Requires: graphviz (dot) installed on system
14
14
  */
15
15
 
16
- const fs = require('fs');
17
- const path = require('path');
18
- const { execSync } = require('child_process');
16
+ const fs = require("fs");
17
+ const path = require("path");
18
+ const { execSync } = require("child_process");
19
19
 
20
20
  function extractDotBlocks(markdown) {
21
21
  const blocks = [];
@@ -38,12 +38,12 @@ function extractDotBlocks(markdown) {
38
38
  function extractGraphBody(dotContent) {
39
39
  // Extract just the body (nodes and edges) from a digraph
40
40
  const match = dotContent.match(/digraph\s+\w+\s*\{([\s\S]*)\}/);
41
- if (!match) return '';
41
+ if (!match) return "";
42
42
 
43
43
  let body = match[1];
44
44
 
45
45
  // Remove rankdir (we'll set it once at the top level)
46
- body = body.replace(/^\s*rankdir\s*=\s*\w+\s*;?\s*$/gm, '');
46
+ body = body.replace(/^\s*rankdir\s*=\s*\w+\s*;?\s*$/gm, "");
47
47
 
48
48
  return body.trim();
49
49
  }
@@ -54,7 +54,10 @@ function combineGraphs(blocks, skillName) {
54
54
  // Wrap each subgraph in a cluster for visual grouping
55
55
  return ` subgraph cluster_${i} {
56
56
  label="${block.name}";
57
- ${body.split('\n').map(line => ' ' + line).join('\n')}
57
+ ${body
58
+ .split("\n")
59
+ .map((line) => " " + line)
60
+ .join("\n")}
58
61
  }`;
59
62
  });
60
63
 
@@ -63,19 +66,19 @@ function combineGraphs(blocks, skillName) {
63
66
  compound=true;
64
67
  newrank=true;
65
68
 
66
- ${bodies.join('\n\n')}
69
+ ${bodies.join("\n\n")}
67
70
  }`;
68
71
  }
69
72
 
70
73
  function renderToSvg(dotContent) {
71
74
  try {
72
- return execSync('dot -Tsvg', {
75
+ return execSync("dot -Tsvg", {
73
76
  input: dotContent,
74
- encoding: 'utf-8',
75
- maxBuffer: 10 * 1024 * 1024
77
+ encoding: "utf-8",
78
+ maxBuffer: 10 * 1024 * 1024,
76
79
  });
77
80
  } catch (err) {
78
- console.error('Error running dot:', err.message);
81
+ console.error("Error running dot:", err.message);
79
82
  if (err.stderr) console.error(err.stderr.toString());
80
83
  return null;
81
84
  }
@@ -83,24 +86,24 @@ function renderToSvg(dotContent) {
83
86
 
84
87
  function main() {
85
88
  const args = process.argv.slice(2);
86
- const combine = args.includes('--combine');
87
- const skillDirArg = args.find(a => !a.startsWith('--'));
89
+ const combine = args.includes("--combine");
90
+ const skillDirArg = args.find((a) => !a.startsWith("--"));
88
91
 
89
92
  if (!skillDirArg) {
90
- console.error('Usage: render-graphs.js <skill-directory> [--combine]');
91
- console.error('');
92
- console.error('Options:');
93
- console.error(' --combine Combine all diagrams into one SVG');
94
- console.error('');
95
- console.error('Example:');
96
- console.error(' ./render-graphs.js ../subagent-driven-development');
97
- console.error(' ./render-graphs.js ../subagent-driven-development --combine');
93
+ console.error("Usage: render-graphs.js <skill-directory> [--combine]");
94
+ console.error("");
95
+ console.error("Options:");
96
+ console.error(" --combine Combine all diagrams into one SVG");
97
+ console.error("");
98
+ console.error("Example:");
99
+ console.error(" ./render-graphs.js ../subagent-driven-development");
100
+ console.error(" ./render-graphs.js ../subagent-driven-development --combine");
98
101
  process.exit(1);
99
102
  }
100
103
 
101
104
  const skillDir = path.resolve(skillDirArg);
102
- const skillFile = path.join(skillDir, 'SKILL.md');
103
- const skillName = path.basename(skillDir).replace(/-/g, '_');
105
+ const skillFile = path.join(skillDir, "SKILL.md");
106
+ const skillName = path.basename(skillDir).replace(/-/g, "_");
104
107
 
105
108
  if (!fs.existsSync(skillFile)) {
106
109
  console.error(`Error: ${skillFile} not found`);
@@ -109,25 +112,27 @@ function main() {
109
112
 
110
113
  // Check if dot is available
111
114
  try {
112
- execSync('which dot', { encoding: 'utf-8' });
115
+ execSync("which dot", { encoding: "utf-8" });
113
116
  } catch {
114
- console.error('Error: graphviz (dot) not found. Install with:');
115
- console.error(' brew install graphviz # macOS');
116
- console.error(' apt install graphviz # Linux');
117
+ console.error("Error: graphviz (dot) not found. Install with:");
118
+ console.error(" brew install graphviz # macOS");
119
+ console.error(" apt install graphviz # Linux");
117
120
  process.exit(1);
118
121
  }
119
122
 
120
- const markdown = fs.readFileSync(skillFile, 'utf-8');
123
+ const markdown = fs.readFileSync(skillFile, "utf-8");
121
124
  const blocks = extractDotBlocks(markdown);
122
125
 
123
126
  if (blocks.length === 0) {
124
- console.log('No ```dot blocks found in', skillFile);
127
+ console.log("No ```dot blocks found in", skillFile);
125
128
  process.exit(0);
126
129
  }
127
130
 
128
- console.log(`Found ${blocks.length} diagram(s) in ${path.basename(skillDir)}/SKILL.md`);
131
+ console.log(
132
+ `Found ${blocks.length} diagram(s) in ${path.basename(skillDir)}/SKILL.md`,
133
+ );
129
134
 
130
- const outputDir = path.join(skillDir, 'diagrams');
135
+ const outputDir = path.join(skillDir, "diagrams");
131
136
  if (!fs.existsSync(outputDir)) {
132
137
  fs.mkdirSync(outputDir);
133
138
  }
@@ -146,7 +151,7 @@ function main() {
146
151
  fs.writeFileSync(dotPath, combined);
147
152
  console.log(` Source: ${skillName}_combined.dot`);
148
153
  } else {
149
- console.error(' Failed to render combined diagram');
154
+ console.error(" Failed to render combined diagram");
150
155
  }
151
156
  } else {
152
157
  // Render each separately
@@ -145,6 +145,22 @@ async function setupClaudeCode(targetDir, force) {
145
145
  const claudeDir = path.join(targetDir, '.claude');
146
146
  fs.ensureDirSync(claudeDir);
147
147
 
148
+ // Copy skills directly to .claude/skills (for slash commands)
149
+ const skillsDir = path.join(claudeDir, 'skills');
150
+ const srcSkills = path.join(VIBEKIT_ROOT, 'skills');
151
+ if (fs.existsSync(srcSkills)) {
152
+ fs.copySync(srcSkills, skillsDir, { overwrite: force });
153
+ console.log(chalk.gray(' ✓ .claude/skills/'));
154
+ }
155
+
156
+ // Copy agents to .claude/agents
157
+ const agentsDir = path.join(claudeDir, 'agents');
158
+ const srcAgents = path.join(VIBEKIT_ROOT, 'agents');
159
+ if (fs.existsSync(srcAgents)) {
160
+ fs.copySync(srcAgents, agentsDir, { overwrite: force });
161
+ console.log(chalk.gray(' ✓ .claude/agents/'));
162
+ }
163
+
148
164
  // CLAUDE.md
149
165
  const claudeMd = path.join(targetDir, 'CLAUDE.md');
150
166
  if (!fs.existsSync(claudeMd) || force) {
@@ -156,7 +172,7 @@ This project uses VibeKit for AI assistance.
156
172
  See \`.vibekit/rules/\` for development rules.
157
173
 
158
174
  ## Skills
159
- See \`.vibekit/skills/\` for available skills (all with \`vk:\` prefix).
175
+ See \`.claude/skills/\` for available skills (all with \`vk:\` prefix).
160
176
 
161
177
  ## Workflows
162
178
  - \`/vk:brainstorm\` - Design & brainstorm
@@ -214,13 +230,20 @@ async function setupCursor(targetDir, force) {
214
230
  const cursorDir = path.join(targetDir, '.cursor');
215
231
  fs.ensureDirSync(cursorDir);
216
232
 
217
- // rules symlink/folder reference
233
+ // Copy rules directly into .cursor/rules
218
234
  const rulesDir = path.join(cursorDir, 'rules');
219
- if (!fs.existsSync(rulesDir) || force) {
220
- fs.removeSync(rulesDir);
221
- // Create symlink to .vibekit/rules
222
- fs.symlinkSync(path.join(targetDir, '.vibekit/rules'), rulesDir, 'junction');
223
- console.log(chalk.gray(' ✓ .cursor/rules → .vibekit/rules'));
235
+ const srcRules = path.join(VIBEKIT_ROOT, 'rules');
236
+ if (fs.existsSync(srcRules)) {
237
+ fs.copySync(srcRules, rulesDir, { overwrite: force });
238
+ console.log(chalk.gray(' ✓ .cursor/rules/'));
239
+ }
240
+
241
+ // Copy skills directly into .cursor/skills
242
+ const skillsDir = path.join(cursorDir, 'skills');
243
+ const srcSkills = path.join(VIBEKIT_ROOT, 'skills');
244
+ if (fs.existsSync(srcSkills)) {
245
+ fs.copySync(srcSkills, skillsDir, { overwrite: force });
246
+ console.log(chalk.gray(' ✓ .cursor/skills/'));
224
247
  }
225
248
 
226
249
  await addToGitignore(targetDir, ['.cursor/']);
@@ -232,6 +255,22 @@ async function setupCodex(targetDir, force) {
232
255
  const codexDir = path.join(targetDir, '.codex');
233
256
  fs.ensureDirSync(codexDir);
234
257
 
258
+ // Copy agents directly into .codex/agents
259
+ const agentsDir = path.join(codexDir, 'agents');
260
+ const srcAgents = path.join(VIBEKIT_ROOT, 'agents');
261
+ if (fs.existsSync(srcAgents)) {
262
+ fs.copySync(srcAgents, agentsDir, { overwrite: force });
263
+ console.log(chalk.gray(' ✓ .codex/agents/'));
264
+ }
265
+
266
+ // Copy skills directly into .codex/skills
267
+ const skillsDir = path.join(codexDir, 'skills');
268
+ const srcSkills = path.join(VIBEKIT_ROOT, 'skills');
269
+ if (fs.existsSync(srcSkills)) {
270
+ fs.copySync(srcSkills, skillsDir, { overwrite: force });
271
+ console.log(chalk.gray(' ✓ .codex/skills/'));
272
+ }
273
+
235
274
  // AGENTS.md
236
275
  const agentsMd = path.join(targetDir, 'AGENTS.md');
237
276
  if (!fs.existsSync(agentsMd) || force) {
@@ -240,7 +279,10 @@ async function setupCodex(targetDir, force) {
240
279
  This project uses VibeKit for AI assistance.
241
280
 
242
281
  ## Available Agents
243
- See \`.vibekit/agents/\` for agent definitions.
282
+ See \`.codex/agents/\` for agent definitions.
283
+
284
+ ## Skills
285
+ See \`.codex/skills/\` for available skills (all with \`vk:\` prefix).
244
286
 
245
287
  `);
246
288
  console.log(chalk.gray(' ✓ AGENTS.md'));
@@ -252,14 +294,35 @@ See \`.vibekit/agents/\` for agent definitions.
252
294
  async function setupOpenCode(targetDir, force) {
253
295
  console.log(chalk.blue('\n🔶 Setting up OpenCode'));
254
296
 
297
+ const opencodeDir = path.join(targetDir, '.opencode');
298
+ fs.ensureDirSync(opencodeDir);
299
+
300
+ // Copy rules directly into .opencode/rules
301
+ const rulesDir = path.join(opencodeDir, 'rules');
302
+ const srcRules = path.join(VIBEKIT_ROOT, 'rules');
303
+ if (fs.existsSync(srcRules)) {
304
+ fs.copySync(srcRules, rulesDir, { overwrite: force });
305
+ console.log(chalk.gray(' ✓ .opencode/rules/'));
306
+ }
307
+
308
+ // Copy skills directly into .opencode/skills
309
+ const skillsDir = path.join(opencodeDir, 'skills');
310
+ const srcSkills = path.join(VIBEKIT_ROOT, 'skills');
311
+ if (fs.existsSync(srcSkills)) {
312
+ fs.copySync(srcSkills, skillsDir, { overwrite: force });
313
+ console.log(chalk.gray(' ✓ .opencode/skills/'));
314
+ }
315
+
255
316
  // opencode.json
256
317
  const opencodeJson = path.join(targetDir, 'opencode.json');
257
318
  if (!fs.existsSync(opencodeJson) || force) {
258
319
  fs.writeJsonSync(opencodeJson, {
259
- instructions: ['.vibekit/rules/*.md', 'CLAUDE.md']
320
+ instructions: ['.opencode/rules/*.md', 'CLAUDE.md']
260
321
  }, { spaces: 2 });
261
322
  console.log(chalk.gray(' ✓ opencode.json'));
262
323
  }
324
+
325
+ await addToGitignore(targetDir, ['.opencode/']);
263
326
  }
264
327
 
265
328
  async function addToGitignore(targetDir, entries) {
@@ -0,0 +1,124 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import chalk from 'chalk';
5
+ import { execSync } from 'child_process';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+ const VIBEKIT_ROOT = path.resolve(__dirname, '../../');
10
+
11
+ export async function updateCommand(options) {
12
+ const targetDir = process.cwd();
13
+
14
+ console.log(chalk.blue('\n🔄 VibeKit Update\n'));
15
+
16
+ // Check if .vibekit exists
17
+ const vibekitDir = path.join(targetDir, '.vibekit');
18
+ if (!fs.existsSync(vibekitDir)) {
19
+ console.log(chalk.red('VibeKit not initialized. Run `vibekit init` first.'));
20
+ return;
21
+ }
22
+
23
+ console.log(chalk.gray('Checking for updates...'));
24
+
25
+ try {
26
+ // Get current version
27
+ const currentPkg = fs.readJsonSync(path.join(VIBEKIT_ROOT, 'package.json'));
28
+ console.log(chalk.gray(`Current version: ${currentPkg.version}`));
29
+
30
+ // Check latest version on npm
31
+ let latestVersion;
32
+ try {
33
+ latestVersion = execSync('npm view @trieungoctam/vibekit version', { encoding: 'utf-8' }).trim();
34
+ console.log(chalk.gray(`Latest version: ${latestVersion}`));
35
+ } catch (e) {
36
+ console.log(chalk.yellow('Could not check npm registry, updating from local...'));
37
+ }
38
+
39
+ // Update folders
40
+ console.log(chalk.blue('\n📁 Updating files...'));
41
+
42
+ const folders = ['skills', 'agents', 'hooks', 'rules'];
43
+ for (const folder of folders) {
44
+ const src = path.join(VIBEKIT_ROOT, folder);
45
+ const dst = path.join(vibekitDir, folder);
46
+ if (fs.existsSync(src)) {
47
+ fs.removeSync(dst);
48
+ fs.copySync(src, dst);
49
+ console.log(chalk.gray(` ✓ ${folder}/`));
50
+ }
51
+ }
52
+
53
+ // Update .claude/skills if exists
54
+ const claudeDir = path.join(targetDir, '.claude');
55
+ if (fs.existsSync(claudeDir)) {
56
+ const claudeSkillsDir = path.join(claudeDir, 'skills');
57
+ const claudeAgentsDir = path.join(claudeDir, 'agents');
58
+
59
+ fs.removeSync(claudeSkillsDir);
60
+ fs.copySync(path.join(VIBEKIT_ROOT, 'skills'), claudeSkillsDir);
61
+ console.log(chalk.gray(' ✓ .claude/skills/'));
62
+
63
+ fs.removeSync(claudeAgentsDir);
64
+ fs.copySync(path.join(VIBEKIT_ROOT, 'agents'), claudeAgentsDir);
65
+ console.log(chalk.gray(' ✓ .claude/agents/'));
66
+ }
67
+
68
+ // Update .cursor if exists
69
+ const cursorDir = path.join(targetDir, '.cursor');
70
+ if (fs.existsSync(cursorDir)) {
71
+ const cursorRulesDir = path.join(cursorDir, 'rules');
72
+ const cursorSkillsDir = path.join(cursorDir, 'skills');
73
+
74
+ fs.removeSync(cursorRulesDir);
75
+ fs.copySync(path.join(VIBEKIT_ROOT, 'rules'), cursorRulesDir);
76
+ console.log(chalk.gray(' ✓ .cursor/rules/'));
77
+
78
+ fs.removeSync(cursorSkillsDir);
79
+ fs.copySync(path.join(VIBEKIT_ROOT, 'skills'), cursorSkillsDir);
80
+ console.log(chalk.gray(' ✓ .cursor/skills/'));
81
+ }
82
+
83
+ // Update .codex if exists
84
+ const codexDir = path.join(targetDir, '.codex');
85
+ if (fs.existsSync(codexDir)) {
86
+ const codexAgentsDir = path.join(codexDir, 'agents');
87
+ const codexSkillsDir = path.join(codexDir, 'skills');
88
+
89
+ fs.removeSync(codexAgentsDir);
90
+ fs.copySync(path.join(VIBEKIT_ROOT, 'agents'), codexAgentsDir);
91
+ console.log(chalk.gray(' ✓ .codex/agents/'));
92
+
93
+ fs.removeSync(codexSkillsDir);
94
+ fs.copySync(path.join(VIBEKIT_ROOT, 'skills'), codexSkillsDir);
95
+ console.log(chalk.gray(' ✓ .codex/skills/'));
96
+ }
97
+
98
+ // Update .opencode if exists
99
+ const opencodeDir = path.join(targetDir, '.opencode');
100
+ if (fs.existsSync(opencodeDir)) {
101
+ const opencodeRulesDir = path.join(opencodeDir, 'rules');
102
+ const opencodeSkillsDir = path.join(opencodeDir, 'skills');
103
+
104
+ fs.removeSync(opencodeRulesDir);
105
+ fs.copySync(path.join(VIBEKIT_ROOT, 'rules'), opencodeRulesDir);
106
+ console.log(chalk.gray(' ✓ .opencode/rules/'));
107
+
108
+ fs.removeSync(opencodeSkillsDir);
109
+ fs.copySync(path.join(VIBEKIT_ROOT, 'skills'), opencodeSkillsDir);
110
+ console.log(chalk.gray(' ✓ .opencode/skills/'));
111
+ }
112
+
113
+ console.log(chalk.green('\n✅ VibeKit updated!\n'));
114
+
115
+ if (latestVersion && latestVersion !== currentPkg.version) {
116
+ console.log(chalk.yellow(`New version available: ${latestVersion}`));
117
+ console.log(chalk.gray('Run: npm install -g @trieungoctam/vibekit@latest'));
118
+ }
119
+
120
+ } catch (error) {
121
+ console.log(chalk.red(`Update failed: ${error.message}`));
122
+ process.exit(1);
123
+ }
124
+ }