@trieungoctam/vibekit 1.0.4 ā 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 +6 -0
- package/package.json +1 -1
- package/skills/utils/vk:write-skill/render-graphs.js +37 -32
- package/src/commands/update.js +124 -0
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
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
* Requires: graphviz (dot) installed on system
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
const fs = require(
|
|
17
|
-
const path = require(
|
|
18
|
-
const { execSync } = require(
|
|
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
|
|
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(
|
|
69
|
+
${bodies.join("\n\n")}
|
|
67
70
|
}`;
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
function renderToSvg(dotContent) {
|
|
71
74
|
try {
|
|
72
|
-
return execSync(
|
|
75
|
+
return execSync("dot -Tsvg", {
|
|
73
76
|
input: dotContent,
|
|
74
|
-
encoding:
|
|
75
|
-
maxBuffer: 10 * 1024 * 1024
|
|
77
|
+
encoding: "utf-8",
|
|
78
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
76
79
|
});
|
|
77
80
|
} catch (err) {
|
|
78
|
-
console.error(
|
|
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(
|
|
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(
|
|
91
|
-
console.error(
|
|
92
|
-
console.error(
|
|
93
|
-
console.error(
|
|
94
|
-
console.error(
|
|
95
|
-
console.error(
|
|
96
|
-
console.error(
|
|
97
|
-
console.error(
|
|
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,
|
|
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(
|
|
115
|
+
execSync("which dot", { encoding: "utf-8" });
|
|
113
116
|
} catch {
|
|
114
|
-
console.error(
|
|
115
|
-
console.error(
|
|
116
|
-
console.error(
|
|
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,
|
|
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(
|
|
127
|
+
console.log("No ```dot blocks found in", skillFile);
|
|
125
128
|
process.exit(0);
|
|
126
129
|
}
|
|
127
130
|
|
|
128
|
-
console.log(
|
|
131
|
+
console.log(
|
|
132
|
+
`Found ${blocks.length} diagram(s) in ${path.basename(skillDir)}/SKILL.md`,
|
|
133
|
+
);
|
|
129
134
|
|
|
130
|
-
const outputDir = path.join(skillDir,
|
|
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(
|
|
154
|
+
console.error(" Failed to render combined diagram");
|
|
150
155
|
}
|
|
151
156
|
} else {
|
|
152
157
|
// Render each separately
|
|
@@ -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
|
+
}
|