Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { notificationsCommand } from "./commands/notifications.js";
import { orgsCommand } from "./commands/orgs.js";
import { contentCommand } from "./commands/content.js";
import { tasksCommand } from "./commands/tasks.js";
import { predictCommand } from "./commands/predict.js";
import { predictionsCommand } from "./commands/predictions.js";

const pkgPath = join(__dirname, "..", "package.json");
const { version } = JSON.parse(readFileSync(pkgPath, "utf-8"));
Expand All @@ -30,5 +32,7 @@ program.addCommand(sandboxesCommand);
program.addCommand(orgsCommand);
program.addCommand(tasksCommand);
program.addCommand(contentCommand);
program.addCommand(predictCommand);
program.addCommand(predictionsCommand);

program.parse();
67 changes: 67 additions & 0 deletions src/commands/predict.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Command } from "commander";
import { post } from "../client.js";
import { printJson, printError } from "../output.js";

/**
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Custom agent: Flag AI Slop and Fabricated Changes

Narrating JSDoc that restates the code. The first line duplicates the .description() string, and the rest summarizes the obvious post() call and console.log output. Remove it or replace with genuinely useful context (e.g., expected API error codes, rate-limit behavior).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/commands/predict.ts, line 5:

<comment>Narrating JSDoc that restates the code. The first line duplicates the `.description()` string, and the rest summarizes the obvious `post()` call and `console.log` output. Remove it or replace with genuinely useful context (e.g., expected API error codes, rate-limit behavior).</comment>

<file context>
@@ -0,0 +1,67 @@
+import { post } from "../client.js";
+import { printJson, printError } from "../output.js";
+
+/**
+ * `recoup predict` — run a neural engagement prediction on content.
+ *
</file context>
Fix with Cubic

* `recoup predict` — run a neural engagement prediction on content.
*
* Sends the file URL and modality to POST /api/predictions, then
* displays the engagement score, peak moments, and weak spots.
*/
export const predictCommand = new Command("predict")
.description("Run a neural engagement prediction on video, audio, or text content")
.requiredOption("--url <fileUrl>", "Public URL to the content file")
.requiredOption(
"--modality <modality>",
"Content type: video, audio, or text",
)
.option("--json", "Output as JSON")
.action(async (opts) => {
try {
const data = await post("/api/predictions", {
file_url: opts.url,
modality: opts.modality,
});

if (opts.json) {
printJson(data);
return;
}

console.log();
console.log(` Engagement Score: ${data.engagement_score}`);
console.log(` Modality: ${data.modality}`);
console.log(
` Duration: ${data.total_duration_seconds}s`,
);
console.log(` Inference Time: ${data.elapsed_seconds}s`);
console.log();

const peaks = data.peak_moments as
| { time_seconds: number; score: number }[]
| undefined;
if (peaks && peaks.length > 0) {
console.log(" Peak Moments:");
for (const p of peaks) {
console.log(` ${p.time_seconds}s → ${p.score}`);
}
console.log();
}

const weak = data.weak_spots as
| { time_seconds: number; score: number }[]
| undefined;
if (weak && weak.length > 0) {
console.log(" Weak Spots:");
for (const w of weak) {
console.log(` ${w.time_seconds}s → ${w.score}`);
}
console.log();
}

console.log(` ID: ${data.id}`);
console.log();
} catch (err) {
printError((err as Error).message);
}
});
96 changes: 96 additions & 0 deletions src/commands/predictions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { Command } from "commander";
import { get } from "../client.js";
import { printJson, printTable, printError } from "../output.js";

const listCommand = new Command("list")
.description("List past engagement predictions")
.option("--json", "Output as JSON")
.option("--limit <limit>", "Maximum results to return", "20")
.option("--offset <offset>", "Number of results to skip", "0")
.action(async (opts) => {
try {
const params: Record<string, string> = {};
if (opts.limit) params.limit = opts.limit;
if (opts.offset) params.offset = opts.offset;

const data = await get("/api/predictions", params);
const predictions =
(data.predictions as Record<string, unknown>[]) || [];

if (opts.json) {
printJson(predictions);
} else {
printTable(predictions, [
{ key: "id", label: "ID" },
{ key: "modality", label: "MODALITY" },
{ key: "engagement_score", label: "SCORE" },
{ key: "created_at", label: "CREATED" },
]);
}
} catch (err) {
printError((err as Error).message);
}
});

const getCommand = new Command("get")
.description("Get a specific prediction by ID")
.argument("<id>", "Prediction UUID")
.option("--json", "Output as JSON")
.action(async (id: string, opts) => {
try {
const data = await get(`/api/predictions/${id}`);

if (opts.json) {
printJson(data);
return;
}

console.log();
console.log(` ID: ${data.id}`);
console.log(` Engagement Score: ${data.engagement_score}`);
console.log(` Modality: ${data.modality}`);
console.log(` File URL: ${data.file_url}`);
console.log(
` Duration: ${data.total_duration_seconds}s`,
);
console.log(` Inference Time: ${data.elapsed_seconds}s`);
console.log(` Created: ${data.created_at}`);
console.log();

const peaks = data.peak_moments as
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The peak-moments and weak-spots rendering blocks are duplicated almost verbatim from predict.ts. If the API response shape changes (e.g., a renamed field), both files need identical edits. Consider extracting a small shared helper (e.g., printMoments(label, items)) to keep them in sync.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/commands/predictions.ts, line 60:

<comment>The peak-moments and weak-spots rendering blocks are duplicated almost verbatim from `predict.ts`. If the API response shape changes (e.g., a renamed field), both files need identical edits. Consider extracting a small shared helper (e.g., `printMoments(label, items)`) to keep them in sync.</comment>

<file context>
@@ -0,0 +1,96 @@
+      console.log(`  Created:          ${data.created_at}`);
+      console.log();
+
+      const peaks = data.peak_moments as
+        | { time_seconds: number; score: number }[]
+        | undefined;
</file context>
Fix with Cubic

| { time_seconds: number; score: number }[]
| undefined;
if (peaks && peaks.length > 0) {
console.log(" Peak Moments:");
for (const p of peaks) {
console.log(` ${p.time_seconds}s → ${p.score}`);
}
console.log();
}

const weak = data.weak_spots as
| { time_seconds: number; score: number }[]
| undefined;
if (weak && weak.length > 0) {
console.log(" Weak Spots:");
for (const w of weak) {
console.log(` ${w.time_seconds}s → ${w.score}`);
}
console.log();
}
} catch (err) {
printError((err as Error).message);
}
});

/**
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Custom agent: Flag AI Slop and Fabricated Changes

Remove this narrating JSDoc block — it restates what .description() and the subcommand definitions already express. No other command file in the project has such a comment, and Commander already exposes this information via --help.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/commands/predictions.ts, line 86:

<comment>Remove this narrating JSDoc block — it restates what `.description()` and the subcommand definitions already express. No other command file in the project has such a comment, and Commander already exposes this information via `--help`.</comment>

<file context>
@@ -0,0 +1,96 @@
+    }
+  });
+
+/**
+ * `recoup predictions` — manage engagement prediction history.
+ *
</file context>
Fix with Cubic

* `recoup predictions` — manage engagement prediction history.
*
* Subcommands:
* list — List past predictions with scores
* get — Get full prediction detail by ID
*/
export const predictionsCommand = new Command("predictions")
.description("Manage engagement prediction history")
.addCommand(listCommand)
.addCommand(getCommand);
Loading