vidgen 0.0.1

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 (61) hide show
  1. package/README.md +781 -0
  2. package/bin/dev.cmd +3 -0
  3. package/bin/dev.js +5 -0
  4. package/bin/run.cmd +3 -0
  5. package/bin/run.js +5 -0
  6. package/dist/commands/db/init.d.ts +6 -0
  7. package/dist/commands/db/init.js +18 -0
  8. package/dist/commands/generate/stt.d.ts +13 -0
  9. package/dist/commands/generate/stt.js +73 -0
  10. package/dist/commands/generate/tts.d.ts +11 -0
  11. package/dist/commands/generate/tts.js +30 -0
  12. package/dist/commands/index/chunk.d.ts +11 -0
  13. package/dist/commands/index/chunk.js +55 -0
  14. package/dist/commands/index/describe.d.ts +11 -0
  15. package/dist/commands/index/describe.js +29 -0
  16. package/dist/commands/index/embed.d.ts +11 -0
  17. package/dist/commands/index/embed.js +29 -0
  18. package/dist/commands/index/save.d.ts +10 -0
  19. package/dist/commands/index/save.js +24 -0
  20. package/dist/commands/project/create.d.ts +11 -0
  21. package/dist/commands/project/create.js +63 -0
  22. package/dist/commands/project/delete.d.ts +9 -0
  23. package/dist/commands/project/delete.js +31 -0
  24. package/dist/commands/project/get.d.ts +9 -0
  25. package/dist/commands/project/get.js +39 -0
  26. package/dist/commands/project/list.d.ts +6 -0
  27. package/dist/commands/project/list.js +26 -0
  28. package/dist/commands/project/validate.d.ts +10 -0
  29. package/dist/commands/project/validate.js +29 -0
  30. package/dist/commands/search/asset.d.ts +12 -0
  31. package/dist/commands/search/asset.js +35 -0
  32. package/dist/commands/segment/add.d.ts +11 -0
  33. package/dist/commands/segment/add.js +49 -0
  34. package/dist/commands/segment/delete.d.ts +9 -0
  35. package/dist/commands/segment/delete.js +29 -0
  36. package/dist/commands/segment/list.d.ts +9 -0
  37. package/dist/commands/segment/list.js +33 -0
  38. package/dist/commands/segment/update.d.ts +13 -0
  39. package/dist/commands/segment/update.js +50 -0
  40. package/dist/commands/video/caption.d.ts +12 -0
  41. package/dist/commands/video/caption.js +43 -0
  42. package/dist/commands/video/trim.d.ts +13 -0
  43. package/dist/commands/video/trim.js +52 -0
  44. package/dist/index.d.ts +1 -0
  45. package/dist/index.js +1 -0
  46. package/dist/lib/db.d.ts +7 -0
  47. package/dist/lib/db.js +39 -0
  48. package/dist/lib/stt/deepgram-to-combo.d.ts +2 -0
  49. package/dist/lib/stt/deepgram-to-combo.js +49 -0
  50. package/dist/lib/stt/deepgram.d.ts +18 -0
  51. package/dist/lib/stt/deepgram.js +71 -0
  52. package/dist/lib/stt/detect-language.d.ts +2 -0
  53. package/dist/lib/stt/detect-language.js +31 -0
  54. package/dist/lib/stt/index.d.ts +50 -0
  55. package/dist/lib/stt/index.js +50 -0
  56. package/dist/lib/stt/types.d.ts +65 -0
  57. package/dist/lib/stt/types.js +1 -0
  58. package/dist/lib/types.d.ts +131 -0
  59. package/dist/lib/types.js +1 -0
  60. package/oclif.manifest.json +874 -0
  61. package/package.json +79 -0
