@vibeo/cli 0.2.0 → 0.3.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.
- package/dist/commands/install-skills.d.ts +8 -0
- package/dist/commands/install-skills.d.ts.map +1 -0
- package/dist/commands/install-skills.js +215 -0
- package/dist/commands/install-skills.js.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/install-skills.ts +246 -0
- package/src/index.ts +24 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-skills.d.ts","sourceRoot":"","sources":["../../src/commands/install-skills.ts"],"names":[],"mappings":"AAsNA,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EAAE,EACjB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;CAAE,CAAC,CAuBlD;AAED,eAAO,MAAM,iBAAiB;;;GAG3B,CAAC"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { join, dirname } from "node:path";
|
|
2
|
+
import { mkdir, writeFile, readFile } from "node:fs/promises";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Embedded skill content (so it works from npm without the skills/ dir)
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
async function loadSkills() {
|
|
9
|
+
// Try to load from the repo's skills/ directory first
|
|
10
|
+
const candidates = [
|
|
11
|
+
join(dirname(import.meta.url.replace("file://", "")), "../../../../skills"),
|
|
12
|
+
join(process.cwd(), "skills"),
|
|
13
|
+
];
|
|
14
|
+
for (const dir of candidates) {
|
|
15
|
+
const names = ["vibeo-core", "vibeo-audio", "vibeo-effects", "vibeo-extras", "vibeo-rendering"];
|
|
16
|
+
const skills = {};
|
|
17
|
+
let found = true;
|
|
18
|
+
for (const name of names) {
|
|
19
|
+
const path = join(dir, name, "SKILL.md");
|
|
20
|
+
if (existsSync(path)) {
|
|
21
|
+
skills[name] = await readFile(path, "utf-8");
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
found = false;
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (found)
|
|
29
|
+
return skills;
|
|
30
|
+
}
|
|
31
|
+
// Fallback: generate a minimal combined skill from --llms-full output
|
|
32
|
+
return {
|
|
33
|
+
vibeo: getEmbeddedSkill(),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function getEmbeddedSkill() {
|
|
37
|
+
return `# Vibeo — React Video Framework
|
|
38
|
+
|
|
39
|
+
Vibeo is a React-based programmatic video framework. Write video compositions as React components, preview in the browser, and render to video with FFmpeg.
|
|
40
|
+
|
|
41
|
+
## Quick Reference
|
|
42
|
+
|
|
43
|
+
\`\`\`bash
|
|
44
|
+
# Get full CLI docs
|
|
45
|
+
bunx @vibeo/cli --llms-full
|
|
46
|
+
|
|
47
|
+
# Create a project
|
|
48
|
+
bunx @vibeo/cli create my-video --template basic
|
|
49
|
+
|
|
50
|
+
# Preview
|
|
51
|
+
bunx @vibeo/cli preview --entry src/index.tsx
|
|
52
|
+
|
|
53
|
+
# Render
|
|
54
|
+
bunx @vibeo/cli render --entry src/index.tsx --composition MyComp
|
|
55
|
+
|
|
56
|
+
# List compositions
|
|
57
|
+
bunx @vibeo/cli list --entry src/index.tsx
|
|
58
|
+
\`\`\`
|
|
59
|
+
|
|
60
|
+
## Packages
|
|
61
|
+
|
|
62
|
+
- \`@vibeo/core\` — Composition, Sequence, Loop, useCurrentFrame, useVideoConfig, interpolate, easing
|
|
63
|
+
- \`@vibeo/audio\` — Audio/Video components, 48kHz sync, volume curves, audio mixing
|
|
64
|
+
- \`@vibeo/effects\` — useKeyframes, useSpring, Transition (fade/wipe/slide/dissolve), useAudioData
|
|
65
|
+
- \`@vibeo/extras\` — Subtitle (SRT/VTT), AudioWaveform, AudioSpectrogram, SceneGraph, AudioMix
|
|
66
|
+
- \`@vibeo/player\` — Interactive Player component with controls
|
|
67
|
+
- \`@vibeo/renderer\` — Headless rendering via Playwright + FFmpeg
|
|
68
|
+
- \`@vibeo/cli\` — CLI with incur (supports --llms, --mcp, --schema)
|
|
69
|
+
|
|
70
|
+
## Core Pattern
|
|
71
|
+
|
|
72
|
+
\`\`\`tsx
|
|
73
|
+
import { Composition, Sequence, VibeoRoot, useCurrentFrame, useVideoConfig, interpolate } from "@vibeo/core";
|
|
74
|
+
|
|
75
|
+
function MyScene() {
|
|
76
|
+
const frame = useCurrentFrame();
|
|
77
|
+
const { width, height, fps } = useVideoConfig();
|
|
78
|
+
const opacity = interpolate(frame, [0, 30], [0, 1], { extrapolateRight: "clamp" });
|
|
79
|
+
return <div style={{ width, height, opacity }}>Hello</div>;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function Root() {
|
|
83
|
+
return (
|
|
84
|
+
<VibeoRoot>
|
|
85
|
+
<Composition id="MyComp" component={MyScene} width={1920} height={1080} fps={30} durationInFrames={150} />
|
|
86
|
+
</VibeoRoot>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
\`\`\`
|
|
90
|
+
|
|
91
|
+
## Key Math
|
|
92
|
+
|
|
93
|
+
- Frame to time: \`time = frame / fps\`
|
|
94
|
+
- Samples per frame (audio): \`(48000 * 2) / fps\`
|
|
95
|
+
- Media time with playback rate: uses interpolation with rate scaling
|
|
96
|
+
- Sequence relative frame: \`absoluteFrame - (cumulatedFrom + relativeFrom)\`
|
|
97
|
+
- Loop iteration: \`floor(currentFrame / durationInFrames)\`
|
|
98
|
+
|
|
99
|
+
For full API details, run \`bunx @vibeo/cli --llms-full\` or \`bunx @vibeo/cli <command> --schema\`.
|
|
100
|
+
`;
|
|
101
|
+
}
|
|
102
|
+
const home = homedir();
|
|
103
|
+
const TARGETS = [
|
|
104
|
+
{
|
|
105
|
+
name: "claude",
|
|
106
|
+
description: "Claude Code (~/.claude/skills/ + project CLAUDE.md)",
|
|
107
|
+
async install(skills, cwd) {
|
|
108
|
+
const files = [];
|
|
109
|
+
// Global skills directory
|
|
110
|
+
const globalDir = join(home, ".claude", "skills");
|
|
111
|
+
await mkdir(globalDir, { recursive: true });
|
|
112
|
+
for (const [name, content] of Object.entries(skills)) {
|
|
113
|
+
const path = join(globalDir, `${name}.md`);
|
|
114
|
+
await writeFile(path, content);
|
|
115
|
+
files.push(path);
|
|
116
|
+
}
|
|
117
|
+
// Project-level .claude/skills/
|
|
118
|
+
const projectDir = join(cwd, ".claude", "skills");
|
|
119
|
+
await mkdir(projectDir, { recursive: true });
|
|
120
|
+
for (const [name, content] of Object.entries(skills)) {
|
|
121
|
+
const path = join(projectDir, `${name}.md`);
|
|
122
|
+
await writeFile(path, content);
|
|
123
|
+
files.push(path);
|
|
124
|
+
}
|
|
125
|
+
return files;
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
name: "codex",
|
|
130
|
+
description: "OpenAI Codex CLI (project AGENTS.md)",
|
|
131
|
+
async install(skills, cwd) {
|
|
132
|
+
const combined = Object.values(skills).join("\n\n---\n\n");
|
|
133
|
+
const path = join(cwd, "AGENTS.md");
|
|
134
|
+
const header = "# Vibeo — Agent Instructions\n\nThis file is auto-generated by `vibeo install-skills`. It helps Codex CLI understand the Vibeo framework.\n\n";
|
|
135
|
+
await writeFile(path, header + combined);
|
|
136
|
+
return [path];
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: "cursor",
|
|
141
|
+
description: "Cursor (.cursor/rules/*.mdc)",
|
|
142
|
+
async install(skills, cwd) {
|
|
143
|
+
const dir = join(cwd, ".cursor", "rules");
|
|
144
|
+
await mkdir(dir, { recursive: true });
|
|
145
|
+
const files = [];
|
|
146
|
+
for (const [name, content] of Object.entries(skills)) {
|
|
147
|
+
const mdcContent = `---\ndescription: ${name} skill for Vibeo video framework\nglobs: **/*.{ts,tsx}\nalwaysApply: false\n---\n\n${content}`;
|
|
148
|
+
const path = join(dir, `${name}.mdc`);
|
|
149
|
+
await writeFile(path, mdcContent);
|
|
150
|
+
files.push(path);
|
|
151
|
+
}
|
|
152
|
+
return files;
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
name: "gemini",
|
|
157
|
+
description: "Gemini CLI (GEMINI.md)",
|
|
158
|
+
async install(skills, cwd) {
|
|
159
|
+
const combined = Object.values(skills).join("\n\n---\n\n");
|
|
160
|
+
const path = join(cwd, "GEMINI.md");
|
|
161
|
+
const header = "# Vibeo — Gemini Instructions\n\nThis file is auto-generated by `vibeo install-skills`. It helps Gemini CLI understand the Vibeo framework.\n\n";
|
|
162
|
+
await writeFile(path, header + combined);
|
|
163
|
+
return [path];
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: "opencode",
|
|
168
|
+
description: "OpenCode (AGENTS.md)",
|
|
169
|
+
async install(skills, cwd) {
|
|
170
|
+
// OpenCode also reads AGENTS.md — same as codex, but we don't double-write
|
|
171
|
+
const path = join(cwd, "AGENTS.md");
|
|
172
|
+
if (existsSync(path))
|
|
173
|
+
return []; // Already written by codex target
|
|
174
|
+
const combined = Object.values(skills).join("\n\n---\n\n");
|
|
175
|
+
const header = "# Vibeo — Agent Instructions\n\nThis file is auto-generated by `vibeo install-skills`. It helps AI agents understand the Vibeo framework.\n\n";
|
|
176
|
+
await writeFile(path, header + combined);
|
|
177
|
+
return [path];
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
name: "aider",
|
|
182
|
+
description: "Aider (.aider.conf.yml conventions file reference)",
|
|
183
|
+
async install(skills, cwd) {
|
|
184
|
+
const combined = Object.values(skills).join("\n\n---\n\n");
|
|
185
|
+
const path = join(cwd, ".aider.vibeo.md");
|
|
186
|
+
await writeFile(path, combined);
|
|
187
|
+
return [path];
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
];
|
|
191
|
+
// ---------------------------------------------------------------------------
|
|
192
|
+
// Public API
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
194
|
+
export async function installSkills(targets, cwd) {
|
|
195
|
+
const skills = await loadSkills();
|
|
196
|
+
const installed = {};
|
|
197
|
+
const selectedTargets = targets.length === 0
|
|
198
|
+
? TARGETS // all
|
|
199
|
+
: TARGETS.filter((t) => targets.includes(t.name));
|
|
200
|
+
if (selectedTargets.length === 0) {
|
|
201
|
+
throw new Error(`No matching targets. Available: ${TARGETS.map((t) => t.name).join(", ")}`);
|
|
202
|
+
}
|
|
203
|
+
for (const target of selectedTargets) {
|
|
204
|
+
const files = await target.install(skills, cwd);
|
|
205
|
+
if (files.length > 0) {
|
|
206
|
+
installed[target.name] = files;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return { installed };
|
|
210
|
+
}
|
|
211
|
+
export const AVAILABLE_TARGETS = TARGETS.map((t) => ({
|
|
212
|
+
name: t.name,
|
|
213
|
+
description: t.description,
|
|
214
|
+
}));
|
|
215
|
+
//# sourceMappingURL=install-skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-skills.js","sourceRoot":"","sources":["../../src/commands/install-skills.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { createProject } from "./commands/create.js";
|
|
|
5
5
|
import { startPreview } from "./commands/preview.js";
|
|
6
6
|
import { listCompositions } from "./commands/list.js";
|
|
7
7
|
import { renderVideo } from "./commands/render.js";
|
|
8
|
+
import { installSkills } from "./commands/install-skills.js";
|
|
8
9
|
const cli = Cli.create("vibeo", {
|
|
9
10
|
description: "React-based programmatic video framework CLI",
|
|
10
11
|
sync: {
|
|
@@ -101,5 +102,24 @@ cli.command("list", {
|
|
|
101
102
|
return { compositions };
|
|
102
103
|
},
|
|
103
104
|
});
|
|
105
|
+
cli.command("install-skills", {
|
|
106
|
+
description: "Install Vibeo skill/rule files for all supported LLM coding tools (Claude, Codex, Cursor, Gemini, OpenCode, Aider)",
|
|
107
|
+
options: z.object({
|
|
108
|
+
targets: z
|
|
109
|
+
.string()
|
|
110
|
+
.optional()
|
|
111
|
+
.describe('Comma-separated list of targets (default: all). Options: claude, codex, cursor, gemini, opencode, aider'),
|
|
112
|
+
}),
|
|
113
|
+
examples: [
|
|
114
|
+
{ description: "Install for all supported tools" },
|
|
115
|
+
{ options: { targets: "claude,cursor" }, description: "Install for Claude and Cursor only" },
|
|
116
|
+
],
|
|
117
|
+
async run(c) {
|
|
118
|
+
const targets = c.options.targets
|
|
119
|
+
? c.options.targets.split(",").map((t) => t.trim())
|
|
120
|
+
: [];
|
|
121
|
+
return await installSkills(targets, process.cwd());
|
|
122
|
+
},
|
|
123
|
+
});
|
|
104
124
|
cli.serve();
|
|
105
125
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { resolve, join, dirname } from "node:path";
|
|
2
|
+
import { mkdir, writeFile, readFile } from "node:fs/promises";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Embedded skill content (so it works from npm without the skills/ dir)
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
async function loadSkills(): Promise<Record<string, string>> {
|
|
11
|
+
// Try to load from the repo's skills/ directory first
|
|
12
|
+
const candidates = [
|
|
13
|
+
join(dirname(import.meta.url.replace("file://", "")), "../../../../skills"),
|
|
14
|
+
join(process.cwd(), "skills"),
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
for (const dir of candidates) {
|
|
18
|
+
const names = ["vibeo-core", "vibeo-audio", "vibeo-effects", "vibeo-extras", "vibeo-rendering"];
|
|
19
|
+
const skills: Record<string, string> = {};
|
|
20
|
+
let found = true;
|
|
21
|
+
|
|
22
|
+
for (const name of names) {
|
|
23
|
+
const path = join(dir, name, "SKILL.md");
|
|
24
|
+
if (existsSync(path)) {
|
|
25
|
+
skills[name] = await readFile(path, "utf-8");
|
|
26
|
+
} else {
|
|
27
|
+
found = false;
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (found) return skills;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Fallback: generate a minimal combined skill from --llms-full output
|
|
36
|
+
return {
|
|
37
|
+
vibeo: getEmbeddedSkill(),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getEmbeddedSkill(): string {
|
|
42
|
+
return `# Vibeo — React Video Framework
|
|
43
|
+
|
|
44
|
+
Vibeo is a React-based programmatic video framework. Write video compositions as React components, preview in the browser, and render to video with FFmpeg.
|
|
45
|
+
|
|
46
|
+
## Quick Reference
|
|
47
|
+
|
|
48
|
+
\`\`\`bash
|
|
49
|
+
# Get full CLI docs
|
|
50
|
+
bunx @vibeo/cli --llms-full
|
|
51
|
+
|
|
52
|
+
# Create a project
|
|
53
|
+
bunx @vibeo/cli create my-video --template basic
|
|
54
|
+
|
|
55
|
+
# Preview
|
|
56
|
+
bunx @vibeo/cli preview --entry src/index.tsx
|
|
57
|
+
|
|
58
|
+
# Render
|
|
59
|
+
bunx @vibeo/cli render --entry src/index.tsx --composition MyComp
|
|
60
|
+
|
|
61
|
+
# List compositions
|
|
62
|
+
bunx @vibeo/cli list --entry src/index.tsx
|
|
63
|
+
\`\`\`
|
|
64
|
+
|
|
65
|
+
## Packages
|
|
66
|
+
|
|
67
|
+
- \`@vibeo/core\` — Composition, Sequence, Loop, useCurrentFrame, useVideoConfig, interpolate, easing
|
|
68
|
+
- \`@vibeo/audio\` — Audio/Video components, 48kHz sync, volume curves, audio mixing
|
|
69
|
+
- \`@vibeo/effects\` — useKeyframes, useSpring, Transition (fade/wipe/slide/dissolve), useAudioData
|
|
70
|
+
- \`@vibeo/extras\` — Subtitle (SRT/VTT), AudioWaveform, AudioSpectrogram, SceneGraph, AudioMix
|
|
71
|
+
- \`@vibeo/player\` — Interactive Player component with controls
|
|
72
|
+
- \`@vibeo/renderer\` — Headless rendering via Playwright + FFmpeg
|
|
73
|
+
- \`@vibeo/cli\` — CLI with incur (supports --llms, --mcp, --schema)
|
|
74
|
+
|
|
75
|
+
## Core Pattern
|
|
76
|
+
|
|
77
|
+
\`\`\`tsx
|
|
78
|
+
import { Composition, Sequence, VibeoRoot, useCurrentFrame, useVideoConfig, interpolate } from "@vibeo/core";
|
|
79
|
+
|
|
80
|
+
function MyScene() {
|
|
81
|
+
const frame = useCurrentFrame();
|
|
82
|
+
const { width, height, fps } = useVideoConfig();
|
|
83
|
+
const opacity = interpolate(frame, [0, 30], [0, 1], { extrapolateRight: "clamp" });
|
|
84
|
+
return <div style={{ width, height, opacity }}>Hello</div>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function Root() {
|
|
88
|
+
return (
|
|
89
|
+
<VibeoRoot>
|
|
90
|
+
<Composition id="MyComp" component={MyScene} width={1920} height={1080} fps={30} durationInFrames={150} />
|
|
91
|
+
</VibeoRoot>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
\`\`\`
|
|
95
|
+
|
|
96
|
+
## Key Math
|
|
97
|
+
|
|
98
|
+
- Frame to time: \`time = frame / fps\`
|
|
99
|
+
- Samples per frame (audio): \`(48000 * 2) / fps\`
|
|
100
|
+
- Media time with playback rate: uses interpolation with rate scaling
|
|
101
|
+
- Sequence relative frame: \`absoluteFrame - (cumulatedFrom + relativeFrom)\`
|
|
102
|
+
- Loop iteration: \`floor(currentFrame / durationInFrames)\`
|
|
103
|
+
|
|
104
|
+
For full API details, run \`bunx @vibeo/cli --llms-full\` or \`bunx @vibeo/cli <command> --schema\`.
|
|
105
|
+
`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
// LLM tool targets
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
|
|
112
|
+
interface Target {
|
|
113
|
+
name: string;
|
|
114
|
+
description: string;
|
|
115
|
+
install: (skills: Record<string, string>, cwd: string) => Promise<string[]>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const home = homedir();
|
|
119
|
+
|
|
120
|
+
const TARGETS: Target[] = [
|
|
121
|
+
{
|
|
122
|
+
name: "claude",
|
|
123
|
+
description: "Claude Code (~/.claude/skills/ + project CLAUDE.md)",
|
|
124
|
+
async install(skills, cwd) {
|
|
125
|
+
const files: string[] = [];
|
|
126
|
+
|
|
127
|
+
// Global skills directory
|
|
128
|
+
const globalDir = join(home, ".claude", "skills");
|
|
129
|
+
await mkdir(globalDir, { recursive: true });
|
|
130
|
+
for (const [name, content] of Object.entries(skills)) {
|
|
131
|
+
const path = join(globalDir, `${name}.md`);
|
|
132
|
+
await writeFile(path, content);
|
|
133
|
+
files.push(path);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Project-level .claude/skills/
|
|
137
|
+
const projectDir = join(cwd, ".claude", "skills");
|
|
138
|
+
await mkdir(projectDir, { recursive: true });
|
|
139
|
+
for (const [name, content] of Object.entries(skills)) {
|
|
140
|
+
const path = join(projectDir, `${name}.md`);
|
|
141
|
+
await writeFile(path, content);
|
|
142
|
+
files.push(path);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return files;
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
name: "codex",
|
|
150
|
+
description: "OpenAI Codex CLI (project AGENTS.md)",
|
|
151
|
+
async install(skills, cwd) {
|
|
152
|
+
const combined = Object.values(skills).join("\n\n---\n\n");
|
|
153
|
+
const path = join(cwd, "AGENTS.md");
|
|
154
|
+
const header = "# Vibeo — Agent Instructions\n\nThis file is auto-generated by `vibeo install-skills`. It helps Codex CLI understand the Vibeo framework.\n\n";
|
|
155
|
+
await writeFile(path, header + combined);
|
|
156
|
+
return [path];
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: "cursor",
|
|
161
|
+
description: "Cursor (.cursor/rules/*.mdc)",
|
|
162
|
+
async install(skills, cwd) {
|
|
163
|
+
const dir = join(cwd, ".cursor", "rules");
|
|
164
|
+
await mkdir(dir, { recursive: true });
|
|
165
|
+
const files: string[] = [];
|
|
166
|
+
for (const [name, content] of Object.entries(skills)) {
|
|
167
|
+
const mdcContent = `---\ndescription: ${name} skill for Vibeo video framework\nglobs: **/*.{ts,tsx}\nalwaysApply: false\n---\n\n${content}`;
|
|
168
|
+
const path = join(dir, `${name}.mdc`);
|
|
169
|
+
await writeFile(path, mdcContent);
|
|
170
|
+
files.push(path);
|
|
171
|
+
}
|
|
172
|
+
return files;
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: "gemini",
|
|
177
|
+
description: "Gemini CLI (GEMINI.md)",
|
|
178
|
+
async install(skills, cwd) {
|
|
179
|
+
const combined = Object.values(skills).join("\n\n---\n\n");
|
|
180
|
+
const path = join(cwd, "GEMINI.md");
|
|
181
|
+
const header = "# Vibeo — Gemini Instructions\n\nThis file is auto-generated by `vibeo install-skills`. It helps Gemini CLI understand the Vibeo framework.\n\n";
|
|
182
|
+
await writeFile(path, header + combined);
|
|
183
|
+
return [path];
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
name: "opencode",
|
|
188
|
+
description: "OpenCode (AGENTS.md)",
|
|
189
|
+
async install(skills, cwd) {
|
|
190
|
+
// OpenCode also reads AGENTS.md — same as codex, but we don't double-write
|
|
191
|
+
const path = join(cwd, "AGENTS.md");
|
|
192
|
+
if (existsSync(path)) return []; // Already written by codex target
|
|
193
|
+
const combined = Object.values(skills).join("\n\n---\n\n");
|
|
194
|
+
const header = "# Vibeo — Agent Instructions\n\nThis file is auto-generated by `vibeo install-skills`. It helps AI agents understand the Vibeo framework.\n\n";
|
|
195
|
+
await writeFile(path, header + combined);
|
|
196
|
+
return [path];
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
name: "aider",
|
|
201
|
+
description: "Aider (.aider.conf.yml conventions file reference)",
|
|
202
|
+
async install(skills, cwd) {
|
|
203
|
+
const combined = Object.values(skills).join("\n\n---\n\n");
|
|
204
|
+
const path = join(cwd, ".aider.vibeo.md");
|
|
205
|
+
await writeFile(path, combined);
|
|
206
|
+
return [path];
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
];
|
|
210
|
+
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
// Public API
|
|
213
|
+
// ---------------------------------------------------------------------------
|
|
214
|
+
|
|
215
|
+
export async function installSkills(
|
|
216
|
+
targets: string[],
|
|
217
|
+
cwd: string,
|
|
218
|
+
): Promise<{ installed: Record<string, string[]> }> {
|
|
219
|
+
const skills = await loadSkills();
|
|
220
|
+
const installed: Record<string, string[]> = {};
|
|
221
|
+
|
|
222
|
+
const selectedTargets =
|
|
223
|
+
targets.length === 0
|
|
224
|
+
? TARGETS // all
|
|
225
|
+
: TARGETS.filter((t) => targets.includes(t.name));
|
|
226
|
+
|
|
227
|
+
if (selectedTargets.length === 0) {
|
|
228
|
+
throw new Error(
|
|
229
|
+
`No matching targets. Available: ${TARGETS.map((t) => t.name).join(", ")}`,
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
for (const target of selectedTargets) {
|
|
234
|
+
const files = await target.install(skills, cwd);
|
|
235
|
+
if (files.length > 0) {
|
|
236
|
+
installed[target.name] = files;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return { installed };
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export const AVAILABLE_TARGETS = TARGETS.map((t) => ({
|
|
244
|
+
name: t.name,
|
|
245
|
+
description: t.description,
|
|
246
|
+
}));
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { createProject } from "./commands/create.js";
|
|
|
5
5
|
import { startPreview } from "./commands/preview.js";
|
|
6
6
|
import { listCompositions } from "./commands/list.js";
|
|
7
7
|
import { renderVideo } from "./commands/render.js";
|
|
8
|
+
import { installSkills } from "./commands/install-skills.js";
|
|
8
9
|
|
|
9
10
|
const cli = Cli.create("vibeo", {
|
|
10
11
|
description: "React-based programmatic video framework CLI",
|
|
@@ -107,4 +108,27 @@ cli.command("list", {
|
|
|
107
108
|
},
|
|
108
109
|
});
|
|
109
110
|
|
|
111
|
+
cli.command("install-skills", {
|
|
112
|
+
description:
|
|
113
|
+
"Install Vibeo skill/rule files for all supported LLM coding tools (Claude, Codex, Cursor, Gemini, OpenCode, Aider)",
|
|
114
|
+
options: z.object({
|
|
115
|
+
targets: z
|
|
116
|
+
.string()
|
|
117
|
+
.optional()
|
|
118
|
+
.describe(
|
|
119
|
+
'Comma-separated list of targets (default: all). Options: claude, codex, cursor, gemini, opencode, aider',
|
|
120
|
+
),
|
|
121
|
+
}),
|
|
122
|
+
examples: [
|
|
123
|
+
{ description: "Install for all supported tools" },
|
|
124
|
+
{ options: { targets: "claude,cursor" }, description: "Install for Claude and Cursor only" },
|
|
125
|
+
],
|
|
126
|
+
async run(c) {
|
|
127
|
+
const targets = c.options.targets
|
|
128
|
+
? c.options.targets.split(",").map((t: string) => t.trim())
|
|
129
|
+
: [];
|
|
130
|
+
return await installSkills(targets, process.cwd());
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
|
|
110
134
|
cli.serve();
|