From 315351a0b45ae7cf70cbc36ef4e39ad7d3cc03ce Mon Sep 17 00:00:00 2001 From: Recoup Agent Date: Sat, 14 Mar 2026 23:12:44 +0000 Subject: [PATCH] agent: @U0AJM7X8FBR @U0AJM7X8FBR become an expert at this repo https://github.c --- __tests__/bin.test.ts | 12 ++--- __tests__/client.test.ts | 6 +-- __tests__/commands/artists.test.ts | 10 ++--- __tests__/commands/chats.test.ts | 10 ++--- __tests__/commands/content.test.ts | 55 +++++++++++++---------- __tests__/commands/notifications.test.ts | 56 ++++++------------------ __tests__/commands/orgs.test.ts | 10 ++--- __tests__/commands/sandboxes.test.ts | 19 +++----- __tests__/commands/songs.test.ts | 55 +++++++++++++++-------- __tests__/commands/tasks.test.ts | 6 +-- __tests__/commands/whoami.test.ts | 10 ++--- __tests__/output.test.ts | 8 +--- src/bin.ts | 5 +-- src/client.ts | 20 +++++---- src/commands/artists.ts | 2 +- src/commands/chats.ts | 4 +- src/commands/content.ts | 5 ++- src/commands/content/parsePositiveInt.ts | 5 +++ src/commands/notifications.ts | 13 ++++-- src/commands/orgs.ts | 2 +- src/commands/sandboxes.ts | 4 +- src/commands/songs.ts | 8 ++-- src/commands/tasks.ts | 5 ++- src/commands/whoami.ts | 2 +- src/config.ts | 10 +++-- src/getErrorMessage.ts | 4 ++ src/output.ts | 30 ++++++++----- 27 files changed, 188 insertions(+), 188 deletions(-) diff --git a/__tests__/bin.test.ts b/__tests__/bin.test.ts index aa1c0ea..df9a5b0 100644 --- a/__tests__/bin.test.ts +++ b/__tests__/bin.test.ts @@ -5,15 +5,11 @@ import { execFileSync } from "node:child_process"; describe("CLI version", () => { it("reports the version from package.json", () => { - const pkg = JSON.parse( - readFileSync(join(__dirname, "..", "package.json"), "utf-8"), - ); + const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8")); - const output = execFileSync( - "node", - [join(__dirname, "..", "dist", "bin.cjs"), "--version"], - { encoding: "utf-8" }, - ).trim(); + const output = execFileSync("node", [join(__dirname, "..", "dist", "bin.cjs"), "--version"], { + encoding: "utf-8", + }).trim(); expect(output).toBe(pkg.version); }); diff --git a/__tests__/client.test.ts b/__tests__/client.test.ts index 40ff3c0..c8860e0 100644 --- a/__tests__/client.test.ts +++ b/__tests__/client.test.ts @@ -73,8 +73,7 @@ describe("get", () => { it("throws on API error status", async () => { mockFetch.mockResolvedValue({ ok: true, - json: () => - Promise.resolve({ status: "error", error: "Something went wrong" }), + json: () => Promise.resolve({ status: "error", error: "Something went wrong" }), }); await expect(get("/api/test")).rejects.toThrow("Something went wrong"); @@ -105,8 +104,7 @@ describe("post", () => { mockFetch.mockResolvedValue({ ok: false, status: 400, - json: () => - Promise.resolve({ status: "error", message: "Bad request" }), + json: () => Promise.resolve({ status: "error", message: "Bad request" }), }); await expect(post("/api/test", {})).rejects.toThrow("Bad request"); diff --git a/__tests__/commands/artists.test.ts b/__tests__/commands/artists.test.ts index b6de57a..86589f9 100644 --- a/__tests__/commands/artists.test.ts +++ b/__tests__/commands/artists.test.ts @@ -1,13 +1,13 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { artistsCommand } from "../../src/commands/artists.js"; +import { get } from "../../src/client.js"; + vi.mock("../../src/client.js", () => ({ get: vi.fn(), post: vi.fn(), })); -import { artistsCommand } from "../../src/commands/artists.js"; -import { get } from "../../src/client.js"; - let logSpy: ReturnType; let errorSpy: ReturnType; let exitSpy: ReturnType; @@ -15,9 +15,7 @@ let exitSpy: ReturnType; beforeEach(() => { logSpy = vi.spyOn(console, "log").mockImplementation(() => {}); errorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); - exitSpy = vi - .spyOn(process, "exit") - .mockImplementation(() => undefined as never); + exitSpy = vi.spyOn(process, "exit").mockImplementation(() => undefined as never); }); afterEach(() => { diff --git a/__tests__/commands/chats.test.ts b/__tests__/commands/chats.test.ts index aa9a5cc..c540257 100644 --- a/__tests__/commands/chats.test.ts +++ b/__tests__/commands/chats.test.ts @@ -1,13 +1,13 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { chatsCommand } from "../../src/commands/chats.js"; +import { get, post } from "../../src/client.js"; + vi.mock("../../src/client.js", () => ({ get: vi.fn(), post: vi.fn(), })); -import { chatsCommand } from "../../src/commands/chats.js"; -import { get, post } from "../../src/client.js"; - let logSpy: ReturnType; let errorSpy: ReturnType; let exitSpy: ReturnType; @@ -15,9 +15,7 @@ let exitSpy: ReturnType; beforeEach(() => { logSpy = vi.spyOn(console, "log").mockImplementation(() => {}); errorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); - exitSpy = vi - .spyOn(process, "exit") - .mockImplementation(() => undefined as never); + exitSpy = vi.spyOn(process, "exit").mockImplementation(() => undefined as never); }); afterEach(() => { diff --git a/__tests__/commands/content.test.ts b/__tests__/commands/content.test.ts index 37717cf..421e422 100644 --- a/__tests__/commands/content.test.ts +++ b/__tests__/commands/content.test.ts @@ -1,13 +1,13 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { contentCommand } from "../../src/commands/content.js"; +import { get, post } from "../../src/client.js"; + vi.mock("../../src/client.js", () => ({ get: vi.fn(), post: vi.fn(), })); -import { contentCommand } from "../../src/commands/content.js"; -import { get, post } from "../../src/client.js"; - let logSpy: ReturnType; let errorSpy: ReturnType; let exitSpy: ReturnType; @@ -26,17 +26,13 @@ describe("content command", () => { it("lists templates", async () => { vi.mocked(get).mockResolvedValue({ status: "success", - templates: [ - { name: "artist-caption-bedroom", description: "Moody purple bedroom setting" }, - ], + templates: [{ name: "artist-caption-bedroom", description: "Moody purple bedroom setting" }], }); await contentCommand.parseAsync(["templates"], { from: "user" }); expect(get).toHaveBeenCalledWith("/api/content/templates"); - expect(logSpy).toHaveBeenCalledWith( - "- artist-caption-bedroom: Moody purple bedroom setting", - ); + expect(logSpy).toHaveBeenCalledWith("- artist-caption-bedroom: Moody purple bedroom setting"); }); it("validates an artist", async () => { @@ -47,7 +43,10 @@ describe("content command", () => { missing: [], }); - await contentCommand.parseAsync(["validate", "--artist", "550e8400-e29b-41d4-a716-446655440000"], { from: "user" }); + await contentCommand.parseAsync( + ["validate", "--artist", "550e8400-e29b-41d4-a716-446655440000"], + { from: "user" }, + ); expect(get).toHaveBeenCalledWith("/api/content/validate", { artist_account_id: "550e8400-e29b-41d4-a716-446655440000", @@ -79,7 +78,13 @@ describe("content command", () => { }); await contentCommand.parseAsync( - ["create", "--artist", "550e8400-e29b-41d4-a716-446655440000", "--template", "artist-caption-bedroom"], + [ + "create", + "--artist", + "550e8400-e29b-41d4-a716-446655440000", + "--template", + "artist-caption-bedroom", + ], { from: "user" }, ); @@ -129,10 +134,9 @@ describe("content command", () => { }); it("errors when --batch is not a positive integer", async () => { - await contentCommand.parseAsync( - ["create", "--artist", "test-artist", "--batch", "abc"], - { from: "user" }, - ); + await contentCommand.parseAsync(["create", "--artist", "test-artist", "--batch", "abc"], { + from: "user", + }); expect(errorSpy).toHaveBeenCalledWith("Error: --batch must be a positive integer"); expect(exitSpy).toHaveBeenCalledWith(1); @@ -155,14 +159,9 @@ describe("content command", () => { status: "error", }); - await contentCommand.parseAsync( - ["create", "--artist", "test-artist"], - { from: "user" }, - ); + await contentCommand.parseAsync(["create", "--artist", "test-artist"], { from: "user" }); - expect(errorSpy).toHaveBeenCalledWith( - "Error: Response did not include any run IDs", - ); + expect(errorSpy).toHaveBeenCalledWith("Error: Response did not include any run IDs"); expect(exitSpy).toHaveBeenCalledWith(1); }); @@ -173,7 +172,16 @@ describe("content command", () => { }); await contentCommand.parseAsync( - ["create", "--artist", "test-artist", "--caption-length", "long", "--upscale", "--batch", "3"], + [ + "create", + "--artist", + "test-artist", + "--caption-length", + "long", + "--upscale", + "--batch", + "3", + ], { from: "user" }, ); @@ -188,4 +196,3 @@ describe("content command", () => { expect(logSpy).toHaveBeenCalledWith("Batch started: 3 videos"); }); }); - diff --git a/__tests__/commands/notifications.test.ts b/__tests__/commands/notifications.test.ts index fd577e9..4c4c786 100644 --- a/__tests__/commands/notifications.test.ts +++ b/__tests__/commands/notifications.test.ts @@ -1,13 +1,13 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { notificationsCommand } from "../../src/commands/notifications.js"; +import { post } from "../../src/client.js"; + vi.mock("../../src/client.js", () => ({ get: vi.fn(), post: vi.fn(), })); -import { notificationsCommand } from "../../src/commands/notifications.js"; -import { post } from "../../src/client.js"; - let logSpy: ReturnType; let errorSpy: ReturnType; let exitSpy: ReturnType; @@ -15,9 +15,7 @@ let exitSpy: ReturnType; beforeEach(() => { logSpy = vi.spyOn(console, "log").mockImplementation(() => {}); errorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); - exitSpy = vi - .spyOn(process, "exit") - .mockImplementation(() => undefined as never); + exitSpy = vi.spyOn(process, "exit").mockImplementation(() => undefined as never); }); afterEach(() => { @@ -32,10 +30,9 @@ describe("notifications command", () => { id: "email-123", }); - await notificationsCommand.parseAsync( - ["--subject", "Test Subject", "--text", "Hello world"], - { from: "user" }, - ); + await notificationsCommand.parseAsync(["--subject", "Test Subject", "--text", "Hello world"], { + from: "user", + }); expect(post).toHaveBeenCalledWith("/api/notifications", { subject: "Test Subject", @@ -70,16 +67,7 @@ describe("notifications command", () => { }); await notificationsCommand.parseAsync( - [ - "--subject", - "Update", - "--text", - "Hello", - "--cc", - "cc@example.com", - "--room-id", - "room-abc", - ], + ["--subject", "Update", "--text", "Hello", "--cc", "cc@example.com", "--room-id", "room-abc"], { from: "user" }, ); @@ -99,14 +87,7 @@ describe("notifications command", () => { }); await notificationsCommand.parseAsync( - [ - "--subject", - "Update", - "--cc", - "a@example.com", - "--cc", - "b@example.com", - ], + ["--subject", "Update", "--cc", "a@example.com", "--cc", "b@example.com"], { from: "user" }, ); @@ -124,14 +105,9 @@ describe("notifications command", () => { }; vi.mocked(post).mockResolvedValue(response); - await notificationsCommand.parseAsync( - ["--subject", "Test", "--json"], - { from: "user" }, - ); + await notificationsCommand.parseAsync(["--subject", "Test", "--json"], { from: "user" }); - expect(logSpy).toHaveBeenCalledWith( - JSON.stringify(response, null, 2), - ); + expect(logSpy).toHaveBeenCalledWith(JSON.stringify(response, null, 2)); }); it("passes account_id when --account flag is provided", async () => { @@ -167,10 +143,7 @@ describe("notifications command", () => { id: "email-no-account", }); - await notificationsCommand.parseAsync( - ["--subject", "Test"], - { from: "user" }, - ); + await notificationsCommand.parseAsync(["--subject", "Test"], { from: "user" }); expect(post).toHaveBeenCalledWith("/api/notifications", { subject: "Test", @@ -180,10 +153,7 @@ describe("notifications command", () => { it("prints error on failure", async () => { vi.mocked(post).mockRejectedValue(new Error("No email address found")); - await notificationsCommand.parseAsync( - ["--subject", "Test"], - { from: "user" }, - ); + await notificationsCommand.parseAsync(["--subject", "Test"], { from: "user" }); expect(errorSpy).toHaveBeenCalledWith("Error: No email address found"); expect(exitSpy).toHaveBeenCalledWith(1); diff --git a/__tests__/commands/orgs.test.ts b/__tests__/commands/orgs.test.ts index 3b10431..8ab4c50 100644 --- a/__tests__/commands/orgs.test.ts +++ b/__tests__/commands/orgs.test.ts @@ -1,13 +1,13 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { orgsCommand } from "../../src/commands/orgs.js"; +import { get } from "../../src/client.js"; + vi.mock("../../src/client.js", () => ({ get: vi.fn(), post: vi.fn(), })); -import { orgsCommand } from "../../src/commands/orgs.js"; -import { get } from "../../src/client.js"; - let logSpy: ReturnType; let errorSpy: ReturnType; let exitSpy: ReturnType; @@ -15,9 +15,7 @@ let exitSpy: ReturnType; beforeEach(() => { logSpy = vi.spyOn(console, "log").mockImplementation(() => {}); errorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); - exitSpy = vi - .spyOn(process, "exit") - .mockImplementation(() => undefined as never); + exitSpy = vi.spyOn(process, "exit").mockImplementation(() => undefined as never); }); afterEach(() => { diff --git a/__tests__/commands/sandboxes.test.ts b/__tests__/commands/sandboxes.test.ts index 3dcdedf..4da5e8f 100644 --- a/__tests__/commands/sandboxes.test.ts +++ b/__tests__/commands/sandboxes.test.ts @@ -1,13 +1,13 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { sandboxesCommand } from "../../src/commands/sandboxes.js"; +import { get, post } from "../../src/client.js"; + vi.mock("../../src/client.js", () => ({ get: vi.fn(), post: vi.fn(), })); -import { sandboxesCommand } from "../../src/commands/sandboxes.js"; -import { get, post } from "../../src/client.js"; - let logSpy: ReturnType; let errorSpy: ReturnType; let exitSpy: ReturnType; @@ -15,9 +15,7 @@ let exitSpy: ReturnType; beforeEach(() => { logSpy = vi.spyOn(console, "log").mockImplementation(() => {}); errorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); - exitSpy = vi - .spyOn(process, "exit") - .mockImplementation(() => undefined as never); + exitSpy = vi.spyOn(process, "exit").mockImplementation(() => undefined as never); }); afterEach(() => { @@ -44,9 +42,7 @@ describe("sandboxes list", () => { }); it("prints JSON with --json flag", async () => { - const sandboxes = [ - { sandboxId: "sb-1", sandboxStatus: "running", createdAt: "2025-01-01" }, - ]; + const sandboxes = [{ sandboxId: "sb-1", sandboxStatus: "running", createdAt: "2025-01-01" }]; vi.mocked(get).mockResolvedValue({ status: "success", sandboxes }); await sandboxesCommand.parseAsync(["list", "--json"], { from: "user" }); @@ -74,10 +70,7 @@ describe("sandboxes create", () => { sandboxes: [{ sandboxId: "sb-new" }], }); - await sandboxesCommand.parseAsync( - ["create", "--command", "echo hello"], - { from: "user" }, - ); + await sandboxesCommand.parseAsync(["create", "--command", "echo hello"], { from: "user" }); expect(post).toHaveBeenCalledWith("/api/sandboxes", { command: "echo hello", diff --git a/__tests__/commands/songs.test.ts b/__tests__/commands/songs.test.ts index c8cfa3f..3125974 100644 --- a/__tests__/commands/songs.test.ts +++ b/__tests__/commands/songs.test.ts @@ -1,13 +1,13 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { songsCommand } from "../../src/commands/songs.js"; +import { get, post } from "../../src/client.js"; + vi.mock("../../src/client.js", () => ({ get: vi.fn(), post: vi.fn(), })); -import { songsCommand } from "../../src/commands/songs.js"; -import { get, post } from "../../src/client.js"; - let logSpy: ReturnType; let errorSpy: ReturnType; let exitSpy: ReturnType; @@ -15,9 +15,7 @@ let exitSpy: ReturnType; beforeEach(() => { logSpy = vi.spyOn(console, "log").mockImplementation(() => {}); errorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); - exitSpy = vi - .spyOn(process, "exit") - .mockImplementation(() => undefined as never); + exitSpy = vi.spyOn(process, "exit").mockImplementation(() => undefined as never); }); afterEach(() => { @@ -47,7 +45,10 @@ describe("songs analyze", () => { elapsed_seconds: 8.0, }); - await songsCommand.parseAsync(["analyze", "--preset", "catalog_metadata", "--audio", "https://example.com/song.mp3"], { from: "user" }); + await songsCommand.parseAsync( + ["analyze", "--preset", "catalog_metadata", "--audio", "https://example.com/song.mp3"], + { from: "user" }, + ); expect(post).toHaveBeenCalledWith("/api/songs/analyze", { preset: "catalog_metadata", @@ -62,7 +63,9 @@ describe("songs analyze", () => { elapsed_seconds: 2.5, }); - await songsCommand.parseAsync(["analyze", "--prompt", "Describe this track."], { from: "user" }); + await songsCommand.parseAsync(["analyze", "--prompt", "Describe this track."], { + from: "user", + }); expect(logSpy).toHaveBeenCalledWith("This is a jazz piece in Bb major."); }); @@ -74,11 +77,12 @@ describe("songs analyze", () => { elapsed_seconds: 10.0, }); - await songsCommand.parseAsync(["analyze", "--preset", "catalog_metadata", "--audio", "https://example.com/song.mp3"], { from: "user" }); - - expect(logSpy).toHaveBeenCalledWith( - JSON.stringify({ genre: "pop", tempo_bpm: 96 }, null, 2), + await songsCommand.parseAsync( + ["analyze", "--preset", "catalog_metadata", "--audio", "https://example.com/song.mp3"], + { from: "user" }, ); + + expect(logSpy).toHaveBeenCalledWith(JSON.stringify({ genre: "pop", tempo_bpm: 96 }, null, 2)); }); it("prints full JSON with --json flag", async () => { @@ -89,7 +93,9 @@ describe("songs analyze", () => { }; vi.mocked(post).mockResolvedValue(data); - await songsCommand.parseAsync(["analyze", "--prompt", "Describe this.", "--json"], { from: "user" }); + await songsCommand.parseAsync(["analyze", "--prompt", "Describe this.", "--json"], { + from: "user", + }); expect(logSpy).toHaveBeenCalledWith(JSON.stringify(data, null, 2)); }); @@ -101,7 +107,10 @@ describe("songs analyze", () => { elapsed_seconds: 10.0, }); - await songsCommand.parseAsync(["analyze", "--prompt", "Describe this.", "--audio", "https://example.com/song.mp3"], { from: "user" }); + await songsCommand.parseAsync( + ["analyze", "--prompt", "Describe this.", "--audio", "https://example.com/song.mp3"], + { from: "user" }, + ); expect(post).toHaveBeenCalledWith("/api/songs/analyze", { prompt: "Describe this.", @@ -131,8 +140,18 @@ describe("songs presets", () => { vi.mocked(get).mockResolvedValue({ status: "success", presets: [ - { name: "catalog_metadata", description: "Catalog enrichment", requiresAudio: true, responseFormat: "json" }, - { name: "mood_tags", description: "Mood tags", requiresAudio: true, responseFormat: "json" }, + { + name: "catalog_metadata", + description: "Catalog enrichment", + requiresAudio: true, + responseFormat: "json", + }, + { + name: "mood_tags", + description: "Mood tags", + requiresAudio: true, + responseFormat: "json", + }, ], }); @@ -143,9 +162,7 @@ describe("songs presets", () => { }); it("prints JSON with --json flag", async () => { - const presets = [ - { name: "catalog_metadata", description: "Catalog enrichment" }, - ]; + const presets = [{ name: "catalog_metadata", description: "Catalog enrichment" }]; vi.mocked(get).mockResolvedValue({ status: "success", presets }); await songsCommand.parseAsync(["presets", "--json"], { from: "user" }); diff --git a/__tests__/commands/tasks.test.ts b/__tests__/commands/tasks.test.ts index 733a26b..82d84d2 100644 --- a/__tests__/commands/tasks.test.ts +++ b/__tests__/commands/tasks.test.ts @@ -1,13 +1,13 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { tasksCommand } from "../../src/commands/tasks.js"; +import { get } from "../../src/client.js"; + vi.mock("../../src/client.js", () => ({ get: vi.fn(), post: vi.fn(), })); -import { tasksCommand } from "../../src/commands/tasks.js"; -import { get } from "../../src/client.js"; - let logSpy: ReturnType; let errorSpy: ReturnType; let exitSpy: ReturnType; diff --git a/__tests__/commands/whoami.test.ts b/__tests__/commands/whoami.test.ts index ae3d2dd..1c5a770 100644 --- a/__tests__/commands/whoami.test.ts +++ b/__tests__/commands/whoami.test.ts @@ -1,13 +1,13 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { whoamiCommand } from "../../src/commands/whoami.js"; +import { get } from "../../src/client.js"; + vi.mock("../../src/client.js", () => ({ get: vi.fn(), post: vi.fn(), })); -import { whoamiCommand } from "../../src/commands/whoami.js"; -import { get } from "../../src/client.js"; - let logSpy: ReturnType; let errorSpy: ReturnType; let exitSpy: ReturnType; @@ -15,9 +15,7 @@ let exitSpy: ReturnType; beforeEach(() => { logSpy = vi.spyOn(console, "log").mockImplementation(() => {}); errorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); - exitSpy = vi - .spyOn(process, "exit") - .mockImplementation(() => undefined as never); + exitSpy = vi.spyOn(process, "exit").mockImplementation(() => undefined as never); }); afterEach(() => { diff --git a/__tests__/output.test.ts b/__tests__/output.test.ts index 5311739..ef7c56d 100644 --- a/__tests__/output.test.ts +++ b/__tests__/output.test.ts @@ -16,9 +16,7 @@ afterEach(() => { describe("printJson", () => { it("prints formatted JSON", () => { printJson({ foo: "bar", count: 42 }); - expect(logSpy).toHaveBeenCalledWith( - JSON.stringify({ foo: "bar", count: 42 }, null, 2), - ); + expect(logSpy).toHaveBeenCalledWith(JSON.stringify({ foo: "bar", count: 42 }, null, 2)); }); }); @@ -62,9 +60,7 @@ describe("printTable", () => { describe("printError", () => { it("prints error to stderr and exits", () => { - const exitSpy = vi - .spyOn(process, "exit") - .mockImplementation(() => undefined as never); + const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => undefined as never); printError("something failed"); diff --git a/src/bin.ts b/src/bin.ts index 5608963..34bedb2 100644 --- a/src/bin.ts +++ b/src/bin.ts @@ -16,10 +16,7 @@ const { version } = JSON.parse(readFileSync(pkgPath, "utf-8")); const program = new Command(); -program - .name("recoup") - .description("Recoup platform CLI") - .version(version); +program.name("recoup").description("Recoup platform CLI").version(version); program.addCommand(whoamiCommand); program.addCommand(artistsCommand); diff --git a/src/client.ts b/src/client.ts index d2d326a..beeda5b 100644 --- a/src/client.ts +++ b/src/client.ts @@ -7,10 +7,12 @@ export interface ApiResponse { [key: string]: unknown; } -export async function get( - path: string, - params?: Record, -): Promise { +/** + * + * @param path + * @param params + */ +export async function get(path: string, params?: Record): Promise { const baseUrl = getBaseUrl(); const url = new URL(path, baseUrl); if (params) { @@ -38,10 +40,12 @@ export async function get( return data; } -export async function post( - path: string, - body: Record, -): Promise { +/** + * + * @param path + * @param body + */ +export async function post(path: string, body: Record): Promise { const baseUrl = getBaseUrl(); const url = new URL(path, baseUrl); diff --git a/src/commands/artists.ts b/src/commands/artists.ts index 123d834..518e344 100644 --- a/src/commands/artists.ts +++ b/src/commands/artists.ts @@ -7,7 +7,7 @@ const listCommand = new Command("list") .option("--json", "Output as JSON") .option("--org ", "Filter by organization ID") .option("--account ", "Filter by account ID") - .action(async (opts) => { + .action(async opts => { try { const params: Record = {}; if (opts.org) params.org_id = opts.org; diff --git a/src/commands/chats.ts b/src/commands/chats.ts index 65761b1..390369d 100644 --- a/src/commands/chats.ts +++ b/src/commands/chats.ts @@ -5,7 +5,7 @@ import { printJson, printTable, printError } from "../output.js"; const listCommand = new Command("list") .description("List chats for the current account") .option("--json", "Output as JSON") - .action(async (opts) => { + .action(async opts => { try { const data = await get("/api/chats"); const chats = (data.chats as Record[]) || []; @@ -29,7 +29,7 @@ const createCommand = new Command("create") .option("--name ", "Chat topic") .option("--artist ", "Artist ID") .option("--json", "Output as JSON") - .action(async (opts) => { + .action(async opts => { try { const body: Record = {}; if (opts.name) body.topic = opts.name; diff --git a/src/commands/content.ts b/src/commands/content.ts index 6180412..6895bab 100644 --- a/src/commands/content.ts +++ b/src/commands/content.ts @@ -4,8 +4,9 @@ import { validateCommand } from "./content/validateCommand.js"; import { estimateCommand } from "./content/estimateCommand.js"; import { createCommand } from "./content/createCommand.js"; -export const contentCommand = new Command("content") - .description("Content-creation pipeline commands"); +export const contentCommand = new Command("content").description( + "Content-creation pipeline commands", +); contentCommand.addCommand(templatesCommand); contentCommand.addCommand(validateCommand); diff --git a/src/commands/content/parsePositiveInt.ts b/src/commands/content/parsePositiveInt.ts index 43dca7e..bac09f0 100644 --- a/src/commands/content/parsePositiveInt.ts +++ b/src/commands/content/parsePositiveInt.ts @@ -1,3 +1,8 @@ +/** + * + * @param value + * @param flag + */ export function parsePositiveInt(value: string, flag: string): number { const parsed = parseInt(value, 10); if (!Number.isInteger(parsed) || parsed < 1) { diff --git a/src/commands/notifications.ts b/src/commands/notifications.ts index 5e33011..474c52b 100644 --- a/src/commands/notifications.ts +++ b/src/commands/notifications.ts @@ -3,15 +3,22 @@ import { post } from "../client.js"; import { printJson, printError } from "../output.js"; export const notificationsCommand = new Command("notifications") - .description("Send an email to the account owner. The recipient is automatically resolved from your API key — no --to flag needed. Only --subject is required.") + .description( + "Send an email to the account owner. The recipient is automatically resolved from your API key — no --to flag needed. Only --subject is required.", + ) .requiredOption("--subject ", "Email subject line") .option("--text ", "Plain text or Markdown body") .option("--html ", "Raw HTML body (takes precedence over --text)") - .option("--cc ", "CC recipient (repeatable)", (val: string, prev: string[]) => prev.concat(val), [] as string[]) + .option( + "--cc ", + "CC recipient (repeatable)", + (val: string, prev: string[]) => prev.concat(val), + [] as string[], + ) .option("--room-id ", "Room ID for chat link in footer") .option("--account ", "Send to a specific account (org keys only)") .option("--json", "Output as JSON") - .action(async (opts) => { + .action(async opts => { try { const body: Record = { subject: opts.subject, diff --git a/src/commands/orgs.ts b/src/commands/orgs.ts index 92443d9..c1afd5c 100644 --- a/src/commands/orgs.ts +++ b/src/commands/orgs.ts @@ -6,7 +6,7 @@ const listCommand = new Command("list") .description("List organizations for the current account") .option("--json", "Output as JSON") .option("--account ", "Filter by account ID") - .action(async (opts) => { + .action(async opts => { try { const params: Record = {}; if (opts.account) params.account_id = opts.account; diff --git a/src/commands/sandboxes.ts b/src/commands/sandboxes.ts index 3a0f17f..09dfa87 100644 --- a/src/commands/sandboxes.ts +++ b/src/commands/sandboxes.ts @@ -5,7 +5,7 @@ import { printJson, printTable, printError } from "../output.js"; const listCommand = new Command("list") .description("List sandboxes for the current account") .option("--json", "Output as JSON") - .action(async (opts) => { + .action(async opts => { try { const data = await get("/api/sandboxes"); const sandboxes = (data.sandboxes as Record[]) || []; @@ -28,7 +28,7 @@ const createCommand = new Command("create") .description("Create a new sandbox") .option("--command ", "Command to run in sandbox") .option("--json", "Output as JSON") - .action(async (opts) => { + .action(async opts => { try { const body: Record = {}; if (opts.command) body.command = opts.command; diff --git a/src/commands/songs.ts b/src/commands/songs.ts index 6f48f5d..d8f9bf5 100644 --- a/src/commands/songs.ts +++ b/src/commands/songs.ts @@ -9,10 +9,12 @@ const analyzeCommand = new Command("analyze") .option("--audio ", "Public URL to an audio file (MP3, WAV, FLAC)") .option("--max-tokens ", "Max tokens to generate (default 512)", parseInt) .option("--json", "Output as JSON") - .action(async (opts) => { + .action(async opts => { try { if (!opts.prompt && !opts.preset) { - console.error("Error: Provide --prompt or use --preset . Run 'recoup songs presets' to see available presets."); + console.error( + "Error: Provide --prompt or use --preset . Run 'recoup songs presets' to see available presets.", + ); process.exit(1); } @@ -57,7 +59,7 @@ const analyzeCommand = new Command("analyze") const presetsCommand = new Command("presets") .description("List available analysis presets") .option("--json", "Output as JSON") - .action(async (opts) => { + .action(async opts => { try { const data = await get("/api/songs/analyze/presets"); const presets = (data.presets as Record[]) || []; diff --git a/src/commands/tasks.ts b/src/commands/tasks.ts index 7379930..21393bc 100644 --- a/src/commands/tasks.ts +++ b/src/commands/tasks.ts @@ -1,7 +1,8 @@ import { Command } from "commander"; import { statusCommand } from "./tasks/statusCommand.js"; -export const tasksCommand = new Command("tasks") - .description("Check the status of background task runs"); +export const tasksCommand = new Command("tasks").description( + "Check the status of background task runs", +); tasksCommand.addCommand(statusCommand); diff --git a/src/commands/whoami.ts b/src/commands/whoami.ts index 10f15be..e3ffa60 100644 --- a/src/commands/whoami.ts +++ b/src/commands/whoami.ts @@ -5,7 +5,7 @@ import { printJson, printError } from "../output.js"; export const whoamiCommand = new Command("whoami") .description("Show the current authenticated account") .option("--json", "Output as JSON") - .action(async (opts) => { + .action(async opts => { try { const data = await get("/api/accounts/id"); if (opts.json) { diff --git a/src/config.ts b/src/config.ts index b7381d2..f4271e1 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,3 +1,6 @@ +/** + * + */ export function getApiKey(): string { const key = process.env.RECOUP_API_KEY; if (!key) { @@ -10,8 +13,9 @@ export function getApiKey(): string { return key; } +/** + * + */ export function getBaseUrl(): string { - return ( - process.env.RECOUP_API_URL || "https://recoup-api.vercel.app" - ); + return process.env.RECOUP_API_URL || "https://recoup-api.vercel.app"; } diff --git a/src/getErrorMessage.ts b/src/getErrorMessage.ts index 6c83786..a42b32e 100644 --- a/src/getErrorMessage.ts +++ b/src/getErrorMessage.ts @@ -1,3 +1,7 @@ +/** + * + * @param err + */ export function getErrorMessage(err: unknown): string { return err instanceof Error ? err.message : String(err); } diff --git a/src/output.ts b/src/output.ts index ce424b7..0073378 100644 --- a/src/output.ts +++ b/src/output.ts @@ -1,7 +1,16 @@ +/** + * + * @param data + */ export function printJson(data: unknown): void { console.log(JSON.stringify(data, null, 2)); } +/** + * + * @param rows + * @param columns + */ export function printTable( rows: Record[], columns: { key: string; label: string }[], @@ -11,29 +20,26 @@ export function printTable( return; } - const widths = columns.map((col) => - Math.max( - col.label.length, - ...rows.map((row) => String(row[col.key] ?? "").length), - ), + const widths = columns.map(col => + Math.max(col.label.length, ...rows.map(row => String(row[col.key] ?? "").length)), ); - const header = columns - .map((col, i) => col.label.padEnd(widths[i])) - .join(" "); - const separator = widths.map((w) => "-".repeat(w)).join(" "); + const header = columns.map((col, i) => col.label.padEnd(widths[i])).join(" "); + const separator = widths.map(w => "-".repeat(w)).join(" "); console.log(header); console.log(separator); for (const row of rows) { - const line = columns - .map((col, i) => String(row[col.key] ?? "").padEnd(widths[i])) - .join(" "); + const line = columns.map((col, i) => String(row[col.key] ?? "").padEnd(widths[i])).join(" "); console.log(line); } } +/** + * + * @param message + */ export function printError(message: string): void { console.error(`Error: ${message}`); process.exit(1);