package/bin/dev.cmd ADDED
@@ -0,0 +1,3 @@
1
+ @echo off
2
+
3
+ node --loader ts-node/esm --no-warnings=ExperimentalWarning "%~dp0\dev" %*
package/bin/dev.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env -S node --loader ts-node/esm --disable-warning=ExperimentalWarning
2
+
3
+ import {execute} from '@oclif/core'
4
+
5
+ await execute({development: true, dir: import.meta.url})
package/bin/run.cmd ADDED
@@ -0,0 +1,3 @@
1
+ @echo off
2
+
3
+ node "%~dp0\run" %*
package/bin/run.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import {execute} from '@oclif/core'
4
+
5
+ await execute({dir: import.meta.url})
@@ -0,0 +1,6 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class DbInit extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
@@ -0,0 +1,18 @@
1
+ import { Command } from '@oclif/core';
2
+ import { initDb } from '../../lib/db.js';
3
+ export default class DbInit extends Command {
4
+ static description = 'Initialize the Turso database schema (projects and segments tables).';
5
+ static examples = [
6
+ '<%= config.bin %> <%= command.id %>',
7
+ ];
8
+ async run() {
9
+ this.log('Initializing database...');
10
+ try {
11
+ await initDb();
12
+ this.log('Database initialized successfully.');
13
+ }
14
+ catch (error) {
15
+ this.error(`Failed to initialize database: ${error instanceof Error ? error.message : error}`);
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,13 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class GenerateStt extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ audio: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
+ language: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
+ model: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
+ output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
+ segmentId: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ };
12
+ run(): Promise<void>;
13
+ }
@@ -0,0 +1,73 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { transcribe } from '../../lib/stt/index.js';
3
+ export default class GenerateStt extends Command {
4
+ static description = 'Generate a Speech-to-Text (STT) transcript from an audio file using Deepgram. Populates the SpeechToText object in a Segment.';
5
+ static examples = [
6
+ '<%= config.bin %> <%= command.id %> --audio https://storage.example.com/seg_001.mp3 --output ./captions/seg_001.json',
7
+ ];
8
+ static flags = {
9
+ audio: Flags.string({
10
+ char: 'a',
11
+ description: 'URL or local path to the audio file to transcribe',
12
+ required: true,
13
+ }),
14
+ language: Flags.string({
15
+ char: 'l',
16
+ description: 'Target language for transcription (e.g. "en"). Omit for auto-detection.',
17
+ }),
18
+ model: Flags.string({
19
+ char: 'm',
20
+ default: 'nova-3',
21
+ description: 'Deepgram model to use',
22
+ }),
23
+ output: Flags.string({
24
+ char: 'o',
25
+ description: 'Path to write the transcript JSON output',
26
+ required: true,
27
+ }),
28
+ segmentId: Flags.string({
29
+ char: 's',
30
+ description: 'Segment ID to update with the STT result',
31
+ }),
32
+ };
33
+ async run() {
34
+ const { flags } = await this.parse(GenerateStt);
35
+ this.log(`[generate:stt] Transcribing: ${flags.audio} → ${flags.output}`);
36
+ const result = await transcribe({
37
+ language: flags.language,
38
+ model: flags.model,
39
+ url: flags.audio,
40
+ });
41
+ const fs = await import('node:fs/promises');
42
+ await fs.writeFile(flags.output, JSON.stringify(result, null, 2), 'utf8');
43
+ this.log(`[generate:stt] Done. Duration: ${result.duration}s`);
44
+ const sttData = {
45
+ duration: result.duration,
46
+ refId: result.id,
47
+ src: flags.output,
48
+ };
49
+ if (flags.segmentId) {
50
+ try {
51
+ const { getDb } = await import('../../lib/db.js');
52
+ const db = getDb();
53
+ const row = await db.execute({
54
+ args: [flags.segmentId],
55
+ sql: 'SELECT data FROM segments WHERE id = ?',
56
+ });
57
+ if (row.rows.length > 0) {
58
+ const segmentData = JSON.parse(row.rows[0].data);
59
+ segmentData.speechToText = sttData;
60
+ await db.execute({
61
+ args: [JSON.stringify(segmentData), flags.segmentId],
62
+ sql: 'UPDATE segments SET data = ? WHERE id = ?',
63
+ });
64
+ this.log(`[generate:stt] Database updated for segment ${flags.segmentId}`);
65
+ }
66
+ }
67
+ catch (error) {
68
+ this.error(`Failed to update database: ${error instanceof Error ? error.message : error}`);
69
+ }
70
+ }
71
+ this.log(JSON.stringify(sttData));
72
+ }
73
+ }
@@ -0,0 +1,11 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class GenerateTts extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
+ text: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
+ voiceId: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
+ };
10
+ run(): Promise<void>;
11
+ }
@@ -0,0 +1,30 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ export default class GenerateTts extends Command {
3
+ static description = 'Generate a Text-to-Speech (TTS) audio file from a script. Populates the TextToSpeech object in a Segment.';
4
+ static examples = [
5
+ '<%= config.bin %> <%= command.id %> --text "Blockchain is revolutionizing..." --voiceId en-US-1 --output ./audio/seg_001.mp3',
6
+ ];
7
+ static flags = {
8
+ output: Flags.string({
9
+ char: 'o',
10
+ description: 'Path or URL to write the generated audio file',
11
+ required: true,
12
+ }),
13
+ text: Flags.string({
14
+ char: 't',
15
+ description: 'The script text to convert to speech',
16
+ required: true,
17
+ }),
18
+ voiceId: Flags.string({
19
+ char: 'v',
20
+ description: 'Voice ID to use for the TTS provider (e.g. ElevenLabs, OpenAI)',
21
+ required: true,
22
+ }),
23
+ };
24
+ async run() {
25
+ const { flags } = await this.parse(GenerateTts);
26
+ this.log(`[generate:tts] Generating audio with voice "${flags.voiceId}" → ${flags.output}`);
27
+ // TODO: call TTS provider and write { refId, src, duration } to stdout as JSON
28
+ // Output shape: TextToSpeech { refId: string, src: string, duration: number }
29
+ }
30
+ }
@@ -0,0 +1,11 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class IndexChunk extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ duration: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
7
+ output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
+ url: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
+ };
10
+ run(): Promise<void>;
11
+ }
@@ -0,0 +1,55 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ export default class IndexChunk extends Command {
3
+ static description = 'Slice a video into fixed-duration chunks and extract keyframes for downstream analysis.';
4
+ static examples = [
5
+ '<%= config.bin %> <%= command.id %> --url ./video.mp4 --duration 5 --output ./chunks',
6
+ ];
7
+ static flags = {
8
+ duration: Flags.integer({
9
+ char: 'd',
10
+ default: 5,
11
+ description: 'Duration in seconds for each chunk',
12
+ }),
13
+ output: Flags.string({
14
+ char: 'o',
15
+ description: 'Output directory for chunk files and keyframes',
16
+ required: true,
17
+ }),
18
+ url: Flags.string({
19
+ char: 'u',
20
+ description: 'URL or local path to the video file',
21
+ required: true,
22
+ }),
23
+ };
24
+ async run() {
25
+ const { flags } = await this.parse(IndexChunk);
26
+ this.log(`[index:chunk] Chunking video: ${flags.url} into ${flags.duration}s segments → ${flags.output}`);
27
+ const fs = await import('node:fs/promises');
28
+ const { exec } = await import('node:child_process');
29
+ const { promisify } = await import('node:util');
30
+ const path = await import('node:path');
31
+ const execAsync = promisify(exec);
32
+ await fs.mkdir(flags.output, { recursive: true });
33
+ const outputPattern = path.join(flags.output, 'chunk_%03d.mp4');
34
+ const cmd = `ffmpeg -i "${flags.url}" -f segment -segment_time ${flags.duration} -reset_timestamps 1 -c copy -map 0 "${outputPattern}"`;
35
+ try {
36
+ await execAsync(cmd);
37
+ const files = await fs.readdir(flags.output);
38
+ const chunks = files.filter(f => f.startsWith('chunk_') && f.endsWith('.mp4'));
39
+ for (const chunk of chunks) {
40
+ const chunkPath = path.join(flags.output, chunk);
41
+ const framePath = path.join(flags.output, chunk.replace('.mp4', '.jpg'));
42
+ await execAsync(`ffmpeg -i "${chunkPath}" -ss ${flags.duration / 2} -vframes 1 "${framePath}" -y`);
43
+ }
44
+ this.log(`[index:chunk] Done.`);
45
+ const result = chunks.map(c => ({
46
+ video: path.join(flags.output, c),
47
+ frame: path.join(flags.output, c.replace('.mp4', '.jpg'))
48
+ }));
49
+ this.log(JSON.stringify(result));
50
+ }
51
+ catch (error) {
52
+ this.error(`FFmpeg failed: ${error instanceof Error ? error.message : error}`);
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,11 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class IndexDescribe extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ image: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
+ model: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
+ output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
+ };
10
+ run(): Promise<void>;
11
+ }
@@ -0,0 +1,29 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ export default class IndexDescribe extends Command {
3
+ static description = 'Use a Vision AI model to generate a text description of an image or video keyframe.';
4
+ static examples = [
5
+ '<%= config.bin %> <%= command.id %> --image ./chunks/frame_001.jpg --output ./descriptions/frame_001.json',
6
+ ];
7
+ static flags = {
8
+ image: Flags.string({
9
+ char: 'i',
10
+ description: 'Path or URL to the image/keyframe to describe',
11
+ required: true,
12
+ }),
13
+ model: Flags.string({
14
+ char: 'm',
15
+ default: 'gemini-flash',
16
+ description: 'Vision model to use for description',
17
+ }),
18
+ output: Flags.string({
19
+ char: 'o',
20
+ description: 'Path to write the description JSON output',
21
+ required: true,
22
+ }),
23
+ };
24
+ async run() {
25
+ const { flags } = await this.parse(IndexDescribe);
26
+ this.log(`[index:describe] Describing image: ${flags.image} using ${flags.model} → ${flags.output}`);
27
+ // TODO: implement Vision AI call and write {description, model, imagePath} to output
28
+ }
29
+ }
@@ -0,0 +1,11 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class IndexEmbed extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ model: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
+ output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
+ text: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
+ };
10
+ run(): Promise<void>;
11
+ }
@@ -0,0 +1,29 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ export default class IndexEmbed extends Command {
3
+ static description = 'Convert a text description into a vector embedding for semantic search.';
4
+ static examples = [
5
+ '<%= config.bin %> <%= command.id %> --text "A bitcoin coin spinning on a blue background" --output ./embeddings/frame_001.json',
6
+ ];
7
+ static flags = {
8
+ model: Flags.string({
9
+ char: 'm',
10
+ default: 'text-embedding-3-small',
11
+ description: 'Embedding model to use',
12
+ }),
13
+ output: Flags.string({
14
+ char: 'o',
15
+ description: 'Path to write the embedding JSON output',
16
+ required: true,
17
+ }),
18
+ text: Flags.string({
19
+ char: 't',
20
+ description: 'The text description to embed',
21
+ required: true,
22
+ }),
23
+ };
24
+ async run() {
25
+ const { flags } = await this.parse(IndexEmbed);
26
+ this.log(`[index:embed] Embedding text with ${flags.model} → ${flags.output}`);
27
+ // TODO: implement embedding API call and write {text, vector, model} to output
28
+ }
29
+ }
@@ -0,0 +1,10 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class IndexSave extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ db: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
+ metadata: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
+ };
9
+ run(): Promise<void>;
10
+ }
@@ -0,0 +1,24 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ export default class IndexSave extends Command {
3
+ static description = 'Save a video chunk\'s metadata (timecodes, description, embedding) to the RAG database.';
4
+ static examples = [
5
+ '<%= config.bin %> <%= command.id %> --metadata ./chunk_001_meta.json --db postgresql://user:pass@localhost/db',
6
+ ];
7
+ static flags = {
8
+ db: Flags.string({
9
+ char: 'd',
10
+ description: 'Database connection string',
11
+ required: true,
12
+ }),
13
+ metadata: Flags.string({
14
+ char: 'm',
15
+ description: 'Path to the metadata JSON file containing chunk info, description, and embedding',
16
+ required: true,
17
+ }),
18
+ };
19
+ async run() {
20
+ const { flags } = await this.parse(IndexSave);
21
+ this.log(`[index:save] Saving chunk metadata from ${flags.metadata} → database`);
22
+ // TODO: parse metadata JSON and upsert into DB (video_chunks table)
23
+ }
24
+ }
@@ -0,0 +1,11 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class ProjectCreate extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ aspectRatio: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
+ description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
+ title: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
+ };
10
+ run(): Promise<void>;
11
+ }
@@ -0,0 +1,63 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { getDb } from '../../lib/db.js';
3
+ import { v4 as uuidv4 } from 'uuid';
4
+ export default class ProjectCreate extends Command {
5
+ static description = 'Create a new video project in the Turso database.';
6
+ static examples = [
7
+ '<%= config.bin %> <%= command.id %> --title "Crypto Explainers" --aspectRatio 9:16',
8
+ ];
9
+ static flags = {
10
+ aspectRatio: Flags.string({
11
+ char: 'a',
12
+ default: '9:16',
13
+ description: 'Project aspect ratio',
14
+ options: ['1:1', '16:9', '9:16', '11'],
15
+ required: true,
16
+ }),
17
+ description: Flags.string({
18
+ char: 'd',
19
+ description: 'Optional project description',
20
+ }),
21
+ title: Flags.string({
22
+ char: 't',
23
+ description: 'Project title',
24
+ required: true,
25
+ }),
26
+ };
27
+ async run() {
28
+ const { flags } = await this.parse(ProjectCreate);
29
+ const id = uuidv4();
30
+ const projectData = {
31
+ aspectRatio: flags.aspectRatio,
32
+ caption: {
33
+ id: 'default',
34
+ name: 'Default',
35
+ position: 'bottom',
36
+ size: 'medium',
37
+ },
38
+ visuals: {
39
+ style: 'cinematic',
40
+ type: 'narrative-video',
41
+ },
42
+ voice: {
43
+ name: 'Default',
44
+ },
45
+ // Initialize with empty arrays as per schema
46
+ segments: [],
47
+ };
48
+ try {
49
+ await getDb().execute({
50
+ args: [id, flags.title, flags.description || '', JSON.stringify(projectData)],
51
+ sql: 'INSERT INTO projects (id, title, description, data) VALUES (?, ?, ?, ?)',
52
+ });
53
+ this.log(`Project created successfully!`);
54
+ this.log(`ID: ${id}`);
55
+ this.log(`Title: ${flags.title}`);
56
+ // Output JSON for agent chaining
57
+ this.log(JSON.stringify({ id, title: flags.title }));
58
+ }
59
+ catch (error) {
60
+ this.error(`Failed to create project: ${error instanceof Error ? error.message : error}`);
61
+ }
62
+ }
63
+ }
@@ -0,0 +1,9 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class ProjectDelete extends Command {
3
+ static args: {
4
+ id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ run(): Promise<void>;
9
+ }
@@ -0,0 +1,31 @@
1
+ import { Args, Command } from '@oclif/core';
2
+ import { getDb } from '../../lib/db.js';
3
+ export default class ProjectDelete extends Command {
4
+ static args = {
5
+ id: Args.string({ description: 'Project ID to delete', required: true }),
6
+ };
7
+ static description = 'Delete a project and all its associated segments from the Turso database.';
8
+ static examples = [
9
+ '<%= config.bin %> <%= command.id %> <project-id>',
10
+ ];
11
+ async run() {
12
+ const { args } = await this.parse(ProjectDelete);
13
+ try {
14
+ // libSQL batch for atomic delete (though CASCADE should handle it if set up)
15
+ await getDb().batch([
16
+ {
17
+ args: [args.id],
18
+ sql: 'DELETE FROM segments WHERE projectId = ?',
19
+ },
20
+ {
21
+ args: [args.id],
22
+ sql: 'DELETE FROM projects WHERE id = ?',
23
+ },
24
+ ], "write");
25
+ this.log(`Project ${args.id} and its segments have been deleted.`);
26
+ }
27
+ catch (error) {
28
+ this.error(`Failed to delete project: ${error instanceof Error ? error.message : error}`);
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,9 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class ProjectGet extends Command {
3
+ static args: {
4
+ id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ run(): Promise<void>;
9
+ }
@@ -0,0 +1,39 @@
1
+ import { Args, Command } from '@oclif/core';
2
+ import { getDb } from '../../lib/db.js';
3
+ export default class ProjectGet extends Command {
4
+ static args = {
5
+ id: Args.string({ description: 'Project ID to retrieve', required: true }),
6
+ };
7
+ static description = 'Retrieve a full project schema including its segments from the Turso database.';
8
+ static examples = [
9
+ '<%= config.bin %> <%= command.id %> <project-id>',
10
+ ];
11
+ async run() {
12
+ const { args } = await this.parse(ProjectGet);
13
+ try {
14
+ const projectRs = await getDb().execute({
15
+ args: [args.id],
16
+ sql: 'SELECT * FROM projects WHERE id = ?',
17
+ });
18
+ if (projectRs.rows.length === 0) {
19
+ this.error(`Project with ID ${args.id} not found.`);
20
+ }
21
+ const project = projectRs.rows[0];
22
+ const segmentsRs = await getDb().execute({
23
+ args: [args.id],
24
+ sql: 'SELECT * FROM segments WHERE projectId = ? ORDER BY orderIndex ASC',
25
+ });
26
+ const schema = {
27
+ ...JSON.parse(project.data),
28
+ description: project.description,
29
+ id: project.id,
30
+ segments: segmentsRs.rows.map((row) => JSON.parse(row.data)),
31
+ title: project.title,
32
+ };
33
+ this.log(JSON.stringify(schema, null, 2));
34
+ }
35
+ catch (error) {
36
+ this.error(`Failed to get project: ${error instanceof Error ? error.message : error}`);
37
+ }
38
+ }
39
+ }
@@ -0,0 +1,6 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class ProjectList extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
@@ -0,0 +1,26 @@
1
+ import { Command } from '@oclif/core';
2
+ import { getDb } from '../../lib/db.js';
3
+ export default class ProjectList extends Command {
4
+ static description = 'List all video projects stored in the Turso database.';
5
+ static examples = [
6
+ '<%= config.bin %> <%= command.id %>',
7
+ ];
8
+ async run() {
9
+ try {
10
+ const rs = await getDb().execute('SELECT id, title, description, createdAt FROM projects ORDER BY createdAt DESC');
11
+ if (rs.rows.length === 0) {
12
+ this.log('No projects found.');
13
+ return;
14
+ }
15
+ this.log('Listing projects:');
16
+ for (const row of rs.rows) {
17
+ this.log(`- ${row.title} (${row.id}) - Created: ${row.createdAt}`);
18
+ }
19
+ // Output JSON for agent
20
+ this.log(JSON.stringify(rs.rows));
21
+ }
22
+ catch (error) {
23
+ this.error(`Failed to list projects: ${error instanceof Error ? error.message : error}`);
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,10 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class ProjectValidate extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ schema: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
+ strict: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ };
9
+ run(): Promise<void>;
10
+ }
@@ -0,0 +1,29 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { getDb } from '../../lib/db.js';
3
+ export default class ProjectValidate extends Command {
4
+ static description = 'Validate a Schema JSON file against the TypeScript Schema interface structure before saving to a database.';
5
+ static examples = [
6
+ '<%= config.bin %> <%= command.id %> --schema ./schema.json',
7
+ '<%= config.bin %> <%= command.id %> --schema ./schema.json --strict',
8
+ ];
9
+ static flags = {
10
+ schema: Flags.string({
11
+ char: 's',
12
+ description: 'Path to the Schema JSON file to validate',
13
+ required: true,
14
+ }),
15
+ strict: Flags.boolean({
16
+ default: false,
17
+ description: 'Fail on missing optional fields in addition to required field validation',
18
+ }),
19
+ };
20
+ async run() {
21
+ const { flags } = await this.parse(ProjectValidate);
22
+ this.log(`[project:validate] Validating schema: ${flags.schema}${flags.strict ? ' (strict mode)' : ''}`);
23
+ try {
24
+ const rs = await getDb().execute('SELECT 1');
25
+ this.log('Database connection verified as well.');
26
+ }
27
+ catch { }
28
+ }
29
+ }
@@ -0,0 +1,12 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class SearchAsset extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ db: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
+ limit: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
8
+ query: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
+ type: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ };
11
+ run(): Promise<void>;
12
+ }