-
Notifications
You must be signed in to change notification settings - Fork 1
feat: add primitive CLI commands for modular content creation #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b6bf3ef
9be84d8
0604709
a1096c5
ac2c062
f3caf4d
473dea2
9ae2f32
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| import { Command } from "commander"; | ||
| import { post } from "../../client.js"; | ||
| import { getErrorMessage } from "../../getErrorMessage.js"; | ||
| import { printError, printJson } from "../../output.js"; | ||
|
|
||
| function parsePositiveInt(value: string): number { | ||
| const n = parseInt(value, 10); | ||
| if (Number.isNaN(n) || n <= 0) { | ||
| throw new Error(`Expected a positive integer, got "${value}"`); | ||
| } | ||
| return n; | ||
| } | ||
|
|
||
| export const analyzeCommand = new Command("analyze") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Export a function instead of a constant command instance. Line 14 violates the repository rule requiring one exported function per file under Refactor direction-export const analyzeCommand = new Command("analyze")
- .description(
- "Analyze a video with AI — describe scenes, check quality, evaluate content",
- )
+export function createAnalyzeCommand(): Command {
+ return new Command("analyze")
+ .description(
+ "Analyze a video with AI — describe scenes, check quality, evaluate content",
+ )
@@
- .action(async (opts: Record<string, unknown>) => {
+ .action(async (opts: Record<string, unknown>) => {
@@
- });
+ });
+}As per coding guidelines: 🤖 Prompt for AI Agents |
||
| .description( | ||
| "Analyze a video with AI — describe scenes, check quality, evaluate content", | ||
| ) | ||
| .requiredOption("--video <url>", "Video URL to analyze") | ||
| .requiredOption("--prompt <text>", "What to analyze") | ||
| .option("--temperature <number>", "Sampling temperature (default: 0.2)", parseFloat) | ||
| .option("--max-tokens <number>", "Maximum output tokens", parsePositiveInt) | ||
| .option("--json", "Output raw JSON") | ||
| .action(async (opts: Record<string, unknown>) => { | ||
| try { | ||
| const body: Record<string, unknown> = { | ||
| video_url: opts.video, | ||
| prompt: opts.prompt, | ||
| }; | ||
|
|
||
| if (opts.temperature !== undefined) { | ||
| body.temperature = opts.temperature; | ||
| } else { | ||
| body.temperature = 0.2; | ||
| } | ||
|
Comment on lines
+20
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: find . -name "analyzeCommand.ts" -type fRepository: recoupable/cli Length of output: 98 🏁 Script executed: cat -n ./src/commands/content/analyzeCommand.tsRepository: recoupable/cli Length of output: 2120 🏁 Script executed: python3 << 'EOF'
import json
# Test JSON behavior with NaN
test_obj = {"temperature": float('nan')}
print("Python JSON with NaN:", json.dumps(test_obj))
# In JavaScript context - verify the claim about NaN serialization
# parseFloat behavior
print("\nparseFloat behavior:")
print("parseFloat('0.5'):", 0.5)
print("parseFloat('invalid'):", float('nan')) # Returns NaN
# JSON.stringify in JS turns NaN to null
print("\nJSON serialization behavior:")
print("JSON.stringify({temp: NaN}) would be {temp: null}")
print("JSON.stringify({temp: 0.5}) would be {temp: 0.5}")
EOFRepository: recoupable/cli Length of output: 301 🏁 Script executed: cat -n ./src/client.jsRepository: recoupable/cli Length of output: 105 🏁 Script executed: find . -name "client.*" -type f | head -10Repository: recoupable/cli Length of output: 100 🏁 Script executed: cat -n ./src/client.tsRepository: recoupable/cli Length of output: 2980 Add validation to Line 20 uses Proposed fix+function parseTemperature(value: string): number {
+ const n = Number(value);
+ if (!Number.isFinite(n)) {
+ throw new Error(`Expected a valid number, got "${value}"`);
+ }
+ return n;
+}
+
export const analyzeCommand = new Command("analyze")
@@
- .option("--temperature <number>", "Sampling temperature (default: 0.2)", parseFloat)
+ .option("--temperature <number>", "Sampling temperature (default: 0.2)", parseTemperature)🤖 Prompt for AI Agents |
||
|
|
||
| if (opts.maxTokens !== undefined) { | ||
| body.max_tokens = opts.maxTokens; | ||
| } | ||
|
|
||
| const data = await post("/api/content/analyze", body); | ||
|
|
||
| if (opts.json) { | ||
| printJson(data); | ||
| return; | ||
| } | ||
|
|
||
| const text = (data as Record<string, unknown>).text; | ||
| if (typeof text === "string") { | ||
| console.log(text); | ||
| } else { | ||
| printJson(data); | ||
| } | ||
| } catch (err) { | ||
| printError(getErrorMessage(err)); | ||
| } | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import { createPrimitiveCommand } from "./createPrimitiveCommand.js"; | ||
|
|
||
| export const audioCommand = createPrimitiveCommand( | ||
| "transcribe", | ||
| "Transcribe audio into timestamped text", | ||
| "/api/content/transcribe", | ||
| [ | ||
| { flag: "--url <urls>", description: "Comma-separated audio URLs to transcribe" }, | ||
| { flag: "--model <id>", description: "Model ID (default: fal-ai/whisper)" }, | ||
| ], | ||
| (opts) => { | ||
| const audioUrls: string[] = opts.url | ||
| ? String(opts.url).split(",").map((s: string) => s.trim()).filter(Boolean) | ||
| : []; | ||
| return { | ||
| audio_urls: audioUrls, | ||
| ...(opts.model && { model: opts.model }), | ||
| }; | ||
| }, | ||
| ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| import { Command } from "commander"; | ||
| import { post } from "../../client.js"; | ||
| import { getErrorMessage } from "../../getErrorMessage.js"; | ||
| import { printError, printJson } from "../../output.js"; | ||
|
|
||
| interface PrimitiveOption { | ||
| flag: string; | ||
| description: string; | ||
| defaultValue?: string; | ||
| } | ||
|
|
||
| /** | ||
| * Creates a CLI command that POSTs to a content primitive endpoint. | ||
| * Each primitive only defines what is unique: name, endpoint, and options. | ||
| */ | ||
| export function createPrimitiveCommand( | ||
| name: string, | ||
| description: string, | ||
| endpoint: string, | ||
| options: PrimitiveOption[], | ||
| buildBody: (opts: Record<string, unknown>) => Record<string, unknown>, | ||
| ): Command { | ||
| const cmd = new Command(name).description(description); | ||
|
|
||
| for (const opt of options) { | ||
| if (opt.defaultValue !== undefined) { | ||
| cmd.option(opt.flag, opt.description, opt.defaultValue); | ||
| } else { | ||
| cmd.option(opt.flag, opt.description); | ||
| } | ||
| } | ||
|
|
||
| cmd.option("--json", "Output as JSON"); | ||
|
|
||
| cmd.action(async (opts: Record<string, unknown>) => { | ||
| try { | ||
| const body = buildBody(opts); | ||
| const data = await post(endpoint, body); | ||
|
|
||
| if (opts.json) { | ||
| printJson(data); | ||
| return; | ||
| } | ||
|
|
||
| if (data.runId) { | ||
| console.log(`Run started: ${data.runId}`); | ||
| console.log("Use `recoup tasks status --run <runId>` to check progress."); | ||
| } else { | ||
| printJson(data); | ||
| } | ||
| } catch (err) { | ||
| printError(getErrorMessage(err)); | ||
| } | ||
| }); | ||
|
|
||
| return cmd; | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,82 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Command } from "commander"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { patch } from "../../client.js"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { getErrorMessage } from "../../getErrorMessage.js"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { printError, printJson } from "../../output.js"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface EditOperation { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [key: string]: unknown; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const editCommand = new Command("edit") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .description("Edit content — trim, crop, resize, overlay text, or add audio") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Description mentions Line 12 currently advertises a capability that this command does not implement, which can mislead users. Suggested fix- .description("Edit content — trim, crop, resize, overlay text, or add audio")
+ .description("Edit content — trim, crop, overlay text, or add audio")📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .option("--video <url>", "Input video URL") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .option("--audio <url>", "Input audio URL") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .option("--template <name>", "Template name for deterministic edit config") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .option("--trim-start <seconds>", "Trim start time in seconds") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .option("--trim-duration <seconds>", "Trim duration in seconds") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .option("--crop-aspect <ratio>", "Crop to aspect ratio (e.g. 9:16)") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .option("--overlay-text <content>", "Overlay text content") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .option("--text-color <color>", "Text color", "white") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .option("--text-position <pos>", "Text position: top, center, bottom", "bottom") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .option("--mux-audio <url>", "Mux audio URL into video") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .option("--output-format <format>", "Output format: mp4, webm, mov", "mp4") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .option("--json", "Output as JSON") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .action(async (opts: Record<string, unknown>) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const operations: EditOperation[] = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (opts.trimStart || opts.trimDuration) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| operations.push({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: "trim", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| start: Number(opts.trimStart ?? 0), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| duration: Number(opts.trimDuration ?? 15), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+29
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Invalid numeric input produces If a user passes a non-numeric value (e.g., Consider validating and providing clear feedback: 🛡️ Proposed fix to validate numeric inputs if (opts.trimStart || opts.trimDuration) {
+ const start = opts.trimStart !== undefined ? Number(opts.trimStart) : 0;
+ const duration = opts.trimDuration !== undefined ? Number(opts.trimDuration) : 15;
+ if (Number.isNaN(start) || Number.isNaN(duration)) {
+ throw new Error("--trim-start and --trim-duration must be valid numbers");
+ }
operations.push({
type: "trim",
- start: Number(opts.trimStart ?? 0),
- duration: Number(opts.trimDuration ?? 15),
+ start,
+ duration,
});
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (opts.cropAspect) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| operations.push({ type: "crop", aspect: opts.cropAspect }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (opts.overlayText) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| operations.push({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: "overlay_text", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content: opts.overlayText, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| color: opts.textColor ?? "white", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| position: opts.textPosition ?? "bottom", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (opts.muxAudio) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| operations.push({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: "mux_audio", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| audio_url: opts.muxAudio, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| replace: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const body: Record<string, unknown> = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(opts.video && { video_url: opts.video }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(opts.audio && { audio_url: opts.audio }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(opts.template && { template: opts.template }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(operations.length > 0 && { operations }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| output_format: opts.outputFormat ?? "mp4", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const data = await patch("/api/content", body); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (opts.json) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| printJson(data); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (data.runId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(`Run started: ${data.runId}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("Use `recoup tasks status --run <runId>` to check progress."); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| printJson(data); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (err) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| printError(getErrorMessage(err)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+11
to
+82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Export a function instead of a constant command object in this file. This file currently exports Suggested refactor-export const editCommand = new Command("edit")
- .description("Edit content — trim, crop, overlay text, or add audio")
+export function editCommand(): Command {
+ return new Command("edit")
+ .description("Edit content — trim, crop, overlay text, or add audio")
.option("--video <url>", "Input video URL")
.option("--audio <url>", "Input audio URL")
.option("--template <name>", "Template name for deterministic edit config")
.option("--trim-start <seconds>", "Trim start time in seconds")
.option("--trim-duration <seconds>", "Trim duration in seconds")
.option("--crop-aspect <ratio>", "Crop to aspect ratio (e.g. 9:16)")
.option("--overlay-text <content>", "Overlay text content")
.option("--text-color <color>", "Text color", "white")
.option("--text-position <pos>", "Text position: top, center, bottom", "bottom")
.option("--mux-audio <url>", "Mux audio URL into video")
.option("--output-format <format>", "Output format: mp4, webm, mov", "mp4")
.option("--json", "Output as JSON")
.action(async (opts: Record<string, unknown>) => {
...
});
+}As per coding guidelines: 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import { createPrimitiveCommand } from "./createPrimitiveCommand.js"; | ||
|
|
||
| export const imageCommand = createPrimitiveCommand( | ||
| "image", | ||
| "Generate an AI image from a prompt and optional reference image", | ||
| "/api/content/image", | ||
| [ | ||
| { flag: "--prompt <text>", description: "Image generation prompt" }, | ||
| { flag: "--reference-image <url>", description: "Reference image URL for conditioning" }, | ||
| { flag: "--model <id>", description: "Model ID (default: fal-ai/nano-banana-pro/edit)" }, | ||
| ], | ||
| (opts) => ({ | ||
| ...(opts.prompt && { prompt: opts.prompt }), | ||
| ...(opts.referenceImage && { reference_image_url: opts.referenceImage }), | ||
| ...(opts.model && { model: opts.model }), | ||
| }), | ||
| ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import { createPrimitiveCommand } from "./createPrimitiveCommand.js"; | ||
|
|
||
| export const textCommand = createPrimitiveCommand( | ||
| "caption", | ||
| "Generate on-screen caption text for a social video", | ||
| "/api/content/caption", | ||
| [ | ||
| { flag: "--topic <text>", description: "Subject or theme for caption generation" }, | ||
| { flag: "--length <size>", description: "Text length: short, medium, long", defaultValue: "short" }, | ||
| ], | ||
| (opts) => ({ | ||
| topic: opts.topic, | ||
| length: opts.length, | ||
| }), | ||
| ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import { createPrimitiveCommand } from "./createPrimitiveCommand.js"; | ||
|
|
||
| export const upscaleCommand = createPrimitiveCommand( | ||
| "upscale", | ||
| "Upscale an image or video", | ||
| "/api/content/upscale", | ||
| [ | ||
| { flag: "--url <url>", description: "URL of the image or video to upscale" }, | ||
| { flag: "--type <type>", description: "Type: image or video", defaultValue: "image" }, | ||
| ], | ||
| (opts) => ({ | ||
| url: opts.url, | ||
| type: opts.type, | ||
| }), | ||
|
Comment on lines
+11
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check how other commands handle required options in this codebase
rg -n "requiredOption" --type=tsRepository: recoupable/cli Length of output: 439 🏁 Script executed: cat src/commands/content/upscaleCommand.tsRepository: recoupable/cli Length of output: 498 🏁 Script executed: cat src/commands/content/createPrimitiveCommand.tsRepository: recoupable/cli Length of output: 1540 Add validation for required The current implementation uses 🤖 Prompt for AI Agents |
||
| ); | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,37 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { createPrimitiveCommand } from "./createPrimitiveCommand.js"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const videoCommand = createPrimitiveCommand( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "video", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Generate a video (prompt, animate, reference, extend, first-last, or lipsync)", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "/api/content/video", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { flag: "--mode <mode>", description: "Mode: prompt, animate, reference, extend, first-last, lipsync" }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { flag: "--prompt <text>", description: "Text prompt describing the video" }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { flag: "--image <url>", description: "Image URL (animate, reference, first-last, lipsync)" }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { flag: "--end-image <url>", description: "End frame image URL (first-last mode)" }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { flag: "--video <url>", description: "Video URL to extend (extend mode)" }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { flag: "--audio <url>", description: "Audio URL (lipsync mode)" }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { flag: "--aspect-ratio <ratio>", description: "auto, 16:9, or 9:16", defaultValue: "auto" }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { flag: "--duration <dur>", description: "4s, 6s, 7s, or 8s", defaultValue: "8s" }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { flag: "--resolution <res>", description: "720p, 1080p, or 4k", defaultValue: "720p" }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { flag: "--negative-prompt <text>", description: "What to avoid in the video" }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { flag: "--generate-audio", description: "Generate audio for the video" }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { flag: "--model <id>", description: "Override model ID" }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { flag: "--template <name>", description: "Template ID for video generation config (moods, movements). Optional — overrides prompt with template defaults." }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (opts) => ({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(opts.mode && { mode: opts.mode }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+8
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Validate Line 8 documents a fixed enum, but Line 22 forwards any value. Invalid modes currently fail late at the API boundary; fail-fast in CLI would improve UX and reduce avoidable requests. ✅ Suggested validation+const ALLOWED_VIDEO_MODES = new Set([
+ "prompt",
+ "animate",
+ "reference",
+ "extend",
+ "first-last",
+ "lipsync",
+]);
+
export const videoCommand = createPrimitiveCommand(
@@
- (opts) => ({
+ (opts) => ({
+ ...(opts.mode &&
+ !ALLOWED_VIDEO_MODES.has(String(opts.mode)) && {
+ // createPrimitiveCommand catches thrown errors and prints nicely
+ ...(function () {
+ throw new Error("Invalid --mode. Allowed: prompt, animate, reference, extend, first-last, lipsync");
+ })(),
+ }),
...(opts.mode && { mode: opts.mode }),📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(opts.prompt && { prompt: opts.prompt }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(opts.image && { image_url: opts.image }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(opts.endImage && { end_image_url: opts.endImage }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(opts.video && { video_url: opts.video }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(opts.audio && { audio_url: opts.audio }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| aspect_ratio: opts.aspectRatio, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| duration: opts.duration, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| resolution: opts.resolution, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(opts.negativePrompt && { negative_prompt: opts.negativePrompt }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| generate_audio: !!opts.generateAudio, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(opts.model && { model: opts.model }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(opts.template && { template: opts.template }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+3
to
+37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Export a function instead of an exported command object. This file currently exports a constant ( ♻️ Proposed refactor-export const videoCommand = createPrimitiveCommand(
- "video",
- "Generate a video (prompt, animate, reference, extend, first-last, or lipsync)",
- "/api/content/video",
- [
- { flag: "--mode <mode>", description: "Mode: prompt, animate, reference, extend, first-last, lipsync" },
- { flag: "--prompt <text>", description: "Text prompt describing the video" },
- { flag: "--image <url>", description: "Image URL (animate, reference, first-last, lipsync)" },
- { flag: "--end-image <url>", description: "End frame image URL (first-last mode)" },
- { flag: "--video <url>", description: "Video URL to extend (extend mode)" },
- { flag: "--audio <url>", description: "Audio URL (lipsync mode)" },
- { flag: "--aspect-ratio <ratio>", description: "auto, 16:9, or 9:16", defaultValue: "auto" },
- { flag: "--duration <dur>", description: "4s, 6s, 7s, or 8s", defaultValue: "8s" },
- { flag: "--resolution <res>", description: "720p, 1080p, or 4k", defaultValue: "720p" },
- { flag: "--negative-prompt <text>", description: "What to avoid in the video" },
- { flag: "--generate-audio", description: "Generate audio for the video" },
- { flag: "--model <id>", description: "Override model ID" },
- ],
- (opts) => ({
- ...(opts.mode && { mode: opts.mode }),
- ...(opts.prompt && { prompt: opts.prompt }),
- ...(opts.image && { image_url: opts.image }),
- ...(opts.endImage && { end_image_url: opts.endImage }),
- ...(opts.video && { video_url: opts.video }),
- ...(opts.audio && { audio_url: opts.audio }),
- aspect_ratio: opts.aspectRatio,
- duration: opts.duration,
- resolution: opts.resolution,
- ...(opts.negativePrompt && { negative_prompt: opts.negativePrompt }),
- generate_audio: !!opts.generateAudio,
- ...(opts.model && { model: opts.model }),
- }),
-);
+export function createVideoCommand() {
+ return createPrimitiveCommand(
+ "video",
+ "Generate a video (prompt, animate, reference, extend, first-last, or lipsync)",
+ "/api/content/video",
+ [
+ { flag: "--mode <mode>", description: "Mode: prompt, animate, reference, extend, first-last, lipsync" },
+ { flag: "--prompt <text>", description: "Text prompt describing the video" },
+ { flag: "--image <url>", description: "Image URL (animate, reference, first-last, lipsync)" },
+ { flag: "--end-image <url>", description: "End frame image URL (first-last mode)" },
+ { flag: "--video <url>", description: "Video URL to extend (extend mode)" },
+ { flag: "--audio <url>", description: "Audio URL (lipsync mode)" },
+ { flag: "--aspect-ratio <ratio>", description: "auto, 16:9, or 9:16", defaultValue: "auto" },
+ { flag: "--duration <dur>", description: "4s, 6s, 7s, or 8s", defaultValue: "8s" },
+ { flag: "--resolution <res>", description: "720p, 1080p, or 4k", defaultValue: "720p" },
+ { flag: "--negative-prompt <text>", description: "What to avoid in the video" },
+ { flag: "--generate-audio", description: "Generate audio for the video" },
+ { flag: "--model <id>", description: "Override model ID" },
+ ],
+ (opts) => ({
+ ...(opts.mode && { mode: opts.mode }),
+ ...(opts.prompt && { prompt: opts.prompt }),
+ ...(opts.image && { image_url: opts.image }),
+ ...(opts.endImage && { end_image_url: opts.endImage }),
+ ...(opts.video && { video_url: opts.video }),
+ ...(opts.audio && { audio_url: opts.audio }),
+ aspect_ratio: opts.aspectRatio,
+ duration: opts.duration,
+ resolution: opts.resolution,
+ ...(opts.negativePrompt && { negative_prompt: opts.negativePrompt }),
+ generate_audio: !!opts.generateAudio,
+ ...(opts.model && { model: opts.model }),
+ }),
+ );
+}As per coding guidelines, 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: recoupable/cli
Length of output: 113
🏁 Script executed:
cat -n src/commands/content/analyzeCommand.ts | head -60Repository: recoupable/cli
Length of output: 2120
🏁 Script executed:
Repository: recoupable/cli
Length of output: 772
parsePositiveIntis currently accepting malformed values.parseIntwill accept partial inputs like"12abc"(returns 12) and"1.5"(returns 1), so this function can silently coerce invalid user input.Proposed fix
function parsePositiveInt(value: string): number { - const n = parseInt(value, 10); - if (Number.isNaN(n) || n <= 0) { + if (!/^[1-9]\d*$/.test(value)) { throw new Error(`Expected a positive integer, got "${value}"`); } - return n; + return Number(value); }🤖 Prompt for AI Agents