wmstudio-cli 0.2.8 → 0.2.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/index.js +37 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -54,6 +54,14 @@ var DEFAULT_MODELS = {
|
|
|
54
54
|
casting: "fal-ai/nano-banana-pro",
|
|
55
55
|
ugcRoom: "fal-ai/nano-banana-pro"
|
|
56
56
|
};
|
|
57
|
+
var ASPECT_RATIOS = [
|
|
58
|
+
{ value: "1:1", label: "Square (1:1)" },
|
|
59
|
+
{ value: "16:9", label: "Landscape (16:9)" },
|
|
60
|
+
{ value: "9:16", label: "Portrait (9:16)" },
|
|
61
|
+
{ value: "4:3", label: "Classic (4:3)" },
|
|
62
|
+
{ value: "3:4", label: "Tall (3:4)" },
|
|
63
|
+
{ value: "21:9", label: "Ultrawide (21:9)" }
|
|
64
|
+
];
|
|
57
65
|
|
|
58
66
|
// src/config.ts
|
|
59
67
|
var FileConfigSchema = z.object({
|
|
@@ -265,11 +273,14 @@ var WmApiClient = class {
|
|
|
265
273
|
clearTimeout(timeout);
|
|
266
274
|
if (err instanceof WmCliError) throw err;
|
|
267
275
|
const aborted = err?.name === "AbortError";
|
|
276
|
+
const e = err;
|
|
277
|
+
const cause = e?.cause;
|
|
278
|
+
const causeMsg = cause?.code ?? cause?.message;
|
|
268
279
|
throw new WmCliError({
|
|
269
280
|
code: aborted ? "timeout" : "network",
|
|
270
281
|
exitCode: aborted ? ExitCode.TIMEOUT : ExitCode.NETWORK,
|
|
271
|
-
message: aborted ? `Request timed out after ${timeoutMs}ms (${req.method} ${
|
|
272
|
-
details: { cause:
|
|
282
|
+
message: aborted ? `Request timed out after ${timeoutMs}ms (${req.method} ${url.toString()})` : `Network error: ${e.message}${causeMsg ? ` (${causeMsg})` : ""} \u2014 ${req.method} ${url.toString()}`,
|
|
283
|
+
details: { cause: causeMsg ?? e.message, url: url.toString() }
|
|
273
284
|
});
|
|
274
285
|
}
|
|
275
286
|
clearTimeout(timeout);
|
|
@@ -370,7 +381,7 @@ ${kleur2.bold("Get an API key:")} ${kleur2.cyan(DEFAULTS.apiKeysUrl)}
|
|
|
370
381
|
}
|
|
371
382
|
|
|
372
383
|
// src/commands/_shared.ts
|
|
373
|
-
import { confirm } from "@inquirer/prompts";
|
|
384
|
+
import { confirm, select } from "@inquirer/prompts";
|
|
374
385
|
import kleur3 from "kleur";
|
|
375
386
|
function makeCtx(program) {
|
|
376
387
|
const root = program.parent ?? program;
|
|
@@ -390,10 +401,10 @@ function renderResult(ctx, payload, summary) {
|
|
|
390
401
|
process.stdout.write(JSON.stringify(payload, null, 2) + "\n");
|
|
391
402
|
}
|
|
392
403
|
async function confirmCost(ctx, skipPrompt, body, summary) {
|
|
393
|
-
let
|
|
404
|
+
let credits = null;
|
|
394
405
|
try {
|
|
395
406
|
const res = await ctx.client.estimatePricing(body);
|
|
396
|
-
|
|
407
|
+
credits = res.credits;
|
|
397
408
|
} catch (err) {
|
|
398
409
|
if (!ctx.json) {
|
|
399
410
|
logger.warn(
|
|
@@ -402,21 +413,19 @@ async function confirmCost(ctx, skipPrompt, body, summary) {
|
|
|
402
413
|
}
|
|
403
414
|
}
|
|
404
415
|
if (ctx.json || skipPrompt) {
|
|
405
|
-
if (
|
|
406
|
-
logger.info(
|
|
407
|
-
`${summary} \u2014 estimated ${kleur3.yellow(`${estimate.credits} credits`)} (~$${estimate.costUSD.toFixed(3)})`
|
|
408
|
-
);
|
|
416
|
+
if (credits !== null && !ctx.json) {
|
|
417
|
+
logger.info(`${summary} \u2014 estimated ${kleur3.yellow(`${credits} credits`)}`);
|
|
409
418
|
}
|
|
410
419
|
return true;
|
|
411
420
|
}
|
|
412
|
-
if (
|
|
421
|
+
if (credits === null) {
|
|
413
422
|
return confirm({
|
|
414
423
|
message: `${summary}. Cost unknown. Proceed anyway?`,
|
|
415
424
|
default: false
|
|
416
425
|
});
|
|
417
426
|
}
|
|
418
427
|
const msg = `${summary}
|
|
419
|
-
Estimated cost: ${kleur3.yellow(`${
|
|
428
|
+
Estimated cost: ${kleur3.yellow(`${credits} credits`)}
|
|
420
429
|
Proceed?`;
|
|
421
430
|
return confirm({ message: msg, default: true });
|
|
422
431
|
}
|
|
@@ -429,6 +438,15 @@ function renderCreditsFooter(ctx, payload) {
|
|
|
429
438
|
logger.info(`${charged}${obj.creditsRemaining} credits remaining`);
|
|
430
439
|
}
|
|
431
440
|
}
|
|
441
|
+
async function promptAspectRatio(cliValue, jsonMode) {
|
|
442
|
+
if (cliValue) return cliValue;
|
|
443
|
+
if (jsonMode) return "1:1";
|
|
444
|
+
return select({
|
|
445
|
+
message: "Choose aspect ratio:",
|
|
446
|
+
choices: ASPECT_RATIOS.map((r) => ({ name: r.label, value: r.value })),
|
|
447
|
+
default: "1:1"
|
|
448
|
+
});
|
|
449
|
+
}
|
|
432
450
|
|
|
433
451
|
// src/commands/whoami.ts
|
|
434
452
|
function registerWhoami(program) {
|
|
@@ -532,6 +550,7 @@ function registerGen(program) {
|
|
|
532
550
|
).option("-i, --image-url <url>", "Reference image URL for img2img variants").option("-a, --aspect-ratio <ratio>", "1:1 | 16:9 | 9:16 | 4:3 | 3:4").option("-n, --negative-prompt <text>", "Negative prompt").option("--num-images <n>", "Batch size", "1").option("--seed <n>", "Deterministic seed").option("-o, --out <file>", "Download the result to this path").option("-y, --yes", "Skip the cost confirmation prompt", false).action(async (prompt, opts) => {
|
|
533
551
|
const ctx = makeCtx(program);
|
|
534
552
|
requireAuth(ctx);
|
|
553
|
+
const aspectRatio = await promptAspectRatio(opts.aspectRatio, ctx.json);
|
|
535
554
|
const model = opts.model ?? (opts.imageUrl ? DEFAULT_MODELS.imageEdit : DEFAULT_MODELS.image);
|
|
536
555
|
const numImages = opts.numImages ? Number(opts.numImages) : void 0;
|
|
537
556
|
const ok = await confirmCost(
|
|
@@ -539,7 +558,7 @@ function registerGen(program) {
|
|
|
539
558
|
Boolean(opts.yes),
|
|
540
559
|
{
|
|
541
560
|
model,
|
|
542
|
-
aspect_ratio:
|
|
561
|
+
aspect_ratio: aspectRatio,
|
|
543
562
|
num_images: numImages
|
|
544
563
|
},
|
|
545
564
|
`Image generation \xB7 ${model}`
|
|
@@ -557,7 +576,7 @@ function registerGen(program) {
|
|
|
557
576
|
prompt,
|
|
558
577
|
model,
|
|
559
578
|
image_url: opts.imageUrl,
|
|
560
|
-
aspect_ratio:
|
|
579
|
+
aspect_ratio: aspectRatio,
|
|
561
580
|
negative_prompt: opts.negativePrompt,
|
|
562
581
|
num_images: numImages,
|
|
563
582
|
seed: opts.seed ? Number(opts.seed) : void 0
|
|
@@ -576,9 +595,10 @@ function registerGen(program) {
|
|
|
576
595
|
throw e;
|
|
577
596
|
}
|
|
578
597
|
});
|
|
579
|
-
gen.command("video <prompt>").description("Text-to-video or image-to-video. Async; polls until done.").option("-m, --model <id>", "Provider/model id (auto-picks i2v vs t2v based on --image).").option("-i, --image <url>", "Starting frame for image-to-video").option("-d, --duration <seconds>", "Clip length", "5").option("-a, --aspect-ratio <ratio>", "16:9 | 9:16 | 1:1
|
|
598
|
+
gen.command("video <prompt>").description("Text-to-video or image-to-video. Async; polls until done.").option("-m, --model <id>", "Provider/model id (auto-picks i2v vs t2v based on --image).").option("-i, --image <url>", "Starting frame for image-to-video").option("-d, --duration <seconds>", "Clip length", "5").option("-a, --aspect-ratio <ratio>", "16:9 | 9:16 | 1:1 | 4:3 | 3:4 | 21:9").option("-o, --out <file>", "Download the final clip to this path").option("-y, --yes", "Skip the cost confirmation prompt", false).action(async (prompt, opts) => {
|
|
580
599
|
const ctx = makeCtx(program);
|
|
581
600
|
requireAuth(ctx);
|
|
601
|
+
const aspectRatio = await promptAspectRatio(opts.aspectRatio, ctx.json);
|
|
582
602
|
const model = opts.model ?? (opts.image ? DEFAULT_MODELS.videoImage : DEFAULT_MODELS.videoText);
|
|
583
603
|
const duration = Number(opts.duration);
|
|
584
604
|
const ok = await confirmCost(
|
|
@@ -587,7 +607,7 @@ function registerGen(program) {
|
|
|
587
607
|
{
|
|
588
608
|
model,
|
|
589
609
|
duration,
|
|
590
|
-
aspect_ratio:
|
|
610
|
+
aspect_ratio: aspectRatio
|
|
591
611
|
},
|
|
592
612
|
`Video generation \xB7 ${model} \xB7 ${duration}s`
|
|
593
613
|
);
|
|
@@ -605,7 +625,7 @@ function registerGen(program) {
|
|
|
605
625
|
model,
|
|
606
626
|
image_url: opts.image,
|
|
607
627
|
duration,
|
|
608
|
-
aspect_ratio:
|
|
628
|
+
aspect_ratio: aspectRatio
|
|
609
629
|
}
|
|
610
630
|
});
|
|
611
631
|
if (spinner) spinner.text = "Rendering video\u2026";
|
|
@@ -853,7 +873,7 @@ async function run(argv) {
|
|
|
853
873
|
registerSearch(program);
|
|
854
874
|
await program.parseAsync(argv);
|
|
855
875
|
}
|
|
856
|
-
var VERSION = "0.2.
|
|
876
|
+
var VERSION = "0.2.10";
|
|
857
877
|
|
|
858
878
|
// src/index.ts
|
|
859
879
|
run(process.argv).catch((err) => {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/commands/login.ts","../src/config.ts","../src/constants.ts","../src/client.ts","../src/errors.ts","../src/logger.ts","../src/commands/_shared.ts","../src/commands/whoami.ts","../src/commands/gen.ts","../src/util/download.ts","../src/util/poll.ts","../src/util/await-job.ts","../src/commands/upscale.ts","../src/commands/campaign.ts","../src/commands/jobs.ts","../src/commands/search.ts","../src/index.ts"],"sourcesContent":["/**\n * Commander root. Each subcommand lives in its own file under ./commands.\n */\nimport { Command } from \"commander\"\nimport { registerLogin } from \"./commands/login.js\"\nimport { registerWhoami } from \"./commands/whoami.js\"\nimport { registerGen } from \"./commands/gen.js\"\nimport { registerUpscale } from \"./commands/upscale.js\"\nimport { registerCampaign } from \"./commands/campaign.js\"\nimport { registerJobs } from \"./commands/jobs.js\"\nimport { registerSearch } from \"./commands/search.js\"\n\nexport async function run(argv: string[]): Promise<void> {\n const program = new Command()\n .name(\"wm\")\n .description(\n \"WM Studio command-line client. Generate images, videos, brand campaigns, and 3D assets.\"\n )\n .version(VERSION, \"-v, --version\")\n .option(\"--api-url <url>\", \"Override WM Studio API base URL\")\n .option(\"--api-key <key>\", \"Override API key (otherwise WM_API_KEY or ~/.wm/config.json)\")\n .option(\"--json\", \"Emit machine-readable JSON output\", false)\n .showHelpAfterError(\"(run `wm <command> --help` for details)\")\n\n registerLogin(program)\n registerWhoami(program)\n registerGen(program)\n registerUpscale(program)\n registerCampaign(program)\n registerJobs(program)\n registerSearch(program)\n\n await program.parseAsync(argv)\n}\n\n// Injected at build time by tsup via `define` — fallback for `tsx`/`vitest`.\ndeclare const __VERSION__: string | undefined\nconst VERSION: string =\n (typeof __VERSION__ !== \"undefined\" && __VERSION__) ||\n process.env.npm_package_version ||\n \"0.0.0-dev\"\n","import type { Command } from \"commander\"\nimport { password } from \"@inquirer/prompts\"\nimport kleur from \"kleur\"\nimport { writeFileConfig } from \"../config.js\"\nimport { WmApiClient } from \"../client.js\"\nimport { resolveConfig } from \"../config.js\"\nimport { logger } from \"../logger.js\"\nimport { WmCliError } from \"../errors.js\"\nimport { DEFAULTS } from \"../constants.js\"\n\nexport function registerLogin(program: Command): void {\n program\n .command(\"login\")\n .description(\"Save your WM Studio API key to ~/.wm/config.json (chmod 0600).\")\n .option(\"--key <apiKey>\", \"Pass the API key non-interactively (useful in CI).\")\n .action(async (opts: { key?: string }) => {\n if (!opts.key) {\n process.stderr.write(\n `\\n${kleur.bold(\"Get an API key:\")} ${kleur.cyan(DEFAULTS.apiKeysUrl)}\\n` +\n kleur.dim(\" Sign in → Dashboard → API keys → Create new key, then paste below.\\n\\n\")\n )\n }\n const apiKey =\n opts.key ??\n (await password({\n message: \"Paste your WM Studio API key:\",\n mask: \"*\",\n }))\n if (!apiKey || apiKey.trim().length === 0) {\n throw WmCliError.usage(\"API key cannot be empty.\")\n }\n\n const cfg = resolveConfig({ apiKey: apiKey.trim() })\n const client = new WmApiClient(cfg)\n const me = await client.whoami()\n\n writeFileConfig({ apiKey: apiKey.trim() })\n logger.info(`Logged in as ${me.email} (${me.creditsRemaining} credits remaining).`)\n })\n}\n","/**\n * On-disk config + env merge.\n *\n * Precedence (highest first):\n * 1. CLI flag (--api-url, --api-key)\n * 2. Environment variables (WMSTUDIO_API_URL, WM_API_KEY)\n * 3. ~/.wm/config.json\n * 4. Built-in defaults (constants.ts)\n */\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from \"node:fs\"\nimport { homedir } from \"node:os\"\nimport { dirname, join } from \"node:path\"\nimport { z } from \"zod\"\nimport { DEFAULTS, ENV } from \"./constants.js\"\n\nconst FileConfigSchema = z.object({\n apiUrl: z.string().url().optional(),\n apiKey: z.string().min(1).optional(),\n uploadUrl: z.string().url().optional(),\n upgradeUrl: z.string().url().optional(),\n lowCreditsThreshold: z.number().int().nonnegative().optional(),\n})\n\nexport type FileConfig = z.infer<typeof FileConfigSchema>\n\nexport interface ResolvedConfig {\n apiUrl: string\n apiKey: string | undefined\n uploadUrl: string\n upgradeUrl: string\n lowCreditsThreshold: number\n configPath: string\n}\n\nexport function configDir(): string {\n const override = process.env[ENV.ConfigDir]\n return override && override.length > 0 ? override : join(homedir(), \".wm\")\n}\n\nexport function configPath(): string {\n return join(configDir(), \"config.json\")\n}\n\nexport function readFileConfig(): FileConfig {\n const path = configPath()\n if (!existsSync(path)) return {}\n try {\n const raw = readFileSync(path, \"utf8\")\n return FileConfigSchema.parse(JSON.parse(raw))\n } catch {\n // Corrupt config — return empty rather than crash the CLI on every command.\n return {}\n }\n}\n\nexport function writeFileConfig(patch: FileConfig): void {\n const merged = { ...readFileConfig(), ...patch }\n const dir = configDir()\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true, mode: 0o700 })\n const file = configPath()\n writeFileSync(file, JSON.stringify(merged, null, 2) + \"\\n\", { mode: 0o600 })\n // Defensive: enforce 0600 even if file pre-existed.\n try {\n chmodSync(file, 0o600)\n } catch {\n /* non-fatal */\n }\n // And 0700 on the dir.\n try {\n chmodSync(dirname(file), 0o700)\n } catch {\n /* non-fatal */\n }\n}\n\nexport interface ConfigOverrides {\n apiUrl?: string\n apiKey?: string\n}\n\nexport function resolveConfig(overrides: ConfigOverrides = {}): ResolvedConfig {\n const file = readFileConfig()\n return {\n apiUrl: overrides.apiUrl ?? process.env[ENV.ApiUrl] ?? file.apiUrl ?? DEFAULTS.apiUrl,\n apiKey: overrides.apiKey ?? process.env[ENV.ApiKey] ?? file.apiKey,\n uploadUrl: process.env[ENV.UploadUrl] ?? file.uploadUrl ?? DEFAULTS.uploadUrl,\n upgradeUrl: process.env[ENV.UpgradeUrl] ?? file.upgradeUrl ?? DEFAULTS.upgradeUrl,\n lowCreditsThreshold:\n numFromEnv(process.env[ENV.LowCreditsThreshold]) ??\n file.lowCreditsThreshold ??\n DEFAULTS.lowCreditsThreshold,\n configPath: configPath(),\n }\n}\n\nfunction numFromEnv(raw: string | undefined): number | undefined {\n if (!raw) return undefined\n const n = Number(raw)\n return Number.isFinite(n) ? n : undefined\n}\n","/**\n * Shared constants. Keep in sync with `mcp-director/src/config.py`.\n * Anything that names an env var, an endpoint, or a model id belongs here.\n */\n\nexport const DEFAULTS = {\n /** Hosted WM Studio REST API base. Override via `WMSTUDIO_API_URL`. */\n apiUrl: \"https://wmstudio.io/api\",\n /** Page surfaced when the API requires a public asset URL. */\n uploadUrl: \"https://wmstudio.io/dashboard/uploads\",\n /** Credit top-up landing page. */\n upgradeUrl: \"https://wmstudio.io/dashboard/credits\",\n /** Where users create API keys. Shown by `wm login`. */\n apiKeysUrl: \"https://wmstudio.io/dashboard/api-keys\",\n /** Below this remaining-credit count we surface a warning. */\n lowCreditsThreshold: 50,\n /** Default request timeout (ms) for non-job calls. */\n requestTimeoutMs: 60_000,\n /** Polling interval (ms) for async jobs. */\n jobPollIntervalMs: 4_000,\n /** Hard ceiling for job polling (ms). */\n jobPollTimeoutMs: 15 * 60 * 1000,\n} as const\n\nexport const ENV = {\n ApiUrl: \"WMSTUDIO_API_URL\",\n ApiKey: \"WM_API_KEY\",\n UploadUrl: \"ASSET_UPLOAD_URL\",\n UpgradeUrl: \"CREDITS_UPGRADE_URL\",\n LowCreditsThreshold: \"CREDITS_LOW_THRESHOLD\",\n LogLevel: \"WM_LOG_LEVEL\",\n ConfigDir: \"WM_CONFIG_DIR\",\n} as const\n\n/** Default model ids per tool — mirror `mcp-director/src/tools/studio.py` defaults. */\nexport const DEFAULT_MODELS = {\n image: \"fal-ai/nano-banana-pro\",\n imageEdit: \"fal-ai/nano-banana-pro/edit\",\n videoText: \"bytedance/seedance-2.0-fast\",\n videoImage: \"bytedance/seedance-2.0-fast\",\n upscaleImage: \"fal-ai/topaz/upscale/image\",\n upscaleVideo: \"fal-ai/topaz/upscale/video\",\n threeD: \"fal-ai/meshy/v6/image-to-3d\",\n brandshot: \"fal-ai/nano-banana-pro\",\n cameraAngles: \"fal-ai/nano-banana-pro\",\n casting: \"fal-ai/nano-banana-pro\",\n ugcRoom: \"fal-ai/nano-banana-pro\",\n} as const\n","/**\n * Thin HTTP client for the WM Studio REST API.\n *\n * Endpoints mirror what `mcp-director/src/wmstudio_client.py` already calls\n * — keeping the contract identical means the CLI is a drop-in alternative\n * to the MCP for the same underlying backend.\n */\nimport { z } from \"zod\"\nimport { DEFAULTS } from \"./constants.js\"\nimport { ExitCode, WmCliError } from \"./errors.js\"\nimport type { ResolvedConfig } from \"./config.js\"\n\nconst ApiErrorSchema = z.object({\n code: z.string().optional(),\n error: z.string().optional(),\n message: z.string().optional(),\n requiresTopUp: z.boolean().optional(),\n upgradeUrl: z.string().url().optional(),\n uploadUrl: z.string().url().optional(),\n})\n\nexport interface JsonRequest {\n method: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\"\n path: string\n body?: Record<string, unknown>\n query?: Record<string, string | number | boolean | undefined>\n timeoutMs?: number\n}\n\nexport class WmApiClient {\n constructor(private readonly cfg: ResolvedConfig) {}\n\n /** GET /me — returns account + credit balance. */\n whoami(): Promise<{\n userId: string\n email: string\n creditsRemaining: number\n plan: string\n }> {\n return this.json({ method: \"GET\", path: \"/me\" })\n }\n\n /**\n * Estimate the credit cost of a generation BEFORE running it.\n * Hits POST /creative-studio/pricing.\n */\n estimatePricing(body: {\n model: string\n [key: string]: unknown\n }): Promise<{ credits: number; costUSD: number; costEUR: number }> {\n return this.json({ method: \"POST\", path: \"/creative-studio/pricing\", body })\n }\n\n /** Validate the current api key without side-effects. */\n async ping(): Promise<boolean> {\n try {\n await this.whoami()\n return true\n } catch (err) {\n if (err instanceof WmCliError && err.code === \"auth_invalid\") return false\n throw err\n }\n }\n\n /** Generic JSON helper. */\n async json<T = unknown>(req: JsonRequest): Promise<T> {\n if (!this.cfg.apiKey) throw WmCliError.authRequired()\n\n const url = new URL(req.path.replace(/^\\//, \"\"), this.cfg.apiUrl.replace(/\\/?$/, \"/\"))\n if (req.query) {\n for (const [k, v] of Object.entries(req.query)) {\n if (v !== undefined) url.searchParams.set(k, String(v))\n }\n }\n\n const ac = new AbortController()\n const timeoutMs = req.timeoutMs ?? DEFAULTS.requestTimeoutMs\n const timeout = setTimeout(() => ac.abort(), timeoutMs)\n\n let res: Response\n try {\n res = await fetch(url, {\n method: req.method,\n headers: {\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n authorization: `Bearer ${this.cfg.apiKey}`,\n \"user-agent\": userAgent(),\n },\n body: req.body ? JSON.stringify(req.body) : undefined,\n signal: ac.signal,\n })\n } catch (err) {\n clearTimeout(timeout)\n if (err instanceof WmCliError) throw err\n const aborted = (err as { name?: string } | null)?.name === \"AbortError\"\n throw new WmCliError({\n code: aborted ? \"timeout\" : \"network\",\n exitCode: aborted ? ExitCode.TIMEOUT : ExitCode.NETWORK,\n message: aborted\n ? `Request timed out after ${timeoutMs}ms (${req.method} ${req.path})`\n : `Network error: ${(err as Error).message}`,\n details: { cause: (err as Error).message },\n })\n }\n clearTimeout(timeout)\n\n const text = await res.text()\n const parsed: unknown = text ? safeJson(text) : undefined\n\n if (res.status >= 200 && res.status < 300) {\n return parsed as T\n }\n throw classify(res.status, parsed, this.cfg)\n }\n}\n\nfunction safeJson(text: string): unknown {\n try {\n return JSON.parse(text)\n } catch {\n return { raw: text }\n }\n}\n\nfunction classify(status: number, payload: unknown, cfg: ResolvedConfig): WmCliError {\n const parsed = ApiErrorSchema.safeParse(payload)\n const data = parsed.success ? parsed.data : {}\n const msg = data.message ?? data.error ?? `HTTP ${status}`\n\n if (status === 401 || status === 403) return WmCliError.authInvalid(msg)\n if (status === 402 || data.requiresTopUp) {\n return WmCliError.upgradeRequired(data.upgradeUrl ?? cfg.upgradeUrl, msg)\n }\n if (status === 422 && data.code === \"asset_url_required\") {\n return WmCliError.assetUrlRequired(data.uploadUrl ?? cfg.uploadUrl, msg)\n }\n return new WmCliError({\n code: status >= 500 ? \"server\" : \"usage\",\n exitCode: status >= 500 ? 50 : 2,\n message: msg,\n details: { status, payload },\n })\n}\n\nfunction userAgent(): string {\n return `wm-cli/${process.env.npm_package_version ?? \"dev\"} (node ${process.version})`\n}\n","/**\n * Error model + exit codes for `wm`.\n *\n * Exit codes are stable contract — kept in sync with `mcp-director` error codes\n * (see ../docs/CONVENTIONS.md). Used by CI, shell scripts, and humans.\n */\n\nexport const ExitCode = {\n OK: 0,\n USAGE: 2, // bad arguments / unknown command\n AUTH_REQUIRED: 10, // not logged in / missing api key\n AUTH_INVALID: 11, // server rejected token (401/403)\n ASSET_URL_REQUIRED: 20, // missing or unreachable user-provided URL\n UPGRADE_REQUIRED: 30, // 402 insufficient credits\n RATE_LIMITED: 31, // 429\n NETWORK: 40, // transport / DNS / TLS\n SERVER: 50, // 5xx\n TIMEOUT: 51, // server-side or client-side deadline exceeded\n UNEXPECTED: 99, // crashed / not classifiable\n} as const\n\nexport type ExitCodeValue = (typeof ExitCode)[keyof typeof ExitCode]\n\n/**\n * The canonical error codes returned by the WM Studio API and `mcp-director`.\n * Keeping the same vocabulary across CLI / MCP / SDK is the whole point.\n */\nexport const ErrorCode = {\n AuthRequired: \"auth_required\",\n AuthInvalid: \"auth_invalid\",\n AssetUrlRequired: \"asset_url_required\",\n UpgradeRequired: \"upgrade_required\",\n RateLimited: \"rate_limited\",\n Network: \"network\",\n Server: \"server\",\n Timeout: \"timeout\",\n Usage: \"usage\",\n Unexpected: \"unexpected\",\n} as const\n\nexport type ErrorCodeValue = (typeof ErrorCode)[keyof typeof ErrorCode]\n\nexport class WmCliError extends Error {\n readonly code: ErrorCodeValue\n readonly exitCode: ExitCodeValue\n readonly details?: Record<string, unknown>\n\n constructor(opts: {\n code: ErrorCodeValue\n exitCode: ExitCodeValue\n message: string\n details?: Record<string, unknown>\n }) {\n super(opts.message)\n this.name = \"WmCliError\"\n this.code = opts.code\n this.exitCode = opts.exitCode\n this.details = opts.details\n }\n\n static authRequired(message = \"Not logged in. Run `wm login` first.\"): WmCliError {\n return new WmCliError({\n code: ErrorCode.AuthRequired,\n exitCode: ExitCode.AUTH_REQUIRED,\n message,\n })\n }\n\n static authInvalid(message = \"Invalid or expired API key.\"): WmCliError {\n return new WmCliError({\n code: ErrorCode.AuthInvalid,\n exitCode: ExitCode.AUTH_INVALID,\n message,\n })\n }\n\n static assetUrlRequired(uploadUrl: string, message?: string): WmCliError {\n return new WmCliError({\n code: ErrorCode.AssetUrlRequired,\n exitCode: ExitCode.ASSET_URL_REQUIRED,\n message: message ?? `A real public asset URL is required. Upload at ${uploadUrl}.`,\n details: { uploadUrl },\n })\n }\n\n static upgradeRequired(upgradeUrl: string, message?: string): WmCliError {\n return new WmCliError({\n code: ErrorCode.UpgradeRequired,\n exitCode: ExitCode.UPGRADE_REQUIRED,\n message: message ?? `Insufficient credits. Top up at ${upgradeUrl} and re-run.`,\n details: { upgradeUrl },\n })\n }\n\n static usage(message: string): WmCliError {\n return new WmCliError({\n code: ErrorCode.Usage,\n exitCode: ExitCode.USAGE,\n message,\n })\n }\n}\n","/**\n * Tiny structured logger. Console output is colourised for humans (stderr);\n * when `WM_LOG_FORMAT=json` is set, emits JSON lines compatible with the same\n * shape used by `mcp-director` (`event`, `level`, `ts`, …extra).\n */\nimport kleur from \"kleur\"\nimport { ENV } from \"./constants.js\"\n\ntype Level = \"debug\" | \"info\" | \"warn\" | \"error\"\n\nconst LEVEL_ORDER: Record<Level, number> = { debug: 10, info: 20, warn: 30, error: 40 }\n\nfunction currentLevel(): Level {\n const raw = process.env[ENV.LogLevel]?.toLowerCase() as Level | undefined\n return raw && raw in LEVEL_ORDER ? raw : \"info\"\n}\n\nfunction asJson(): boolean {\n return process.env.WM_LOG_FORMAT === \"json\"\n}\n\nfunction emit(level: Level, message: string, extra?: Record<string, unknown>): void {\n if (LEVEL_ORDER[level] < LEVEL_ORDER[currentLevel()]) return\n\n if (asJson()) {\n const line = JSON.stringify({\n ts: new Date().toISOString(),\n level,\n event: message,\n ...extra,\n })\n process.stderr.write(line + \"\\n\")\n return\n }\n\n const tag =\n level === \"error\"\n ? kleur.red().bold(\"✖\")\n : level === \"warn\"\n ? kleur.yellow().bold(\"!\")\n : level === \"info\"\n ? kleur.cyan().bold(\"›\")\n : kleur.gray(\"·\")\n const detail = extra && Object.keys(extra).length ? \" \" + kleur.gray(JSON.stringify(extra)) : \"\"\n process.stderr.write(`${tag} ${message}${detail}\\n`)\n}\n\nexport const logger = {\n debug: (m: string, e?: Record<string, unknown>) => emit(\"debug\", m, e),\n info: (m: string, e?: Record<string, unknown>) => emit(\"info\", m, e),\n warn: (m: string, e?: Record<string, unknown>) => emit(\"warn\", m, e),\n error: (m: string, e?: Record<string, unknown>) => emit(\"error\", m, e),\n}\n","/**\n * Shared command helpers: resolve config, build client, render output.\n */\nimport type { Command } from \"commander\"\nimport { confirm } from \"@inquirer/prompts\"\nimport kleur from \"kleur\"\nimport { resolveConfig, type ResolvedConfig } from \"../config.js\"\nimport { WmApiClient } from \"../client.js\"\nimport { logger } from \"../logger.js\"\nimport { WmCliError } from \"../errors.js\"\n\nexport interface GlobalFlags {\n apiUrl?: string\n apiKey?: string\n json?: boolean\n}\n\nexport interface CommandCtx {\n cfg: ResolvedConfig\n client: WmApiClient\n json: boolean\n}\n\nexport function makeCtx(program: Command): CommandCtx {\n // Walk up to the root program so subcommands inherit global flags.\n const root = program.parent ?? program\n const opts = root.opts<GlobalFlags>()\n const cfg = resolveConfig({ apiUrl: opts.apiUrl, apiKey: opts.apiKey })\n return { cfg, client: new WmApiClient(cfg), json: Boolean(opts.json) }\n}\n\nexport function requireAuth(\n ctx: CommandCtx\n): asserts ctx is CommandCtx & { cfg: ResolvedConfig & { apiKey: string } } {\n if (!ctx.cfg.apiKey) throw WmCliError.authRequired()\n}\n\nexport function renderResult(ctx: CommandCtx, payload: unknown, summary?: string): void {\n if (ctx.json) {\n process.stdout.write(JSON.stringify(payload, null, 2) + \"\\n\")\n return\n }\n if (summary) logger.info(summary)\n process.stdout.write(JSON.stringify(payload, null, 2) + \"\\n\")\n}\n\n/**\n * Estimate the credit cost of a generation, show it to the user, and\n * ask for confirmation. Returns true if the user accepted (or was\n * auto-skipped via --yes / --json), false if rejected.\n *\n * The pricing endpoint can fail (unknown model, network) — in that case\n * we surface a warning and let the user decide whether to proceed.\n *\n * @param ctx command context (has client + json flag)\n * @param skipPrompt when true (e.g. --yes flag), skip interactive confirm\n * @param body what gets POSTed to /creative-studio/pricing — at minimum { model }\n * @param summary one-line label like \"Image generation · nano-banana-pro\"\n */\nexport async function confirmCost(\n ctx: CommandCtx,\n skipPrompt: boolean,\n body: { model: string; [key: string]: unknown },\n summary: string\n): Promise<boolean> {\n // --json mode + --yes flag both skip the interactive prompt.\n // We ALWAYS still fetch the estimate so the JSON output can include it.\n let estimate: { credits: number; costUSD: number } | null = null\n try {\n const res = await ctx.client.estimatePricing(body)\n estimate = { credits: res.credits, costUSD: res.costUSD }\n } catch (err) {\n if (!ctx.json) {\n logger.warn(\n `Could not fetch cost estimate (${err instanceof Error ? err.message : String(err)}). ` +\n `You will be charged the actual amount on success.`\n )\n }\n }\n\n if (ctx.json || skipPrompt) {\n if (estimate && !ctx.json) {\n logger.info(\n `${summary} — estimated ${kleur.yellow(`${estimate.credits} credits`)} ` +\n `(~$${estimate.costUSD.toFixed(3)})`\n )\n }\n return true\n }\n\n if (!estimate) {\n // No estimate available — prompt without a number.\n return confirm({\n message: `${summary}. Cost unknown. Proceed anyway?`,\n default: false,\n })\n }\n\n const msg =\n `${summary}\\n Estimated cost: ${kleur.yellow(`${estimate.credits} credits`)} ` +\n `(~$${estimate.costUSD.toFixed(3)})\\n Proceed?`\n return confirm({ message: msg, default: true })\n}\n\n/** Render the post-generation credits-remaining footer. */\nexport function renderCreditsFooter(ctx: CommandCtx, payload: unknown): void {\n if (ctx.json) return\n const obj = payload as { creditsRemaining?: number; creditsCharged?: number } | null\n if (!obj || typeof obj !== \"object\") return\n const charged =\n typeof obj.creditsCharged === \"number\" ? `${obj.creditsCharged} credits charged · ` : \"\"\n if (typeof obj.creditsRemaining === \"number\") {\n logger.info(`${charged}${obj.creditsRemaining} credits remaining`)\n }\n}\n","import type { Command } from \"commander\"\nimport { makeCtx, requireAuth, renderResult } from \"./_shared.js\"\n\nexport function registerWhoami(program: Command): void {\n program\n .command(\"whoami\")\n .description(\"Show the logged-in account and remaining credits.\")\n .action(async () => {\n const ctx = makeCtx(program)\n requireAuth(ctx)\n const me = await ctx.client.whoami()\n renderResult(ctx, me, `${me.email} · ${me.creditsRemaining} credits · plan ${me.plan}`)\n })\n}\n","/**\n * `wm gen image|video` — image and video generation.\n *\n * Calls the same REST endpoints `mcp-director` already proxies to:\n * POST /studio/generate-image\n * POST /studio/generate-video\n */\nimport type { Command } from \"commander\"\nimport ora from \"ora\"\nimport { makeCtx, requireAuth, renderResult, confirmCost, renderCreditsFooter } from \"./_shared.js\"\nimport { DEFAULT_MODELS } from \"../constants.js\"\nimport { downloadToFile } from \"../util/download.js\"\nimport { awaitJob } from \"../util/await-job.js\"\nimport { logger } from \"../logger.js\"\n\ninterface ImageOpts {\n model?: string\n imageUrl?: string\n aspectRatio?: string\n negativePrompt?: string\n numImages?: string\n seed?: string\n out?: string\n yes?: boolean\n}\n\ninterface VideoOpts {\n model?: string\n image?: string\n duration?: string\n aspectRatio?: string\n out?: string\n yes?: boolean\n}\n\nexport function registerGen(program: Command): void {\n const gen = program.command(\"gen\").description(\"Generate creative assets (image, video).\")\n\n gen\n .command(\"image <prompt>\")\n .description(\"Text-to-image or image-to-image generation.\")\n .option(\n \"-m, --model <id>\",\n \"Provider/model id (auto-picks edit variant when --image-url is passed)\"\n )\n .option(\"-i, --image-url <url>\", \"Reference image URL for img2img variants\")\n .option(\"-a, --aspect-ratio <ratio>\", \"1:1 | 16:9 | 9:16 | 4:3 | 3:4\")\n .option(\"-n, --negative-prompt <text>\", \"Negative prompt\")\n .option(\"--num-images <n>\", \"Batch size\", \"1\")\n .option(\"--seed <n>\", \"Deterministic seed\")\n .option(\"-o, --out <file>\", \"Download the result to this path\")\n .option(\"-y, --yes\", \"Skip the cost confirmation prompt\", false)\n .action(async (prompt: string, opts: ImageOpts) => {\n const ctx = makeCtx(program)\n requireAuth(ctx)\n\n // Pick edit variant for img2img when no explicit model was given.\n const model = opts.model ?? (opts.imageUrl ? DEFAULT_MODELS.imageEdit : DEFAULT_MODELS.image)\n const numImages = opts.numImages ? Number(opts.numImages) : undefined\n\n const ok = await confirmCost(\n ctx,\n Boolean(opts.yes),\n {\n model,\n aspect_ratio: opts.aspectRatio,\n num_images: numImages,\n },\n `Image generation · ${model}`\n )\n if (!ok) {\n logger.info(\"Cancelled.\")\n return\n }\n\n const spinner = ctx.json ? null : ora(\"Generating image…\").start()\n try {\n const submit = await ctx.client.json<Record<string, unknown>>({\n method: \"POST\",\n path: \"/studio/generate-image\",\n body: {\n prompt,\n model,\n image_url: opts.imageUrl,\n aspect_ratio: opts.aspectRatio,\n negative_prompt: opts.negativePrompt,\n num_images: numImages,\n seed: opts.seed ? Number(opts.seed) : undefined,\n },\n })\n if (spinner) spinner.text = \"Rendering image…\"\n const result = await awaitJob(ctx.client, submit, \"image\", (s) => {\n if (spinner) spinner.text = `Image · ${s.status}`\n })\n spinner?.succeed(\"Image ready.\")\n if (opts.out && result.imageUrl) await downloadToFile(result.imageUrl, opts.out)\n renderResult(ctx, result, `→ ${result.imageUrl}`)\n renderCreditsFooter(ctx, result)\n } catch (e) {\n spinner?.fail(\"Image generation failed.\")\n throw e\n }\n })\n\n gen\n .command(\"video <prompt>\")\n .description(\"Text-to-video or image-to-video. Async; polls until done.\")\n .option(\"-m, --model <id>\", \"Provider/model id (auto-picks i2v vs t2v based on --image).\")\n .option(\"-i, --image <url>\", \"Starting frame for image-to-video\")\n .option(\"-d, --duration <seconds>\", \"Clip length\", \"5\")\n .option(\"-a, --aspect-ratio <ratio>\", \"16:9 | 9:16 | 1:1\", \"16:9\")\n .option(\"-o, --out <file>\", \"Download the final clip to this path\")\n .option(\"-y, --yes\", \"Skip the cost confirmation prompt\", false)\n .action(async (prompt: string, opts: VideoOpts) => {\n const ctx = makeCtx(program)\n requireAuth(ctx)\n const model =\n opts.model ?? (opts.image ? DEFAULT_MODELS.videoImage : DEFAULT_MODELS.videoText)\n const duration = Number(opts.duration)\n\n const ok = await confirmCost(\n ctx,\n Boolean(opts.yes),\n {\n model,\n duration,\n aspect_ratio: opts.aspectRatio,\n },\n `Video generation · ${model} · ${duration}s`\n )\n if (!ok) {\n logger.info(\"Cancelled.\")\n return\n }\n\n const spinner = ctx.json ? null : ora(\"Submitting video job…\").start()\n try {\n const submit = await ctx.client.json<Record<string, unknown>>({\n method: \"POST\",\n path: \"/studio/generate-video\",\n body: {\n prompt,\n model,\n image_url: opts.image,\n duration,\n aspect_ratio: opts.aspectRatio,\n },\n })\n if (spinner) spinner.text = \"Rendering video…\"\n const final = await awaitJob(ctx.client, submit, \"video\", (s) => {\n if (spinner) spinner.text = `Video · ${s.status}`\n })\n spinner?.succeed(\"Video ready.\")\n if (opts.out && final.videoUrl) await downloadToFile(final.videoUrl, opts.out)\n renderResult(ctx, final, `→ ${final.videoUrl}`)\n renderCreditsFooter(ctx, final)\n } catch (e) {\n spinner?.fail(\"Video generation failed.\")\n throw e\n }\n })\n}\n","/**\n * Stream a remote asset to a local path. Used by `--out` flags.\n */\nimport { createWriteStream } from \"node:fs\"\nimport { mkdir } from \"node:fs/promises\"\nimport { dirname } from \"node:path\"\nimport { pipeline } from \"node:stream/promises\"\nimport { request } from \"undici\"\n\nexport async function downloadToFile(url: string, outPath: string): Promise<void> {\n await mkdir(dirname(outPath), { recursive: true })\n const res = await request(url, { method: \"GET\" })\n if (res.statusCode >= 400) throw new Error(`download failed: HTTP ${res.statusCode}`)\n // undici's res.body is already a Node Readable — pipe it straight.\n await pipeline(res.body, createWriteStream(outPath))\n}\n","/**\n * Generic async-job poller. Used by `gen video` and `campaign` commands.\n */\nimport { DEFAULTS } from \"../constants.js\"\nimport { WmCliError, ExitCode } from \"../errors.js\"\n\nexport interface PollOptions<T> {\n /** Function that fetches the latest status. */\n fetch: () => Promise<T>\n /** Returns true when the job has reached a terminal state. */\n done: (state: T) => boolean\n /** Optional hook fired on each tick (for spinners / progress). */\n onTick?: (state: T) => void\n intervalMs?: number\n timeoutMs?: number\n}\n\nexport async function poll<T>(opts: PollOptions<T>): Promise<T> {\n const interval = opts.intervalMs ?? DEFAULTS.jobPollIntervalMs\n const deadline = Date.now() + (opts.timeoutMs ?? DEFAULTS.jobPollTimeoutMs)\n\n for (;;) {\n const state = await opts.fetch()\n opts.onTick?.(state)\n if (opts.done(state)) return state\n if (Date.now() > deadline) {\n throw new WmCliError({\n code: \"timeout\",\n exitCode: ExitCode.TIMEOUT,\n message: \"Job polling timed out.\",\n })\n }\n await sleep(interval)\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms))\n}\n","/**\n * Handle the queued-job response shape returned by /studio/generate-image,\n * /studio/generate-video and /studio/upscale-image.\n *\n * If the response carries `queued: true`, poll `/studio/jobs/:id` until it\n * reports `status: \"succeeded\"` (and the requested URL field is present)\n * or `status: \"failed\"`. Otherwise, return the response as-is so old/sync\n * code paths keep working.\n */\nimport type { WmApiClient } from \"../client.js\"\nimport { poll } from \"./poll.js\"\nimport { WmCliError, ExitCode } from \"../errors.js\"\n\nexport type Asset = \"image\" | \"video\"\n\ninterface SubmitResponse {\n queued?: boolean\n generationId?: string\n id?: string\n jobId?: string\n imageUrl?: string\n videoUrl?: string\n creditsRemaining?: number\n}\n\ninterface JobStatus {\n jobId: string\n status: \"succeeded\" | \"running\" | \"failed\"\n imageUrl?: string | null\n videoUrl?: string | null\n creditsCharged?: number | null\n}\n\nexport interface AwaitedJob {\n imageUrl?: string\n videoUrl?: string\n creditsRemaining?: number\n jobId?: string\n}\n\nexport async function awaitJob(\n client: WmApiClient,\n submit: SubmitResponse,\n asset: Asset,\n onTick?: (s: JobStatus) => void\n): Promise<AwaitedJob> {\n // Sync response: URL already present.\n if (!submit.queued) {\n const url = asset === \"image\" ? submit.imageUrl : submit.videoUrl\n if (url) {\n return {\n [asset === \"image\" ? \"imageUrl\" : \"videoUrl\"]: url,\n creditsRemaining: submit.creditsRemaining,\n }\n }\n }\n\n const id = submit.generationId ?? submit.id\n if (!id) {\n throw new WmCliError({\n code: \"server\",\n exitCode: ExitCode.SERVER,\n message: \"Server did not return a generationId to poll.\",\n })\n }\n\n const final = await poll<JobStatus>({\n fetch: () => client.json<JobStatus>({ method: \"GET\", path: `/studio/jobs/${id}` }),\n done: (s) => s.status === \"succeeded\" || s.status === \"failed\",\n onTick,\n })\n\n if (final.status !== \"succeeded\") {\n throw new WmCliError({\n code: \"server\",\n exitCode: ExitCode.SERVER,\n message: `Job ${id} finished with status ${final.status}.`,\n })\n }\n\n const url = asset === \"image\" ? final.imageUrl : final.videoUrl\n if (!url) {\n throw new WmCliError({\n code: \"server\",\n exitCode: ExitCode.SERVER,\n message: `Job ${id} succeeded but no ${asset} URL was returned.`,\n })\n }\n\n return {\n [asset === \"image\" ? \"imageUrl\" : \"videoUrl\"]: url,\n jobId: id,\n }\n}\n","import type { Command } from \"commander\"\nimport ora from \"ora\"\nimport { makeCtx, requireAuth, renderResult, confirmCost, renderCreditsFooter } from \"./_shared.js\"\nimport { DEFAULT_MODELS } from \"../constants.js\"\nimport { downloadToFile } from \"../util/download.js\"\nimport { awaitJob } from \"../util/await-job.js\"\nimport { logger } from \"../logger.js\"\n\ninterface UpscaleOpts {\n factor?: string\n topazModel?: string\n faceEnhancement?: boolean\n out?: string\n yes?: boolean\n}\n\nexport function registerUpscale(program: Command): void {\n program\n .command(\"upscale <imageUrl>\")\n .description(\"Topaz upscale of an image (factor 1–4).\")\n .option(\"-f, --factor <n>\", \"Upscale factor (1|2|3|4)\", \"2\")\n .option(\"--topaz-model <name>\", \"Topaz preset\", \"Standard V2\")\n .option(\"--no-face-enhancement\", \"Disable Topaz face enhancement\")\n .option(\"-o, --out <file>\", \"Download the result to this path\")\n .option(\"-y, --yes\", \"Skip the cost confirmation prompt\", false)\n .action(async (imageUrl: string, opts: UpscaleOpts) => {\n const ctx = makeCtx(program)\n requireAuth(ctx)\n\n const factor = opts.factor ? Number(opts.factor) : 2\n const ok = await confirmCost(\n ctx,\n Boolean(opts.yes),\n {\n model: DEFAULT_MODELS.upscaleImage,\n upscale_factor: factor,\n },\n `Upscale ${factor}x · ${DEFAULT_MODELS.upscaleImage}`\n )\n if (!ok) {\n logger.info(\"Cancelled.\")\n return\n }\n\n const spinner = ctx.json ? null : ora(\"Upscaling…\").start()\n try {\n const submit = await ctx.client.json<Record<string, unknown>>({\n method: \"POST\",\n path: \"/studio/upscale-image\",\n body: {\n image_url: imageUrl,\n upscale_factor: factor,\n topaz_model: opts.topazModel,\n face_enhancement: opts.faceEnhancement,\n },\n })\n const result = await awaitJob(ctx.client, submit, \"image\", (s) => {\n if (spinner) spinner.text = `Upscale · ${s.status}`\n })\n spinner?.succeed(\"Upscaled.\")\n if (opts.out && result.imageUrl) await downloadToFile(result.imageUrl, opts.out)\n renderResult(ctx, result, `→ ${result.imageUrl}`)\n renderCreditsFooter(ctx, result)\n } catch (e) {\n spinner?.fail(\"Upscale failed.\")\n throw e\n }\n })\n}\n","/**\n * `wm campaign` — submit a brief to `director_creative_brief_to_run` or\n * `director_creative_batch_variations`, then poll the resulting run(s).\n */\nimport type { Command } from \"commander\"\nimport ora from \"ora\"\nimport { makeCtx, requireAuth, renderResult } from \"./_shared.js\"\nimport { poll } from \"../util/poll.js\"\n\ninterface CampaignOpts {\n variations?: string\n duration?: string\n platform?: string\n style?: string\n projectId?: string\n follow?: boolean\n}\n\ninterface RunStatus {\n runId: string\n status: string\n masterVideoUrl?: string\n}\n\nexport function registerCampaign(program: Command): void {\n program\n .command(\"campaign <brief>\")\n .description(\n \"Turn a creative brief into a full video run (or N variations) via the director_* pipeline.\"\n )\n .option(\"-n, --variations <n>\", \"Generate N parallel variations (1 = single run)\", \"1\")\n .option(\"-d, --duration <seconds>\", \"Target duration\", \"60\")\n .option(\"-p, --platform <name>\", \"youtube | tiktok | instagram\", \"youtube\")\n .option(\"-s, --style <name>\", \"cinematic | ugc | documentary | …\", \"cinematic\")\n .option(\"--project-id <id>\", \"Existing wmstudio project id (required for variations)\")\n .option(\"--no-follow\", \"Submit and return immediately without polling\")\n .action(async (brief: string, opts: CampaignOpts) => {\n const ctx = makeCtx(program)\n requireAuth(ctx)\n const variations = Math.max(1, Number(opts.variations ?? \"1\"))\n const spinner = ctx.json ? null : ora(\"Submitting brief…\").start()\n\n try {\n const submission =\n variations > 1\n ? await ctx.client.json<{ runIds: string[] }>({\n method: \"POST\",\n path: \"/studio/director/batch-variations\",\n body: {\n base_prompt: brief,\n max_concurrent: variations,\n project_id: opts.projectId,\n },\n })\n : await ctx.client.json<{ runIds: string[] }>({\n method: \"POST\",\n path: \"/studio/director/brief-to-run\",\n body: {\n brief,\n duration_target_seconds: Number(opts.duration),\n platform: opts.platform,\n style: opts.style,\n },\n })\n\n const runIds = submission.runIds ?? []\n if (!opts.follow || runIds.length === 0) {\n spinner?.succeed(`Submitted ${runIds.length} run(s).`)\n renderResult(ctx, submission)\n return\n }\n\n if (spinner) spinner.text = `Polling ${runIds.length} run(s)…`\n const finals = await Promise.all(\n runIds.map((id) =>\n poll<RunStatus>({\n fetch: () => ctx.client.json({ method: \"GET\", path: `/studio/runs/${id}` }),\n done: (s) => [\"succeeded\", \"failed\", \"cancelled\"].includes(s.status),\n })\n )\n )\n spinner?.succeed(\"Run(s) complete.\")\n renderResult(ctx, { runs: finals })\n } catch (e) {\n spinner?.fail(\"Campaign failed.\")\n throw e\n }\n })\n}\n","/**\n * `wm jobs list|get` — inspect async generation jobs and runs.\n */\nimport type { Command } from \"commander\"\nimport { makeCtx, requireAuth, renderResult } from \"./_shared.js\"\n\nexport function registerJobs(program: Command): void {\n const jobs = program.command(\"jobs\").description(\"List and inspect generation jobs.\")\n\n jobs\n .command(\"list\")\n .description(\"List recent jobs (default: 20 most recent).\")\n .option(\"-l, --limit <n>\", \"Number of jobs\", \"20\")\n .option(\"-s, --status <s>\", \"Filter by status (running|succeeded|failed|cancelled)\")\n .action(async (opts: { limit?: string; status?: string }) => {\n const ctx = makeCtx(program)\n requireAuth(ctx)\n const data = await ctx.client.json({\n method: \"GET\",\n path: \"/studio/jobs\",\n query: { limit: opts.limit, status: opts.status },\n })\n renderResult(ctx, data)\n })\n\n jobs\n .command(\"get <jobId>\")\n .description(\"Fetch a single job by id.\")\n .action(async (jobId: string) => {\n const ctx = makeCtx(program)\n requireAuth(ctx)\n const data = await ctx.client.json({ method: \"GET\", path: `/studio/jobs/${jobId}` })\n renderResult(ctx, data)\n })\n}\n","/**\n * `wm search` — programmatic web search powered by the WM Studio backend.\n *\n * Calls POST /api/me/tools/web-search. Auth + credit metering happen\n * server-side; the CLI is purely a presentation layer.\n *\n * Pretty output by default. Use `--json` (global flag) for piping:\n * wm search \"next.js 16 release\" --json | jq '.results[].url'\n */\nimport type { Command } from \"commander\"\nimport ora from \"ora\"\nimport { makeCtx, requireAuth, renderResult } from \"./_shared.js\"\nimport { logger } from \"../logger.js\"\n\ninterface SearchOpts {\n max?: string\n depth?: string\n time?: string\n includeDomain?: string[]\n excludeDomain?: string[]\n}\n\ninterface SearchResultItem {\n title: string\n url: string\n content: string\n score?: unknown\n}\n\ninterface SearchResponse {\n v: 1\n answer: string | null\n results: SearchResultItem[]\n images: string[]\n followUpQuestions: string[]\n creditsCharged: number\n creditsRemaining: number\n}\n\nexport function registerSearch(program: Command): void {\n program\n .command(\"search <query>\")\n .description(\"Search the web (Tavily-powered). Costs 1 credit (basic) or 2 (advanced).\")\n .option(\"-n, --max <n>\", \"Max results to return (1–10)\", \"5\")\n .option(\"-d, --depth <level>\", \"Search depth: basic | advanced\", \"basic\")\n .option(\"-t, --time <range>\", \"Time filter: day | week | month | year (omit for all-time)\")\n .option(\n \"--include-domain <domain>\",\n \"Restrict to this domain (repeatable)\",\n collectArg,\n [] as string[]\n )\n .option(\n \"--exclude-domain <domain>\",\n \"Exclude this domain (repeatable)\",\n collectArg,\n [] as string[]\n )\n .action(async (query: string, opts: SearchOpts) => {\n const ctx = makeCtx(program)\n requireAuth(ctx)\n\n const depth = opts.depth === \"advanced\" ? \"advanced\" : \"basic\"\n const max = clampInt(opts.max, 1, 10, 5)\n\n const spinner = ctx.json ? null : ora(`Searching · ${truncate(query, 50)}`).start()\n\n try {\n const body: Record<string, unknown> = {\n query,\n maxResults: max,\n searchDepth: depth,\n }\n if (opts.time) body.timeRange = opts.time\n if (opts.includeDomain && opts.includeDomain.length > 0)\n body.includeDomains = opts.includeDomain\n if (opts.excludeDomain && opts.excludeDomain.length > 0)\n body.excludeDomains = opts.excludeDomain\n\n const result = await ctx.client.json<SearchResponse>({\n method: \"POST\",\n path: \"/me/tools/web-search\",\n body,\n // Advanced search can take ~10s; allow generous headroom.\n timeoutMs: 35_000,\n })\n\n spinner?.succeed(\n `Found ${result.results.length} result(s) · ${result.creditsCharged} credit(s) · ${result.creditsRemaining} remaining`\n )\n\n if (ctx.json) {\n renderResult(ctx, result)\n return\n }\n\n renderPretty(result)\n } catch (e) {\n spinner?.fail(\"Search failed.\")\n throw e\n }\n })\n}\n\nfunction collectArg(value: string, previous: string[]): string[] {\n return [...previous, value]\n}\n\nfunction clampInt(raw: string | undefined, min: number, max: number, fallback: number): number {\n if (!raw) return fallback\n const n = Number.parseInt(raw, 10)\n if (!Number.isFinite(n)) return fallback\n return Math.max(min, Math.min(max, n))\n}\n\nfunction truncate(s: string, n: number): string {\n return s.length <= n ? s : s.slice(0, n - 1) + \"…\"\n}\n\nfunction renderPretty(r: SearchResponse): void {\n const out = process.stdout\n\n if (r.answer) {\n logger.info(\"\\nAnswer:\")\n out.write(` ${r.answer}\\n`)\n }\n\n if (r.results.length > 0) {\n logger.info(\"\\nResults:\")\n r.results.forEach((item, i) => {\n out.write(`\\n ${i + 1}. ${item.title || \"(untitled)\"}\\n`)\n out.write(` ${item.url}\\n`)\n const snippet = item.content?.trim().replace(/\\s+/g, \" \") ?? \"\"\n if (snippet) out.write(` ${truncate(snippet, 200)}\\n`)\n })\n }\n\n if (r.followUpQuestions.length > 0) {\n logger.info(\"\\nFollow-up questions:\")\n r.followUpQuestions.forEach((q) => out.write(` · ${q}\\n`))\n }\n\n if (r.images.length > 0) {\n logger.info(\"\\nImages:\")\n r.images.forEach((url) => out.write(` ${url}\\n`))\n }\n\n out.write(\"\\n\")\n}\n","// Entrypoint. tsup prepends the `#!/usr/bin/env node` shebang in the build banner.\nimport { run } from \"./cli.js\"\nimport { WmCliError, ExitCode } from \"./errors.js\"\nimport { logger } from \"./logger.js\"\n\nrun(process.argv).catch((err: unknown) => {\n if (err instanceof WmCliError) {\n logger.error(err.message, err.details)\n process.exit(err.exitCode)\n }\n const message = err instanceof Error ? err.message : String(err)\n logger.error(`unexpected error: ${message}`)\n process.exit(ExitCode.UNEXPECTED)\n})\n"],"mappings":"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","names":["kleur","z","z","kleur","kleur","kleur","dirname","url","ora","ora","ora","ora","ora","ora"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/commands/login.ts","../src/config.ts","../src/constants.ts","../src/client.ts","../src/errors.ts","../src/logger.ts","../src/commands/_shared.ts","../src/commands/whoami.ts","../src/commands/gen.ts","../src/util/download.ts","../src/util/poll.ts","../src/util/await-job.ts","../src/commands/upscale.ts","../src/commands/campaign.ts","../src/commands/jobs.ts","../src/commands/search.ts","../src/index.ts"],"sourcesContent":["/**\n * Commander root. Each subcommand lives in its own file under ./commands.\n */\nimport { Command } from \"commander\"\nimport { registerLogin } from \"./commands/login.js\"\nimport { registerWhoami } from \"./commands/whoami.js\"\nimport { registerGen } from \"./commands/gen.js\"\nimport { registerUpscale } from \"./commands/upscale.js\"\nimport { registerCampaign } from \"./commands/campaign.js\"\nimport { registerJobs } from \"./commands/jobs.js\"\nimport { registerSearch } from \"./commands/search.js\"\n\nexport async function run(argv: string[]): Promise<void> {\n const program = new Command()\n .name(\"wm\")\n .description(\n \"WM Studio command-line client. Generate images, videos, brand campaigns, and 3D assets.\"\n )\n .version(VERSION, \"-v, --version\")\n .option(\"--api-url <url>\", \"Override WM Studio API base URL\")\n .option(\"--api-key <key>\", \"Override API key (otherwise WM_API_KEY or ~/.wm/config.json)\")\n .option(\"--json\", \"Emit machine-readable JSON output\", false)\n .showHelpAfterError(\"(run `wm <command> --help` for details)\")\n\n registerLogin(program)\n registerWhoami(program)\n registerGen(program)\n registerUpscale(program)\n registerCampaign(program)\n registerJobs(program)\n registerSearch(program)\n\n await program.parseAsync(argv)\n}\n\n// Injected at build time by tsup via `define` — fallback for `tsx`/`vitest`.\ndeclare const __VERSION__: string | undefined\nconst VERSION: string =\n (typeof __VERSION__ !== \"undefined\" && __VERSION__) ||\n process.env.npm_package_version ||\n \"0.0.0-dev\"\n","import type { Command } from \"commander\"\nimport { password } from \"@inquirer/prompts\"\nimport kleur from \"kleur\"\nimport { writeFileConfig } from \"../config.js\"\nimport { WmApiClient } from \"../client.js\"\nimport { resolveConfig } from \"../config.js\"\nimport { logger } from \"../logger.js\"\nimport { WmCliError } from \"../errors.js\"\nimport { DEFAULTS } from \"../constants.js\"\n\nexport function registerLogin(program: Command): void {\n program\n .command(\"login\")\n .description(\"Save your WM Studio API key to ~/.wm/config.json (chmod 0600).\")\n .option(\"--key <apiKey>\", \"Pass the API key non-interactively (useful in CI).\")\n .action(async (opts: { key?: string }) => {\n if (!opts.key) {\n process.stderr.write(\n `\\n${kleur.bold(\"Get an API key:\")} ${kleur.cyan(DEFAULTS.apiKeysUrl)}\\n` +\n kleur.dim(\" Sign in → Dashboard → API keys → Create new key, then paste below.\\n\\n\")\n )\n }\n const apiKey =\n opts.key ??\n (await password({\n message: \"Paste your WM Studio API key:\",\n mask: \"*\",\n }))\n if (!apiKey || apiKey.trim().length === 0) {\n throw WmCliError.usage(\"API key cannot be empty.\")\n }\n\n const cfg = resolveConfig({ apiKey: apiKey.trim() })\n const client = new WmApiClient(cfg)\n const me = await client.whoami()\n\n writeFileConfig({ apiKey: apiKey.trim() })\n logger.info(`Logged in as ${me.email} (${me.creditsRemaining} credits remaining).`)\n })\n}\n","/**\n * On-disk config + env merge.\n *\n * Precedence (highest first):\n * 1. CLI flag (--api-url, --api-key)\n * 2. Environment variables (WMSTUDIO_API_URL, WM_API_KEY)\n * 3. ~/.wm/config.json\n * 4. Built-in defaults (constants.ts)\n */\nimport { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from \"node:fs\"\nimport { homedir } from \"node:os\"\nimport { dirname, join } from \"node:path\"\nimport { z } from \"zod\"\nimport { DEFAULTS, ENV } from \"./constants.js\"\n\nconst FileConfigSchema = z.object({\n apiUrl: z.string().url().optional(),\n apiKey: z.string().min(1).optional(),\n uploadUrl: z.string().url().optional(),\n upgradeUrl: z.string().url().optional(),\n lowCreditsThreshold: z.number().int().nonnegative().optional(),\n})\n\nexport type FileConfig = z.infer<typeof FileConfigSchema>\n\nexport interface ResolvedConfig {\n apiUrl: string\n apiKey: string | undefined\n uploadUrl: string\n upgradeUrl: string\n lowCreditsThreshold: number\n configPath: string\n}\n\nexport function configDir(): string {\n const override = process.env[ENV.ConfigDir]\n return override && override.length > 0 ? override : join(homedir(), \".wm\")\n}\n\nexport function configPath(): string {\n return join(configDir(), \"config.json\")\n}\n\nexport function readFileConfig(): FileConfig {\n const path = configPath()\n if (!existsSync(path)) return {}\n try {\n const raw = readFileSync(path, \"utf8\")\n return FileConfigSchema.parse(JSON.parse(raw))\n } catch {\n // Corrupt config — return empty rather than crash the CLI on every command.\n return {}\n }\n}\n\nexport function writeFileConfig(patch: FileConfig): void {\n const merged = { ...readFileConfig(), ...patch }\n const dir = configDir()\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true, mode: 0o700 })\n const file = configPath()\n writeFileSync(file, JSON.stringify(merged, null, 2) + \"\\n\", { mode: 0o600 })\n // Defensive: enforce 0600 even if file pre-existed.\n try {\n chmodSync(file, 0o600)\n } catch {\n /* non-fatal */\n }\n // And 0700 on the dir.\n try {\n chmodSync(dirname(file), 0o700)\n } catch {\n /* non-fatal */\n }\n}\n\nexport interface ConfigOverrides {\n apiUrl?: string\n apiKey?: string\n}\n\nexport function resolveConfig(overrides: ConfigOverrides = {}): ResolvedConfig {\n const file = readFileConfig()\n return {\n apiUrl: overrides.apiUrl ?? process.env[ENV.ApiUrl] ?? file.apiUrl ?? DEFAULTS.apiUrl,\n apiKey: overrides.apiKey ?? process.env[ENV.ApiKey] ?? file.apiKey,\n uploadUrl: process.env[ENV.UploadUrl] ?? file.uploadUrl ?? DEFAULTS.uploadUrl,\n upgradeUrl: process.env[ENV.UpgradeUrl] ?? file.upgradeUrl ?? DEFAULTS.upgradeUrl,\n lowCreditsThreshold:\n numFromEnv(process.env[ENV.LowCreditsThreshold]) ??\n file.lowCreditsThreshold ??\n DEFAULTS.lowCreditsThreshold,\n configPath: configPath(),\n }\n}\n\nfunction numFromEnv(raw: string | undefined): number | undefined {\n if (!raw) return undefined\n const n = Number(raw)\n return Number.isFinite(n) ? n : undefined\n}\n","/**\n * Shared constants. Keep in sync with `mcp-director/src/config.py`.\n * Anything that names an env var, an endpoint, or a model id belongs here.\n */\n\nexport const DEFAULTS = {\n /** Hosted WM Studio REST API base. Override via `WMSTUDIO_API_URL`. */\n apiUrl: \"https://wmstudio.io/api\",\n /** Page surfaced when the API requires a public asset URL. */\n uploadUrl: \"https://wmstudio.io/dashboard/uploads\",\n /** Credit top-up landing page. */\n upgradeUrl: \"https://wmstudio.io/dashboard/credits\",\n /** Where users create API keys. Shown by `wm login`. */\n apiKeysUrl: \"https://wmstudio.io/dashboard/api-keys\",\n /** Below this remaining-credit count we surface a warning. */\n lowCreditsThreshold: 50,\n /** Default request timeout (ms) for non-job calls. */\n requestTimeoutMs: 60_000,\n /** Polling interval (ms) for async jobs. */\n jobPollIntervalMs: 4_000,\n /** Hard ceiling for job polling (ms). */\n jobPollTimeoutMs: 15 * 60 * 1000,\n} as const\n\nexport const ENV = {\n ApiUrl: \"WMSTUDIO_API_URL\",\n ApiKey: \"WM_API_KEY\",\n UploadUrl: \"ASSET_UPLOAD_URL\",\n UpgradeUrl: \"CREDITS_UPGRADE_URL\",\n LowCreditsThreshold: \"CREDITS_LOW_THRESHOLD\",\n LogLevel: \"WM_LOG_LEVEL\",\n ConfigDir: \"WM_CONFIG_DIR\",\n} as const\n\n/** Default model ids per tool — mirror `mcp-director/src/tools/studio.py` defaults. */\nexport const DEFAULT_MODELS = {\n image: \"fal-ai/nano-banana-pro\",\n imageEdit: \"fal-ai/nano-banana-pro/edit\",\n videoText: \"bytedance/seedance-2.0-fast\",\n videoImage: \"bytedance/seedance-2.0-fast\",\n upscaleImage: \"fal-ai/topaz/upscale/image\",\n upscaleVideo: \"fal-ai/topaz/upscale/video\",\n threeD: \"fal-ai/meshy/v6/image-to-3d\",\n brandshot: \"fal-ai/nano-banana-pro\",\n cameraAngles: \"fal-ai/nano-banana-pro\",\n casting: \"fal-ai/nano-banana-pro\",\n ugcRoom: \"fal-ai/nano-banana-pro\",\n} as const\n\n/**\n * Aspect-ratio options for image generation.\n * Single source of truth — keep in sync with\n * `mcp-director` `studio://options/image-aspect-ratios` resource.\n *\n * To add a new ratio, append an entry here and to the MCP resource.\n * The CLI picker and MCP agent instructions both read from their\n * respective lists automatically.\n */\nexport const ASPECT_RATIOS = [\n { value: \"1:1\", label: \"Square (1:1)\" },\n { value: \"16:9\", label: \"Landscape (16:9)\" },\n { value: \"9:16\", label: \"Portrait (9:16)\" },\n { value: \"4:3\", label: \"Classic (4:3)\" },\n { value: \"3:4\", label: \"Tall (3:4)\" },\n { value: \"21:9\", label: \"Ultrawide (21:9)\" },\n] as const\n","/**\n * Thin HTTP client for the WM Studio REST API.\n *\n * Endpoints mirror what `mcp-director/src/wmstudio_client.py` already calls\n * — keeping the contract identical means the CLI is a drop-in alternative\n * to the MCP for the same underlying backend.\n */\nimport { z } from \"zod\"\nimport { DEFAULTS } from \"./constants.js\"\nimport { ExitCode, WmCliError } from \"./errors.js\"\nimport type { ResolvedConfig } from \"./config.js\"\n\nconst ApiErrorSchema = z.object({\n code: z.string().optional(),\n error: z.string().optional(),\n message: z.string().optional(),\n requiresTopUp: z.boolean().optional(),\n upgradeUrl: z.string().url().optional(),\n uploadUrl: z.string().url().optional(),\n})\n\nexport interface JsonRequest {\n method: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\"\n path: string\n body?: Record<string, unknown>\n query?: Record<string, string | number | boolean | undefined>\n timeoutMs?: number\n}\n\nexport class WmApiClient {\n constructor(private readonly cfg: ResolvedConfig) {}\n\n /** GET /me — returns account + credit balance. */\n whoami(): Promise<{\n userId: string\n email: string\n creditsRemaining: number\n plan: string\n }> {\n return this.json({ method: \"GET\", path: \"/me\" })\n }\n\n /**\n * Estimate the credit cost of a generation BEFORE running it.\n * Hits POST /creative-studio/pricing.\n */\n estimatePricing(body: { model: string; [key: string]: unknown }): Promise<{ credits: number }> {\n return this.json({ method: \"POST\", path: \"/creative-studio/pricing\", body })\n }\n\n /** Validate the current api key without side-effects. */\n async ping(): Promise<boolean> {\n try {\n await this.whoami()\n return true\n } catch (err) {\n if (err instanceof WmCliError && err.code === \"auth_invalid\") return false\n throw err\n }\n }\n\n /** Generic JSON helper. */\n async json<T = unknown>(req: JsonRequest): Promise<T> {\n if (!this.cfg.apiKey) throw WmCliError.authRequired()\n\n const url = new URL(req.path.replace(/^\\//, \"\"), this.cfg.apiUrl.replace(/\\/?$/, \"/\"))\n if (req.query) {\n for (const [k, v] of Object.entries(req.query)) {\n if (v !== undefined) url.searchParams.set(k, String(v))\n }\n }\n\n const ac = new AbortController()\n const timeoutMs = req.timeoutMs ?? DEFAULTS.requestTimeoutMs\n const timeout = setTimeout(() => ac.abort(), timeoutMs)\n\n let res: Response\n try {\n res = await fetch(url, {\n method: req.method,\n headers: {\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n authorization: `Bearer ${this.cfg.apiKey}`,\n \"user-agent\": userAgent(),\n },\n body: req.body ? JSON.stringify(req.body) : undefined,\n signal: ac.signal,\n })\n } catch (err) {\n clearTimeout(timeout)\n if (err instanceof WmCliError) throw err\n const aborted = (err as { name?: string } | null)?.name === \"AbortError\"\n // undici wraps the real reason (ENOTFOUND, ECONNREFUSED, certificate, etc.)\n // inside `.cause`. Surfacing it makes \"fetch failed\" actually debuggable.\n const e = err as Error & { cause?: { code?: string; message?: string } }\n const cause = e?.cause\n const causeMsg = cause?.code ?? cause?.message\n throw new WmCliError({\n code: aborted ? \"timeout\" : \"network\",\n exitCode: aborted ? ExitCode.TIMEOUT : ExitCode.NETWORK,\n message: aborted\n ? `Request timed out after ${timeoutMs}ms (${req.method} ${url.toString()})`\n : `Network error: ${e.message}${causeMsg ? ` (${causeMsg})` : \"\"} — ${req.method} ${url.toString()}`,\n details: { cause: causeMsg ?? e.message, url: url.toString() },\n })\n }\n clearTimeout(timeout)\n\n const text = await res.text()\n const parsed: unknown = text ? safeJson(text) : undefined\n\n if (res.status >= 200 && res.status < 300) {\n return parsed as T\n }\n throw classify(res.status, parsed, this.cfg)\n }\n}\n\nfunction safeJson(text: string): unknown {\n try {\n return JSON.parse(text)\n } catch {\n return { raw: text }\n }\n}\n\nfunction classify(status: number, payload: unknown, cfg: ResolvedConfig): WmCliError {\n const parsed = ApiErrorSchema.safeParse(payload)\n const data = parsed.success ? parsed.data : {}\n const msg = data.message ?? data.error ?? `HTTP ${status}`\n\n if (status === 401 || status === 403) return WmCliError.authInvalid(msg)\n if (status === 402 || data.requiresTopUp) {\n return WmCliError.upgradeRequired(data.upgradeUrl ?? cfg.upgradeUrl, msg)\n }\n if (status === 422 && data.code === \"asset_url_required\") {\n return WmCliError.assetUrlRequired(data.uploadUrl ?? cfg.uploadUrl, msg)\n }\n return new WmCliError({\n code: status >= 500 ? \"server\" : \"usage\",\n exitCode: status >= 500 ? 50 : 2,\n message: msg,\n details: { status, payload },\n })\n}\n\nfunction userAgent(): string {\n return `wm-cli/${process.env.npm_package_version ?? \"dev\"} (node ${process.version})`\n}\n","/**\n * Error model + exit codes for `wm`.\n *\n * Exit codes are stable contract — kept in sync with `mcp-director` error codes\n * (see ../docs/CONVENTIONS.md). Used by CI, shell scripts, and humans.\n */\n\nexport const ExitCode = {\n OK: 0,\n USAGE: 2, // bad arguments / unknown command\n AUTH_REQUIRED: 10, // not logged in / missing api key\n AUTH_INVALID: 11, // server rejected token (401/403)\n ASSET_URL_REQUIRED: 20, // missing or unreachable user-provided URL\n UPGRADE_REQUIRED: 30, // 402 insufficient credits\n RATE_LIMITED: 31, // 429\n NETWORK: 40, // transport / DNS / TLS\n SERVER: 50, // 5xx\n TIMEOUT: 51, // server-side or client-side deadline exceeded\n UNEXPECTED: 99, // crashed / not classifiable\n} as const\n\nexport type ExitCodeValue = (typeof ExitCode)[keyof typeof ExitCode]\n\n/**\n * The canonical error codes returned by the WM Studio API and `mcp-director`.\n * Keeping the same vocabulary across CLI / MCP / SDK is the whole point.\n */\nexport const ErrorCode = {\n AuthRequired: \"auth_required\",\n AuthInvalid: \"auth_invalid\",\n AssetUrlRequired: \"asset_url_required\",\n UpgradeRequired: \"upgrade_required\",\n RateLimited: \"rate_limited\",\n Network: \"network\",\n Server: \"server\",\n Timeout: \"timeout\",\n Usage: \"usage\",\n Unexpected: \"unexpected\",\n} as const\n\nexport type ErrorCodeValue = (typeof ErrorCode)[keyof typeof ErrorCode]\n\nexport class WmCliError extends Error {\n readonly code: ErrorCodeValue\n readonly exitCode: ExitCodeValue\n readonly details?: Record<string, unknown>\n\n constructor(opts: {\n code: ErrorCodeValue\n exitCode: ExitCodeValue\n message: string\n details?: Record<string, unknown>\n }) {\n super(opts.message)\n this.name = \"WmCliError\"\n this.code = opts.code\n this.exitCode = opts.exitCode\n this.details = opts.details\n }\n\n static authRequired(message = \"Not logged in. Run `wm login` first.\"): WmCliError {\n return new WmCliError({\n code: ErrorCode.AuthRequired,\n exitCode: ExitCode.AUTH_REQUIRED,\n message,\n })\n }\n\n static authInvalid(message = \"Invalid or expired API key.\"): WmCliError {\n return new WmCliError({\n code: ErrorCode.AuthInvalid,\n exitCode: ExitCode.AUTH_INVALID,\n message,\n })\n }\n\n static assetUrlRequired(uploadUrl: string, message?: string): WmCliError {\n return new WmCliError({\n code: ErrorCode.AssetUrlRequired,\n exitCode: ExitCode.ASSET_URL_REQUIRED,\n message: message ?? `A real public asset URL is required. Upload at ${uploadUrl}.`,\n details: { uploadUrl },\n })\n }\n\n static upgradeRequired(upgradeUrl: string, message?: string): WmCliError {\n return new WmCliError({\n code: ErrorCode.UpgradeRequired,\n exitCode: ExitCode.UPGRADE_REQUIRED,\n message: message ?? `Insufficient credits. Top up at ${upgradeUrl} and re-run.`,\n details: { upgradeUrl },\n })\n }\n\n static usage(message: string): WmCliError {\n return new WmCliError({\n code: ErrorCode.Usage,\n exitCode: ExitCode.USAGE,\n message,\n })\n }\n}\n","/**\n * Tiny structured logger. Console output is colourised for humans (stderr);\n * when `WM_LOG_FORMAT=json` is set, emits JSON lines compatible with the same\n * shape used by `mcp-director` (`event`, `level`, `ts`, …extra).\n */\nimport kleur from \"kleur\"\nimport { ENV } from \"./constants.js\"\n\ntype Level = \"debug\" | \"info\" | \"warn\" | \"error\"\n\nconst LEVEL_ORDER: Record<Level, number> = { debug: 10, info: 20, warn: 30, error: 40 }\n\nfunction currentLevel(): Level {\n const raw = process.env[ENV.LogLevel]?.toLowerCase() as Level | undefined\n return raw && raw in LEVEL_ORDER ? raw : \"info\"\n}\n\nfunction asJson(): boolean {\n return process.env.WM_LOG_FORMAT === \"json\"\n}\n\nfunction emit(level: Level, message: string, extra?: Record<string, unknown>): void {\n if (LEVEL_ORDER[level] < LEVEL_ORDER[currentLevel()]) return\n\n if (asJson()) {\n const line = JSON.stringify({\n ts: new Date().toISOString(),\n level,\n event: message,\n ...extra,\n })\n process.stderr.write(line + \"\\n\")\n return\n }\n\n const tag =\n level === \"error\"\n ? kleur.red().bold(\"✖\")\n : level === \"warn\"\n ? kleur.yellow().bold(\"!\")\n : level === \"info\"\n ? kleur.cyan().bold(\"›\")\n : kleur.gray(\"·\")\n const detail = extra && Object.keys(extra).length ? \" \" + kleur.gray(JSON.stringify(extra)) : \"\"\n process.stderr.write(`${tag} ${message}${detail}\\n`)\n}\n\nexport const logger = {\n debug: (m: string, e?: Record<string, unknown>) => emit(\"debug\", m, e),\n info: (m: string, e?: Record<string, unknown>) => emit(\"info\", m, e),\n warn: (m: string, e?: Record<string, unknown>) => emit(\"warn\", m, e),\n error: (m: string, e?: Record<string, unknown>) => emit(\"error\", m, e),\n}\n","/**\n * Shared command helpers: resolve config, build client, render output.\n */\nimport type { Command } from \"commander\"\nimport { confirm, select } from \"@inquirer/prompts\"\nimport kleur from \"kleur\"\nimport { resolveConfig, type ResolvedConfig } from \"../config.js\"\nimport { WmApiClient } from \"../client.js\"\nimport { logger } from \"../logger.js\"\nimport { WmCliError } from \"../errors.js\"\nimport { ASPECT_RATIOS } from \"../constants.js\"\n\nexport interface GlobalFlags {\n apiUrl?: string\n apiKey?: string\n json?: boolean\n}\n\nexport interface CommandCtx {\n cfg: ResolvedConfig\n client: WmApiClient\n json: boolean\n}\n\nexport function makeCtx(program: Command): CommandCtx {\n // Walk up to the root program so subcommands inherit global flags.\n const root = program.parent ?? program\n const opts = root.opts<GlobalFlags>()\n const cfg = resolveConfig({ apiUrl: opts.apiUrl, apiKey: opts.apiKey })\n return { cfg, client: new WmApiClient(cfg), json: Boolean(opts.json) }\n}\n\nexport function requireAuth(\n ctx: CommandCtx\n): asserts ctx is CommandCtx & { cfg: ResolvedConfig & { apiKey: string } } {\n if (!ctx.cfg.apiKey) throw WmCliError.authRequired()\n}\n\nexport function renderResult(ctx: CommandCtx, payload: unknown, summary?: string): void {\n if (ctx.json) {\n process.stdout.write(JSON.stringify(payload, null, 2) + \"\\n\")\n return\n }\n if (summary) logger.info(summary)\n process.stdout.write(JSON.stringify(payload, null, 2) + \"\\n\")\n}\n\n/**\n * Estimate the credit cost of a generation, show it to the user, and\n * ask for confirmation. Returns true if the user accepted (or was\n * auto-skipped via --yes / --json), false if rejected.\n *\n * The pricing endpoint can fail (unknown model, network) — in that case\n * we surface a warning and let the user decide whether to proceed.\n *\n * @param ctx command context (has client + json flag)\n * @param skipPrompt when true (e.g. --yes flag), skip interactive confirm\n * @param body what gets POSTed to /creative-studio/pricing — at minimum { model }\n * @param summary one-line label like \"Image generation · nano-banana-pro\"\n */\nexport async function confirmCost(\n ctx: CommandCtx,\n skipPrompt: boolean,\n body: { model: string; [key: string]: unknown },\n summary: string\n): Promise<boolean> {\n let credits: number | null = null\n try {\n const res = await ctx.client.estimatePricing(body)\n credits = res.credits\n } catch (err) {\n if (!ctx.json) {\n logger.warn(\n `Could not fetch cost estimate (${err instanceof Error ? err.message : String(err)}). ` +\n `You will be charged the actual amount on success.`\n )\n }\n }\n\n if (ctx.json || skipPrompt) {\n if (credits !== null && !ctx.json) {\n logger.info(`${summary} — estimated ${kleur.yellow(`${credits} credits`)}`)\n }\n return true\n }\n\n if (credits === null) {\n return confirm({\n message: `${summary}. Cost unknown. Proceed anyway?`,\n default: false,\n })\n }\n\n const msg = `${summary}\\n Estimated cost: ${kleur.yellow(`${credits} credits`)}\\n Proceed?`\n return confirm({ message: msg, default: true })\n}\n\n/** Render the post-generation credits-remaining footer. */\nexport function renderCreditsFooter(ctx: CommandCtx, payload: unknown): void {\n if (ctx.json) return\n const obj = payload as { creditsRemaining?: number; creditsCharged?: number } | null\n if (!obj || typeof obj !== \"object\") return\n const charged =\n typeof obj.creditsCharged === \"number\" ? `${obj.creditsCharged} credits charged · ` : \"\"\n if (typeof obj.creditsRemaining === \"number\") {\n logger.info(`${charged}${obj.creditsRemaining} credits remaining`)\n }\n}\n\n/**\n * Prompt the user for an aspect ratio when none was provided via CLI flag.\n *\n * Extensible: when more image params are added in the future (e.g. style\n * presets, output format), add them as separate prompt functions following\n * the same pattern — each reads from a shared constant list and only fires\n * when the corresponding CLI flag is absent.\n *\n * @param cliValue value from --aspect-ratio (may be undefined)\n * @param jsonMode when true, skip interactive prompts entirely\n * @returns the resolved aspect ratio string (e.g. \"16:9\")\n */\nexport async function promptAspectRatio(\n cliValue: string | undefined,\n jsonMode: boolean\n): Promise<string> {\n if (cliValue) return cliValue\n if (jsonMode) return \"1:1\" // non-interactive mode: pick the default\n return select({\n message: \"Choose aspect ratio:\",\n choices: ASPECT_RATIOS.map((r) => ({ name: r.label, value: r.value })),\n default: \"1:1\",\n })\n}\n","import type { Command } from \"commander\"\nimport { makeCtx, requireAuth, renderResult } from \"./_shared.js\"\n\nexport function registerWhoami(program: Command): void {\n program\n .command(\"whoami\")\n .description(\"Show the logged-in account and remaining credits.\")\n .action(async () => {\n const ctx = makeCtx(program)\n requireAuth(ctx)\n const me = await ctx.client.whoami()\n renderResult(ctx, me, `${me.email} · ${me.creditsRemaining} credits · plan ${me.plan}`)\n })\n}\n","/**\n * `wm gen image|video` — image and video generation.\n *\n * Calls the same REST endpoints `mcp-director` already proxies to:\n * POST /studio/generate-image\n * POST /studio/generate-video\n */\nimport type { Command } from \"commander\"\nimport ora from \"ora\"\nimport {\n makeCtx,\n requireAuth,\n renderResult,\n confirmCost,\n renderCreditsFooter,\n promptAspectRatio,\n} from \"./_shared.js\"\nimport { DEFAULT_MODELS } from \"../constants.js\"\nimport { downloadToFile } from \"../util/download.js\"\nimport { awaitJob } from \"../util/await-job.js\"\nimport { logger } from \"../logger.js\"\n\ninterface ImageOpts {\n model?: string\n imageUrl?: string\n aspectRatio?: string\n negativePrompt?: string\n numImages?: string\n seed?: string\n out?: string\n yes?: boolean\n}\n\ninterface VideoOpts {\n model?: string\n image?: string\n duration?: string\n aspectRatio?: string\n out?: string\n yes?: boolean\n}\n\nexport function registerGen(program: Command): void {\n const gen = program.command(\"gen\").description(\"Generate creative assets (image, video).\")\n\n gen\n .command(\"image <prompt>\")\n .description(\"Text-to-image or image-to-image generation.\")\n .option(\n \"-m, --model <id>\",\n \"Provider/model id (auto-picks edit variant when --image-url is passed)\"\n )\n .option(\"-i, --image-url <url>\", \"Reference image URL for img2img variants\")\n .option(\"-a, --aspect-ratio <ratio>\", \"1:1 | 16:9 | 9:16 | 4:3 | 3:4\")\n .option(\"-n, --negative-prompt <text>\", \"Negative prompt\")\n .option(\"--num-images <n>\", \"Batch size\", \"1\")\n .option(\"--seed <n>\", \"Deterministic seed\")\n .option(\"-o, --out <file>\", \"Download the result to this path\")\n .option(\"-y, --yes\", \"Skip the cost confirmation prompt\", false)\n .action(async (prompt: string, opts: ImageOpts) => {\n const ctx = makeCtx(program)\n requireAuth(ctx)\n\n // Prompt for aspect ratio when not passed via --aspect-ratio.\n const aspectRatio = await promptAspectRatio(opts.aspectRatio, ctx.json)\n\n // Pick edit variant for img2img when no explicit model was given.\n const model = opts.model ?? (opts.imageUrl ? DEFAULT_MODELS.imageEdit : DEFAULT_MODELS.image)\n const numImages = opts.numImages ? Number(opts.numImages) : undefined\n\n const ok = await confirmCost(\n ctx,\n Boolean(opts.yes),\n {\n model,\n aspect_ratio: aspectRatio,\n num_images: numImages,\n },\n `Image generation · ${model}`\n )\n if (!ok) {\n logger.info(\"Cancelled.\")\n return\n }\n\n const spinner = ctx.json ? null : ora(\"Generating image…\").start()\n try {\n const submit = await ctx.client.json<Record<string, unknown>>({\n method: \"POST\",\n path: \"/studio/generate-image\",\n body: {\n prompt,\n model,\n image_url: opts.imageUrl,\n aspect_ratio: aspectRatio,\n negative_prompt: opts.negativePrompt,\n num_images: numImages,\n seed: opts.seed ? Number(opts.seed) : undefined,\n },\n })\n if (spinner) spinner.text = \"Rendering image…\"\n const result = await awaitJob(ctx.client, submit, \"image\", (s) => {\n if (spinner) spinner.text = `Image · ${s.status}`\n })\n spinner?.succeed(\"Image ready.\")\n if (opts.out && result.imageUrl) await downloadToFile(result.imageUrl, opts.out)\n renderResult(ctx, result, `→ ${result.imageUrl}`)\n renderCreditsFooter(ctx, result)\n } catch (e) {\n spinner?.fail(\"Image generation failed.\")\n throw e\n }\n })\n\n gen\n .command(\"video <prompt>\")\n .description(\"Text-to-video or image-to-video. Async; polls until done.\")\n .option(\"-m, --model <id>\", \"Provider/model id (auto-picks i2v vs t2v based on --image).\")\n .option(\"-i, --image <url>\", \"Starting frame for image-to-video\")\n .option(\"-d, --duration <seconds>\", \"Clip length\", \"5\")\n .option(\"-a, --aspect-ratio <ratio>\", \"16:9 | 9:16 | 1:1 | 4:3 | 3:4 | 21:9\")\n .option(\"-o, --out <file>\", \"Download the final clip to this path\")\n .option(\"-y, --yes\", \"Skip the cost confirmation prompt\", false)\n .action(async (prompt: string, opts: VideoOpts) => {\n const ctx = makeCtx(program)\n requireAuth(ctx)\n\n const aspectRatio = await promptAspectRatio(opts.aspectRatio, ctx.json)\n\n const model =\n opts.model ?? (opts.image ? DEFAULT_MODELS.videoImage : DEFAULT_MODELS.videoText)\n const duration = Number(opts.duration)\n\n const ok = await confirmCost(\n ctx,\n Boolean(opts.yes),\n {\n model,\n duration,\n aspect_ratio: aspectRatio,\n },\n `Video generation · ${model} · ${duration}s`\n )\n if (!ok) {\n logger.info(\"Cancelled.\")\n return\n }\n\n const spinner = ctx.json ? null : ora(\"Submitting video job…\").start()\n try {\n const submit = await ctx.client.json<Record<string, unknown>>({\n method: \"POST\",\n path: \"/studio/generate-video\",\n body: {\n prompt,\n model,\n image_url: opts.image,\n duration,\n aspect_ratio: aspectRatio,\n },\n })\n if (spinner) spinner.text = \"Rendering video…\"\n const final = await awaitJob(ctx.client, submit, \"video\", (s) => {\n if (spinner) spinner.text = `Video · ${s.status}`\n })\n spinner?.succeed(\"Video ready.\")\n if (opts.out && final.videoUrl) await downloadToFile(final.videoUrl, opts.out)\n renderResult(ctx, final, `→ ${final.videoUrl}`)\n renderCreditsFooter(ctx, final)\n } catch (e) {\n spinner?.fail(\"Video generation failed.\")\n throw e\n }\n })\n}\n","/**\n * Stream a remote asset to a local path. Used by `--out` flags.\n */\nimport { createWriteStream } from \"node:fs\"\nimport { mkdir } from \"node:fs/promises\"\nimport { dirname } from \"node:path\"\nimport { pipeline } from \"node:stream/promises\"\nimport { request } from \"undici\"\n\nexport async function downloadToFile(url: string, outPath: string): Promise<void> {\n await mkdir(dirname(outPath), { recursive: true })\n const res = await request(url, { method: \"GET\" })\n if (res.statusCode >= 400) throw new Error(`download failed: HTTP ${res.statusCode}`)\n // undici's res.body is already a Node Readable — pipe it straight.\n await pipeline(res.body, createWriteStream(outPath))\n}\n","/**\n * Generic async-job poller. Used by `gen video` and `campaign` commands.\n */\nimport { DEFAULTS } from \"../constants.js\"\nimport { WmCliError, ExitCode } from \"../errors.js\"\n\nexport interface PollOptions<T> {\n /** Function that fetches the latest status. */\n fetch: () => Promise<T>\n /** Returns true when the job has reached a terminal state. */\n done: (state: T) => boolean\n /** Optional hook fired on each tick (for spinners / progress). */\n onTick?: (state: T) => void\n intervalMs?: number\n timeoutMs?: number\n}\n\nexport async function poll<T>(opts: PollOptions<T>): Promise<T> {\n const interval = opts.intervalMs ?? DEFAULTS.jobPollIntervalMs\n const deadline = Date.now() + (opts.timeoutMs ?? DEFAULTS.jobPollTimeoutMs)\n\n for (;;) {\n const state = await opts.fetch()\n opts.onTick?.(state)\n if (opts.done(state)) return state\n if (Date.now() > deadline) {\n throw new WmCliError({\n code: \"timeout\",\n exitCode: ExitCode.TIMEOUT,\n message: \"Job polling timed out.\",\n })\n }\n await sleep(interval)\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms))\n}\n","/**\n * Handle the queued-job response shape returned by /studio/generate-image,\n * /studio/generate-video and /studio/upscale-image.\n *\n * If the response carries `queued: true`, poll `/studio/jobs/:id` until it\n * reports `status: \"succeeded\"` (and the requested URL field is present)\n * or `status: \"failed\"`. Otherwise, return the response as-is so old/sync\n * code paths keep working.\n */\nimport type { WmApiClient } from \"../client.js\"\nimport { poll } from \"./poll.js\"\nimport { WmCliError, ExitCode } from \"../errors.js\"\n\nexport type Asset = \"image\" | \"video\"\n\ninterface SubmitResponse {\n queued?: boolean\n generationId?: string\n id?: string\n jobId?: string\n imageUrl?: string\n videoUrl?: string\n creditsRemaining?: number\n}\n\ninterface JobStatus {\n jobId: string\n status: \"succeeded\" | \"running\" | \"failed\"\n imageUrl?: string | null\n videoUrl?: string | null\n creditsCharged?: number | null\n}\n\nexport interface AwaitedJob {\n imageUrl?: string\n videoUrl?: string\n creditsRemaining?: number\n jobId?: string\n}\n\nexport async function awaitJob(\n client: WmApiClient,\n submit: SubmitResponse,\n asset: Asset,\n onTick?: (s: JobStatus) => void\n): Promise<AwaitedJob> {\n // Sync response: URL already present.\n if (!submit.queued) {\n const url = asset === \"image\" ? submit.imageUrl : submit.videoUrl\n if (url) {\n return {\n [asset === \"image\" ? \"imageUrl\" : \"videoUrl\"]: url,\n creditsRemaining: submit.creditsRemaining,\n }\n }\n }\n\n const id = submit.generationId ?? submit.id\n if (!id) {\n throw new WmCliError({\n code: \"server\",\n exitCode: ExitCode.SERVER,\n message: \"Server did not return a generationId to poll.\",\n })\n }\n\n const final = await poll<JobStatus>({\n fetch: () => client.json<JobStatus>({ method: \"GET\", path: `/studio/jobs/${id}` }),\n done: (s) => s.status === \"succeeded\" || s.status === \"failed\",\n onTick,\n })\n\n if (final.status !== \"succeeded\") {\n throw new WmCliError({\n code: \"server\",\n exitCode: ExitCode.SERVER,\n message: `Job ${id} finished with status ${final.status}.`,\n })\n }\n\n const url = asset === \"image\" ? final.imageUrl : final.videoUrl\n if (!url) {\n throw new WmCliError({\n code: \"server\",\n exitCode: ExitCode.SERVER,\n message: `Job ${id} succeeded but no ${asset} URL was returned.`,\n })\n }\n\n return {\n [asset === \"image\" ? \"imageUrl\" : \"videoUrl\"]: url,\n jobId: id,\n }\n}\n","import type { Command } from \"commander\"\nimport ora from \"ora\"\nimport { makeCtx, requireAuth, renderResult, confirmCost, renderCreditsFooter } from \"./_shared.js\"\nimport { DEFAULT_MODELS } from \"../constants.js\"\nimport { downloadToFile } from \"../util/download.js\"\nimport { awaitJob } from \"../util/await-job.js\"\nimport { logger } from \"../logger.js\"\n\ninterface UpscaleOpts {\n factor?: string\n topazModel?: string\n faceEnhancement?: boolean\n out?: string\n yes?: boolean\n}\n\nexport function registerUpscale(program: Command): void {\n program\n .command(\"upscale <imageUrl>\")\n .description(\"Topaz upscale of an image (factor 1–4).\")\n .option(\"-f, --factor <n>\", \"Upscale factor (1|2|3|4)\", \"2\")\n .option(\"--topaz-model <name>\", \"Topaz preset\", \"Standard V2\")\n .option(\"--no-face-enhancement\", \"Disable Topaz face enhancement\")\n .option(\"-o, --out <file>\", \"Download the result to this path\")\n .option(\"-y, --yes\", \"Skip the cost confirmation prompt\", false)\n .action(async (imageUrl: string, opts: UpscaleOpts) => {\n const ctx = makeCtx(program)\n requireAuth(ctx)\n\n const factor = opts.factor ? Number(opts.factor) : 2\n const ok = await confirmCost(\n ctx,\n Boolean(opts.yes),\n {\n model: DEFAULT_MODELS.upscaleImage,\n upscale_factor: factor,\n },\n `Upscale ${factor}x · ${DEFAULT_MODELS.upscaleImage}`\n )\n if (!ok) {\n logger.info(\"Cancelled.\")\n return\n }\n\n const spinner = ctx.json ? null : ora(\"Upscaling…\").start()\n try {\n const submit = await ctx.client.json<Record<string, unknown>>({\n method: \"POST\",\n path: \"/studio/upscale-image\",\n body: {\n image_url: imageUrl,\n upscale_factor: factor,\n topaz_model: opts.topazModel,\n face_enhancement: opts.faceEnhancement,\n },\n })\n const result = await awaitJob(ctx.client, submit, \"image\", (s) => {\n if (spinner) spinner.text = `Upscale · ${s.status}`\n })\n spinner?.succeed(\"Upscaled.\")\n if (opts.out && result.imageUrl) await downloadToFile(result.imageUrl, opts.out)\n renderResult(ctx, result, `→ ${result.imageUrl}`)\n renderCreditsFooter(ctx, result)\n } catch (e) {\n spinner?.fail(\"Upscale failed.\")\n throw e\n }\n })\n}\n","/**\n * `wm campaign` — submit a brief to `director_creative_brief_to_run` or\n * `director_creative_batch_variations`, then poll the resulting run(s).\n */\nimport type { Command } from \"commander\"\nimport ora from \"ora\"\nimport { makeCtx, requireAuth, renderResult } from \"./_shared.js\"\nimport { poll } from \"../util/poll.js\"\n\ninterface CampaignOpts {\n variations?: string\n duration?: string\n platform?: string\n style?: string\n projectId?: string\n follow?: boolean\n}\n\ninterface RunStatus {\n runId: string\n status: string\n masterVideoUrl?: string\n}\n\nexport function registerCampaign(program: Command): void {\n program\n .command(\"campaign <brief>\")\n .description(\n \"Turn a creative brief into a full video run (or N variations) via the director_* pipeline.\"\n )\n .option(\"-n, --variations <n>\", \"Generate N parallel variations (1 = single run)\", \"1\")\n .option(\"-d, --duration <seconds>\", \"Target duration\", \"60\")\n .option(\"-p, --platform <name>\", \"youtube | tiktok | instagram\", \"youtube\")\n .option(\"-s, --style <name>\", \"cinematic | ugc | documentary | …\", \"cinematic\")\n .option(\"--project-id <id>\", \"Existing wmstudio project id (required for variations)\")\n .option(\"--no-follow\", \"Submit and return immediately without polling\")\n .action(async (brief: string, opts: CampaignOpts) => {\n const ctx = makeCtx(program)\n requireAuth(ctx)\n const variations = Math.max(1, Number(opts.variations ?? \"1\"))\n const spinner = ctx.json ? null : ora(\"Submitting brief…\").start()\n\n try {\n const submission =\n variations > 1\n ? await ctx.client.json<{ runIds: string[] }>({\n method: \"POST\",\n path: \"/studio/director/batch-variations\",\n body: {\n base_prompt: brief,\n max_concurrent: variations,\n project_id: opts.projectId,\n },\n })\n : await ctx.client.json<{ runIds: string[] }>({\n method: \"POST\",\n path: \"/studio/director/brief-to-run\",\n body: {\n brief,\n duration_target_seconds: Number(opts.duration),\n platform: opts.platform,\n style: opts.style,\n },\n })\n\n const runIds = submission.runIds ?? []\n if (!opts.follow || runIds.length === 0) {\n spinner?.succeed(`Submitted ${runIds.length} run(s).`)\n renderResult(ctx, submission)\n return\n }\n\n if (spinner) spinner.text = `Polling ${runIds.length} run(s)…`\n const finals = await Promise.all(\n runIds.map((id) =>\n poll<RunStatus>({\n fetch: () => ctx.client.json({ method: \"GET\", path: `/studio/runs/${id}` }),\n done: (s) => [\"succeeded\", \"failed\", \"cancelled\"].includes(s.status),\n })\n )\n )\n spinner?.succeed(\"Run(s) complete.\")\n renderResult(ctx, { runs: finals })\n } catch (e) {\n spinner?.fail(\"Campaign failed.\")\n throw e\n }\n })\n}\n","/**\n * `wm jobs list|get` — inspect async generation jobs and runs.\n */\nimport type { Command } from \"commander\"\nimport { makeCtx, requireAuth, renderResult } from \"./_shared.js\"\n\nexport function registerJobs(program: Command): void {\n const jobs = program.command(\"jobs\").description(\"List and inspect generation jobs.\")\n\n jobs\n .command(\"list\")\n .description(\"List recent jobs (default: 20 most recent).\")\n .option(\"-l, --limit <n>\", \"Number of jobs\", \"20\")\n .option(\"-s, --status <s>\", \"Filter by status (running|succeeded|failed|cancelled)\")\n .action(async (opts: { limit?: string; status?: string }) => {\n const ctx = makeCtx(program)\n requireAuth(ctx)\n const data = await ctx.client.json({\n method: \"GET\",\n path: \"/studio/jobs\",\n query: { limit: opts.limit, status: opts.status },\n })\n renderResult(ctx, data)\n })\n\n jobs\n .command(\"get <jobId>\")\n .description(\"Fetch a single job by id.\")\n .action(async (jobId: string) => {\n const ctx = makeCtx(program)\n requireAuth(ctx)\n const data = await ctx.client.json({ method: \"GET\", path: `/studio/jobs/${jobId}` })\n renderResult(ctx, data)\n })\n}\n","/**\n * `wm search` — programmatic web search powered by the WM Studio backend.\n *\n * Calls POST /api/me/tools/web-search. Auth + credit metering happen\n * server-side; the CLI is purely a presentation layer.\n *\n * Pretty output by default. Use `--json` (global flag) for piping:\n * wm search \"next.js 16 release\" --json | jq '.results[].url'\n */\nimport type { Command } from \"commander\"\nimport ora from \"ora\"\nimport { makeCtx, requireAuth, renderResult } from \"./_shared.js\"\nimport { logger } from \"../logger.js\"\n\ninterface SearchOpts {\n max?: string\n depth?: string\n time?: string\n includeDomain?: string[]\n excludeDomain?: string[]\n}\n\ninterface SearchResultItem {\n title: string\n url: string\n content: string\n score?: unknown\n}\n\ninterface SearchResponse {\n v: 1\n answer: string | null\n results: SearchResultItem[]\n images: string[]\n followUpQuestions: string[]\n creditsCharged: number\n creditsRemaining: number\n}\n\nexport function registerSearch(program: Command): void {\n program\n .command(\"search <query>\")\n .description(\"Search the web (Tavily-powered). Costs 1 credit (basic) or 2 (advanced).\")\n .option(\"-n, --max <n>\", \"Max results to return (1–10)\", \"5\")\n .option(\"-d, --depth <level>\", \"Search depth: basic | advanced\", \"basic\")\n .option(\"-t, --time <range>\", \"Time filter: day | week | month | year (omit for all-time)\")\n .option(\n \"--include-domain <domain>\",\n \"Restrict to this domain (repeatable)\",\n collectArg,\n [] as string[]\n )\n .option(\n \"--exclude-domain <domain>\",\n \"Exclude this domain (repeatable)\",\n collectArg,\n [] as string[]\n )\n .action(async (query: string, opts: SearchOpts) => {\n const ctx = makeCtx(program)\n requireAuth(ctx)\n\n const depth = opts.depth === \"advanced\" ? \"advanced\" : \"basic\"\n const max = clampInt(opts.max, 1, 10, 5)\n\n const spinner = ctx.json ? null : ora(`Searching · ${truncate(query, 50)}`).start()\n\n try {\n const body: Record<string, unknown> = {\n query,\n maxResults: max,\n searchDepth: depth,\n }\n if (opts.time) body.timeRange = opts.time\n if (opts.includeDomain && opts.includeDomain.length > 0)\n body.includeDomains = opts.includeDomain\n if (opts.excludeDomain && opts.excludeDomain.length > 0)\n body.excludeDomains = opts.excludeDomain\n\n const result = await ctx.client.json<SearchResponse>({\n method: \"POST\",\n path: \"/me/tools/web-search\",\n body,\n // Advanced search can take ~10s; allow generous headroom.\n timeoutMs: 35_000,\n })\n\n spinner?.succeed(\n `Found ${result.results.length} result(s) · ${result.creditsCharged} credit(s) · ${result.creditsRemaining} remaining`\n )\n\n if (ctx.json) {\n renderResult(ctx, result)\n return\n }\n\n renderPretty(result)\n } catch (e) {\n spinner?.fail(\"Search failed.\")\n throw e\n }\n })\n}\n\nfunction collectArg(value: string, previous: string[]): string[] {\n return [...previous, value]\n}\n\nfunction clampInt(raw: string | undefined, min: number, max: number, fallback: number): number {\n if (!raw) return fallback\n const n = Number.parseInt(raw, 10)\n if (!Number.isFinite(n)) return fallback\n return Math.max(min, Math.min(max, n))\n}\n\nfunction truncate(s: string, n: number): string {\n return s.length <= n ? s : s.slice(0, n - 1) + \"…\"\n}\n\nfunction renderPretty(r: SearchResponse): void {\n const out = process.stdout\n\n if (r.answer) {\n logger.info(\"\\nAnswer:\")\n out.write(` ${r.answer}\\n`)\n }\n\n if (r.results.length > 0) {\n logger.info(\"\\nResults:\")\n r.results.forEach((item, i) => {\n out.write(`\\n ${i + 1}. ${item.title || \"(untitled)\"}\\n`)\n out.write(` ${item.url}\\n`)\n const snippet = item.content?.trim().replace(/\\s+/g, \" \") ?? \"\"\n if (snippet) out.write(` ${truncate(snippet, 200)}\\n`)\n })\n }\n\n if (r.followUpQuestions.length > 0) {\n logger.info(\"\\nFollow-up questions:\")\n r.followUpQuestions.forEach((q) => out.write(` · ${q}\\n`))\n }\n\n if (r.images.length > 0) {\n logger.info(\"\\nImages:\")\n r.images.forEach((url) => out.write(` ${url}\\n`))\n }\n\n out.write(\"\\n\")\n}\n","// Entrypoint. tsup prepends the `#!/usr/bin/env node` shebang in the build banner.\nimport { run } from \"./cli.js\"\nimport { WmCliError, ExitCode } from \"./errors.js\"\nimport { logger } from \"./logger.js\"\n\nrun(process.argv).catch((err: unknown) => {\n if (err instanceof WmCliError) {\n logger.error(err.message, err.details)\n process.exit(err.exitCode)\n }\n const message = err instanceof Error ? err.message : String(err)\n logger.error(`unexpected error: ${message}`)\n process.exit(ExitCode.UNEXPECTED)\n})\n"],"mappings":"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","names":["kleur","z","z","kleur","kleur","kleur","dirname","url","ora","ora","ora","ora","ora","ora"]}
|
package/package.json
CHANGED