veogent 1.3.0 → 1.4.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/README.md +155 -324
- package/index.js +123 -165
- package/package.json +1 -1
- package/skills/SKILL.md +314 -734
package/index.js
CHANGED
|
@@ -201,13 +201,12 @@ program
|
|
|
201
201
|
}
|
|
202
202
|
});
|
|
203
203
|
|
|
204
|
-
// [REMOVED v1.3.0] create-project-description — use docs or compound commands instead
|
|
205
204
|
program
|
|
206
205
|
.command('create-project')
|
|
207
|
-
.description('Create a new project')
|
|
206
|
+
.description('Create a new project (auto-generates rich description from idea)')
|
|
208
207
|
.requiredOption('--name <name>', 'Project name')
|
|
209
|
-
.requiredOption('--
|
|
210
|
-
.
|
|
208
|
+
.requiredOption('--idea <idea>', 'Story idea')
|
|
209
|
+
.option('--desc <desc>', 'Description (if omitted, auto-generated from idea via AI)')
|
|
211
210
|
.requiredOption('--lang <lang>', 'Story language')
|
|
212
211
|
.option('--sound <sound>', 'Sound effects (true/false)', 'true')
|
|
213
212
|
.requiredOption('--material <material>', 'Image material')
|
|
@@ -216,19 +215,32 @@ program
|
|
|
216
215
|
.option('--objects <objects...>', 'List of specific objects for the project as JSON strings (optional)')
|
|
217
216
|
.action(async (options) => {
|
|
218
217
|
try {
|
|
218
|
+
// Step 1: Generate rich description from keyword if not provided
|
|
219
|
+
let description = options.desc;
|
|
220
|
+
if (!description) {
|
|
221
|
+
humanLog('📝 Generating description from idea...');
|
|
222
|
+
const descData = unwrapData(await api.post('/app/description', {
|
|
223
|
+
keyword: options.idea,
|
|
224
|
+
language: options.lang,
|
|
225
|
+
}));
|
|
226
|
+
description = descData?.description || descData?.text || String(descData);
|
|
227
|
+
humanLog(`✅ Description generated (${description.length} chars)`);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Step 2: Create project with rich description
|
|
219
231
|
let parsedObjects = [];
|
|
220
232
|
if (options.objects && options.objects.length > 0) {
|
|
221
233
|
try {
|
|
222
234
|
parsedObjects = options.objects.map(objStr => typeof objStr === 'string' ? JSON.parse(objStr) : objStr);
|
|
223
235
|
} catch (e) {
|
|
224
|
-
throw new Error("Invalid JSON format for --objects.
|
|
236
|
+
throw new Error("Invalid JSON format for --objects.");
|
|
225
237
|
}
|
|
226
238
|
}
|
|
227
239
|
|
|
228
240
|
const payload = {
|
|
229
241
|
projectName: options.name,
|
|
230
|
-
keyword: options.
|
|
231
|
-
description
|
|
242
|
+
keyword: options.idea,
|
|
243
|
+
description,
|
|
232
244
|
storyLanguage: options.lang,
|
|
233
245
|
soundEffects: options.sound === 'true' || options.sound === true,
|
|
234
246
|
imageMaterial: options.material,
|
|
@@ -238,149 +250,12 @@ program
|
|
|
238
250
|
if (options.customPromptId) payload.customPromptId = options.customPromptId;
|
|
239
251
|
|
|
240
252
|
const data = await api.post('/app/project', payload);
|
|
241
|
-
console.log(JSON.stringify({ status: "success", project: unwrapData(data) }, null, 2));
|
|
253
|
+
console.log(JSON.stringify({ status: "success", description, project: unwrapData(data) }, null, 2));
|
|
242
254
|
} catch (error) {
|
|
243
255
|
console.log(JSON.stringify({ status: "error", ...formatCliError(error) }));
|
|
244
256
|
}
|
|
245
257
|
});
|
|
246
258
|
|
|
247
|
-
// --- Quick Project (compound: create project + chapter content + scenes + wait) ---
|
|
248
|
-
program
|
|
249
|
-
.command('quick-project')
|
|
250
|
-
.description('Create a full project with scenes in one command (create-project → create-chapter-content → create-scene → wait materialization)')
|
|
251
|
-
.requiredOption('--keyword <keyword>', 'Story keyword/brief')
|
|
252
|
-
.requiredOption('--lang <lang>', 'Story language (e.g. "Vietnamese", "English")')
|
|
253
|
-
.requiredOption('--material <material>', 'Image material (e.g. CINEMATIC, PIXAR_3D)')
|
|
254
|
-
.option('--name <name>', 'Project name (auto-generated from keyword if omitted)')
|
|
255
|
-
.option('--scenes <count>', 'Number of scenes per chapter', '5')
|
|
256
|
-
.option('--chapters <count>', 'Number of chapters', '1')
|
|
257
|
-
.option('--customPromptId <customPromptId>', 'Custom Prompt ID')
|
|
258
|
-
.option('--objects <objects...>', 'Character objects as JSON strings')
|
|
259
|
-
.option('--wait', 'Wait for materialization + characters to be ready')
|
|
260
|
-
.action(async (options) => {
|
|
261
|
-
try {
|
|
262
|
-
const results = { steps: [] };
|
|
263
|
-
|
|
264
|
-
// Step 1: Generate description
|
|
265
|
-
humanLog('📝 Step 1/4: Generating project description...');
|
|
266
|
-
const descData = unwrapData(await api.post('/app/description', {
|
|
267
|
-
keyword: options.keyword,
|
|
268
|
-
language: options.lang,
|
|
269
|
-
}));
|
|
270
|
-
const description = descData?.description || descData?.text || String(descData);
|
|
271
|
-
results.steps.push({ step: 'description', status: 'success' });
|
|
272
|
-
|
|
273
|
-
// Step 2: Create project
|
|
274
|
-
humanLog('🎬 Step 2/4: Creating project...');
|
|
275
|
-
let parsedObjects = [];
|
|
276
|
-
if (options.objects?.length > 0) {
|
|
277
|
-
parsedObjects = options.objects.map(o => typeof o === 'string' ? JSON.parse(o) : o);
|
|
278
|
-
}
|
|
279
|
-
const projectPayload = {
|
|
280
|
-
projectName: options.name || options.keyword.slice(0, 50),
|
|
281
|
-
keyword: options.keyword,
|
|
282
|
-
description,
|
|
283
|
-
storyLanguage: options.lang,
|
|
284
|
-
soundEffects: true,
|
|
285
|
-
imageMaterial: options.material,
|
|
286
|
-
numberChapters: parseInt(options.chapters),
|
|
287
|
-
objects: parsedObjects,
|
|
288
|
-
};
|
|
289
|
-
if (options.customPromptId) projectPayload.customPromptId = options.customPromptId;
|
|
290
|
-
|
|
291
|
-
const projectData = unwrapData(await api.post('/app/project', projectPayload));
|
|
292
|
-
const projectId = projectData?.id || projectData?.projectId;
|
|
293
|
-
if (!projectId) throw new Error('Failed to create project — no ID returned');
|
|
294
|
-
results.projectId = projectId;
|
|
295
|
-
results.steps.push({ step: 'create-project', status: 'success', projectId });
|
|
296
|
-
|
|
297
|
-
// Get chapter ID
|
|
298
|
-
const chaptersData = unwrapData(await api.get(`/app/chapters/${projectId}`));
|
|
299
|
-
const chapters = Array.isArray(chaptersData) ? chaptersData : (chaptersData?.chapters || []);
|
|
300
|
-
const chapterId = chapters[0]?.id || chapters[0]?.chapterId;
|
|
301
|
-
if (!chapterId) throw new Error('No chapter found after project creation');
|
|
302
|
-
results.chapterId = chapterId;
|
|
303
|
-
|
|
304
|
-
// Step 3: Create chapter content + scenes
|
|
305
|
-
humanLog('✍️ Step 3/4: Generating chapter content + creating scenes...');
|
|
306
|
-
const contentData = unwrapData(await api.post('/app/chapter/content', {
|
|
307
|
-
project: projectId,
|
|
308
|
-
chapter: chapterId,
|
|
309
|
-
numberScene: parseInt(options.scenes),
|
|
310
|
-
}));
|
|
311
|
-
let chapterContent = contentData?.chapterContent || contentData?.content || contentData;
|
|
312
|
-
if (!Array.isArray(chapterContent)) chapterContent = [chapterContent];
|
|
313
|
-
results.steps.push({ step: 'chapter-content', status: 'success', scenes: chapterContent.length });
|
|
314
|
-
|
|
315
|
-
// Create scenes
|
|
316
|
-
const scenePayload = {
|
|
317
|
-
project: projectId,
|
|
318
|
-
chapter: chapterId,
|
|
319
|
-
chapterContent,
|
|
320
|
-
useFlowKey: true,
|
|
321
|
-
};
|
|
322
|
-
const sceneData = unwrapData(await api.post('/app/scene', scenePayload));
|
|
323
|
-
results.steps.push({ step: 'create-scenes', status: 'success' });
|
|
324
|
-
|
|
325
|
-
// Step 4: Wait for materialization + characters (optional)
|
|
326
|
-
if (options.wait) {
|
|
327
|
-
humanLog('⏳ Step 4/4: Waiting for materialization + characters...');
|
|
328
|
-
|
|
329
|
-
// Wait materialization
|
|
330
|
-
const matStart = Date.now();
|
|
331
|
-
const matTimeout = 600000; // 10 min
|
|
332
|
-
while (Date.now() - matStart < matTimeout) {
|
|
333
|
-
try {
|
|
334
|
-
const matData = unwrapData(await api.get(
|
|
335
|
-
`/app/scene/materialization-status?projectId=${projectId}&chapterId=${chapterId}`
|
|
336
|
-
));
|
|
337
|
-
if (matData?.materialization === 'READY') {
|
|
338
|
-
results.steps.push({ step: 'materialization', status: 'success' });
|
|
339
|
-
break;
|
|
340
|
-
}
|
|
341
|
-
} catch { /* retry */ }
|
|
342
|
-
await new Promise(r => setTimeout(r, 30000));
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// Wait characters
|
|
346
|
-
const charStart = Date.now();
|
|
347
|
-
const charTimeout = 900000; // 15 min
|
|
348
|
-
while (Date.now() - charStart < charTimeout) {
|
|
349
|
-
try {
|
|
350
|
-
const charRaw = unwrapData(await api.get(`/app/characters/${projectId}`));
|
|
351
|
-
const chars = Array.isArray(charRaw) ? charRaw : (charRaw?.characters || []);
|
|
352
|
-
const allReady = chars.length > 0 && chars.every(c => c?.imageUri || c?.imageUrl || c?.image);
|
|
353
|
-
if (allReady) {
|
|
354
|
-
results.characters = chars.map(c => ({
|
|
355
|
-
id: c?.id, name: c?.name,
|
|
356
|
-
imageUri: c?.imageUri || c?.imageUrl || c?.image,
|
|
357
|
-
}));
|
|
358
|
-
results.steps.push({ step: 'characters', status: 'success', count: chars.length });
|
|
359
|
-
break;
|
|
360
|
-
}
|
|
361
|
-
} catch { /* retry */ }
|
|
362
|
-
await new Promise(r => setTimeout(r, 30000));
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// Fetch final scene list
|
|
367
|
-
const finalScenes = unwrapData(await api.get(`/app/scenes/${projectId}/${chapterId}`));
|
|
368
|
-
const sceneList = (Array.isArray(finalScenes) ? finalScenes : (finalScenes?.scenes || finalScenes?.items || []))
|
|
369
|
-
.map((s, i) => ({
|
|
370
|
-
id: s?.id || s?.sceneId,
|
|
371
|
-
displayOrder: s?.displayOrder ?? i,
|
|
372
|
-
scriptSegment: s?.scriptSegment || s?.content,
|
|
373
|
-
characterNames: (s?.imagePromptJson?.character_names) || [],
|
|
374
|
-
}));
|
|
375
|
-
results.scenes = sceneList;
|
|
376
|
-
results.status = 'success';
|
|
377
|
-
|
|
378
|
-
emitJson(results);
|
|
379
|
-
} catch (error) {
|
|
380
|
-
emitJson({ status: "error", ...formatCliError(error) });
|
|
381
|
-
}
|
|
382
|
-
});
|
|
383
|
-
|
|
384
259
|
// --- Chapters ---
|
|
385
260
|
program
|
|
386
261
|
.command('chapters <projectId>')
|
|
@@ -468,20 +343,57 @@ program
|
|
|
468
343
|
}
|
|
469
344
|
});
|
|
470
345
|
|
|
346
|
+
program
|
|
347
|
+
.command('add-character')
|
|
348
|
+
.description('Add a new character to a project (does NOT generate image — use generate-character after)')
|
|
349
|
+
.requiredOption('--project <project>', 'Project ID')
|
|
350
|
+
.requiredOption('--name <name>', 'Character name')
|
|
351
|
+
.option('--type <type>', 'Entity type: character, creature, location, visual_asset, faction, generic_troop', 'character')
|
|
352
|
+
.action(async (options) => {
|
|
353
|
+
try {
|
|
354
|
+
const payload = {
|
|
355
|
+
name: options.name,
|
|
356
|
+
entityType: options.type,
|
|
357
|
+
};
|
|
358
|
+
const data = await api.post(`/app/character/${options.project}`, payload);
|
|
359
|
+
console.log(JSON.stringify({ status: "success", character: unwrapData(data) }, null, 2));
|
|
360
|
+
} catch (error) {
|
|
361
|
+
console.log(JSON.stringify({ status: "error", ...formatCliError(error) }));
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
program
|
|
366
|
+
.command('generate-character')
|
|
367
|
+
.description('Generate reference image for a character (first time — no existing image)')
|
|
368
|
+
.requiredOption('--project <project>', 'Project ID')
|
|
369
|
+
.requiredOption('--character <character>', 'Character ID')
|
|
370
|
+
.requiredOption('--prompt <prompt>', 'Description of the character for image generation')
|
|
371
|
+
.action(async (options) => {
|
|
372
|
+
try {
|
|
373
|
+
const payload = {
|
|
374
|
+
userPrompt: options.prompt,
|
|
375
|
+
useFlowKey: true,
|
|
376
|
+
editImageMode: false, // false = generate new image (no existing image)
|
|
377
|
+
};
|
|
378
|
+
const data = await api.post(`/app/character/${options.project}/${options.character}/update-by-prompt`, payload);
|
|
379
|
+
console.log(JSON.stringify({ status: "success", character: unwrapData(data) }, null, 2));
|
|
380
|
+
} catch (error) {
|
|
381
|
+
console.log(JSON.stringify({ status: "error", ...formatCliError(error) }));
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
|
|
471
385
|
program
|
|
472
386
|
.command('edit-character')
|
|
473
|
-
.description('
|
|
387
|
+
.description('Edit an existing character reference image directly via AI prompt')
|
|
474
388
|
.requiredOption('--project <project>', 'Project ID')
|
|
475
|
-
.requiredOption('--character <character>', 'Character ID
|
|
476
|
-
.requiredOption('--
|
|
477
|
-
.option('--editimage', 'Enable direct Image Editing Mode (true). Default is Regenerate Profile Mode (false)', false)
|
|
478
|
-
.option('--flowkey', 'Enable useFlowKey to sync context via FireBase', true)
|
|
389
|
+
.requiredOption('--character <character>', 'Character ID')
|
|
390
|
+
.requiredOption('--prompt <prompt>', 'Edit instruction (what to change in the existing image)')
|
|
479
391
|
.action(async (options) => {
|
|
480
392
|
try {
|
|
481
393
|
const payload = {
|
|
482
|
-
userPrompt: options.
|
|
483
|
-
useFlowKey:
|
|
484
|
-
editImageMode:
|
|
394
|
+
userPrompt: options.prompt,
|
|
395
|
+
useFlowKey: true,
|
|
396
|
+
editImageMode: true, // true = edit existing image directly
|
|
485
397
|
};
|
|
486
398
|
const data = await api.post(`/app/character/${options.project}/${options.character}/update-by-prompt`, payload);
|
|
487
399
|
console.log(JSON.stringify({ status: "success", character: unwrapData(data) }, null, 2));
|
|
@@ -740,33 +652,80 @@ program
|
|
|
740
652
|
}
|
|
741
653
|
});
|
|
742
654
|
|
|
743
|
-
|
|
655
|
+
program
|
|
656
|
+
.command('delete-project')
|
|
657
|
+
.description('⚠️ DANGER: Permanently delete a project and all its data. Requires explicit confirmation.')
|
|
658
|
+
.requiredOption('--project <project>', 'Project ID to delete')
|
|
659
|
+
.option('--confirm', 'Skip confirmation prompt (required for agent-safe mode)')
|
|
660
|
+
.action(async (options) => {
|
|
661
|
+
try {
|
|
662
|
+
if (!options.confirm) {
|
|
663
|
+
// In agent-safe mode, require --confirm flag
|
|
664
|
+
console.log(JSON.stringify({
|
|
665
|
+
status: "error",
|
|
666
|
+
code: "CONFIRMATION_REQUIRED",
|
|
667
|
+
message: "⚠️ This will PERMANENTLY DELETE the project and all its scenes, characters, images, and videos. Re-run with --confirm to proceed."
|
|
668
|
+
}));
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
const data = await api.delete(`/app/project/${options.project}`);
|
|
672
|
+
console.log(JSON.stringify({ status: "success", deleted: options.project, data: unwrapData(data) }, null, 2));
|
|
673
|
+
} catch (error) {
|
|
674
|
+
console.log(JSON.stringify({ status: "error", ...formatCliError(error) }));
|
|
675
|
+
}
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
program
|
|
679
|
+
.command('insert-scene')
|
|
680
|
+
.description('Insert a new scene into an existing chapter (after a specific scene)')
|
|
681
|
+
.requiredOption('--project <project>', 'Project ID')
|
|
682
|
+
.requiredOption('--chapter <chapter>', 'Chapter ID')
|
|
683
|
+
.requiredOption('--prompt <prompt>', 'Scene narrative/script text')
|
|
684
|
+
.option('--after <sceneId>', 'Insert after this scene ID (appends to end if omitted)')
|
|
685
|
+
.action(async (options) => {
|
|
686
|
+
try {
|
|
687
|
+
const payload = {
|
|
688
|
+
projectId: options.project,
|
|
689
|
+
chapterId: options.chapter,
|
|
690
|
+
userPrompt: options.prompt,
|
|
691
|
+
};
|
|
692
|
+
if (options.after) {
|
|
693
|
+
payload.afterSceneId = options.after;
|
|
694
|
+
}
|
|
695
|
+
const data = await api.post('/app/scene', payload);
|
|
696
|
+
console.log(JSON.stringify({ status: "success", scene: unwrapData(data) }, null, 2));
|
|
697
|
+
} catch (error) {
|
|
698
|
+
console.log(JSON.stringify({ status: "error", ...formatCliError(error) }));
|
|
699
|
+
}
|
|
700
|
+
});
|
|
701
|
+
|
|
744
702
|
program
|
|
745
703
|
.command('edit-scene')
|
|
746
|
-
.description('Edit
|
|
704
|
+
.description('Edit scene storyboard/image prompt, or regenerate image with a request ID')
|
|
747
705
|
.requiredOption('--project <project>', 'Project ID')
|
|
748
706
|
.requiredOption('--chapter <chapter>', 'Chapter ID')
|
|
749
707
|
.requiredOption('--scene <scene>', 'Scene ID')
|
|
750
|
-
.requiredOption('--
|
|
751
|
-
.option('--
|
|
752
|
-
.option('--
|
|
753
|
-
.option('--wait', 'Wait for image regeneration to complete (only if regenerate is enabled)')
|
|
708
|
+
.requiredOption('--prompt <prompt>', 'Edit instruction or new scene prompt')
|
|
709
|
+
.option('--request <requestId>', 'Target a request ID — VEOGENT AI regenerates the scene image')
|
|
710
|
+
.option('--wait', 'Wait for image regeneration to complete (only with --request)')
|
|
754
711
|
.action(async (options) => {
|
|
755
712
|
try {
|
|
713
|
+
// Auto-derive regenerate: with --request → regenerate (direct image edit), without → no regenerate (prompt update only)
|
|
714
|
+
const hasRequest = !!options.request;
|
|
756
715
|
const payload = {
|
|
757
|
-
userPrompt: options.
|
|
758
|
-
regenerateImage:
|
|
716
|
+
userPrompt: options.prompt,
|
|
717
|
+
regenerateImage: hasRequest,
|
|
759
718
|
};
|
|
760
719
|
|
|
761
|
-
if (
|
|
720
|
+
if (hasRequest) {
|
|
762
721
|
payload.requestId = options.request;
|
|
763
722
|
}
|
|
764
723
|
|
|
765
724
|
const data = await api.patch(`/app/scene/script-segment/${options.project}/${options.chapter}/${options.scene}`, payload);
|
|
766
725
|
const result = { status: "success", scene: unwrapData(data) };
|
|
767
726
|
|
|
768
|
-
// Wait for image regen if requested
|
|
769
|
-
if (options.wait &&
|
|
727
|
+
// Wait for image regen if requested (only when regenerating via --request)
|
|
728
|
+
if (options.wait && hasRequest) {
|
|
770
729
|
humanLog('⏳ Waiting for image regeneration...');
|
|
771
730
|
const waitResult = await waitForAssets(api, options.project, options.chapter, 'GENERATE_IMAGES', [options.scene]);
|
|
772
731
|
result.waitResult = waitResult;
|
|
@@ -1296,7 +1255,6 @@ program
|
|
|
1296
1255
|
// --- System ---
|
|
1297
1256
|
// NOTE: Standalone commands (gen-image, gen-video, standalone-requests, standalone-request)
|
|
1298
1257
|
// have been removed in v1.3.0. Use project-scoped workflows instead.
|
|
1299
|
-
// For quick generation, use: quick-project --keyword "..." --wait
|
|
1300
1258
|
|
|
1301
1259
|
// --- System ---
|
|
1302
1260
|
program
|