veogent 1.0.25 → 1.1.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.
Files changed (3) hide show
  1. package/index.js +183 -1
  2. package/package.json +1 -1
  3. package/skills/SKILL.md +734 -185
package/index.js CHANGED
@@ -744,7 +744,11 @@ program
744
744
  }
745
745
 
746
746
  const data = await api.post('/app/request', payload);
747
- const requestResult = unwrapData(data);
747
+ let requestResult = unwrapData(data);
748
+ // Ensure requestResult is an object (backend may return boolean/primitive)
749
+ if (typeof requestResult !== 'object' || requestResult === null) {
750
+ requestResult = { raw: requestResult };
751
+ }
748
752
  // P2-7: Persist endScene metadata when chained video generation
749
753
  if (options.endscene) {
750
754
  requestResult.end_scene_id = options.endscene;
@@ -1046,6 +1050,184 @@ program
1046
1050
  }
1047
1051
  });
1048
1052
 
1053
+ // --- Standalone Generate (Image / Video from text) ---
1054
+ program
1055
+ .command('gen-image')
1056
+ .description('Generate an image from a text prompt (standalone, no project needed). Costs 3 credits. Uses Imagen 3.5.')
1057
+ .requiredOption('-p, --prompt <prompt>', 'Text prompt to generate image from (10-2000 chars)')
1058
+ .option('-n, --negative <negative>', 'Negative prompt — things to avoid')
1059
+ .option('-o, --orientation <orientation>', 'Orientation: HORIZONTAL or VERTICAL', 'HORIZONTAL')
1060
+ .option('-w, --wait', 'Wait for completion (poll until done)', false)
1061
+ .option('-i, --interval <sec>', 'Polling interval in seconds (with --wait)', '5')
1062
+ .option('-t, --timeout <sec>', 'Timeout in seconds (with --wait)', '300')
1063
+ .action(async (options) => {
1064
+ try {
1065
+ const payload = {
1066
+ prompt: options.prompt,
1067
+ orientation: options.orientation.toUpperCase(),
1068
+ };
1069
+ if (options.negative) payload.negativePrompt = options.negative;
1070
+
1071
+ humanLog('🎨 Submitting standalone image generation request...');
1072
+ const data = await api.post('/app/standalone/generate-image', payload);
1073
+ const result = unwrapData(data);
1074
+ const requestId = result?.requestId || result?.request_id;
1075
+
1076
+ if (!requestId) {
1077
+ emitJson({ status: 'error', message: 'No requestId returned', data: result });
1078
+ return;
1079
+ }
1080
+
1081
+ humanLog(`✅ Request created: ${requestId}`);
1082
+
1083
+ if (!options.wait) {
1084
+ emitJson({ status: 'success', requestId, message: 'Request submitted. Use --wait to poll for completion, or check with: veogent standalone-request ' + requestId });
1085
+ return;
1086
+ }
1087
+
1088
+ // Poll for completion
1089
+ const intervalMs = Math.max(1, Number(options.interval || 5)) * 1000;
1090
+ const timeoutMs = Math.max(10, Number(options.timeout || 300)) * 1000;
1091
+ const startedAt = Date.now();
1092
+
1093
+ while (Date.now() - startedAt < timeoutMs) {
1094
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
1095
+ try {
1096
+ const statusData = await api.get(`/app/standalone/request/${requestId}`);
1097
+ const req = unwrapData(statusData);
1098
+ const status = String(req?.status || '').toUpperCase();
1099
+ humanLog(`⏳ Status: ${status}`);
1100
+
1101
+ if (status === 'COMPLETED') {
1102
+ emitJson({ status: 'success', requestId, imageUri: req?.outputData?.imageUri || null, data: req });
1103
+ return;
1104
+ }
1105
+ if (status === 'FAILED') {
1106
+ emitJson({ status: 'error', requestId, message: req?.message || 'Generation failed', data: req });
1107
+ process.exit(1);
1108
+ }
1109
+ } catch (pollErr) {
1110
+ humanError(`⚠️ Poll error: ${pollErr.message}`);
1111
+ }
1112
+ }
1113
+
1114
+ emitJson({ status: 'error', code: 'WAIT_TIMEOUT', requestId, message: `Timeout after ${options.timeout}s` });
1115
+ process.exit(1);
1116
+ } catch (error) {
1117
+ emitJson({ status: 'error', ...formatCliError(error) });
1118
+ process.exit(1);
1119
+ }
1120
+ });
1121
+
1122
+ program
1123
+ .command('gen-video')
1124
+ .description('Generate a video from a text prompt (standalone, no project needed). Costs 5 credits. Uses Veo 3.1 Fast.')
1125
+ .requiredOption('-p, --prompt <prompt>', 'Text prompt to generate video from (10-2000 chars)')
1126
+ .option('-n, --negative <negative>', 'Negative prompt — things to avoid')
1127
+ .option('-o, --orientation <orientation>', 'Orientation: HORIZONTAL or VERTICAL', 'HORIZONTAL')
1128
+ .option('-r, --reference <imageUri>', 'Reference image URI for image-to-video generation')
1129
+ .option('-w, --wait', 'Wait for completion (poll until done)', false)
1130
+ .option('-i, --interval <sec>', 'Polling interval in seconds (with --wait)', '10')
1131
+ .option('-t, --timeout <sec>', 'Timeout in seconds (with --wait)', '600')
1132
+ .action(async (options) => {
1133
+ try {
1134
+ const payload = {
1135
+ prompt: options.prompt,
1136
+ orientation: options.orientation.toUpperCase(),
1137
+ };
1138
+ if (options.negative) payload.negativePrompt = options.negative;
1139
+ if (options.reference) payload.referenceImageUri = options.reference;
1140
+
1141
+ humanLog('🎬 Submitting standalone video generation request...');
1142
+ const data = await api.post('/app/standalone/generate-video', payload);
1143
+ const result = unwrapData(data);
1144
+ const requestId = result?.requestId || result?.request_id;
1145
+
1146
+ if (!requestId) {
1147
+ emitJson({ status: 'error', message: 'No requestId returned', data: result });
1148
+ return;
1149
+ }
1150
+
1151
+ humanLog(`✅ Request created: ${requestId}`);
1152
+
1153
+ if (!options.wait) {
1154
+ emitJson({ status: 'success', requestId, message: 'Request submitted. Use --wait to poll for completion, or check with: veogent standalone-request ' + requestId });
1155
+ return;
1156
+ }
1157
+
1158
+ // Poll for completion
1159
+ const intervalMs = Math.max(1, Number(options.interval || 10)) * 1000;
1160
+ const timeoutMs = Math.max(30, Number(options.timeout || 600)) * 1000;
1161
+ const startedAt = Date.now();
1162
+
1163
+ while (Date.now() - startedAt < timeoutMs) {
1164
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
1165
+ try {
1166
+ const statusData = await api.get(`/app/standalone/request/${requestId}`);
1167
+ const req = unwrapData(statusData);
1168
+ const status = String(req?.status || '').toUpperCase();
1169
+ humanLog(`⏳ Status: ${status}`);
1170
+
1171
+ if (status === 'COMPLETED') {
1172
+ emitJson({ status: 'success', requestId, videoUri: req?.outputData?.videoUri || null, data: req });
1173
+ return;
1174
+ }
1175
+ if (status === 'FAILED') {
1176
+ emitJson({ status: 'error', requestId, message: req?.message || 'Generation failed', data: req });
1177
+ process.exit(1);
1178
+ }
1179
+ } catch (pollErr) {
1180
+ humanError(`⚠️ Poll error: ${pollErr.message}`);
1181
+ }
1182
+ }
1183
+
1184
+ emitJson({ status: 'error', code: 'WAIT_TIMEOUT', requestId, message: `Timeout after ${options.timeout}s` });
1185
+ process.exit(1);
1186
+ } catch (error) {
1187
+ emitJson({ status: 'error', ...formatCliError(error) });
1188
+ process.exit(1);
1189
+ }
1190
+ });
1191
+
1192
+ program
1193
+ .command('standalone-requests')
1194
+ .description('List your standalone image/video generation requests')
1195
+ .option('-n, --limit <n>', 'Return only the N most recent', null)
1196
+ .option('-s, --status <status>', 'Filter by status (PENDING, PROCESSING, COMPLETED, FAILED)')
1197
+ .action(async (options) => {
1198
+ try {
1199
+ const data = await api.get('/app/standalone/requests');
1200
+ let items = unwrapData(data);
1201
+ items = Array.isArray(items) ? items : (items?.items || []);
1202
+
1203
+ if (options.status) {
1204
+ const s = options.status.toUpperCase();
1205
+ items = items.filter((r) => String(r?.status || '').toUpperCase() === s);
1206
+ }
1207
+
1208
+ if (options.limit !== null && options.limit !== undefined) {
1209
+ const n = parseInt(options.limit, 10);
1210
+ if (!isNaN(n) && n > 0) items = items.slice(0, n);
1211
+ }
1212
+
1213
+ emitJson({ status: 'success', total: items.length, data: items });
1214
+ } catch (error) {
1215
+ emitJson({ status: 'error', ...formatCliError(error) });
1216
+ }
1217
+ });
1218
+
1219
+ program
1220
+ .command('standalone-request <requestId>')
1221
+ .description('Get details of a specific standalone request')
1222
+ .action(async (requestId) => {
1223
+ try {
1224
+ const data = await api.get(`/app/standalone/request/${requestId}`);
1225
+ emitJson({ status: 'success', data: unwrapData(data) });
1226
+ } catch (error) {
1227
+ emitJson({ status: 'error', ...formatCliError(error) });
1228
+ }
1229
+ });
1230
+
1049
1231
  // --- System ---
1050
1232
  program
1051
1233
  .command('skill')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veogent",
3
- "version": "1.0.25",
3
+ "version": "1.1.0",
4
4
  "description": "The official CLI to interact with the VEOGENT API - AI Video and Image generation platform",
5
5
  "main": "index.js",
6
6
  "bin": {