makefx 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +3 -1
  2. package/makefx.mjs +2934 -147
  3. package/package.json +1 -1
package/makefx.mjs CHANGED
@@ -44,7 +44,19 @@ var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["modu
44
44
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
45
45
  //#endregion
46
46
  //#region src/cli/lib/utils.ts
47
- var BOOLEAN_LONG_OPTIONS = new Set(["audio", "no-audio"]);
47
+ var BOOLEAN_LONG_OPTIONS = new Set([
48
+ "audio",
49
+ "append",
50
+ "default",
51
+ "disable",
52
+ "enable",
53
+ "json",
54
+ "local",
55
+ "no-collection",
56
+ "no-default",
57
+ "no-audio",
58
+ "no-style"
59
+ ]);
48
60
  function parseArgs(argv) {
49
61
  const options = {};
50
62
  const positionals = [];
@@ -689,6 +701,7 @@ async function handleBillingOpsCheck(env) {
689
701
  if (product?.productId) console.log(` Product: ${product.productId}${product.name ? ` (${product.name})` : ""}`);
690
702
  console.log(` Metered prices: ${product?.meteredPriceMeters.length ?? 0}/${productCheck.expectedMeteredPriceMeters.length}`);
691
703
  if (productCheck.missingMeteredPriceMeters.length > 0) console.log(` Missing metered prices: ${productCheck.missingMeteredPriceMeters.join(", ")}`);
704
+ if (productCheck.unexpectedMeterCreditBenefitMeters.length > 0) console.log(` Unexpected meter-credit benefits: ${productCheck.unexpectedMeterCreditBenefitMeters.join(", ")}`);
692
705
  }
693
706
  const syncCheck = billingChecks.checks.syncHealth;
694
707
  console.log("\nSync health:");
@@ -725,8 +738,26 @@ async function handleBillingReconcile(env, parsed) {
725
738
  const marker = meter.matched ? "OK " : "MISMATCH";
726
739
  console.log(` ${marker} ${meter.name.padEnd(22)} local=${meter.local} polar=${meter.polar} delta=${meter.delta}`);
727
740
  }
728
- if (data.mismatches.length > 0) {
729
- console.log("\nMismatched meters need sync/retry investigation before billing is considered reconciled.");
741
+ if (data.customerCharges) {
742
+ console.log("\nCustomer charge ledger:");
743
+ console.log(` usageEvents=${data.customerCharges.usageEvents} chargeRows=${data.customerCharges.chargeRows} missing=${data.customerCharges.missingChargeRows} orphan=${data.customerCharges.orphanChargeRows}`);
744
+ console.log(` billableUsage=${data.customerCharges.billableUsageQuantity} billableCharges=${data.customerCharges.billableChargeQuantity} delta=${data.customerCharges.billableQuantityDelta}`);
745
+ }
746
+ if (data.providerCost) {
747
+ console.log("\nProvider cost ledger:");
748
+ console.log(` amount=$${data.providerCost.totals.amountUsd.toFixed(6)} entries=${data.providerCost.totals.entries} unpriced=${data.providerCost.totals.unpricedEntries}`);
749
+ console.log(` linkedUsage=${data.providerCost.linkedUsageEvents} linkedCharges=${data.providerCost.linkedCustomerCharges} missingUsage=${data.providerCost.missingUsageEventLinks} missingCharges=${data.providerCost.missingCustomerChargeLinks}`);
750
+ }
751
+ if (data.platformUsage) {
752
+ console.log("\nPlatform usage:");
753
+ console.log(` storageBytes=${data.platformUsage.totals.storageBytes} workflowRuns=${data.platformUsage.totals.workflowRuns} deliveryBytes=${data.platformUsage.totals.deliveryBytes}`);
754
+ }
755
+ if (data.alerts && data.alerts.length > 0) {
756
+ console.log("\nAlerts:");
757
+ for (const alert of data.alerts) console.log(` ${alert.severity.toUpperCase().padEnd(8)} ${alert.code}: ${alert.message}`);
758
+ }
759
+ if (data.status === "mismatch") {
760
+ console.log("\nMismatched billing ledgers need sync/retry or attribution investigation before billing is considered reconciled.");
730
761
  process$1.exitCode = 1;
731
762
  }
732
763
  } catch (error) {
@@ -808,7 +839,7 @@ function validateProjectConfig(config, configPath) {
808
839
  * makefx spaces --id <space_id> Show details for a specific space
809
840
  * makefx spaces create <name> Create a new space
810
841
  */
811
- var defaultDeps$9 = {
842
+ var defaultDeps$13 = {
812
843
  loadConfig: loadStoredConfig,
813
844
  resolveBaseUrl,
814
845
  saveProjectConfig,
@@ -823,7 +854,7 @@ async function handleSpaces(parsed) {
823
854
  process$1.exitCode = 1;
824
855
  }
825
856
  }
826
- async function executeSpaces(parsed, deps = defaultDeps$9) {
857
+ async function executeSpaces(parsed, deps = defaultDeps$13) {
827
858
  const env = resolveCommandEnvironment(parsed);
828
859
  const showDetails = parsed.options.details === "true";
829
860
  const spaceId = parsed.options.id;
@@ -4962,18 +4993,6 @@ function printMessageDetails(message, type) {
4962
4993
  }
4963
4994
  }
4964
4995
  }
4965
- //#endregion
4966
- //#region src/cli/commands/upload.ts
4967
- /**
4968
- * Upload Command - Upload media to create variants
4969
- *
4970
- * Usage:
4971
- * makefx upload <file> --space <id> --asset <id> Upload to existing asset
4972
- * makefx upload <file> --space <id> --name <name> Create new asset
4973
- * makefx upload <file> --space <id> --name <name> --type <type>
4974
- */
4975
- var MAX_FILE_SIZE_MB$1 = 10;
4976
- var MAX_FILE_SIZE_BYTES$1 = MAX_FILE_SIZE_MB$1 * 1024 * 1024;
4977
4996
  var EXT_TO_MEDIA_TYPE = {
4978
4997
  ".aac": {
4979
4998
  mediaKind: "audio",
@@ -5037,7 +5056,7 @@ var EXT_TO_MEDIA_TYPE = {
5037
5056
  }
5038
5057
  };
5039
5058
  var ALLOWED_EXTENSIONS$1 = Object.keys(EXT_TO_MEDIA_TYPE).sort();
5040
- var defaultDeps$8 = {
5059
+ var defaultDeps$12 = {
5041
5060
  loadConfig: loadStoredConfig,
5042
5061
  loadProjectConfig,
5043
5062
  resolveBaseUrl,
@@ -5052,18 +5071,17 @@ async function handleUpload(parsed) {
5052
5071
  await executeUpload(parsed);
5053
5072
  } catch (error) {
5054
5073
  console.error(error instanceof Error ? `Error: ${error.message}` : "Error: Upload failed");
5055
- if (error instanceof UploadUsageError) printUsage$9();
5074
+ if (error instanceof UploadUsageError) printUsage$12();
5056
5075
  process$1.exitCode = 1;
5057
5076
  }
5058
5077
  }
5059
- async function executeUpload(parsed, deps = defaultDeps$8) {
5078
+ async function executeUpload(parsed, deps = defaultDeps$12) {
5060
5079
  const projectConfig = await deps.loadProjectConfig();
5061
5080
  const env = resolveCommandEnvironment(parsed, projectConfig);
5062
5081
  const spaceId = resolveCommandSpace(parsed, projectConfig);
5063
5082
  const assetId = parsed.options.asset;
5064
5083
  const assetName = parsed.options.name;
5065
5084
  const assetType = parsed.options.type || "character";
5066
- const parentAssetId = parsed.options.parent;
5067
5085
  const requestedMediaKind = parsed.options["media-kind"] || parsed.options.mediaKind;
5068
5086
  const filePath = parsed.positionals[0];
5069
5087
  if (!filePath) throw new UploadUsageError("File path is required");
@@ -5079,7 +5097,7 @@ async function executeUpload(parsed, deps = defaultDeps$8) {
5079
5097
  try {
5080
5098
  const fileStat = await deps.stat(filePath);
5081
5099
  if (!fileStat.isFile()) throw new Error(`"${filePath}" is not a file`);
5082
- if (fileStat.size > MAX_FILE_SIZE_BYTES$1) throw new Error(`File too large (${(fileStat.size / 1024 / 1024).toFixed(2)}MB). Maximum size: ${MAX_FILE_SIZE_MB$1}MB`);
5100
+ if (fileStat.size > 10485760) throw new Error(`File too large (${(fileStat.size / 1024 / 1024).toFixed(2)}MB). Maximum size: 10MB`);
5083
5101
  const fileBuffer = await deps.readFile(filePath);
5084
5102
  const fileName = path.basename(filePath);
5085
5103
  const formData = new FormData();
@@ -5090,7 +5108,6 @@ async function executeUpload(parsed, deps = defaultDeps$8) {
5090
5108
  else {
5091
5109
  formData.append("assetName", assetName);
5092
5110
  formData.append("assetType", assetType);
5093
- if (parentAssetId) formData.append("parentAssetId", parentAssetId);
5094
5111
  }
5095
5112
  deps.print(`\nUploading "${fileName}" to space ${spaceId}...`);
5096
5113
  deps.print(` Media kind: ${mediaType.mediaKind}`);
@@ -5150,7 +5167,7 @@ function resolveMediaType(ext, requestedMediaKind) {
5150
5167
  if (requestedMediaKind && requestedMediaKind !== mediaType.mediaKind) throw new Error(`--media-kind ${requestedMediaKind} does not match ${ext} (${mediaType.mediaKind})`);
5151
5168
  return mediaType;
5152
5169
  }
5153
- function printUsage$9() {
5170
+ function printUsage$12() {
5154
5171
  console.log(`
5155
5172
  Usage:
5156
5173
  makefx upload <file> --asset <id> [--space <id>] Upload media to existing asset
@@ -5162,7 +5179,6 @@ Options:
5162
5179
  --name <name> New asset name (creates asset + variant)
5163
5180
  --type <type> Asset type for new assets (default: character)
5164
5181
  --media-kind <k> Optional explicit kind: image, audio, or video
5165
- --parent <id> Parent asset ID for new assets
5166
5182
  --env <env> Environment (production|stage|local)
5167
5183
  --local Shortcut for --env local
5168
5184
 
@@ -5171,7 +5187,877 @@ Examples:
5171
5187
  makefx upload theme.mp3 --space abc123 --name "Theme Music" --type audio
5172
5188
  makefx upload cutscene.mp4 --space abc123 --name "Opening Cutscene" --type video
5173
5189
  makefx upload variant.jpg --space abc123 --asset def456
5174
- makefx upload sword.png --space abc123 --name "Sword" --type item --parent abc789
5190
+ `);
5191
+ }
5192
+ //#endregion
5193
+ //#region src/cli/commands/import.ts
5194
+ var defaultDeps$11 = {
5195
+ loadConfig: loadStoredConfig,
5196
+ loadProjectConfig,
5197
+ resolveBaseUrl,
5198
+ fetch,
5199
+ readFile,
5200
+ stat,
5201
+ print: console.log
5202
+ };
5203
+ async function handleImport(parsed) {
5204
+ try {
5205
+ await executeImport(parsed);
5206
+ } catch (error) {
5207
+ console.error(error instanceof Error ? `Error: ${error.message}` : "Error: Import failed");
5208
+ printUsage$11();
5209
+ process$1.exitCode = 1;
5210
+ }
5211
+ }
5212
+ async function executeImport(parsed, deps = defaultDeps$11) {
5213
+ const manifestPath = parsed.positionals[0] || parsed.options.manifest;
5214
+ if (!manifestPath || manifestPath === "true") throw new Error("Manifest path is required: makefx import <manifest.json>");
5215
+ const ctx = await buildContext$8(parsed, deps);
5216
+ const manifest = await readManifest(manifestPath, deps);
5217
+ await validateLocalRecords(manifest.records, deps);
5218
+ const plan = validateManifestPlan(manifest, await fetchSpaceState(ctx, deps));
5219
+ const uploadOrder = buildUploadOrder(manifest.records);
5220
+ if (parsed.options["dry-run"] === "true" || parsed.options.dryRun === "true") {
5221
+ const result = {
5222
+ dryRun: true,
5223
+ records: uploadOrder.map((record) => ({
5224
+ key: record.localKey,
5225
+ file: record.displayPath,
5226
+ target: record.assetId ?? `new:${record.assetName}`,
5227
+ lineageInputs: record.lineage.length
5228
+ })),
5229
+ collections: plan.collections.map((collection) => ({
5230
+ name: collection.name,
5231
+ create: collection.create
5232
+ })),
5233
+ collectionItems: plan.collectionItems.length,
5234
+ relations: plan.relations.length,
5235
+ compositions: plan.compositions.map((composition) => ({
5236
+ name: composition.name,
5237
+ create: composition.create
5238
+ })),
5239
+ compositionItems: plan.compositionItems.length,
5240
+ stylePresets: plan.stylePresets.map((preset) => ({
5241
+ name: preset.name,
5242
+ action: preset.action
5243
+ }))
5244
+ };
5245
+ printResult$1(result, parsed, deps);
5246
+ return result;
5247
+ }
5248
+ const uploadedByKey = /* @__PURE__ */ new Map();
5249
+ const imported = [];
5250
+ const jsonOutput = parsed.options.json === "true";
5251
+ for (const record of uploadOrder) {
5252
+ const lineage = record.lineage.map((input) => ({
5253
+ parentVariantId: input.sourceVariantId ?? uploadedByKey.get(input.sourceFile)?.variantId,
5254
+ relationType: input.relationType
5255
+ }));
5256
+ if (lineage.find((input) => !input.parentVariantId)) throw new Error(`Could not resolve same-batch lineage for ${record.localKey}`);
5257
+ const response = await uploadRecord(ctx, deps, record, lineage, { quiet: jsonOutput });
5258
+ uploadedByKey.set(record.localKey, {
5259
+ assetId: response.variant.asset_id,
5260
+ variantId: response.variant.id
5261
+ });
5262
+ imported.push({
5263
+ key: record.localKey,
5264
+ file: record.displayPath,
5265
+ assetId: response.variant.asset_id,
5266
+ variantId: response.variant.id,
5267
+ lineageIds: (response.lineage ?? []).map((lineageRecord) => lineageRecord.id)
5268
+ });
5269
+ }
5270
+ const result = {
5271
+ dryRun: false,
5272
+ records: imported,
5273
+ ...await applyOrganizationPlan(ctx, deps, plan, uploadedByKey)
5274
+ };
5275
+ printResult$1(result, parsed, deps);
5276
+ return result;
5277
+ }
5278
+ async function buildContext$8(parsed, deps) {
5279
+ const projectConfig = await deps.loadProjectConfig();
5280
+ const env = resolveCommandEnvironment(parsed, projectConfig);
5281
+ const spaceId = resolveCommandSpace(parsed, projectConfig);
5282
+ if (!spaceId) throw new Error("--space is required, or run: makefx init --space <id>");
5283
+ const config = await deps.loadConfig(env);
5284
+ if (!config) throw new Error(`Not logged in to ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
5285
+ if (config.token.expiresAt < Date.now()) throw new Error(`Token expired for ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
5286
+ if (env === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
5287
+ return {
5288
+ env,
5289
+ spaceId,
5290
+ baseUrl: deps.resolveBaseUrl(env),
5291
+ accessToken: config.token.accessToken
5292
+ };
5293
+ }
5294
+ async function readManifest(manifestPath, deps) {
5295
+ const manifestText = await deps.readFile(manifestPath, "utf8");
5296
+ const manifestDir = path.dirname(path.resolve(manifestPath));
5297
+ let parsed;
5298
+ try {
5299
+ parsed = JSON.parse(manifestText);
5300
+ } catch (error) {
5301
+ throw new Error(`Manifest is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
5302
+ }
5303
+ const root = Array.isArray(parsed) ? {} : parsed;
5304
+ const rawRecords = Array.isArray(parsed) ? parsed : parsed && typeof parsed === "object" ? root.records ?? root.files : null;
5305
+ if (!Array.isArray(rawRecords)) throw new Error("Manifest must be an array or contain a records/files array");
5306
+ const records = rawRecords.map((raw, index) => normalizeRecord(raw, index, manifestDir));
5307
+ const keys = /* @__PURE__ */ new Set();
5308
+ for (const record of records) {
5309
+ if (keys.has(record.localKey)) throw new Error(`Duplicate local key in manifest: ${record.localKey}`);
5310
+ keys.add(record.localKey);
5311
+ }
5312
+ return {
5313
+ records,
5314
+ collections: normalizeCollections(readArray(root.collections, "collections"), false),
5315
+ styleCollections: normalizeStyleCollections(readArray(root.styleCollections, "styleCollections")),
5316
+ collectionItems: [...records.flatMap((record) => record.collectionItems), ...normalizeCollectionItems(readArray(root.collectionItems, "collectionItems"), "collectionItems")],
5317
+ relations: [...records.flatMap((record) => record.relations), ...normalizeRelations(readArray(root.relations, "relations"), "relations")],
5318
+ compositions: normalizeCompositions(readArray(root.compositions, "compositions")),
5319
+ compositionItems: [...records.flatMap((record) => record.compositionItems), ...normalizeCompositionItems(readArray(root.compositionItems, "compositionItems"), "compositionItems")],
5320
+ stylePresets: normalizeStylePresets(readArray(root.stylePresets, "stylePresets"))
5321
+ };
5322
+ }
5323
+ function normalizeRecord(raw, index, manifestDir) {
5324
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) throw new Error(`Record ${index + 1} must be an object`);
5325
+ const record = raw;
5326
+ const displayPath = record.file ?? record.path;
5327
+ if (!displayPath) throw new Error(`Record ${index + 1} is missing file`);
5328
+ const filePath = path.resolve(manifestDir, displayPath);
5329
+ const mediaType = resolveMediaType(path.extname(filePath).toLowerCase(), record.mediaKind);
5330
+ const assetId = record.assetId ?? record.targetAssetId;
5331
+ const assetName = record.assetName ?? record.name;
5332
+ if (assetId && assetName) throw new Error(`Record ${index + 1} must set either assetId or name, not both`);
5333
+ if (!assetId && !assetName) throw new Error(`Record ${index + 1} must set assetId for an existing asset or name for a new asset`);
5334
+ const lineage = normalizeLineage(record.lineage ?? [], index);
5335
+ const activeVariantBehavior = normalizeActiveBehavior(record.activeVariantBehavior, index);
5336
+ const providerMetadata = record.providerMetadata ?? record.provider_metadata;
5337
+ const generationProvenance = record.generationProvenance ?? record.generation_provenance ?? {};
5338
+ validateObjectField(providerMetadata, `Record ${index + 1} providerMetadata`);
5339
+ validateObjectField(generationProvenance, `Record ${index + 1} generationProvenance`);
5340
+ const localKey = record.localKey ?? record.key ?? displayPath;
5341
+ return {
5342
+ index,
5343
+ localKey,
5344
+ filePath,
5345
+ displayPath,
5346
+ fileName: path.basename(filePath),
5347
+ assetName,
5348
+ assetType: record.assetType ?? record.type ?? "character",
5349
+ assetId,
5350
+ mediaKind: mediaType.mediaKind,
5351
+ mimeType: mediaType.mimeType,
5352
+ activeVariantBehavior,
5353
+ prompt: record.prompt,
5354
+ model: record.model,
5355
+ provider: record.provider,
5356
+ providerMetadata,
5357
+ generationProvenance,
5358
+ lineage,
5359
+ collectionItems: normalizeCollectionItems([...readArray(record.collections, `Record ${index + 1} collections`), ...readArray(record.collectionItems, `Record ${index + 1} collectionItems`)], `Record ${index + 1} collections`, localKey),
5360
+ relations: normalizeRelations(readArray(record.relations, `Record ${index + 1} relations`), `Record ${index + 1} relations`, localKey),
5361
+ compositionItems: normalizeCompositionItems(readArray(record.compositionItems, `Record ${index + 1} compositionItems`), `Record ${index + 1} compositionItems`, localKey),
5362
+ styleCollections: normalizeStyleCollections(readArray(record.styleCollections, `Record ${index + 1} styleCollections`), localKey)
5363
+ };
5364
+ }
5365
+ function readArray(value, label) {
5366
+ if (value === void 0) return [];
5367
+ if (!Array.isArray(value)) throw new Error(`${label} must be an array`);
5368
+ return value;
5369
+ }
5370
+ function normalizeLineage(inputs, recordIndex) {
5371
+ if (!Array.isArray(inputs)) throw new Error(`Record ${recordIndex + 1} lineage must be an array`);
5372
+ return inputs.map((input, index) => {
5373
+ if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error(`Record ${recordIndex + 1} lineage[${index}] must be an object`);
5374
+ const sourceVariantId = input.sourceVariantId ?? input.parentVariantId;
5375
+ if (sourceVariantId && input.sourceFile || !sourceVariantId && !input.sourceFile) throw new Error(`Record ${recordIndex + 1} lineage[${index}] must set exactly one of sourceVariantId or sourceFile`);
5376
+ if (input.relationType !== "derived" && input.relationType !== "refined" && input.relationType !== "forked") throw new Error(`Record ${recordIndex + 1} lineage[${index}] relationType must be derived, refined, or forked`);
5377
+ return {
5378
+ relationType: input.relationType,
5379
+ ...sourceVariantId ? { sourceVariantId } : { sourceFile: input.sourceFile }
5380
+ };
5381
+ });
5382
+ }
5383
+ function normalizeCollections(inputs, styleOnly) {
5384
+ return inputs.map((input, index) => {
5385
+ const collection = requireObject(input, `collections[${index}]`);
5386
+ const name = collection.name ?? collection.collectionName ?? collection.collection;
5387
+ if (!name || typeof name !== "string") throw new Error(`collections[${index}] name is required`);
5388
+ if (collection.description !== void 0 && collection.description !== null && typeof collection.description !== "string") throw new Error(`collections[${index}] description must be a string or null`);
5389
+ validateSortIndex(collection.sortIndex, `collections[${index}] sortIndex`);
5390
+ return {
5391
+ key: collection.id ?? name,
5392
+ name,
5393
+ description: collection.description,
5394
+ sortIndex: collection.sortIndex,
5395
+ create: styleOnly || collection.create === true || collection.createIfMissing === true
5396
+ };
5397
+ });
5398
+ }
5399
+ function normalizeStyleCollections(inputs, recordKey) {
5400
+ return inputs.map((input, index) => {
5401
+ if (typeof input === "string") return {
5402
+ key: input,
5403
+ name: input,
5404
+ create: false,
5405
+ refs: recordKey ? [recordKey] : []
5406
+ };
5407
+ const collection = requireObject(input, labelFor("styleCollections", index, recordKey));
5408
+ const name = collection.name ?? collection.collectionName ?? collection.collection;
5409
+ if (!name || typeof name !== "string") throw new Error(`${labelFor("styleCollections", index, recordKey)} name is required`);
5410
+ validateSortIndex(collection.sortIndex, `${labelFor("styleCollections", index, recordKey)} sortIndex`);
5411
+ const refs = [
5412
+ ...collection.refs ?? [],
5413
+ ...collection.records ?? [],
5414
+ ...recordKey ? [recordKey] : []
5415
+ ];
5416
+ if (!refs.every((ref) => typeof ref === "string" && ref.trim())) throw new Error(`${labelFor("styleCollections", index, recordKey)} refs must be strings`);
5417
+ return {
5418
+ key: collection.id ?? name,
5419
+ name,
5420
+ description: collection.description,
5421
+ sortIndex: collection.sortIndex,
5422
+ create: collection.create === true || collection.createIfMissing === true,
5423
+ refs
5424
+ };
5425
+ });
5426
+ }
5427
+ function normalizeCollectionItems(inputs, label, defaultRecordKey) {
5428
+ return inputs.map((input, index) => {
5429
+ const item = requireObject(input, `${label}[${index}]`);
5430
+ const collectionName = item.collectionName ?? item.collection ?? item.collectionId;
5431
+ if (!collectionName || typeof collectionName !== "string") throw new Error(`${label}[${index}] collection is required`);
5432
+ if (item.role !== void 0 && typeof item.role !== "string") throw new Error(`${label}[${index}] role must be a string`);
5433
+ const subjectType = normalizeSubjectType(item.subjectType ?? (item.variantId ? "variant" : "asset"), `${label}[${index}] subjectType`);
5434
+ const recordKey = item.recordKey ?? item.sourceFile ?? defaultRecordKey;
5435
+ validateSortIndex(item.sortIndex, `${label}[${index}] sortIndex`);
5436
+ if (item.pinnedVariantId !== void 0 && item.pinnedVariantId !== null && typeof item.pinnedVariantId !== "string") throw new Error(`${label}[${index}] pinnedVariantId must be a string or null`);
5437
+ return {
5438
+ id: item.id,
5439
+ collectionName,
5440
+ role: item.role ?? "member",
5441
+ subjectType,
5442
+ assetId: item.assetId,
5443
+ variantId: item.variantId,
5444
+ recordKey,
5445
+ pinnedVariantId: item.pinnedVariantId,
5446
+ pinnedVariantBehavior: normalizePinnedVariantBehavior(item.pinnedVariantBehavior, `${label}[${index}] pinnedVariantBehavior`),
5447
+ sortIndex: item.sortIndex
5448
+ };
5449
+ });
5450
+ }
5451
+ function normalizeRelations(inputs, label, defaultSubjectRecordKey) {
5452
+ return inputs.map((input, index) => {
5453
+ const relation = requireObject(input, `${label}[${index}]`);
5454
+ const subject = relation.subject ? normalizeSubject(relation.subject, `${label}[${index}] subject`) : normalizeSubject({
5455
+ subjectType: relation.subjectType,
5456
+ assetId: relation.subjectAssetId,
5457
+ variantId: relation.subjectVariantId,
5458
+ recordKey: defaultSubjectRecordKey
5459
+ }, `${label}[${index}] subject`);
5460
+ const object = normalizeSubject(relation.object ?? relation.target ?? {
5461
+ subjectType: relation.objectType,
5462
+ assetId: relation.objectAssetId,
5463
+ variantId: relation.objectVariantId
5464
+ }, `${label}[${index}] object`);
5465
+ const relationType = normalizeRelationType(relation.relationType, `${label}[${index}] relationType`);
5466
+ validateObjectField(relation.metadata, `${label}[${index}] metadata`);
5467
+ validateSortIndex(relation.sortIndex, `${label}[${index}] sortIndex`);
5468
+ if (relation.label !== void 0 && relation.label !== null && typeof relation.label !== "string") throw new Error(`${label}[${index}] label must be a string or null`);
5469
+ if (relation.context !== void 0 && relation.context !== null && typeof relation.context !== "string" && (typeof relation.context !== "object" || Array.isArray(relation.context))) throw new Error(`${label}[${index}] context must be a string, object, or null`);
5470
+ return {
5471
+ id: relation.id,
5472
+ subject,
5473
+ object,
5474
+ relationType,
5475
+ label: relation.label,
5476
+ context: relation.context,
5477
+ metadata: relation.metadata,
5478
+ sortIndex: relation.sortIndex
5479
+ };
5480
+ });
5481
+ }
5482
+ function normalizeCompositions(inputs) {
5483
+ return inputs.map((input, index) => {
5484
+ const composition = requireObject(input, `compositions[${index}]`);
5485
+ const name = composition.name ?? composition.compositionName ?? composition.composition;
5486
+ if (!name || typeof name !== "string") throw new Error(`compositions[${index}] name is required`);
5487
+ if (composition.description !== void 0 && composition.description !== null && typeof composition.description !== "string") throw new Error(`compositions[${index}] description must be a string or null`);
5488
+ validateObjectField(composition.metadata, `compositions[${index}] metadata`);
5489
+ validateSortIndex(composition.sortIndex, `compositions[${index}] sortIndex`);
5490
+ const output = composition.output ? normalizeSubject(composition.output, `compositions[${index}] output`) : composition.outputRecordKey || composition.outputAssetId || composition.outputVariantId ? normalizeSubject({
5491
+ subjectType: composition.outputVariantId || composition.outputRecordKey ? "variant" : "asset",
5492
+ assetId: composition.outputAssetId ?? void 0,
5493
+ variantId: composition.outputVariantId ?? void 0,
5494
+ recordKey: composition.outputRecordKey
5495
+ }, `compositions[${index}] output`) : void 0;
5496
+ return {
5497
+ key: composition.id ?? name,
5498
+ name,
5499
+ description: composition.description,
5500
+ status: normalizeCompositionStatus(composition.status, `compositions[${index}] status`),
5501
+ output,
5502
+ metadata: composition.metadata,
5503
+ sortIndex: composition.sortIndex,
5504
+ create: composition.create === true || composition.createIfMissing === true
5505
+ };
5506
+ });
5507
+ }
5508
+ function normalizeCompositionItems(inputs, label, defaultRecordKey) {
5509
+ return inputs.map((input, index) => {
5510
+ const item = requireObject(input, `${label}[${index}]`);
5511
+ const compositionName = item.compositionName ?? item.composition ?? item.compositionId;
5512
+ if (!compositionName || typeof compositionName !== "string") throw new Error(`${label}[${index}] composition is required`);
5513
+ const role = normalizeCompositionItemRole(item.role, `${label}[${index}] role`);
5514
+ validateObjectField(item.metadata, `${label}[${index}] metadata`);
5515
+ validateSortIndex(item.sortIndex, `${label}[${index}] sortIndex`);
5516
+ if (item.label !== void 0 && item.label !== null && typeof item.label !== "string") throw new Error(`${label}[${index}] label must be a string or null`);
5517
+ return {
5518
+ id: item.id,
5519
+ compositionName,
5520
+ role,
5521
+ label: item.label,
5522
+ assetId: item.assetId,
5523
+ variantId: item.variantId,
5524
+ recordKey: item.recordKey ?? item.sourceFile ?? defaultRecordKey,
5525
+ metadata: item.metadata,
5526
+ sortIndex: item.sortIndex
5527
+ };
5528
+ });
5529
+ }
5530
+ function normalizeStylePresets(inputs) {
5531
+ return inputs.map((input, index) => {
5532
+ const preset = requireObject(input, `stylePresets[${index}]`);
5533
+ const name = preset.name ?? preset.presetName;
5534
+ if (!name || typeof name !== "string") throw new Error(`stylePresets[${index}] name is required`);
5535
+ const stylePrompt = preset.stylePrompt ?? preset.prompt;
5536
+ if (stylePrompt !== void 0 && typeof stylePrompt !== "string") throw new Error(`stylePresets[${index}] stylePrompt must be a string`);
5537
+ if (preset.description !== void 0 && preset.description !== null && typeof preset.description !== "string") throw new Error(`stylePresets[${index}] description must be a string or null`);
5538
+ if ([
5539
+ preset.create,
5540
+ preset.update,
5541
+ preset.upsert
5542
+ ].filter((value) => value === true).length !== 1) throw new Error(`stylePresets[${index}] must set exactly one of create, update, or upsert`);
5543
+ return {
5544
+ id: preset.id,
5545
+ name,
5546
+ description: preset.description,
5547
+ stylePrompt,
5548
+ collectionName: preset.collectionName ?? preset.collection ?? void 0,
5549
+ collectionId: preset.collectionId,
5550
+ enabled: preset.enabled,
5551
+ isDefault: preset.isDefault ?? preset.default,
5552
+ action: preset.create ? "create" : preset.update ? "update" : "upsert"
5553
+ };
5554
+ });
5555
+ }
5556
+ function normalizeSubject(input, label) {
5557
+ const subjectType = normalizeSubjectType(input.subjectType ?? input.type ?? (input.assetId ? "asset" : "variant"), `${label} subjectType`);
5558
+ const recordKey = input.recordKey ?? input.sourceFile;
5559
+ if (subjectType === "asset" && input.variantId && !recordKey && !input.assetId) throw new Error(`${label} asset subject must use assetId or recordKey`);
5560
+ if (subjectType === "variant" && input.assetId && !input.variantId && !recordKey) throw new Error(`${label} variant subject must use variantId or recordKey`);
5561
+ return {
5562
+ subjectType,
5563
+ assetId: input.assetId,
5564
+ variantId: input.variantId,
5565
+ recordKey
5566
+ };
5567
+ }
5568
+ function normalizeSubjectType(value, label) {
5569
+ if (value === "asset" || value === "variant") return value;
5570
+ throw new Error(`${label} must be asset or variant`);
5571
+ }
5572
+ function normalizeRelationType(value, label) {
5573
+ if ([
5574
+ "appears_in",
5575
+ "background_for",
5576
+ "style_reference_for",
5577
+ "thumbnail_for",
5578
+ "alternate_of",
5579
+ "prop_in",
5580
+ "map_for",
5581
+ "part_of",
5582
+ "reference_for",
5583
+ "custom"
5584
+ ].includes(value)) return value;
5585
+ throw new Error(`${label} is invalid`);
5586
+ }
5587
+ function normalizeCompositionItemRole(value, label) {
5588
+ if ([
5589
+ "output",
5590
+ "background",
5591
+ "character",
5592
+ "prop",
5593
+ "style_ref",
5594
+ "overlay",
5595
+ "map",
5596
+ "thumbnail",
5597
+ "custom"
5598
+ ].includes(value)) return value;
5599
+ throw new Error(`${label} is invalid`);
5600
+ }
5601
+ function normalizeCompositionStatus(value, label) {
5602
+ if (value === void 0) return void 0;
5603
+ if (value === "draft" || value === "final") return value;
5604
+ throw new Error(`${label} must be draft or final`);
5605
+ }
5606
+ function normalizePinnedVariantBehavior(value, label) {
5607
+ if (!value || value === "imported") return "imported";
5608
+ if (value === "none" || value === "unpin") return "none";
5609
+ throw new Error(`${label} must be imported or none`);
5610
+ }
5611
+ function requireObject(value, label) {
5612
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${label} must be an object`);
5613
+ return value;
5614
+ }
5615
+ function validateSortIndex(value, label) {
5616
+ if (value !== void 0 && !Number.isInteger(value)) throw new Error(`${label} must be an integer`);
5617
+ }
5618
+ function labelFor(section, index, recordKey) {
5619
+ return recordKey ? `Record ${recordKey} ${section}[${index}]` : `${section}[${index}]`;
5620
+ }
5621
+ function normalizeActiveBehavior(value, recordIndex) {
5622
+ if (!value || value === "if-missing" || value === "if_missing") return "if-missing";
5623
+ if (value === "set-active" || value === "set_active") return "set-active";
5624
+ if (value === "keep") return "keep";
5625
+ throw new Error(`Record ${recordIndex + 1} activeVariantBehavior must be if-missing, set-active, or keep`);
5626
+ }
5627
+ function validateObjectField(value, label) {
5628
+ if (value === void 0) return;
5629
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${label} must be an object`);
5630
+ }
5631
+ async function validateLocalRecords(records, deps) {
5632
+ for (const record of records) {
5633
+ let fileStat;
5634
+ try {
5635
+ fileStat = await deps.stat(record.filePath);
5636
+ } catch (error) {
5637
+ if (error.code === "ENOENT") throw new Error(`File not found for ${record.localKey}: ${record.displayPath}`);
5638
+ throw error;
5639
+ }
5640
+ if (!fileStat.isFile()) throw new Error(`Manifest file is not a file for ${record.localKey}: ${record.displayPath}`);
5641
+ if (fileStat.size > 10485760) throw new Error(`File too large for ${record.localKey} (${(fileStat.size / 1024 / 1024).toFixed(2)}MB). Maximum size: 10MB`);
5642
+ }
5643
+ }
5644
+ async function fetchSpaceState(ctx, deps) {
5645
+ const [assetsData, collectionsData, compositionsData, stylePresetsData] = await Promise.all([
5646
+ fetchJson$1(ctx, deps, `/api/spaces/${ctx.spaceId}/assets`),
5647
+ fetchJson$1(ctx, deps, `/api/spaces/${ctx.spaceId}/collections`),
5648
+ fetchJson$1(ctx, deps, `/api/spaces/${ctx.spaceId}/compositions`),
5649
+ fetchJson$1(ctx, deps, `/api/spaces/${ctx.spaceId}/style-presets`)
5650
+ ]);
5651
+ const assets = assetsData.assets ?? [];
5652
+ const variantsById = /* @__PURE__ */ new Map();
5653
+ for (const asset of assets) {
5654
+ const details = await fetchJson$1(ctx, deps, `/api/spaces/${ctx.spaceId}/assets/${encodeURIComponent(asset.id)}`);
5655
+ for (const variant of details.variants ?? []) variantsById.set(variant.id, variant);
5656
+ }
5657
+ return {
5658
+ assets,
5659
+ variantsById,
5660
+ collections: collectionsData.collections ?? [],
5661
+ compositions: compositionsData.compositions ?? [],
5662
+ stylePresets: stylePresetsData.presets ?? []
5663
+ };
5664
+ }
5665
+ function validateSpaceReferences(records, state) {
5666
+ const assetsById = new Map(state.assets.map((asset) => [asset.id, asset]));
5667
+ const recordsByKey = new Map(records.map((record) => [record.localKey, record]));
5668
+ for (const record of records) {
5669
+ if (record.assetId) {
5670
+ const asset = assetsById.get(record.assetId);
5671
+ if (!asset) throw new Error(`Target asset not found for ${record.localKey}: ${record.assetId}`);
5672
+ if (asset.media_kind && asset.media_kind !== record.mediaKind) throw new Error(`Target asset ${record.assetId} is ${asset.media_kind}, but ${record.localKey} is ${record.mediaKind}`);
5673
+ }
5674
+ for (const lineage of record.lineage) {
5675
+ if (lineage.sourceVariantId && !state.variantsById.has(lineage.sourceVariantId)) throw new Error(`Source variant not found in space for ${record.localKey}: ${lineage.sourceVariantId}`);
5676
+ if (lineage.sourceFile) {
5677
+ const sourceRecord = recordsByKey.get(lineage.sourceFile);
5678
+ if (!sourceRecord) throw new Error(`Source file key not found for ${record.localKey}: ${lineage.sourceFile}`);
5679
+ if (sourceRecord.localKey === record.localKey) throw new Error(`Record ${record.localKey} cannot use itself as a lineage source`);
5680
+ }
5681
+ }
5682
+ }
5683
+ }
5684
+ function validateManifestPlan(manifest, state) {
5685
+ validateSpaceReferences(manifest.records, state);
5686
+ const recordsByKey = new Map(manifest.records.map((record) => [record.localKey, record]));
5687
+ const collectionsByName = new Map(state.collections.map((collection) => [collection.name, collection]));
5688
+ const compositionsByName = new Map(state.compositions.map((composition) => [composition.name, composition]));
5689
+ const stylePresetsByName = new Map(state.stylePresets.map((preset) => [preset.name, preset]));
5690
+ const stylePresetsById = new Map(state.stylePresets.map((preset) => [preset.id, preset]));
5691
+ const collections = dedupeCollections([
5692
+ ...manifest.collections,
5693
+ ...manifest.styleCollections,
5694
+ ...manifest.records.flatMap((record) => record.styleCollections)
5695
+ ]);
5696
+ const collectionItems = [
5697
+ ...manifest.collectionItems,
5698
+ ...manifest.styleCollections.flatMap((collection) => styleCollectionItems(collection)),
5699
+ ...manifest.records.flatMap((record) => record.styleCollections.flatMap((collection) => styleCollectionItems(collection)))
5700
+ ];
5701
+ const compositions = dedupeCompositions(manifest.compositions);
5702
+ const compositionItems = manifest.compositionItems;
5703
+ for (const collection of collections) if (!collectionsByName.has(collection.name) && !collection.create) throw new Error(`Collection not found: ${collection.name}. Add it to manifest collections with create: true.`);
5704
+ for (const item of collectionItems) {
5705
+ if (!collectionsByName.has(item.collectionName) && !collections.some((collection) => collection.name === item.collectionName && collection.create)) throw new Error(`Collection not found for collection item: ${item.collectionName}`);
5706
+ validateCollectionSubject(item, recordsByKey, state);
5707
+ }
5708
+ for (const relation of manifest.relations) {
5709
+ validateSubjectReference(relation.subject, recordsByKey, state, "Relation subject");
5710
+ validateSubjectReference(relation.object, recordsByKey, state, "Relation object");
5711
+ }
5712
+ for (const composition of compositions) {
5713
+ if (!compositionsByName.has(composition.name) && !composition.create) throw new Error(`Composition not found: ${composition.name}. Add it to manifest compositions with create: true.`);
5714
+ if (composition.output) {
5715
+ validateSubjectReference(composition.output, recordsByKey, state, `Composition ${composition.name} output`);
5716
+ if (composition.output.subjectType !== "variant") throw new Error(`Composition ${composition.name} output must reference a variant`);
5717
+ }
5718
+ }
5719
+ for (const item of compositionItems) {
5720
+ if (!compositionsByName.has(item.compositionName) && !compositions.some((composition) => composition.name === item.compositionName && composition.create)) throw new Error(`Composition not found for composition item: ${item.compositionName}`);
5721
+ if (item.recordKey) {
5722
+ if (!recordsByKey.has(item.recordKey)) throw new Error(`Composition item references unknown same-batch record: ${item.recordKey}`);
5723
+ } else if (!item.variantId) throw new Error(`Composition item for ${item.compositionName} must set variantId or recordKey`);
5724
+ else if (!state.variantsById.has(item.variantId)) throw new Error(`Composition item references unknown variant: ${item.variantId}`);
5725
+ if (item.assetId && !state.assets.some((asset) => asset.id === item.assetId)) throw new Error(`Composition item references unknown asset: ${item.assetId}`);
5726
+ }
5727
+ for (const preset of manifest.stylePresets) {
5728
+ const existingPresetById = preset.id ? stylePresetsById.get(preset.id) : void 0;
5729
+ const existingPresetByName = stylePresetsByName.get(preset.name);
5730
+ const existingPreset = preset.id ? existingPresetById : existingPresetByName;
5731
+ const createConflict = preset.id ? existingPresetById ?? existingPresetByName : existingPresetByName;
5732
+ if (preset.action === "create" && createConflict) throw new Error(`Style preset already exists: ${preset.name}`);
5733
+ if (preset.action === "update" && !existingPreset) throw new Error(`Style preset not found for update: ${preset.id ?? preset.name}`);
5734
+ if (preset.collectionName) {
5735
+ const willCreate = collections.some((collection) => collection.name === preset.collectionName && collection.create);
5736
+ if (!collectionsByName.has(preset.collectionName) && !willCreate) throw new Error(`Style preset ${preset.name} references missing collection: ${preset.collectionName}`);
5737
+ }
5738
+ }
5739
+ return {
5740
+ ...manifest,
5741
+ collections,
5742
+ collectionItems,
5743
+ compositions,
5744
+ compositionItems
5745
+ };
5746
+ }
5747
+ function dedupeCollections(collections) {
5748
+ const byName = /* @__PURE__ */ new Map();
5749
+ for (const collection of collections) {
5750
+ const existing = byName.get(collection.name);
5751
+ byName.set(collection.name, {
5752
+ key: collection.key,
5753
+ name: collection.name,
5754
+ description: collection.description ?? existing?.description,
5755
+ sortIndex: collection.sortIndex ?? existing?.sortIndex,
5756
+ create: Boolean(existing?.create || collection.create)
5757
+ });
5758
+ }
5759
+ return [...byName.values()];
5760
+ }
5761
+ function dedupeCompositions(compositions) {
5762
+ const byName = /* @__PURE__ */ new Map();
5763
+ for (const composition of compositions) {
5764
+ const existing = byName.get(composition.name);
5765
+ byName.set(composition.name, {
5766
+ ...existing,
5767
+ ...composition,
5768
+ create: Boolean(existing?.create || composition.create)
5769
+ });
5770
+ }
5771
+ return [...byName.values()];
5772
+ }
5773
+ function styleCollectionItems(collection) {
5774
+ return collection.refs.map((recordKey, index) => ({
5775
+ collectionName: collection.name,
5776
+ role: "style_ref",
5777
+ subjectType: "asset",
5778
+ recordKey,
5779
+ pinnedVariantBehavior: "imported",
5780
+ sortIndex: index
5781
+ }));
5782
+ }
5783
+ function validateCollectionSubject(item, recordsByKey, state) {
5784
+ if (item.recordKey) {
5785
+ if (!recordsByKey.has(item.recordKey)) throw new Error(`Collection item references unknown same-batch record: ${item.recordKey}`);
5786
+ return;
5787
+ }
5788
+ if (item.subjectType === "asset") {
5789
+ if (!item.assetId) throw new Error(`Collection item for ${item.collectionName} must set assetId or recordKey`);
5790
+ if (!state.assets.some((asset) => asset.id === item.assetId)) throw new Error(`Collection item references unknown asset: ${item.assetId}`);
5791
+ if (item.pinnedVariantId && !state.variantsById.has(item.pinnedVariantId)) throw new Error(`Collection item references unknown pinned variant: ${item.pinnedVariantId}`);
5792
+ return;
5793
+ }
5794
+ if (!item.variantId) throw new Error(`Collection item for ${item.collectionName} must set variantId or recordKey`);
5795
+ if (!state.variantsById.has(item.variantId)) throw new Error(`Collection item references unknown variant: ${item.variantId}`);
5796
+ }
5797
+ function validateSubjectReference(subject, recordsByKey, state, label) {
5798
+ if (subject.recordKey) {
5799
+ if (!recordsByKey.has(subject.recordKey)) throw new Error(`${label} references unknown same-batch record: ${subject.recordKey}`);
5800
+ return;
5801
+ }
5802
+ if (subject.subjectType === "asset") {
5803
+ if (!subject.assetId) throw new Error(`${label} must set assetId or recordKey`);
5804
+ if (!state.assets.some((asset) => asset.id === subject.assetId)) throw new Error(`${label} references unknown asset: ${subject.assetId}`);
5805
+ return;
5806
+ }
5807
+ if (!subject.variantId) throw new Error(`${label} must set variantId or recordKey`);
5808
+ if (!state.variantsById.has(subject.variantId)) throw new Error(`${label} references unknown variant: ${subject.variantId}`);
5809
+ }
5810
+ function buildUploadOrder(records) {
5811
+ const pending = new Map(records.map((record) => [record.localKey, record]));
5812
+ const uploaded = /* @__PURE__ */ new Set();
5813
+ const order = [];
5814
+ while (pending.size > 0) {
5815
+ let progressed = false;
5816
+ for (const [key, record] of pending) {
5817
+ if (!record.lineage.every((lineage) => !lineage.sourceFile || uploaded.has(lineage.sourceFile))) continue;
5818
+ order.push(record);
5819
+ uploaded.add(key);
5820
+ pending.delete(key);
5821
+ progressed = true;
5822
+ }
5823
+ if (!progressed) throw new Error(`Same-batch lineage contains a cycle or unresolved dependency: ${[...pending.keys()].join(", ")}`);
5824
+ }
5825
+ return order;
5826
+ }
5827
+ async function uploadRecord(ctx, deps, record, lineage, options) {
5828
+ const fileBuffer = await deps.readFile(record.filePath);
5829
+ const formData = new FormData();
5830
+ formData.append("file", new Blob([fileBuffer], { type: record.mimeType }), record.fileName);
5831
+ formData.append("operation", "import");
5832
+ formData.append("mediaKind", record.mediaKind);
5833
+ formData.append("assetType", record.assetType);
5834
+ formData.append("activeVariantBehavior", record.activeVariantBehavior);
5835
+ formData.append("generationProvenance", JSON.stringify(record.generationProvenance));
5836
+ if (record.assetId) formData.append("assetId", record.assetId);
5837
+ else formData.append("assetName", record.assetName);
5838
+ if (record.prompt) formData.append("prompt", record.prompt);
5839
+ if (record.model) formData.append("model", record.model);
5840
+ if (record.provider) formData.append("provider", record.provider);
5841
+ if (record.providerMetadata) formData.append("providerMetadata", JSON.stringify(record.providerMetadata));
5842
+ if (lineage.length > 0) formData.append("lineage", JSON.stringify(lineage));
5843
+ if (!options.quiet) deps.print(`Importing ${record.displayPath}...`);
5844
+ const response = await deps.fetch(`${ctx.baseUrl}/api/spaces/${ctx.spaceId}/upload`, {
5845
+ method: "POST",
5846
+ headers: { Authorization: `Bearer ${ctx.accessToken}` },
5847
+ body: formData
5848
+ });
5849
+ const data = await response.json();
5850
+ if (!response.ok) throw new Error(`Import failed for ${record.localKey}: ${"error" in data ? data.error : response.statusText}`);
5851
+ return data;
5852
+ }
5853
+ async function applyOrganizationPlan(ctx, deps, plan, uploadedByKey) {
5854
+ const collectionIds = [];
5855
+ const collectionItemIds = [];
5856
+ const relationIds = [];
5857
+ const compositionIds = [];
5858
+ const compositionItemIds = [];
5859
+ const stylePresetIds = [];
5860
+ const collections = await fetchJson$1(ctx, deps, `/api/spaces/${ctx.spaceId}/collections`);
5861
+ const collectionsByName = new Map((collections.collections ?? []).map((collection) => [collection.name, collection]));
5862
+ for (const collection of plan.collections) if (!collectionsByName.has(collection.name) && collection.create) {
5863
+ const created = await postJson(ctx, deps, `/api/spaces/${ctx.spaceId}/collections`, {
5864
+ name: collection.name,
5865
+ description: collection.description,
5866
+ sortIndex: collection.sortIndex
5867
+ });
5868
+ collectionsByName.set(created.collection.name, created.collection);
5869
+ collectionIds.push(created.collection.id);
5870
+ }
5871
+ for (const item of plan.collectionItems) {
5872
+ const collection = collectionsByName.get(item.collectionName);
5873
+ if (!collection) throw new Error(`Collection not found during import: ${item.collectionName}`);
5874
+ const created = await postJson(ctx, deps, `/api/spaces/${ctx.spaceId}/collections/${encodeURIComponent(collection.id)}/items`, resolveCollectionItemRequest(item, uploadedByKey));
5875
+ collectionItemIds.push(created.item.id);
5876
+ }
5877
+ for (const relation of plan.relations) {
5878
+ const created = await postJson(ctx, deps, `/api/spaces/${ctx.spaceId}/relations`, {
5879
+ id: relation.id,
5880
+ subject: resolveSubject(relation.subject, uploadedByKey),
5881
+ object: resolveSubject(relation.object, uploadedByKey),
5882
+ relationType: relation.relationType,
5883
+ label: relation.label,
5884
+ context: relation.context,
5885
+ metadata: relation.metadata,
5886
+ sortIndex: relation.sortIndex
5887
+ });
5888
+ relationIds.push(created.relation.id);
5889
+ }
5890
+ const compositions = await fetchJson$1(ctx, deps, `/api/spaces/${ctx.spaceId}/compositions`);
5891
+ const compositionsByName = new Map((compositions.compositions ?? []).map((composition) => [composition.name, composition]));
5892
+ for (const composition of plan.compositions) if (!compositionsByName.has(composition.name) && composition.create) {
5893
+ const output = composition.output ? resolveSubject(composition.output, uploadedByKey) : void 0;
5894
+ const created = await postJson(ctx, deps, `/api/spaces/${ctx.spaceId}/compositions`, {
5895
+ name: composition.name,
5896
+ description: composition.description,
5897
+ status: composition.status,
5898
+ outputAssetId: output?.assetId,
5899
+ outputVariantId: output?.variantId,
5900
+ metadata: composition.metadata,
5901
+ sortIndex: composition.sortIndex
5902
+ });
5903
+ compositionsByName.set(created.composition.name, created.composition);
5904
+ compositionIds.push(created.composition.id);
5905
+ }
5906
+ for (const item of plan.compositionItems) {
5907
+ const composition = compositionsByName.get(item.compositionName);
5908
+ if (!composition) throw new Error(`Composition not found during import: ${item.compositionName}`);
5909
+ const created = await postJson(ctx, deps, `/api/spaces/${ctx.spaceId}/compositions/${encodeURIComponent(composition.id)}/items`, resolveCompositionItemRequest(item, uploadedByKey));
5910
+ compositionItemIds.push(created.item.id);
5911
+ }
5912
+ const presets = await fetchJson$1(ctx, deps, `/api/spaces/${ctx.spaceId}/style-presets`);
5913
+ const presetsByName = new Map((presets.presets ?? []).map((preset) => [preset.name, preset]));
5914
+ const presetsById = new Map((presets.presets ?? []).map((preset) => [preset.id, preset]));
5915
+ for (const preset of plan.stylePresets) {
5916
+ const collectionId = preset.collectionId === null ? null : preset.collectionId ?? (preset.collectionName ? collectionsByName.get(preset.collectionName)?.id : void 0);
5917
+ if (preset.collectionName && collectionId === void 0) throw new Error(`Style preset ${preset.name} references missing collection during import: ${preset.collectionName}`);
5918
+ const request = {
5919
+ id: preset.id,
5920
+ name: preset.name,
5921
+ description: preset.description,
5922
+ stylePrompt: preset.stylePrompt,
5923
+ collectionId,
5924
+ enabled: preset.enabled,
5925
+ isDefault: preset.isDefault
5926
+ };
5927
+ const existing = preset.id ? presetsById.get(preset.id) : presetsByName.get(preset.name);
5928
+ if (preset.action === "update" || preset.action === "upsert" && existing) {
5929
+ const updated = await patchJson(ctx, deps, `/api/spaces/${ctx.spaceId}/style-presets/${encodeURIComponent(existing.id)}`, request);
5930
+ stylePresetIds.push(updated.preset.id);
5931
+ presetsByName.set(updated.preset.name, updated.preset);
5932
+ presetsById.set(updated.preset.id, updated.preset);
5933
+ } else {
5934
+ const created = await postJson(ctx, deps, `/api/spaces/${ctx.spaceId}/style-presets`, request);
5935
+ stylePresetIds.push(created.preset.id);
5936
+ presetsByName.set(created.preset.name, created.preset);
5937
+ presetsById.set(created.preset.id, created.preset);
5938
+ }
5939
+ }
5940
+ return {
5941
+ collectionIds,
5942
+ collectionItemIds,
5943
+ relationIds,
5944
+ compositionIds,
5945
+ compositionItemIds,
5946
+ stylePresetIds
5947
+ };
5948
+ }
5949
+ function resolveCollectionItemRequest(item, uploadedByKey) {
5950
+ const subject = item.recordKey ? resolveSubject({
5951
+ subjectType: item.subjectType,
5952
+ recordKey: item.recordKey
5953
+ }, uploadedByKey) : {
5954
+ subjectType: item.subjectType,
5955
+ assetId: item.assetId,
5956
+ variantId: item.variantId
5957
+ };
5958
+ return {
5959
+ id: item.id,
5960
+ ...subject,
5961
+ role: item.role,
5962
+ pinnedVariantId: item.pinnedVariantBehavior === "none" ? item.pinnedVariantId ?? null : item.pinnedVariantId ?? (item.recordKey ? uploadedByKey.get(item.recordKey).variantId : void 0),
5963
+ sortIndex: item.sortIndex
5964
+ };
5965
+ }
5966
+ function resolveCompositionItemRequest(item, uploadedByKey) {
5967
+ const uploaded = item.recordKey ? uploadedByKey.get(item.recordKey) : void 0;
5968
+ if (item.recordKey && !uploaded) throw new Error(`Could not resolve same-batch composition item: ${item.recordKey}`);
5969
+ return {
5970
+ id: item.id,
5971
+ role: item.role,
5972
+ label: item.label,
5973
+ assetId: item.assetId ?? uploaded?.assetId,
5974
+ variantId: item.variantId ?? uploaded.variantId,
5975
+ metadata: item.metadata,
5976
+ sortIndex: item.sortIndex
5977
+ };
5978
+ }
5979
+ function resolveSubject(subject, uploadedByKey) {
5980
+ if (!subject.recordKey) return {
5981
+ subjectType: subject.subjectType,
5982
+ assetId: subject.assetId,
5983
+ variantId: subject.variantId
5984
+ };
5985
+ const uploaded = uploadedByKey.get(subject.recordKey);
5986
+ if (!uploaded) throw new Error(`Could not resolve same-batch reference: ${subject.recordKey}`);
5987
+ return subject.subjectType === "asset" ? {
5988
+ subjectType: "asset",
5989
+ assetId: uploaded.assetId
5990
+ } : {
5991
+ subjectType: "variant",
5992
+ variantId: uploaded.variantId
5993
+ };
5994
+ }
5995
+ async function postJson(ctx, deps, requestPath, json) {
5996
+ return sendJson(ctx, deps, "POST", requestPath, json);
5997
+ }
5998
+ async function patchJson(ctx, deps, requestPath, json) {
5999
+ return sendJson(ctx, deps, "PATCH", requestPath, json);
6000
+ }
6001
+ async function sendJson(ctx, deps, method, requestPath, json) {
6002
+ const response = await deps.fetch(`${ctx.baseUrl}${requestPath}`, {
6003
+ method,
6004
+ headers: {
6005
+ Authorization: `Bearer ${ctx.accessToken}`,
6006
+ Accept: "application/json",
6007
+ "Content-Type": "application/json"
6008
+ },
6009
+ body: JSON.stringify(stripUndefined(json))
6010
+ });
6011
+ const data = await response.json().catch(() => ({}));
6012
+ if (!response.ok) throw new Error("error" in data ? data.error : `Request failed: ${response.status}`);
6013
+ return data;
6014
+ }
6015
+ function stripUndefined(value) {
6016
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
6017
+ }
6018
+ async function fetchJson$1(ctx, deps, requestPath) {
6019
+ const response = await deps.fetch(`${ctx.baseUrl}${requestPath}`, { headers: {
6020
+ Authorization: `Bearer ${ctx.accessToken}`,
6021
+ Accept: "application/json"
6022
+ } });
6023
+ const data = await response.json().catch(() => ({}));
6024
+ if (!response.ok) throw new Error("error" in data ? data.error : `Request failed: ${response.status}`);
6025
+ return data;
6026
+ }
6027
+ function printResult$1(result, parsed, deps) {
6028
+ if (parsed.options.json === "true") {
6029
+ deps.print(JSON.stringify(result, null, 2));
6030
+ return;
6031
+ }
6032
+ if (result.dryRun) {
6033
+ deps.print(`Dry run passed for ${result.records.length} import records.`);
6034
+ const organizationCount = result.collections.length + result.collectionItems + result.relations + result.compositions.length + result.compositionItems + result.stylePresets.length;
6035
+ if (organizationCount > 0) deps.print(` Organization changes: ${organizationCount}`);
6036
+ return;
6037
+ }
6038
+ deps.print(`Imported ${result.records.length} records.`);
6039
+ for (const record of result.records) deps.print(` ${record.key}: asset ${record.assetId}, variant ${record.variantId}`);
6040
+ const organizationCount = result.collectionIds.length + result.collectionItemIds.length + result.relationIds.length + result.compositionIds.length + result.compositionItemIds.length + result.stylePresetIds.length;
6041
+ if (organizationCount > 0) deps.print(` Organization records: ${organizationCount}`);
6042
+ }
6043
+ function printUsage$11() {
6044
+ console.log(`
6045
+ Usage:
6046
+ makefx import <manifest.json> [--space <id>]
6047
+ makefx import <manifest.json> --dry-run [--json]
6048
+
6049
+ Manifest:
6050
+ Top-level array, or { "records": [...] }. Each record sets file plus either
6051
+ assetId for an existing asset or name for a new asset. Records can include
6052
+ prompt, model, provider, providerMetadata, and generationProvenance for
6053
+ immutable import provenance. Lineage entries use sourceVariantId or sourceFile
6054
+ with relationType derived, refined, or forked; lineage is not editable
6055
+ organization state. Optional collections, collectionItems, relations,
6056
+ compositions, compositionItems, styleCollections, and stylePresets sections
6057
+ organize imported records after upload. Style references are normal assets in
6058
+ collections and presets point to those collections. Missing
6059
+ collections/compositions are only created when their manifest entry sets
6060
+ create: true.
5175
6061
  `);
5176
6062
  }
5177
6063
  //#endregion
@@ -19110,7 +19996,8 @@ var UserProfileSchema = object({
19110
19996
  }).openapi("UserProfile");
19111
19997
  var SessionConfigSchema = object({
19112
19998
  googleClientId: string$1(),
19113
- environment: string$1()
19999
+ environment: string$1(),
20000
+ features: object({ rotation: boolean$1() })
19114
20001
  }).openapi("SessionConfig");
19115
20002
  var AuthSessionResponseSchema = object({
19116
20003
  user: ApiUserSchema.nullable(),
@@ -19138,6 +20025,33 @@ var UserSettingsResponseSchema = object({
19138
20025
  success: literal(true),
19139
20026
  user: ApiUserSchema
19140
20027
  }).openapi("UserSettingsResponse");
20028
+ var ProviderKeyProviderSchema = _enum([
20029
+ "google_ai",
20030
+ "anthropic",
20031
+ "elevenlabs",
20032
+ "lyria"
20033
+ ]).openapi("ProviderKeyProvider");
20034
+ var ProviderKeyParamsSchema = object({ provider: ProviderKeyProviderSchema.openapi({ param: {
20035
+ name: "provider",
20036
+ in: "path"
20037
+ } }) });
20038
+ var ProviderKeySummarySchema = object({
20039
+ provider: ProviderKeyProviderSchema,
20040
+ label: string$1(),
20041
+ configured: boolean$1(),
20042
+ keyHint: string$1().nullable(),
20043
+ updatedAt: string$1().nullable(),
20044
+ platformConfigured: boolean$1()
20045
+ }).openapi("ProviderKeySummary");
20046
+ var ListProviderKeysResponseSchema = object({
20047
+ success: literal(true),
20048
+ providers: array(ProviderKeySummarySchema)
20049
+ }).openapi("ListProviderKeysResponse");
20050
+ var UpsertProviderKeyRequestSchema = object({ apiKey: string$1() }).openapi("UpsertProviderKeyRequest");
20051
+ var ProviderKeyResponseSchema = object({
20052
+ success: literal(true),
20053
+ provider: ProviderKeySummarySchema
20054
+ }).openapi("ProviderKeyResponse");
19141
20055
  var SpaceRoleSchema = _enum([
19142
20056
  "owner",
19143
20057
  "editor",
@@ -19191,6 +20105,12 @@ var VariantStatusSchema = _enum([
19191
20105
  "completed",
19192
20106
  "failed"
19193
20107
  ]);
20108
+ var PlatformUsageTypeSchema = _enum([
20109
+ "storage",
20110
+ "workflow",
20111
+ "delivery"
20112
+ ]);
20113
+ var PlatformUsageUnitSchema = _enum(["byte", "run"]);
19194
20114
  var BooleanFromSqliteSchema = union([
19195
20115
  boolean$1(),
19196
20116
  literal(0),
@@ -19240,28 +20160,472 @@ var VariantSchema = object({
19240
20160
  created_at: number$1(),
19241
20161
  updated_at: number$1().nullable()
19242
20162
  }).passthrough().openapi("Variant");
20163
+ var LineageSchema = object({
20164
+ id: string$1(),
20165
+ parent_variant_id: string$1(),
20166
+ child_variant_id: string$1(),
20167
+ relation_type: _enum([
20168
+ "derived",
20169
+ "refined",
20170
+ "forked"
20171
+ ]),
20172
+ severed: BooleanFromSqliteSchema.optional(),
20173
+ created_at: number$1().optional()
20174
+ }).passthrough().openapi("Lineage");
19243
20175
  var ListSpaceAssetsResponseSchema = object({
19244
20176
  success: literal(true),
19245
20177
  assets: array(AssetSchema)
19246
20178
  }).openapi("ListSpaceAssetsResponse");
19247
- var ProductionRecordSchema = object({
20179
+ var SpaceSubjectTypeSchema = _enum(["asset", "variant"]);
20180
+ var CollectionKindSchema = _enum([
20181
+ "cast",
20182
+ "style_refs",
20183
+ "backgrounds",
20184
+ "scenes",
20185
+ "thumbnails",
20186
+ "maps",
20187
+ "deliverables",
20188
+ "custom"
20189
+ ]);
20190
+ var SpaceRelationTypeSchema = _enum([
20191
+ "appears_in",
20192
+ "background_for",
20193
+ "style_reference_for",
20194
+ "thumbnail_for",
20195
+ "alternate_of",
20196
+ "prop_in",
20197
+ "map_for",
20198
+ "part_of",
20199
+ "reference_for",
20200
+ "custom"
20201
+ ]);
20202
+ var CompositionItemRoleSchema = _enum([
20203
+ "output",
20204
+ "background",
20205
+ "character",
20206
+ "prop",
20207
+ "style_ref",
20208
+ "overlay",
20209
+ "map",
20210
+ "thumbnail",
20211
+ "custom"
20212
+ ]);
20213
+ var CompositionStatusSchema = _enum(["draft", "final"]);
20214
+ var CollectionIdParamsSchema = SpaceIdParamsSchema.extend({ collectionId: string$1().openapi({ param: {
20215
+ name: "collectionId",
20216
+ in: "path"
20217
+ } }) });
20218
+ var CollectionItemParamsSchema = CollectionIdParamsSchema.extend({ itemId: string$1().openapi({ param: {
20219
+ name: "itemId",
20220
+ in: "path"
20221
+ } }) });
20222
+ var StylePresetParamsSchema = SpaceIdParamsSchema.extend({ presetId: string$1().openapi({ param: {
20223
+ name: "presetId",
20224
+ in: "path"
20225
+ } }) });
20226
+ var RelationParamsSchema = SpaceIdParamsSchema.extend({ relationId: string$1().openapi({ param: {
20227
+ name: "relationId",
20228
+ in: "path"
20229
+ } }) });
20230
+ var CompositionIdParamsSchema = SpaceIdParamsSchema.extend({ compositionId: string$1().openapi({ param: {
20231
+ name: "compositionId",
20232
+ in: "path"
20233
+ } }) });
20234
+ var CompositionItemParamsSchema = CompositionIdParamsSchema.extend({ itemId: string$1().openapi({ param: {
20235
+ name: "itemId",
20236
+ in: "path"
20237
+ } }) });
20238
+ var SpaceSubjectSchema = object({
20239
+ subjectType: SpaceSubjectTypeSchema,
20240
+ assetId: string$1().optional(),
20241
+ variantId: string$1().optional()
20242
+ }).openapi("SpaceSubject");
20243
+ var SpaceCollectionSchema = object({
19248
20244
  id: string$1(),
19249
- production_id: string$1(),
20245
+ name: string$1(),
20246
+ kind: CollectionKindSchema,
20247
+ color: string$1().nullable(),
20248
+ description: string$1().nullable(),
20249
+ sort_index: number$1().int(),
20250
+ created_by: string$1(),
20251
+ created_at: number$1(),
20252
+ updated_at: number$1()
20253
+ }).openapi("SpaceCollection");
20254
+ var CollectionItemSchema = object({
20255
+ id: string$1(),
20256
+ collection_id: string$1(),
20257
+ subject_type: SpaceSubjectTypeSchema,
20258
+ asset_id: string$1().nullable(),
20259
+ variant_id: string$1().nullable(),
20260
+ role: string$1(),
20261
+ pinned_variant_id: string$1().nullable(),
20262
+ sort_index: number$1().int(),
20263
+ created_by: string$1(),
20264
+ created_at: number$1(),
20265
+ updated_at: number$1()
20266
+ }).openapi("CollectionItem");
20267
+ var StyleReferenceCollectionSchema = SpaceCollectionSchema.extend({
20268
+ reference_count: number$1().int(),
20269
+ preset_count: number$1().int()
20270
+ }).openapi("StyleReferenceCollection");
20271
+ var StylePresetSchema = object({
20272
+ id: string$1(),
20273
+ name: string$1(),
20274
+ description: string$1().nullable(),
20275
+ style_prompt: string$1(),
20276
+ collection_id: string$1().nullable(),
20277
+ enabled: BooleanFromSqliteSchema,
20278
+ is_default: BooleanFromSqliteSchema,
20279
+ created_by: string$1(),
20280
+ created_at: number$1(),
20281
+ updated_at: number$1(),
20282
+ collection_name: string$1().nullable(),
20283
+ reference_count: number$1().int(),
20284
+ style_reference_variant_ids: array(string$1()),
20285
+ style_reference_image_keys: array(string$1())
20286
+ }).openapi("StylePreset");
20287
+ var SpaceRelationSchema = object({
20288
+ id: string$1(),
20289
+ subject_type: SpaceSubjectTypeSchema,
20290
+ subject_asset_id: string$1().nullable(),
20291
+ subject_variant_id: string$1().nullable(),
20292
+ object_type: SpaceSubjectTypeSchema,
20293
+ object_asset_id: string$1().nullable(),
20294
+ object_variant_id: string$1().nullable(),
20295
+ relation_type: SpaceRelationTypeSchema,
20296
+ label: string$1().nullable(),
20297
+ context: string$1().nullable(),
20298
+ metadata: string$1(),
20299
+ sort_index: number$1().int(),
20300
+ created_by: string$1(),
20301
+ created_at: number$1(),
20302
+ updated_at: number$1()
20303
+ }).openapi("SpaceRelation");
20304
+ var CompositionSchema = object({
20305
+ id: string$1(),
20306
+ name: string$1(),
20307
+ description: string$1().nullable(),
20308
+ status: CompositionStatusSchema,
20309
+ output_asset_id: string$1().nullable(),
20310
+ output_variant_id: string$1().nullable(),
20311
+ metadata: string$1(),
20312
+ sort_index: number$1().int(),
20313
+ created_by: string$1(),
20314
+ created_at: number$1(),
20315
+ updated_at: number$1()
20316
+ }).openapi("Composition");
20317
+ var CompositionItemSchema = object({
20318
+ id: string$1(),
20319
+ composition_id: string$1(),
20320
+ role: CompositionItemRoleSchema,
20321
+ label: string$1().nullable(),
20322
+ asset_id: string$1().nullable(),
19250
20323
  variant_id: string$1(),
19251
- asset_id: string$1(),
19252
- media_kind: MediaKindSchema,
19253
- shot_id: string$1().nullable(),
19254
- scene_label: string$1(),
19255
- timeline_start_ms: number$1().int().nonnegative(),
19256
- duration_ms: number$1().int().nonnegative().nullable(),
19257
- motion_prompt: string$1().nullable(),
19258
- source_refs: string$1(),
19259
- source_variant_ids: string$1(),
19260
20324
  metadata: string$1(),
20325
+ sort_index: number$1().int(),
19261
20326
  created_by: string$1(),
19262
20327
  created_at: number$1(),
19263
20328
  updated_at: number$1()
19264
- }).openapi("ProductionRecord");
20329
+ }).openapi("CompositionItem");
20330
+ var UpsertCollectionRequestSchema = object({
20331
+ id: string$1().optional(),
20332
+ name: string$1().min(1),
20333
+ kind: CollectionKindSchema.optional(),
20334
+ color: string$1().nullable().optional(),
20335
+ description: string$1().nullable().optional(),
20336
+ sortIndex: number$1().int().optional()
20337
+ }).openapi("UpsertCollectionRequest");
20338
+ var UpdateCollectionRequestSchema = UpsertCollectionRequestSchema.omit({ id: true }).partial().openapi("UpdateCollectionRequest");
20339
+ var UpsertCollectionItemRequestSchema = object({
20340
+ id: string$1().optional(),
20341
+ subjectType: SpaceSubjectTypeSchema,
20342
+ assetId: string$1().optional(),
20343
+ variantId: string$1().optional(),
20344
+ role: string$1().optional(),
20345
+ pinnedVariantId: string$1().nullable().optional(),
20346
+ sortIndex: number$1().int().optional()
20347
+ }).openapi("UpsertCollectionItemRequest");
20348
+ var UpsertStylePresetRequestSchema = object({
20349
+ id: string$1().optional(),
20350
+ name: string$1().min(1),
20351
+ description: string$1().nullable().optional(),
20352
+ stylePrompt: string$1().optional(),
20353
+ collectionId: string$1().nullable().optional(),
20354
+ enabled: boolean$1().optional(),
20355
+ isDefault: boolean$1().optional()
20356
+ }).openapi("UpsertStylePresetRequest");
20357
+ var UpdateStylePresetRequestSchema = UpsertStylePresetRequestSchema.omit({
20358
+ id: true,
20359
+ name: true
20360
+ }).extend({ name: string$1().min(1).optional() }).openapi("UpdateStylePresetRequest");
20361
+ var UpdateCollectionItemRequestSchema = object({
20362
+ role: string$1().optional(),
20363
+ pinnedVariantId: string$1().nullable().optional(),
20364
+ sortIndex: number$1().int().optional()
20365
+ }).openapi("UpdateCollectionItemRequest");
20366
+ var ReorderItemsRequestSchema = object({ itemIds: array(string$1()) }).openapi("ReorderItemsRequest");
20367
+ var UpsertRelationRequestSchema = object({
20368
+ id: string$1().optional(),
20369
+ subject: SpaceSubjectSchema,
20370
+ object: SpaceSubjectSchema,
20371
+ relationType: SpaceRelationTypeSchema,
20372
+ label: string$1().nullable().optional(),
20373
+ context: union([string$1(), record(string$1(), unknown())]).nullable().optional(),
20374
+ metadata: record(string$1(), unknown()).optional(),
20375
+ sortIndex: number$1().int().optional()
20376
+ }).openapi("UpsertRelationRequest");
20377
+ var UpdateRelationRequestSchema = object({
20378
+ relationType: SpaceRelationTypeSchema.optional(),
20379
+ label: string$1().nullable().optional(),
20380
+ context: union([string$1(), record(string$1(), unknown())]).nullable().optional(),
20381
+ metadata: record(string$1(), unknown()).optional(),
20382
+ sortIndex: number$1().int().optional()
20383
+ }).openapi("UpdateRelationRequest");
20384
+ var UpsertCompositionRequestSchema = object({
20385
+ id: string$1().optional(),
20386
+ name: string$1().min(1),
20387
+ description: string$1().nullable().optional(),
20388
+ status: CompositionStatusSchema.optional(),
20389
+ outputAssetId: string$1().nullable().optional(),
20390
+ outputVariantId: string$1().nullable().optional(),
20391
+ metadata: record(string$1(), unknown()).optional(),
20392
+ sortIndex: number$1().int().optional()
20393
+ }).openapi("UpsertCompositionRequest");
20394
+ var UpdateCompositionRequestSchema = UpsertCompositionRequestSchema.omit({
20395
+ id: true,
20396
+ name: true
20397
+ }).extend({ name: string$1().min(1).optional() }).openapi("UpdateCompositionRequest");
20398
+ var UpsertCompositionItemRequestSchema = object({
20399
+ id: string$1().optional(),
20400
+ role: CompositionItemRoleSchema,
20401
+ label: string$1().nullable().optional(),
20402
+ assetId: string$1().nullable().optional(),
20403
+ variantId: string$1().min(1),
20404
+ metadata: record(string$1(), unknown()).optional(),
20405
+ sortIndex: number$1().int().optional()
20406
+ }).openapi("UpsertCompositionItemRequest");
20407
+ var UpdateCompositionItemRequestSchema = object({
20408
+ role: CompositionItemRoleSchema.optional(),
20409
+ label: string$1().nullable().optional(),
20410
+ assetId: string$1().nullable().optional(),
20411
+ variantId: string$1().optional(),
20412
+ metadata: record(string$1(), unknown()).optional(),
20413
+ sortIndex: number$1().int().optional()
20414
+ }).openapi("UpdateCompositionItemRequest");
20415
+ var ListCollectionsResponseSchema = object({
20416
+ success: literal(true),
20417
+ collections: array(SpaceCollectionSchema)
20418
+ }).openapi("ListCollectionsResponse");
20419
+ var CollectionResponseSchema = object({
20420
+ success: literal(true),
20421
+ collection: SpaceCollectionSchema
20422
+ }).openapi("CollectionResponse");
20423
+ var ListCollectionItemsResponseSchema = object({
20424
+ success: literal(true),
20425
+ items: array(CollectionItemSchema)
20426
+ }).openapi("ListCollectionItemsResponse");
20427
+ var CollectionItemResponseSchema = object({
20428
+ success: literal(true),
20429
+ item: CollectionItemSchema
20430
+ }).openapi("CollectionItemResponse");
20431
+ var ListStyleReferenceCollectionsResponseSchema = object({
20432
+ success: literal(true),
20433
+ collections: array(StyleReferenceCollectionSchema)
20434
+ }).openapi("ListStyleReferenceCollectionsResponse");
20435
+ var ListStylePresetsResponseSchema = object({
20436
+ success: literal(true),
20437
+ presets: array(StylePresetSchema)
20438
+ }).openapi("ListStylePresetsResponse");
20439
+ var StylePresetResponseSchema = object({
20440
+ success: literal(true),
20441
+ preset: StylePresetSchema
20442
+ }).openapi("StylePresetResponse");
20443
+ var ListRelationsResponseSchema = object({
20444
+ success: literal(true),
20445
+ relations: array(SpaceRelationSchema)
20446
+ }).openapi("ListRelationsResponse");
20447
+ var RelationResponseSchema = object({
20448
+ success: literal(true),
20449
+ relation: SpaceRelationSchema
20450
+ }).openapi("RelationResponse");
20451
+ var ListCompositionsResponseSchema = object({
20452
+ success: literal(true),
20453
+ compositions: array(CompositionSchema)
20454
+ }).openapi("ListCompositionsResponse");
20455
+ var CompositionResponseSchema = object({
20456
+ success: literal(true),
20457
+ composition: CompositionSchema
20458
+ }).openapi("CompositionResponse");
20459
+ var ListCompositionItemsResponseSchema = object({
20460
+ success: literal(true),
20461
+ items: array(CompositionItemSchema)
20462
+ }).openapi("ListCompositionItemsResponse");
20463
+ var CompositionItemResponseSchema = object({
20464
+ success: literal(true),
20465
+ item: CompositionItemSchema
20466
+ }).openapi("CompositionItemResponse");
20467
+ var UsageSummaryQuerySchema = object({
20468
+ from: string$1().optional(),
20469
+ to: string$1().optional()
20470
+ });
20471
+ var PlatformUsageTypeSummarySchema = object({
20472
+ usageType: PlatformUsageTypeSchema,
20473
+ unit: PlatformUsageUnitSchema,
20474
+ quantity: number$1().int(),
20475
+ events: number$1().int().nonnegative()
20476
+ }).openapi("PlatformUsageTypeSummary");
20477
+ var PlatformUsageMediaKindSummarySchema = object({
20478
+ mediaKind: MediaKindSchema.nullable(),
20479
+ storageBytes: number$1().int(),
20480
+ workflowRuns: number$1().int(),
20481
+ deliveryBytes: number$1().int(),
20482
+ events: number$1().int().nonnegative()
20483
+ }).openapi("PlatformUsageMediaKindSummary");
20484
+ var PlatformUsageSummaryResponseSchema = object({
20485
+ success: literal(true),
20486
+ spaceId: string$1(),
20487
+ period: object({
20488
+ from: string$1().nullable(),
20489
+ to: string$1().nullable()
20490
+ }),
20491
+ totals: object({
20492
+ storageBytes: number$1().int(),
20493
+ workflowRuns: number$1().int(),
20494
+ deliveryBytes: number$1().int()
20495
+ }),
20496
+ byType: array(PlatformUsageTypeSummarySchema),
20497
+ byMediaKind: array(PlatformUsageMediaKindSummarySchema)
20498
+ }).openapi("PlatformUsageSummaryResponse");
20499
+ var ProviderSpendSummaryQuerySchema = object({
20500
+ from: string$1().optional(),
20501
+ to: string$1().optional(),
20502
+ user_id: string$1().optional(),
20503
+ userId: string$1().optional(),
20504
+ space_id: string$1().optional(),
20505
+ spaceId: string$1().optional(),
20506
+ provider: string$1().optional(),
20507
+ media_kind: MediaKindSchema.optional(),
20508
+ mediaKind: MediaKindSchema.optional()
20509
+ });
20510
+ var ProviderSpendAggregateSchema = object({
20511
+ amountMicroUsd: number$1().int(),
20512
+ amountUsd: number$1(),
20513
+ quantity: number$1(),
20514
+ entries: number$1().int().nonnegative(),
20515
+ unpricedEntries: number$1().int().nonnegative()
20516
+ }).openapi("ProviderSpendAggregate");
20517
+ var ProviderSpendSummaryResponseSchema = object({
20518
+ success: literal(true),
20519
+ period: object({
20520
+ from: string$1().nullable(),
20521
+ to: string$1().nullable()
20522
+ }),
20523
+ filters: object({
20524
+ userId: number$1().int().nullable(),
20525
+ spaceId: string$1().nullable(),
20526
+ provider: string$1().nullable(),
20527
+ mediaKind: MediaKindSchema.nullable()
20528
+ }),
20529
+ totals: ProviderSpendAggregateSchema,
20530
+ byProvider: array(ProviderSpendAggregateSchema.extend({ provider: string$1() })),
20531
+ byModel: array(ProviderSpendAggregateSchema.extend({
20532
+ provider: string$1(),
20533
+ providerModel: string$1()
20534
+ })),
20535
+ byMediaKind: array(ProviderSpendAggregateSchema.extend({ mediaKind: MediaKindSchema.nullable() })),
20536
+ byMeterEventName: array(ProviderSpendAggregateSchema.extend({ meterEventName: string$1().nullable() })),
20537
+ bySpace: array(ProviderSpendAggregateSchema.extend({ spaceId: string$1().nullable() })),
20538
+ byAsset: array(ProviderSpendAggregateSchema.extend({
20539
+ spaceId: string$1().nullable(),
20540
+ assetId: string$1().nullable()
20541
+ }))
20542
+ }).openapi("ProviderSpendSummaryResponse");
20543
+ var BillingEntitlementSchema = _enum([
20544
+ "none",
20545
+ "paid",
20546
+ "internal"
20547
+ ]).openapi("BillingEntitlement");
20548
+ var BillingPlanStatusSchema = _enum([
20549
+ "inactive",
20550
+ "active",
20551
+ "internal"
20552
+ ]).openapi("BillingPlanStatus");
20553
+ var BillingPlanStatusResponseSchema = object({
20554
+ key: literal("paid_generation"),
20555
+ displayName: string$1(),
20556
+ status: BillingPlanStatusSchema,
20557
+ checkoutAvailable: boolean$1(),
20558
+ portalAvailable: boolean$1()
20559
+ }).openapi("BillingPlanStatusResponse");
20560
+ var BillingMeterStatusSchema = object({
20561
+ name: string$1(),
20562
+ consumed: number$1(),
20563
+ credited: number$1(),
20564
+ remaining: number$1(),
20565
+ percentUsed: number$1(),
20566
+ hasLimit: boolean$1(),
20567
+ status: _enum([
20568
+ "ok",
20569
+ "warning",
20570
+ "critical",
20571
+ "exceeded"
20572
+ ])
20573
+ }).openapi("BillingMeterStatus");
20574
+ var BillingStatusResponseSchema = object({
20575
+ configured: boolean$1(),
20576
+ available: boolean$1(),
20577
+ hasSubscription: boolean$1(),
20578
+ entitlement: BillingEntitlementSchema,
20579
+ plan: BillingPlanStatusResponseSchema,
20580
+ meters: array(BillingMeterStatusSchema),
20581
+ subscription: object({
20582
+ status: string$1(),
20583
+ periodStart: string$1().nullable().optional(),
20584
+ renewsAt: string$1().nullable()
20585
+ }).nullable(),
20586
+ portalUrl: string$1().nullable(),
20587
+ error: string$1().optional()
20588
+ }).openapi("BillingStatusResponse");
20589
+ var BillingUsageMeterSchema = object({
20590
+ used: number$1(),
20591
+ limit: number$1().nullable(),
20592
+ remaining: number$1().nullable(),
20593
+ costUsd: number$1().optional()
20594
+ }).openapi("BillingUsageMeter");
20595
+ var BillingUsageResponseSchema = object({
20596
+ period: object({
20597
+ start: string$1(),
20598
+ end: string$1()
20599
+ }),
20600
+ usage: record(string$1(), BillingUsageMeterSchema),
20601
+ estimatedCost: object({
20602
+ amount: number$1(),
20603
+ currency: string$1()
20604
+ }).optional()
20605
+ }).openapi("BillingUsageResponse");
20606
+ var BillingUrlResponseSchema = object({ url: string$1() }).openapi("BillingUrlResponse");
20607
+ var BillingUrlQuerySchema = object({
20608
+ return_url: string$1().optional(),
20609
+ success_url: string$1().optional()
20610
+ });
20611
+ var ProductionRecordSchema = object({
20612
+ id: string$1(),
20613
+ production_id: string$1(),
20614
+ variant_id: string$1(),
20615
+ asset_id: string$1(),
20616
+ media_kind: MediaKindSchema,
20617
+ shot_id: string$1().nullable(),
20618
+ scene_label: string$1(),
20619
+ timeline_start_ms: number$1().int().nonnegative(),
20620
+ duration_ms: number$1().int().nonnegative().nullable(),
20621
+ motion_prompt: string$1().nullable(),
20622
+ source_refs: string$1(),
20623
+ source_variant_ids: string$1(),
20624
+ metadata: string$1(),
20625
+ created_by: string$1(),
20626
+ created_at: number$1(),
20627
+ updated_at: number$1()
20628
+ }).openapi("ProductionRecord");
19265
20629
  var PlaceProductionRecordRequestSchema = object({
19266
20630
  id: string$1().optional(),
19267
20631
  productionId: string$1().min(1),
@@ -19413,7 +20777,14 @@ var UploadMediaRequestSchema = object({
19413
20777
  assetName: string$1().optional(),
19414
20778
  assetType: string$1().optional(),
19415
20779
  mediaKind: MediaKindSchema.optional(),
19416
- parentAssetId: string$1().optional(),
20780
+ operation: string$1().optional(),
20781
+ prompt: string$1().optional(),
20782
+ model: string$1().optional(),
20783
+ provider: string$1().optional(),
20784
+ providerMetadata: string$1().optional(),
20785
+ generationProvenance: string$1().optional(),
20786
+ lineage: string$1().optional(),
20787
+ activeVariantBehavior: string$1().optional(),
19417
20788
  transcript: UploadFileSchema.optional(),
19418
20789
  wordTimings: UploadFileSchema.optional(),
19419
20790
  renderMetadata: UploadFileSchema.optional()
@@ -19421,14 +20792,9 @@ var UploadMediaRequestSchema = object({
19421
20792
  var UploadMediaResponseSchema = object({
19422
20793
  success: literal(true),
19423
20794
  variant: VariantSchema,
19424
- asset: AssetSchema.optional()
20795
+ asset: AssetSchema.optional(),
20796
+ lineage: array(LineageSchema).optional()
19425
20797
  }).openapi("UploadMediaResponse");
19426
- var UploadStyleImageRequestSchema = object({ file: UploadFileSchema }).openapi("UploadStyleImageRequest");
19427
- var UploadStyleImageResponseSchema = object({
19428
- success: literal(true),
19429
- imageKey: string$1(),
19430
- warning: string$1().optional()
19431
- }).openapi("UploadStyleImageResponse");
19432
20798
  var VariantMediaParamsSchema = object({
19433
20799
  spaceId: string$1().openapi({ param: {
19434
20800
  name: "spaceId",
@@ -19479,6 +20845,24 @@ var apiEndpoints = {
19479
20845
  jsonSchema: UpdateUserProfileRequestSchema,
19480
20846
  responseSchema: UserProfileUpdateResponseSchema
19481
20847
  },
20848
+ "GET /api/user/provider-keys": {
20849
+ method: "GET",
20850
+ path: "/api/user/provider-keys",
20851
+ responseSchema: ListProviderKeysResponseSchema
20852
+ },
20853
+ "PUT /api/user/provider-keys/:provider": {
20854
+ method: "PUT",
20855
+ path: "/api/user/provider-keys/:provider",
20856
+ paramsSchema: ProviderKeyParamsSchema,
20857
+ jsonSchema: UpsertProviderKeyRequestSchema,
20858
+ responseSchema: ProviderKeyResponseSchema
20859
+ },
20860
+ "DELETE /api/user/provider-keys/:provider": {
20861
+ method: "DELETE",
20862
+ path: "/api/user/provider-keys/:provider",
20863
+ paramsSchema: ProviderKeyParamsSchema,
20864
+ responseSchema: ProviderKeyResponseSchema
20865
+ },
19482
20866
  "POST /api/spaces": {
19483
20867
  method: "POST",
19484
20868
  path: "/api/spaces",
@@ -19502,6 +20886,217 @@ var apiEndpoints = {
19502
20886
  paramsSchema: SpaceIdParamsSchema,
19503
20887
  responseSchema: ListSpaceAssetsResponseSchema
19504
20888
  },
20889
+ "GET /api/spaces/:id/collections": {
20890
+ method: "GET",
20891
+ path: "/api/spaces/:id/collections",
20892
+ paramsSchema: SpaceIdParamsSchema,
20893
+ responseSchema: ListCollectionsResponseSchema
20894
+ },
20895
+ "POST /api/spaces/:id/collections": {
20896
+ method: "POST",
20897
+ path: "/api/spaces/:id/collections",
20898
+ paramsSchema: SpaceIdParamsSchema,
20899
+ jsonSchema: UpsertCollectionRequestSchema,
20900
+ responseSchema: CollectionResponseSchema
20901
+ },
20902
+ "PATCH /api/spaces/:id/collections/:collectionId": {
20903
+ method: "PATCH",
20904
+ path: "/api/spaces/:id/collections/:collectionId",
20905
+ paramsSchema: CollectionIdParamsSchema,
20906
+ jsonSchema: UpdateCollectionRequestSchema,
20907
+ responseSchema: CollectionResponseSchema
20908
+ },
20909
+ "DELETE /api/spaces/:id/collections/:collectionId": {
20910
+ method: "DELETE",
20911
+ path: "/api/spaces/:id/collections/:collectionId",
20912
+ paramsSchema: CollectionIdParamsSchema,
20913
+ responseSchema: SuccessResponseSchema
20914
+ },
20915
+ "GET /api/spaces/:id/collections/:collectionId/items": {
20916
+ method: "GET",
20917
+ path: "/api/spaces/:id/collections/:collectionId/items",
20918
+ paramsSchema: CollectionIdParamsSchema,
20919
+ responseSchema: ListCollectionItemsResponseSchema
20920
+ },
20921
+ "POST /api/spaces/:id/collections/:collectionId/items": {
20922
+ method: "POST",
20923
+ path: "/api/spaces/:id/collections/:collectionId/items",
20924
+ paramsSchema: CollectionIdParamsSchema,
20925
+ jsonSchema: UpsertCollectionItemRequestSchema,
20926
+ responseSchema: CollectionItemResponseSchema
20927
+ },
20928
+ "PATCH /api/spaces/:id/collections/:collectionId/items/:itemId": {
20929
+ method: "PATCH",
20930
+ path: "/api/spaces/:id/collections/:collectionId/items/:itemId",
20931
+ paramsSchema: CollectionItemParamsSchema,
20932
+ jsonSchema: UpdateCollectionItemRequestSchema,
20933
+ responseSchema: CollectionItemResponseSchema
20934
+ },
20935
+ "POST /api/spaces/:id/collections/:collectionId/items/reorder": {
20936
+ method: "POST",
20937
+ path: "/api/spaces/:id/collections/:collectionId/items/reorder",
20938
+ paramsSchema: CollectionIdParamsSchema,
20939
+ jsonSchema: ReorderItemsRequestSchema,
20940
+ responseSchema: ListCollectionItemsResponseSchema
20941
+ },
20942
+ "DELETE /api/spaces/:id/collections/:collectionId/items/:itemId": {
20943
+ method: "DELETE",
20944
+ path: "/api/spaces/:id/collections/:collectionId/items/:itemId",
20945
+ paramsSchema: CollectionItemParamsSchema,
20946
+ responseSchema: SuccessResponseSchema
20947
+ },
20948
+ "GET /api/spaces/:id/style-reference-collections": {
20949
+ method: "GET",
20950
+ path: "/api/spaces/:id/style-reference-collections",
20951
+ paramsSchema: SpaceIdParamsSchema,
20952
+ responseSchema: ListStyleReferenceCollectionsResponseSchema
20953
+ },
20954
+ "GET /api/spaces/:id/style-presets": {
20955
+ method: "GET",
20956
+ path: "/api/spaces/:id/style-presets",
20957
+ paramsSchema: SpaceIdParamsSchema,
20958
+ responseSchema: ListStylePresetsResponseSchema
20959
+ },
20960
+ "POST /api/spaces/:id/style-presets": {
20961
+ method: "POST",
20962
+ path: "/api/spaces/:id/style-presets",
20963
+ paramsSchema: SpaceIdParamsSchema,
20964
+ jsonSchema: UpsertStylePresetRequestSchema,
20965
+ responseSchema: StylePresetResponseSchema
20966
+ },
20967
+ "PATCH /api/spaces/:id/style-presets/:presetId": {
20968
+ method: "PATCH",
20969
+ path: "/api/spaces/:id/style-presets/:presetId",
20970
+ paramsSchema: StylePresetParamsSchema,
20971
+ jsonSchema: UpdateStylePresetRequestSchema,
20972
+ responseSchema: StylePresetResponseSchema
20973
+ },
20974
+ "DELETE /api/spaces/:id/style-presets/:presetId": {
20975
+ method: "DELETE",
20976
+ path: "/api/spaces/:id/style-presets/:presetId",
20977
+ paramsSchema: StylePresetParamsSchema,
20978
+ responseSchema: SuccessResponseSchema
20979
+ },
20980
+ "GET /api/spaces/:id/relations": {
20981
+ method: "GET",
20982
+ path: "/api/spaces/:id/relations",
20983
+ paramsSchema: SpaceIdParamsSchema,
20984
+ responseSchema: ListRelationsResponseSchema
20985
+ },
20986
+ "POST /api/spaces/:id/relations": {
20987
+ method: "POST",
20988
+ path: "/api/spaces/:id/relations",
20989
+ paramsSchema: SpaceIdParamsSchema,
20990
+ jsonSchema: UpsertRelationRequestSchema,
20991
+ responseSchema: RelationResponseSchema
20992
+ },
20993
+ "PATCH /api/spaces/:id/relations/:relationId": {
20994
+ method: "PATCH",
20995
+ path: "/api/spaces/:id/relations/:relationId",
20996
+ paramsSchema: RelationParamsSchema,
20997
+ jsonSchema: UpdateRelationRequestSchema,
20998
+ responseSchema: RelationResponseSchema
20999
+ },
21000
+ "DELETE /api/spaces/:id/relations/:relationId": {
21001
+ method: "DELETE",
21002
+ path: "/api/spaces/:id/relations/:relationId",
21003
+ paramsSchema: RelationParamsSchema,
21004
+ responseSchema: SuccessResponseSchema
21005
+ },
21006
+ "GET /api/spaces/:id/compositions": {
21007
+ method: "GET",
21008
+ path: "/api/spaces/:id/compositions",
21009
+ paramsSchema: SpaceIdParamsSchema,
21010
+ responseSchema: ListCompositionsResponseSchema
21011
+ },
21012
+ "POST /api/spaces/:id/compositions": {
21013
+ method: "POST",
21014
+ path: "/api/spaces/:id/compositions",
21015
+ paramsSchema: SpaceIdParamsSchema,
21016
+ jsonSchema: UpsertCompositionRequestSchema,
21017
+ responseSchema: CompositionResponseSchema
21018
+ },
21019
+ "PATCH /api/spaces/:id/compositions/:compositionId": {
21020
+ method: "PATCH",
21021
+ path: "/api/spaces/:id/compositions/:compositionId",
21022
+ paramsSchema: CompositionIdParamsSchema,
21023
+ jsonSchema: UpdateCompositionRequestSchema,
21024
+ responseSchema: CompositionResponseSchema
21025
+ },
21026
+ "DELETE /api/spaces/:id/compositions/:compositionId": {
21027
+ method: "DELETE",
21028
+ path: "/api/spaces/:id/compositions/:compositionId",
21029
+ paramsSchema: CompositionIdParamsSchema,
21030
+ responseSchema: SuccessResponseSchema
21031
+ },
21032
+ "GET /api/spaces/:id/compositions/:compositionId/items": {
21033
+ method: "GET",
21034
+ path: "/api/spaces/:id/compositions/:compositionId/items",
21035
+ paramsSchema: CompositionIdParamsSchema,
21036
+ responseSchema: ListCompositionItemsResponseSchema
21037
+ },
21038
+ "POST /api/spaces/:id/compositions/:compositionId/items": {
21039
+ method: "POST",
21040
+ path: "/api/spaces/:id/compositions/:compositionId/items",
21041
+ paramsSchema: CompositionIdParamsSchema,
21042
+ jsonSchema: UpsertCompositionItemRequestSchema,
21043
+ responseSchema: CompositionItemResponseSchema
21044
+ },
21045
+ "PATCH /api/spaces/:id/compositions/:compositionId/items/:itemId": {
21046
+ method: "PATCH",
21047
+ path: "/api/spaces/:id/compositions/:compositionId/items/:itemId",
21048
+ paramsSchema: CompositionItemParamsSchema,
21049
+ jsonSchema: UpdateCompositionItemRequestSchema,
21050
+ responseSchema: CompositionItemResponseSchema
21051
+ },
21052
+ "POST /api/spaces/:id/compositions/:compositionId/items/reorder": {
21053
+ method: "POST",
21054
+ path: "/api/spaces/:id/compositions/:compositionId/items/reorder",
21055
+ paramsSchema: CompositionIdParamsSchema,
21056
+ jsonSchema: ReorderItemsRequestSchema,
21057
+ responseSchema: ListCompositionItemsResponseSchema
21058
+ },
21059
+ "DELETE /api/spaces/:id/compositions/:compositionId/items/:itemId": {
21060
+ method: "DELETE",
21061
+ path: "/api/spaces/:id/compositions/:compositionId/items/:itemId",
21062
+ paramsSchema: CompositionItemParamsSchema,
21063
+ responseSchema: SuccessResponseSchema
21064
+ },
21065
+ "GET /api/spaces/:id/usage/summary": {
21066
+ method: "GET",
21067
+ path: "/api/spaces/:id/usage/summary",
21068
+ paramsSchema: SpaceIdParamsSchema,
21069
+ querySchema: UsageSummaryQuerySchema,
21070
+ responseSchema: PlatformUsageSummaryResponseSchema
21071
+ },
21072
+ "GET /api/billing/status": {
21073
+ method: "GET",
21074
+ path: "/api/billing/status",
21075
+ responseSchema: BillingStatusResponseSchema
21076
+ },
21077
+ "GET /api/billing/usage": {
21078
+ method: "GET",
21079
+ path: "/api/billing/usage",
21080
+ responseSchema: BillingUsageResponseSchema
21081
+ },
21082
+ "GET /api/billing/checkout": {
21083
+ method: "GET",
21084
+ path: "/api/billing/checkout",
21085
+ querySchema: BillingUrlQuerySchema,
21086
+ responseSchema: BillingUrlResponseSchema
21087
+ },
21088
+ "GET /api/billing/portal": {
21089
+ method: "GET",
21090
+ path: "/api/billing/portal",
21091
+ querySchema: BillingUrlQuerySchema,
21092
+ responseSchema: BillingUrlResponseSchema
21093
+ },
21094
+ "GET /api/billing/spend/summary": {
21095
+ method: "GET",
21096
+ path: "/api/billing/spend/summary",
21097
+ querySchema: ProviderSpendSummaryQuerySchema,
21098
+ responseSchema: ProviderSpendSummaryResponseSchema
21099
+ },
19505
21100
  "GET /api/spaces/:id/productions": {
19506
21101
  method: "GET",
19507
21102
  path: "/api/spaces/:id/productions",
@@ -19598,13 +21193,6 @@ var apiEndpoints = {
19598
21193
  formSchema: UploadMediaRequestSchema,
19599
21194
  responseSchema: UploadMediaResponseSchema
19600
21195
  },
19601
- "POST /api/spaces/:id/style-images": {
19602
- method: "POST",
19603
- path: "/api/spaces/:id/style-images",
19604
- paramsSchema: SpaceIdParamsSchema,
19605
- formSchema: UploadStyleImageRequestSchema,
19606
- responseSchema: UploadStyleImageResponseSchema
19607
- },
19608
21196
  "GET /api/spaces/:spaceId/variants/:variantId/media": {
19609
21197
  method: "GET",
19610
21198
  path: "/api/spaces/:spaceId/variants/:variantId/media",
@@ -19648,6 +21236,17 @@ function resolveUrl(path, baseUrl) {
19648
21236
  if (baseUrl) return new URL(path, baseUrl).toString();
19649
21237
  return path;
19650
21238
  }
21239
+ function appendQuery(path, query) {
21240
+ if (!query) return path;
21241
+ const params = new URLSearchParams();
21242
+ for (const [key, value] of Object.entries(query)) {
21243
+ if (value === void 0 || value === null) continue;
21244
+ params.set(key, String(value));
21245
+ }
21246
+ const search = params.toString();
21247
+ if (!search) return path;
21248
+ return `${path}${path.includes("?") ? "&" : "?"}${search}`;
21249
+ }
19651
21250
  function buildFormData(form) {
19652
21251
  const formData = new FormData();
19653
21252
  for (const [key, value] of Object.entries(form)) {
@@ -19679,8 +21278,9 @@ async function apiFetch(key, ...args) {
19679
21278
  const fetchImpl = options.fetch ?? fetch;
19680
21279
  const params = "paramsSchema" in endpoint ? endpoint.paramsSchema.parse(options.params) : void 0;
19681
21280
  const json = "jsonSchema" in endpoint ? endpoint.jsonSchema.parse(options.json) : void 0;
21281
+ const query = "querySchema" in endpoint ? endpoint.querySchema.parse(options.query ?? {}) : void 0;
19682
21282
  const form = "formSchema" in endpoint ? endpoint.formSchema.parse(options.form) : void 0;
19683
- const path = buildPath(endpoint.path, params);
21283
+ const path = appendQuery(buildPath(endpoint.path, params), query);
19684
21284
  const headers = new Headers(options.headers);
19685
21285
  const init = {
19686
21286
  ...options,
@@ -19691,6 +21291,7 @@ async function apiFetch(key, ...args) {
19691
21291
  delete init.baseUrl;
19692
21292
  delete init.fetch;
19693
21293
  delete init.params;
21294
+ delete init.query;
19694
21295
  delete init.json;
19695
21296
  delete init.form;
19696
21297
  if (json !== void 0) {
@@ -19710,7 +21311,7 @@ async function apiFetch(key, ...args) {
19710
21311
  }
19711
21312
  //#endregion
19712
21313
  //#region src/cli/commands/productions.ts
19713
- var defaultDeps$7 = {
21314
+ var defaultDeps$10 = {
19714
21315
  loadConfig: loadStoredConfig,
19715
21316
  loadProjectConfig,
19716
21317
  resolveBaseUrl,
@@ -19724,12 +21325,12 @@ async function handleProductions(parsed) {
19724
21325
  await executeProductions(parsed);
19725
21326
  } catch (error) {
19726
21327
  console.error("Error:", error instanceof Error ? error.message : error);
19727
- printUsage$8();
21328
+ printUsage$10();
19728
21329
  process$1.exitCode = 1;
19729
21330
  }
19730
21331
  }
19731
- async function executeProductions(parsed, deps = defaultDeps$7) {
19732
- const ctx = await buildContext$4(parsed, deps);
21332
+ async function executeProductions(parsed, deps = defaultDeps$10) {
21333
+ const ctx = await buildContext$7(parsed, deps);
19733
21334
  const subcommand = parsed.positionals[0] || "list";
19734
21335
  if (subcommand === "list") {
19735
21336
  const records = await listProductionRecords(ctx, deps, readProductionId(parsed, 1));
@@ -19802,7 +21403,7 @@ async function placeProductionRecordForCli(input) {
19802
21403
  }
19803
21404
  })).record;
19804
21405
  }
19805
- async function buildContext$4(parsed, deps) {
21406
+ async function buildContext$7(parsed, deps) {
19806
21407
  const projectConfig = await deps.loadProjectConfig();
19807
21408
  const env = resolveCommandEnvironment(parsed, projectConfig);
19808
21409
  const spaceId = resolveCommandSpace(parsed, projectConfig);
@@ -19861,10 +21462,10 @@ function readProductionId(parsed, positionalIndex) {
19861
21462
  return productionId;
19862
21463
  }
19863
21464
  function parsePlaceRequest(parsed) {
19864
- const productionId = readRequiredOption(parsed, "production-id", "productionId");
19865
- const variantId = readRequiredOption(parsed, "variant", "variantId");
19866
- const sceneLabel = readRequiredOption(parsed, "scene-label", "sceneLabel");
19867
- const timelineStartMs = parseNonNegativeInteger$1(readRequiredOption(parsed, "timeline-start-ms", "timelineStartMs"), "--timeline-start-ms");
21465
+ const productionId = readRequiredOption$1(parsed, "production-id", "productionId");
21466
+ const variantId = readRequiredOption$1(parsed, "variant", "variantId");
21467
+ const sceneLabel = readRequiredOption$1(parsed, "scene-label", "sceneLabel");
21468
+ const timelineStartMs = parseNonNegativeInteger$1(readRequiredOption$1(parsed, "timeline-start-ms", "timelineStartMs"), "--timeline-start-ms");
19868
21469
  const durationValue = readOptionalOption$1(parsed, "duration-ms", "durationMs");
19869
21470
  return {
19870
21471
  id: readOptionalOption$1(parsed, "id", "id"),
@@ -19880,7 +21481,7 @@ function parsePlaceRequest(parsed) {
19880
21481
  metadata: parseMetadataJson(readOptionalOption$1(parsed, "metadata-json", "metadataJson"))
19881
21482
  };
19882
21483
  }
19883
- function readRequiredOption(parsed, kebabName, camelName) {
21484
+ function readRequiredOption$1(parsed, kebabName, camelName) {
19884
21485
  const value = readOptionalOption$1(parsed, kebabName, camelName);
19885
21486
  if (value === void 0) throw new Error(`--${kebabName} is required`);
19886
21487
  return value;
@@ -20025,7 +21626,7 @@ function parseJsonObject$1(value) {
20025
21626
  function shellQuote$1(value) {
20026
21627
  return `'${value.replace(/'/g, "'\\''")}'`;
20027
21628
  }
20028
- function printUsage$8() {
21629
+ function printUsage$10() {
20029
21630
  console.log(`
20030
21631
  Usage:
20031
21632
  makefx productions list --production-id <id>
@@ -20230,6 +21831,7 @@ var WebSocketClient = class WebSocketClient {
20230
21831
  chatHandlers = /* @__PURE__ */ new Map();
20231
21832
  generateHandlers = /* @__PURE__ */ new Map();
20232
21833
  batchHandlers = /* @__PURE__ */ new Map();
21834
+ estimateHandlers = /* @__PURE__ */ new Map();
20233
21835
  batchVariantToRequestId = /* @__PURE__ */ new Map();
20234
21836
  variantCompletionHandlers = /* @__PURE__ */ new Map();
20235
21837
  describeHandlers = /* @__PURE__ */ new Map();
@@ -20430,6 +22032,16 @@ var WebSocketClient = class WebSocketClient {
20430
22032
  }
20431
22033
  break;
20432
22034
  }
22035
+ case "generation:estimate": {
22036
+ const estimateMsg = message;
22037
+ const handler = this.estimateHandlers.get(estimateMsg.requestId);
22038
+ if (handler) {
22039
+ this.estimateHandlers.delete(estimateMsg.requestId);
22040
+ clearTimeout(handler.timeout);
22041
+ handler.resolve(estimateMsg);
22042
+ }
22043
+ break;
22044
+ }
20433
22045
  case "variant:updated": {
20434
22046
  const variant = message.variant;
20435
22047
  const batchRequestId = this.batchVariantToRequestId.get(variant.id);
@@ -20519,7 +22131,8 @@ var WebSocketClient = class WebSocketClient {
20519
22131
  const error = /* @__PURE__ */ new Error(`${errorMsg.code}: ${errorMsg.message}`);
20520
22132
  const mutationConsumed = this.failMutationWaiters(error);
20521
22133
  const pipelineConsumed = this.failPipelineHandlers(error);
20522
- if (!(mutationConsumed || pipelineConsumed)) {
22134
+ const estimateConsumed = this.failEstimateHandlers(error);
22135
+ if (!(mutationConsumed || pipelineConsumed || estimateConsumed)) {
20523
22136
  console.error(`[WebSocketClient] Server error: ${errorMsg.code} - ${errorMsg.message}`);
20524
22137
  this.onError?.(new Error(errorMsg.message));
20525
22138
  }
@@ -20616,6 +22229,15 @@ var WebSocketClient = class WebSocketClient {
20616
22229
  this.tileSetToRequestId.clear();
20617
22230
  return true;
20618
22231
  }
22232
+ failEstimateHandlers(error) {
22233
+ if (this.estimateHandlers.size === 0) return false;
22234
+ for (const [requestId, handler] of this.estimateHandlers) {
22235
+ clearTimeout(handler.timeout);
22236
+ this.estimateHandlers.delete(requestId);
22237
+ handler.reject(error);
22238
+ }
22239
+ return true;
22240
+ }
20619
22241
  handleRotationPipelineMessage(message) {
20620
22242
  if (message.type === "rotation:started") {
20621
22243
  const handler = this.rotationHandlers.get(message.requestId);
@@ -20874,6 +22496,8 @@ var WebSocketClient = class WebSocketClient {
20874
22496
  subjectDescription: params.subjectDescription,
20875
22497
  aspectRatio: params.aspectRatio,
20876
22498
  disableStyle: params.disableStyle,
22499
+ stylePresetId: params.stylePresetId,
22500
+ styleVariantIds: params.styleVariantIds,
20877
22501
  generationMode: params.generationMode
20878
22502
  });
20879
22503
  } catch (err) {
@@ -20921,6 +22545,8 @@ var WebSocketClient = class WebSocketClient {
20921
22545
  seedVariantId: params.seedVariantId,
20922
22546
  aspectRatio: params.aspectRatio,
20923
22547
  disableStyle: params.disableStyle,
22548
+ stylePresetId: params.stylePresetId,
22549
+ styleVariantIds: params.styleVariantIds,
20924
22550
  generationMode: params.generationMode
20925
22551
  });
20926
22552
  } catch (err) {
@@ -20975,6 +22601,46 @@ var WebSocketClient = class WebSocketClient {
20975
22601
  }, 12e4);
20976
22602
  });
20977
22603
  }
22604
+ async sendGenerationEstimateRequest(params) {
22605
+ const requestId = crypto.randomUUID();
22606
+ return new Promise((resolve, reject) => {
22607
+ const timeout = setTimeout(() => {
22608
+ if (this.estimateHandlers.has(requestId)) {
22609
+ this.estimateHandlers.delete(requestId);
22610
+ reject(/* @__PURE__ */ new Error("Generation estimate request timed out"));
22611
+ }
22612
+ }, 3e4);
22613
+ this.estimateHandlers.set(requestId, {
22614
+ resolve,
22615
+ reject,
22616
+ timeout
22617
+ });
22618
+ const message = {
22619
+ type: "generation:estimate",
22620
+ requestId,
22621
+ operation: params.operation,
22622
+ assetId: params.assetId,
22623
+ assetType: params.assetType,
22624
+ mediaKind: params.mediaKind,
22625
+ prompt: params.prompt,
22626
+ count: params.count,
22627
+ model: params.model,
22628
+ imageSize: params.imageSize,
22629
+ musicProvider: params.musicProvider,
22630
+ generateAudio: params.generateAudio,
22631
+ videoResolution: params.videoResolution,
22632
+ videoDurationSeconds: params.videoDurationSeconds,
22633
+ videoTier: params.videoTier
22634
+ };
22635
+ try {
22636
+ this.send(message);
22637
+ } catch (err) {
22638
+ this.estimateHandlers.delete(requestId);
22639
+ clearTimeout(timeout);
22640
+ reject(err);
22641
+ }
22642
+ });
22643
+ }
20978
22644
  /**
20979
22645
  * Send a generate request and wait for result
20980
22646
  */
@@ -21011,8 +22677,9 @@ var WebSocketClient = class WebSocketClient {
21011
22677
  model: params.model,
21012
22678
  aspectRatio: params.aspectRatio,
21013
22679
  imageSize: params.imageSize,
21014
- parentAssetId: params.parentAssetId,
21015
22680
  disableStyle: params.disableStyle,
22681
+ stylePresetId: params.stylePresetId,
22682
+ styleVariantIds: params.styleVariantIds,
21016
22683
  mediaKind: params.mediaKind,
21017
22684
  voiceId: params.voiceId,
21018
22685
  dialogueVoiceIds: params.dialogueVoiceIds,
@@ -21096,6 +22763,8 @@ var WebSocketClient = class WebSocketClient {
21096
22763
  aspectRatio: params.aspectRatio,
21097
22764
  imageSize: params.imageSize,
21098
22765
  disableStyle: params.disableStyle,
22766
+ stylePresetId: params.stylePresetId,
22767
+ styleVariantIds: params.styleVariantIds,
21099
22768
  mediaKind: params.mediaKind,
21100
22769
  voiceId: params.voiceId,
21101
22770
  dialogueVoiceIds: params.dialogueVoiceIds,
@@ -21148,8 +22817,9 @@ var WebSocketClient = class WebSocketClient {
21148
22817
  model: params.model,
21149
22818
  aspectRatio: params.aspectRatio,
21150
22819
  imageSize: params.imageSize,
21151
- parentAssetId: params.parentAssetId,
21152
22820
  disableStyle: params.disableStyle,
22821
+ stylePresetId: params.stylePresetId,
22822
+ styleVariantIds: params.styleVariantIds,
21153
22823
  mediaKind: params.mediaKind,
21154
22824
  voiceId: params.voiceId,
21155
22825
  dialogueVoiceIds: params.dialogueVoiceIds,
@@ -21297,6 +22967,7 @@ var VIDEO_GENERATION_TIERS = [
21297
22967
  "fast",
21298
22968
  "lite"
21299
22969
  ];
22970
+ var VIDEO_GENERATION_AUDIO_TOGGLE_MODELS = [];
21300
22971
  var VIDEO_GENERATION_RESOLUTIONS_BY_TIER = {
21301
22972
  generate: VIDEO_GENERATION_RESOLUTIONS,
21302
22973
  fast: VIDEO_GENERATION_RESOLUTIONS,
@@ -21306,6 +22977,11 @@ var DEFAULT_VIDEO_GENERATION_TIER = "generate";
21306
22977
  function normalizeVideoGenerationAspectRatio(value) {
21307
22978
  return VIDEO_GENERATION_ASPECT_RATIOS.includes(value) ? value : void 0;
21308
22979
  }
22980
+ var VIDEO_GENERATION_TIER_MODELS = {
22981
+ generate: "veo-3.1-generate-preview",
22982
+ fast: "veo-3.1-fast-generate-preview",
22983
+ lite: "veo-3.1-lite-generate-preview"
22984
+ };
21309
22985
  function normalizeVideoGenerationResolution(value) {
21310
22986
  return VIDEO_GENERATION_RESOLUTIONS.includes(value) ? value : void 0;
21311
22987
  }
@@ -21316,12 +22992,18 @@ function normalizeVideoGenerationDurationSeconds(value) {
21316
22992
  function normalizeVideoGenerationTier(value) {
21317
22993
  return VIDEO_GENERATION_TIERS.includes(value) ? value : void 0;
21318
22994
  }
22995
+ function getVideoGenerationModelForTier(tier = DEFAULT_VIDEO_GENERATION_TIER) {
22996
+ return VIDEO_GENERATION_TIER_MODELS[tier];
22997
+ }
21319
22998
  function getVideoGenerationResolutionsForTier(tier = DEFAULT_VIDEO_GENERATION_TIER) {
21320
22999
  return VIDEO_GENERATION_RESOLUTIONS_BY_TIER[tier];
21321
23000
  }
21322
23001
  function isVideoGenerationResolutionSupportedForTier(resolution, tier = DEFAULT_VIDEO_GENERATION_TIER) {
21323
23002
  return VIDEO_GENERATION_RESOLUTIONS_BY_TIER[tier].includes(resolution);
21324
23003
  }
23004
+ function doesVideoGenerationModelSupportAudioToggle(model) {
23005
+ return VIDEO_GENERATION_AUDIO_TOGGLE_MODELS.includes(model);
23006
+ }
21325
23007
  //#endregion
21326
23008
  //#region src/shared/imageGenerationOptions.ts
21327
23009
  var IMAGE_MODEL_SELECTIONS = ["pro", "flash"];
@@ -21563,7 +23245,7 @@ function cliGenerationSupportsRefs(namespace) {
21563
23245
  //#endregion
21564
23246
  //#region src/cli/commands/forge.ts
21565
23247
  var CLI_GENERATION_MEDIA_KIND = getCliGenerationMediaKind("top-level");
21566
- var defaultDeps$6 = {
23248
+ var defaultDeps$9 = {
21567
23249
  loadConfig: loadStoredConfig,
21568
23250
  loadProjectConfig,
21569
23251
  resolveBaseUrl,
@@ -21573,6 +23255,7 @@ var defaultDeps$6 = {
21573
23255
  downloadFile,
21574
23256
  saveRunManifest,
21575
23257
  placeProductionRecord: placeProductionRecordForCli,
23258
+ fetch,
21576
23259
  createRunId,
21577
23260
  getWorkingDir: () => process$1.cwd(),
21578
23261
  fileExists: async (filePath) => {
@@ -21584,6 +23267,43 @@ var defaultDeps$6 = {
21584
23267
  }
21585
23268
  }
21586
23269
  };
23270
+ var ESTIMATE_METER_LABELS = {
23271
+ gemini_images: "Gemini image",
23272
+ gemini_videos: "Veo video unit",
23273
+ gemini_audio: "Lyria generation",
23274
+ elevenlabs_audio: "ElevenLabs unit"
23275
+ };
23276
+ function formatEstimatedUsd(microUsd) {
23277
+ if (!Number.isFinite(microUsd) || microUsd <= 0) return "$0.00";
23278
+ if (microUsd < 1e4) return "<$0.01";
23279
+ return `$${(microUsd / 1e6).toFixed(2)}`;
23280
+ }
23281
+ function formatEstimateQuantity(quantity, singular) {
23282
+ const normalized = Number.isFinite(quantity) ? quantity : 0;
23283
+ const suffix = normalized === 1 ? singular : `${singular}s`;
23284
+ return `${normalized.toLocaleString()} ${suffix}`;
23285
+ }
23286
+ async function printPreflightEstimate(client, params) {
23287
+ let result;
23288
+ try {
23289
+ result = await client.sendGenerationEstimateRequest(params);
23290
+ } catch (error) {
23291
+ console.warn(`Preflight estimate unavailable: ${error instanceof Error ? error.message : String(error)}`);
23292
+ return;
23293
+ }
23294
+ if (!result.success || !result.estimate) {
23295
+ console.warn(`Preflight estimate unavailable: ${result.error || "unknown error"}`);
23296
+ return;
23297
+ }
23298
+ const estimate = result.estimate;
23299
+ const meterLabel = ESTIMATE_METER_LABELS[estimate.meterEventName] ?? estimate.meterEventName;
23300
+ const quotaLine = estimate.quota?.limit === null || estimate.quota?.limit === void 0 ? void 0 : `${estimate.quota.used.toLocaleString()} used / ${estimate.quota.limit.toLocaleString()} limit`;
23301
+ console.log("Preflight estimate:");
23302
+ console.log(` Usage: ${formatEstimateQuantity(estimate.quotaQuantity, meterLabel)}, ${formatEstimateQuantity(estimate.platformWorkflowRuns, "workflow")}`);
23303
+ console.log(` Estimated provider cost: ${formatEstimatedUsd(estimate.providerCostMicroUsd)}${estimate.billingMode === "byok" ? " (BYOK)" : ""}`);
23304
+ if (quotaLine) console.log(` Quota: ${quotaLine}`);
23305
+ if (!estimate.allowed) throw new Error(estimate.denyMessage || "Preflight check denied this generation request");
23306
+ }
21587
23307
  async function handleGenerate(parsed) {
21588
23308
  await handleForgeCommand("generate", parsed);
21589
23309
  }
@@ -21598,18 +23318,18 @@ async function handleBatch(parsed) {
21598
23318
  }
21599
23319
  async function handleForgeCommand(command, parsed) {
21600
23320
  try {
21601
- await executeForgeCommand(command, parsed, defaultDeps$6);
23321
+ await executeForgeCommand(command, parsed, defaultDeps$9);
21602
23322
  } catch (error) {
21603
23323
  console.error("Error:", error instanceof Error ? error.message : error);
21604
- printUsage$7(command);
23324
+ printUsage$9(command);
21605
23325
  process$1.exitCode = 1;
21606
23326
  }
21607
23327
  }
21608
- async function executeForgeCommand(command, parsed, deps = defaultDeps$6, options = {}) {
23328
+ async function executeForgeCommand(command, parsed, deps = defaultDeps$9, options = {}) {
21609
23329
  const mediaKind = options.mediaKind || CLI_GENERATION_MEDIA_KIND;
21610
23330
  if (parsed.options.follow) {
21611
23331
  if (command === "batch") throw new Error("--follow is only supported for single-output generation commands");
21612
- const ctx = await buildContext$3(parsed, deps);
23332
+ const ctx = await buildContext$6(parsed, deps);
21613
23333
  const client = await deps.createClient(ctx.env, ctx.spaceId);
21614
23334
  try {
21615
23335
  await client.connect();
@@ -21623,7 +23343,7 @@ async function executeForgeCommand(command, parsed, deps = defaultDeps$6, option
21623
23343
  validateVideoAudioOptions(parsed, mediaKind);
21624
23344
  parseVideoGenerationOptions(parsed, mediaKind);
21625
23345
  if (command !== "batch") validateProductionMetadataOptions(parsed);
21626
- const ctx = await buildContext$3(parsed, deps);
23346
+ const ctx = await buildContext$6(parsed, deps);
21627
23347
  const client = await deps.createClient(ctx.env, ctx.spaceId);
21628
23348
  try {
21629
23349
  await client.connect();
@@ -21637,7 +23357,7 @@ async function executeForgeCommand(command, parsed, deps = defaultDeps$6, option
21637
23357
  client.disconnect();
21638
23358
  }
21639
23359
  }
21640
- async function executeAudioCommand(command, parsed, deps = defaultDeps$6, options = {}) {
23360
+ async function executeAudioCommand(command, parsed, deps = defaultDeps$9, options = {}) {
21641
23361
  const audioProfile = getCliGenerationProfile("audio");
21642
23362
  if (!audioProfile.commands.includes(command)) throw new Error(`Audio generation does not support ${command}`);
21643
23363
  const modeEntry = options.mode ? getMediaOperationEntry(options.mode) : void 0;
@@ -21650,7 +23370,7 @@ async function executeAudioCommand(command, parsed, deps = defaultDeps$6, option
21650
23370
  audioMode: options.mode
21651
23371
  });
21652
23372
  }
21653
- async function executeVideoCommand(command, parsed, deps = defaultDeps$6) {
23373
+ async function executeVideoCommand(command, parsed, deps = defaultDeps$9) {
21654
23374
  const videoProfile = getCliGenerationProfile("video");
21655
23375
  if (!videoProfile.commands.includes(command)) throw new Error(`Video generation does not support ${command}`);
21656
23376
  return executeForgeCommand(command, parsed, deps, {
@@ -21696,6 +23416,20 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
21696
23416
  const imageOptions = parseImageGenerationOptions(parsed, mediaKind);
21697
23417
  const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
21698
23418
  const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
23419
+ const styleSelection = await resolveStyleSelection(parsed, ctx, deps);
23420
+ await printPreflightEstimate(client, {
23421
+ operation: "generate",
23422
+ assetType,
23423
+ mediaKind,
23424
+ prompt,
23425
+ count: 1,
23426
+ model: imageOptions.model,
23427
+ imageSize: imageOptions.imageSize,
23428
+ ...musicProvider ? { musicProvider } : {},
23429
+ ...videoAudioOptions,
23430
+ ...videoOptions
23431
+ });
23432
+ printStyleSelection(styleSelection);
21699
23433
  console.log(`Generating "${name}" in space ${ctx.spaceId}...`);
21700
23434
  const audioVoiceOptions = mediaKind === "audio" ? parseAudioVoiceOptions(parsed) : {};
21701
23435
  const result = await client.sendGenerateRequest({
@@ -21704,8 +23438,8 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
21704
23438
  prompt,
21705
23439
  ...imageOptions,
21706
23440
  aspectRatio: imageOptions.aspectRatio ?? videoOptions.aspectRatio,
21707
- parentAssetId: parsed.options.parent,
21708
23441
  disableStyle: parsed.options["no-style"] === "true",
23442
+ ...styleSelection.stylePresetId ? { stylePresetId: styleSelection.stylePresetId } : {},
21709
23443
  mediaKind,
21710
23444
  ...audioVoiceOptions,
21711
23445
  ...musicProvider ? { musicProvider } : {},
@@ -21773,6 +23507,20 @@ async function executeRefine(parsed, ctx, client, deps, mediaKind) {
21773
23507
  const imageOptions = parseImageGenerationOptions(parsed, mediaKind);
21774
23508
  const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
21775
23509
  const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
23510
+ const styleSelection = await resolveStyleSelection(parsed, ctx, deps);
23511
+ await printPreflightEstimate(client, {
23512
+ operation: "refine",
23513
+ assetId: sourceVariant.asset_id,
23514
+ assetType: sourceAsset?.type || void 0,
23515
+ mediaKind,
23516
+ prompt,
23517
+ count: 1,
23518
+ model: imageOptions.model,
23519
+ imageSize: imageOptions.imageSize,
23520
+ ...videoAudioOptions,
23521
+ ...videoOptions
23522
+ });
23523
+ printStyleSelection(styleSelection);
21776
23524
  console.log(`Refining variant ${sourceVariantId}...`);
21777
23525
  const result = await client.sendRefineRequest({
21778
23526
  assetId: sourceVariant.asset_id,
@@ -21781,6 +23529,7 @@ async function executeRefine(parsed, ctx, client, deps, mediaKind) {
21781
23529
  ...imageOptions,
21782
23530
  aspectRatio: imageOptions.aspectRatio ?? videoOptions.aspectRatio,
21783
23531
  disableStyle: parsed.options["no-style"] === "true",
23532
+ ...styleSelection.stylePresetId ? { stylePresetId: styleSelection.stylePresetId } : {},
21784
23533
  mediaKind,
21785
23534
  ...videoAudioOptions,
21786
23535
  ...videoOptions,
@@ -21831,6 +23580,19 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
21831
23580
  });
21832
23581
  const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
21833
23582
  const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
23583
+ const styleSelection = await resolveStyleSelection(parsed, ctx, deps);
23584
+ await printPreflightEstimate(client, {
23585
+ operation: "derive",
23586
+ assetType,
23587
+ mediaKind,
23588
+ prompt,
23589
+ count: 1,
23590
+ model: imageOptions.model,
23591
+ imageSize: imageOptions.imageSize,
23592
+ ...videoAudioOptions,
23593
+ ...videoOptions
23594
+ });
23595
+ printStyleSelection(styleSelection);
21834
23596
  console.log(`Deriving "${name}" from ${referenceVariantIds.length} reference(s)...`);
21835
23597
  const result = await client.sendGenerateRequest({
21836
23598
  name,
@@ -21839,8 +23601,8 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
21839
23601
  referenceVariantIds,
21840
23602
  ...imageOptions,
21841
23603
  aspectRatio: imageOptions.aspectRatio ?? videoOptions.aspectRatio,
21842
- parentAssetId: parsed.options.parent,
21843
23604
  disableStyle: parsed.options["no-style"] === "true",
23605
+ ...styleSelection.stylePresetId ? { stylePresetId: styleSelection.stylePresetId } : {},
21844
23606
  mediaKind,
21845
23607
  ...videoAudioOptions,
21846
23608
  ...videoOptions,
@@ -22035,7 +23797,20 @@ async function executeBatch(parsed, ctx, client, deps, mediaKind, saveBatchManif
22035
23797
  const referenceVariantIds = refs.length > 0 ? await resolveReferenceVariantIds(refs, ctx, deps, state.variants, mediaKind) : void 0;
22036
23798
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
22037
23799
  const runId = deps.createRunId();
22038
- console.log(`Batch generating ${count} ${mediaKind === "image" ? "image" : mediaKind === "video" ? "video" : "audio file"}(s) for "${name}"...`);
23800
+ const styleSelection = await resolveStyleSelection(parsed, ctx, deps);
23801
+ await printPreflightEstimate(client, {
23802
+ operation: "batch",
23803
+ assetType,
23804
+ mediaKind,
23805
+ prompt,
23806
+ count,
23807
+ model: imageOptions.model,
23808
+ imageSize: imageOptions.imageSize,
23809
+ ...musicProvider ? { musicProvider } : {}
23810
+ });
23811
+ const mediaLabel = mediaKind === "image" ? "image" : mediaKind === "video" ? "video" : "audio file";
23812
+ printStyleSelection(styleSelection);
23813
+ console.log(`Batch generating ${count} ${mediaLabel}(s) for "${name}"...`);
22039
23814
  const audioVoiceOptions = mediaKind === "audio" ? parseAudioVoiceOptions(parsed) : {};
22040
23815
  const result = await client.sendBatchRequest({
22041
23816
  name,
@@ -22046,8 +23821,8 @@ async function executeBatch(parsed, ctx, client, deps, mediaKind, saveBatchManif
22046
23821
  referenceVariantIds,
22047
23822
  ...imageOptions,
22048
23823
  aspectRatio: imageOptions.aspectRatio,
22049
- parentAssetId: parsed.options.parent,
22050
23824
  disableStyle: parsed.options["no-style"] === "true",
23825
+ ...styleSelection.stylePresetId ? { stylePresetId: styleSelection.stylePresetId } : {},
22051
23826
  mediaKind,
22052
23827
  ...audioVoiceOptions,
22053
23828
  ...musicProvider ? { musicProvider } : {}
@@ -22165,7 +23940,7 @@ async function placeProductionRecordFromScene(input) {
22165
23940
  record
22166
23941
  });
22167
23942
  }
22168
- async function buildContext$3(parsed, deps) {
23943
+ async function buildContext$6(parsed, deps) {
22169
23944
  const projectConfig = await deps.loadProjectConfig();
22170
23945
  const env = resolveCommandEnvironment(parsed, projectConfig);
22171
23946
  const spaceId = resolveCommandSpace(parsed, projectConfig);
@@ -22231,6 +24006,51 @@ function requestSpaceState(client) {
22231
24006
  client.requestSync();
22232
24007
  });
22233
24008
  }
24009
+ async function resolveStyleSelection(parsed, ctx, deps) {
24010
+ const stylePresetRef = readStylePresetOption(parsed);
24011
+ if (parsed.options["no-style"] === "true") {
24012
+ if (stylePresetRef) throw new Error("--style-preset cannot be used with --no-style");
24013
+ return {};
24014
+ }
24015
+ if (!stylePresetRef) return {};
24016
+ const presets = (await apiFetch("GET /api/spaces/:id/style-presets", {
24017
+ baseUrl: ctx.baseUrl,
24018
+ fetch: deps.fetch ?? fetch,
24019
+ params: { id: ctx.spaceId },
24020
+ headers: {
24021
+ "Authorization": `Bearer ${ctx.accessToken}`,
24022
+ "Accept": "application/json"
24023
+ }
24024
+ })).presets;
24025
+ const byId = presets.find((preset) => preset.id === stylePresetRef);
24026
+ const byName = presets.filter((preset) => preset.name === stylePresetRef);
24027
+ const preset = byId ?? (byName.length === 1 ? byName[0] : void 0);
24028
+ if (!preset) {
24029
+ if (byName.length > 1) throw new Error(`Style preset name is ambiguous: ${stylePresetRef}. Use a preset ID.`);
24030
+ throw new Error(`Style preset not found: ${stylePresetRef}`);
24031
+ }
24032
+ if (!isTruthyFlag(preset.enabled)) throw new Error(`Style preset is disabled: ${preset.name} (${preset.id})`);
24033
+ return {
24034
+ stylePresetId: preset.id,
24035
+ preset
24036
+ };
24037
+ }
24038
+ function readStylePresetOption(parsed) {
24039
+ return readOptionalOption(parsed, "style-preset", "stylePreset") ?? readOptionalOption(parsed, "preset", "preset");
24040
+ }
24041
+ function printStyleSelection(selection) {
24042
+ if (selection.preset) {
24043
+ const preset = selection.preset;
24044
+ const defaultLabel = isTruthyFlag(preset.is_default) ? ", default" : "";
24045
+ console.log(`Style preset: ${preset.name} (${preset.id}${defaultLabel})`);
24046
+ console.log(` References: ${preset.reference_count}`);
24047
+ console.log(` Collection: ${preset.collection_name || "-"}`);
24048
+ return;
24049
+ }
24050
+ }
24051
+ function isTruthyFlag(value) {
24052
+ return value === true || value === 1;
24053
+ }
22234
24054
  async function downloadResult(result, outputPath, ctx, deps) {
22235
24055
  const variant = result.variant;
22236
24056
  if (!result.success || !variant) throw new Error(result.error || "Generation failed without a completed variant");
@@ -22341,6 +24161,13 @@ function validateVideoAudioOptions(parsed, mediaKind) {
22341
24161
  if (!(parsed.options.audio !== void 0 || parsed.options["no-audio"] !== void 0 || parsed.options.noAudio !== void 0)) return;
22342
24162
  if (mediaKind !== "video") throw new Error("--audio and --no-audio are only supported for video generation");
22343
24163
  if (parsed.options.audio !== void 0 && (parsed.options["no-audio"] !== void 0 || parsed.options.noAudio !== void 0)) throw new Error("Pass either --audio or --no-audio, not both");
24164
+ if (parsed.options["no-audio"] !== void 0 || parsed.options.noAudio !== void 0) {
24165
+ const tierValue = readOptionalOption(parsed, "tier", "tier") ?? readOptionalOption(parsed, "video-tier", "videoTier");
24166
+ const videoTier = tierValue === void 0 ? DEFAULT_VIDEO_GENERATION_TIER : normalizeVideoGenerationTier(tierValue);
24167
+ if (!videoTier) throw new Error("--tier must be generate, fast, or lite");
24168
+ const model = getVideoGenerationModelForTier(videoTier);
24169
+ if (!doesVideoGenerationModelSupportAudioToggle(model)) throw new Error(`${model} does not support --no-audio. Use the default audio-enabled output or omit the flag.`);
24170
+ }
22344
24171
  }
22345
24172
  function parseVideoAudioOptions(parsed, mediaKind) {
22346
24173
  if (mediaKind === "video") {
@@ -22509,7 +24336,7 @@ function cliImageSizeValues() {
22509
24336
  function cliImageAspectValues() {
22510
24337
  return cliOptionValues(getImageModelCapabilities().supportedAspectRatios);
22511
24338
  }
22512
- function printUsage$7(command) {
24339
+ function printUsage$9(command) {
22513
24340
  if (command === "generate") {
22514
24341
  console.log(`
22515
24342
  Usage:
@@ -22562,7 +24389,7 @@ function printBatchResult(result, outputDir, manifestPath, ctx, mediaKind) {
22562
24389
  }
22563
24390
  //#endregion
22564
24391
  //#region src/cli/commands/audio.ts
22565
- var defaultDeps$5 = {
24392
+ var defaultDeps$8 = {
22566
24393
  loadConfig: loadStoredConfig,
22567
24394
  loadProjectConfig,
22568
24395
  resolveBaseUrl,
@@ -22575,11 +24402,11 @@ async function handleAudio(parsed) {
22575
24402
  await executeAudio(parsed);
22576
24403
  } catch (error) {
22577
24404
  console.error("Error:", error instanceof Error ? error.message : error);
22578
- printUsage$6();
24405
+ printUsage$8();
22579
24406
  process$1.exitCode = 1;
22580
24407
  }
22581
24408
  }
22582
- async function executeAudio(parsed, deps = defaultDeps$5) {
24409
+ async function executeAudio(parsed, deps = defaultDeps$8) {
22583
24410
  const invocation = parseAudioInvocation(parsed.positionals);
22584
24411
  if (invocation.command === "voices") return executeAudioVoices({
22585
24412
  ...parsed,
@@ -22652,7 +24479,7 @@ function printVoices(response, print) {
22652
24479
  function formatLabels(labels) {
22653
24480
  return Object.entries(labels).map(([key, value]) => `${key}:${value}`).join(", ");
22654
24481
  }
22655
- function printUsage$6() {
24482
+ function printUsage$8() {
22656
24483
  const modes = AUDIO_FORGE_MEDIA_MODES.join("|");
22657
24484
  console.log(`
22658
24485
  Usage:
@@ -22681,7 +24508,7 @@ async function handleVideo(parsed) {
22681
24508
  });
22682
24509
  } catch (error) {
22683
24510
  console.error("Error:", error instanceof Error ? error.message : error);
22684
- printUsage$5();
24511
+ printUsage$7();
22685
24512
  process$1.exitCode = 1;
22686
24513
  }
22687
24514
  }
@@ -22690,7 +24517,7 @@ function parseVideoCommand(value) {
22690
24517
  if (value && commands.includes(value)) return value;
22691
24518
  throw new Error("Video command is required: generate, refine, or derive");
22692
24519
  }
22693
- function printUsage$5() {
24520
+ function printUsage$7() {
22694
24521
  const aspectValues = VIDEO_GENERATION_ASPECT_RATIOS.join("|");
22695
24522
  const resolutionValues = Array.from(new Set(VIDEO_GENERATION_TIERS.flatMap((tier) => getVideoGenerationResolutionsForTier(tier)))).join("|");
22696
24523
  const durationValues = VIDEO_GENERATION_DURATION_SECONDS.join("|");
@@ -22698,11 +24525,11 @@ function printUsage$5() {
22698
24525
  const resolutionByTier = VIDEO_GENERATION_TIERS.map((tier) => `${tier}: ${getVideoGenerationResolutionsForTier(tier).join(", ")}`).join("; ");
22699
24526
  console.log(`
22700
24527
  Usage:
22701
- makefx video generate "prompt" --name <name> --type <type> -o <file> [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio|--no-audio] [--space <id>]
24528
+ makefx video generate "prompt" --name <name> --type <type> -o <file> [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
22702
24529
  makefx video generate --follow <variant_id> -o <file> [--space <id>]
22703
- makefx video refine --variant <variant_id> "prompt" -o <file> [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio|--no-audio] [--space <id>]
24530
+ makefx video refine --variant <variant_id> "prompt" -o <file> [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
22704
24531
  makefx video refine --follow <variant_id> -o <file> [--space <id>]
22705
- makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio|--no-audio] [--space <id>]
24532
+ makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
22706
24533
  makefx video derive --follow <variant_id> -o <file> [--space <id>]
22707
24534
 
22708
24535
  Video:
@@ -22713,7 +24540,7 @@ Video:
22713
24540
 
22714
24541
  Audio:
22715
24542
  --audio Request native synchronized Veo audio (default)
22716
- --no-audio Request a silent video; MakeFX records this and adds a silent-video instruction.
24543
+ --no-audio Not supported by current Veo models; rejected before a job is created.
22717
24544
 
22718
24545
  Production metadata:
22719
24546
  --scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
@@ -22722,17 +24549,17 @@ Production metadata:
22722
24549
  }
22723
24550
  //#endregion
22724
24551
  //#region src/cli/commands/init.ts
22725
- var defaultDeps$4 = { saveProjectConfig };
24552
+ var defaultDeps$7 = { saveProjectConfig };
22726
24553
  async function handleInit(parsed) {
22727
24554
  try {
22728
24555
  await executeInit(parsed);
22729
24556
  } catch (error) {
22730
24557
  console.error("Error:", error instanceof Error ? error.message : error);
22731
- printUsage$4();
24558
+ printUsage$6();
22732
24559
  process$1.exitCode = 1;
22733
24560
  }
22734
24561
  }
22735
- async function executeInit(parsed, deps = defaultDeps$4) {
24562
+ async function executeInit(parsed, deps = defaultDeps$7) {
22736
24563
  const environment = resolveCommandEnvironment(parsed);
22737
24564
  const spaceId = resolveCommandSpace(parsed);
22738
24565
  if (!spaceId) throw new Error("--space is required");
@@ -22758,7 +24585,7 @@ async function executeInit(parsed, deps = defaultDeps$4) {
22758
24585
  spaceId
22759
24586
  };
22760
24587
  }
22761
- function printUsage$4() {
24588
+ function printUsage$6() {
22762
24589
  console.log(`
22763
24590
  Usage:
22764
24591
  makefx init --space <id> [--env production|stage|local]
@@ -22767,7 +24594,7 @@ Usage:
22767
24594
  }
22768
24595
  //#endregion
22769
24596
  //#region src/cli/commands/runs.ts
22770
- var defaultDeps$3 = {
24597
+ var defaultDeps$6 = {
22771
24598
  loadProjectConfig,
22772
24599
  listRunManifests,
22773
24600
  readRunManifest,
@@ -22780,11 +24607,11 @@ async function handleRuns(parsed) {
22780
24607
  await executeRuns(parsed);
22781
24608
  } catch (error) {
22782
24609
  console.error("Error:", error instanceof Error ? error.message : error);
22783
- printUsage$3();
24610
+ printUsage$5();
22784
24611
  process$1.exitCode = 1;
22785
24612
  }
22786
24613
  }
22787
- async function executeRuns(parsed, deps = defaultDeps$3) {
24614
+ async function executeRuns(parsed, deps = defaultDeps$6) {
22788
24615
  const projectConfig = await deps.loadProjectConfig();
22789
24616
  if (!projectConfig?.projectRoot) throw new Error("Make Effects project config not found. Run: makefx init --space <id>");
22790
24617
  requireDebugAcknowledgement(parsed);
@@ -22902,7 +24729,7 @@ function formatCreated(value) {
22902
24729
  if (Number.isNaN(date.getTime())) return value;
22903
24730
  return value.replace("T", " ").replace(/\.\d{3}Z$/, "Z").slice(0, 20);
22904
24731
  }
22905
- function printUsage$3() {
24732
+ function printUsage$5() {
22906
24733
  console.log(`
22907
24734
  Usage:
22908
24735
  makefx runs --debug
@@ -22920,7 +24747,7 @@ For timed scene assembly, use:
22920
24747
  }
22921
24748
  //#endregion
22922
24749
  //#region src/cli/commands/assets.ts
22923
- var defaultDeps$2 = {
24750
+ var defaultDeps$5 = {
22924
24751
  loadConfig: loadStoredConfig,
22925
24752
  loadProjectConfig,
22926
24753
  resolveBaseUrl,
@@ -22943,15 +24770,15 @@ async function handleAssets(parsed) {
22943
24770
  await executeAssets(parsed);
22944
24771
  } catch (error) {
22945
24772
  console.error("Error:", error instanceof Error ? error.message : error);
22946
- printUsage$2();
24773
+ printUsage$4();
22947
24774
  process$1.exitCode = 1;
22948
24775
  }
22949
24776
  }
22950
- async function executeAssets(parsed, deps = defaultDeps$2) {
22951
- const ctx = await buildContext$2(parsed, deps);
24777
+ async function executeAssets(parsed, deps = defaultDeps$5) {
24778
+ const ctx = await buildContext$5(parsed, deps);
22952
24779
  const subcommand = parsed.positionals[0] || "list";
22953
24780
  if (subcommand === "list") {
22954
- const assets = await listAssets(ctx, deps);
24781
+ const assets = await listAssets$1(ctx, deps);
22955
24782
  if (parsed.options.json === "true") deps.print(JSON.stringify(assets.map(toAssetJson), null, 2));
22956
24783
  else printAssetList(assets, deps.print);
22957
24784
  return {
@@ -23027,7 +24854,7 @@ async function executeAssets(parsed, deps = defaultDeps$2) {
23027
24854
  function normalizeOption(value) {
23028
24855
  return !value || value === "true" ? void 0 : value;
23029
24856
  }
23030
- async function buildContext$2(parsed, deps) {
24857
+ async function buildContext$5(parsed, deps) {
23031
24858
  const projectConfig = await deps.loadProjectConfig();
23032
24859
  const env = resolveCommandEnvironment(parsed, projectConfig);
23033
24860
  const spaceId = resolveCommandSpace(parsed, projectConfig);
@@ -23044,7 +24871,7 @@ async function buildContext$2(parsed, deps) {
23044
24871
  force: parsed.options.force === "true"
23045
24872
  };
23046
24873
  }
23047
- async function listAssets(ctx, deps) {
24874
+ async function listAssets$1(ctx, deps) {
23048
24875
  return (await fetchJson(ctx, deps, `/api/spaces/${ctx.spaceId}/assets`)).assets || [];
23049
24876
  }
23050
24877
  async function getAssetDetails(ctx, deps, assetId) {
@@ -23069,7 +24896,7 @@ async function resolveDownloadRef(ref, ctx, deps) {
23069
24896
  requestPath: `/api/images/${ref}`
23070
24897
  };
23071
24898
  }
23072
- const assets = await listAssets(ctx, deps);
24899
+ const assets = await listAssets$1(ctx, deps);
23073
24900
  for (const asset of assets) {
23074
24901
  const variant = (await getAssetDetails(ctx, deps, asset.id)).variants.find((candidate) => candidate.id === ref);
23075
24902
  if (!variant) continue;
@@ -23127,7 +24954,6 @@ function printAssetDetails(details, ctx, print) {
23127
24954
  print(` Type: ${asset.type || "unknown"}`);
23128
24955
  print(` Media: ${asset.media_kind || "-"}`);
23129
24956
  print(` Active: ${asset.active_variant_id || "-"}`);
23130
- print(` Parent: ${asset.parent_asset_id || "-"}`);
23131
24957
  print(` Created: ${formatTimestamp(asset.created_at)}`);
23132
24958
  print(` Updated: ${formatTimestamp(asset.updated_at)}`);
23133
24959
  print(` Web: ${ctx.baseUrl}/spaces/${ctx.spaceId}/assets/${asset.id}`);
@@ -23176,7 +25002,6 @@ function toAssetJson(asset) {
23176
25002
  type: asset.type,
23177
25003
  media_kind: asset.media_kind || null,
23178
25004
  activeVariantId: asset.active_variant_id,
23179
- parentAssetId: asset.parent_asset_id || null,
23180
25005
  createdAt: asset.created_at || null,
23181
25006
  updatedAt: asset.updated_at || null
23182
25007
  };
@@ -23208,7 +25033,7 @@ function formatTimestamp(value) {
23208
25033
  if (Number.isNaN(date.getTime())) return String(value);
23209
25034
  return date.toISOString().replace("T", " ").replace(/\.\d{3}Z$/, "Z").slice(0, 20);
23210
25035
  }
23211
- function printUsage$2() {
25036
+ function printUsage$4() {
23212
25037
  console.log(`
23213
25038
  Usage:
23214
25039
  makefx assets
@@ -23223,7 +25048,7 @@ Usage:
23223
25048
  }
23224
25049
  //#endregion
23225
25050
  //#region src/cli/commands/variants.ts
23226
- var defaultDeps$1 = {
25051
+ var defaultDeps$4 = {
23227
25052
  loadConfig: loadStoredConfig,
23228
25053
  loadProjectConfig,
23229
25054
  resolveBaseUrl,
@@ -23235,12 +25060,12 @@ async function handleVariants(parsed) {
23235
25060
  await executeVariants(parsed);
23236
25061
  } catch (error) {
23237
25062
  console.error("Error:", error instanceof Error ? error.message : error);
23238
- printUsage$1();
25063
+ printUsage$3();
23239
25064
  process$1.exitCode = 1;
23240
25065
  }
23241
25066
  }
23242
- async function executeVariants(parsed, deps = defaultDeps$1) {
23243
- const ctx = await buildContext$1(parsed, deps);
25067
+ async function executeVariants(parsed, deps = defaultDeps$4) {
25068
+ const ctx = await buildContext$4(parsed, deps);
23244
25069
  const subcommand = parsed.positionals[0];
23245
25070
  if (subcommand === "delete") {
23246
25071
  const variantId = requireVariantId(parsed, "delete");
@@ -23288,7 +25113,7 @@ function requireVariantId(parsed, verb) {
23288
25113
  if (!variantId) throw new Error(`Variant ID is required: makefx variants ${verb} <variant-id>`);
23289
25114
  return variantId;
23290
25115
  }
23291
- async function buildContext$1(parsed, deps) {
25116
+ async function buildContext$4(parsed, deps) {
23292
25117
  const projectConfig = await deps.loadProjectConfig();
23293
25118
  const env = resolveCommandEnvironment(parsed, projectConfig);
23294
25119
  const spaceId = resolveCommandSpace(parsed, projectConfig);
@@ -23311,7 +25136,7 @@ async function withVariantClient(ctx, deps, run) {
23311
25136
  client.disconnect();
23312
25137
  }
23313
25138
  }
23314
- function printUsage$1() {
25139
+ function printUsage$3() {
23315
25140
  console.log(`
23316
25141
  Usage:
23317
25142
  makefx variants delete <variant-id>
@@ -23327,6 +25152,809 @@ Options:
23327
25152
  `);
23328
25153
  }
23329
25154
  //#endregion
25155
+ //#region src/cli/commands/styles.ts
25156
+ var defaultDeps$3 = {
25157
+ loadConfig: loadStoredConfig,
25158
+ loadProjectConfig,
25159
+ resolveBaseUrl,
25160
+ fetch,
25161
+ print: console.log
25162
+ };
25163
+ async function handleStyles(parsed) {
25164
+ try {
25165
+ await executeStyles(parsed);
25166
+ } catch (error) {
25167
+ console.error("Error:", error instanceof Error ? error.message : error);
25168
+ printUsage$2();
25169
+ process$1.exitCode = 1;
25170
+ }
25171
+ }
25172
+ async function executeStyles(parsed, deps = defaultDeps$3) {
25173
+ const namespace = parsed.positionals[0] || "presets";
25174
+ if (namespace === "references" || namespace === "refs") return executeReferences(parsed, deps);
25175
+ if (namespace === "collections" || namespace === "collection") return executeCollections(parsed, deps);
25176
+ if (namespace === "presets" || namespace === "preset") return executePresets(parsed, deps);
25177
+ throw new Error(`Unknown styles command: ${namespace}`);
25178
+ }
25179
+ async function executeReferences(parsed, deps) {
25180
+ const ctx = await buildContext$3(parsed, deps);
25181
+ const collectionFilter = readOption(parsed, "collection", "collectionId") || parsed.positionals[1];
25182
+ const collections = await listStyleReferenceCollections(ctx, deps);
25183
+ const selected = collectionFilter ? collections.filter((collection) => collection.id === collectionFilter || collection.name === collectionFilter) : collections;
25184
+ if (collectionFilter && selected.length === 0) throw new Error(`Style reference collection not found: ${collectionFilter}`);
25185
+ const references = [];
25186
+ for (const collection of selected) {
25187
+ const items = await listCollectionItems(ctx, deps, collection.id);
25188
+ for (const item of items.filter((candidate) => candidate.role === "style_ref")) references.push({
25189
+ collectionId: collection.id,
25190
+ collectionName: collection.name,
25191
+ item
25192
+ });
25193
+ }
25194
+ if (parsed.options.json === "true") deps.print(JSON.stringify(references, null, 2));
25195
+ else printReferences(references, deps.print);
25196
+ return {
25197
+ type: "references",
25198
+ references
25199
+ };
25200
+ }
25201
+ async function executeCollections(parsed, deps) {
25202
+ const ctx = await buildContext$3(parsed, deps);
25203
+ const action = parsed.positionals[1] || "list";
25204
+ if (action === "list") {
25205
+ const collections = await listStyleReferenceCollections(ctx, deps);
25206
+ if (parsed.options.json === "true") deps.print(JSON.stringify(collections, null, 2));
25207
+ else printCollections(collections, deps.print);
25208
+ return {
25209
+ type: "collections",
25210
+ collections
25211
+ };
25212
+ }
25213
+ if (action === "create") {
25214
+ const name = parsed.positionals[2] || readRequiredOption(parsed, "name", "name");
25215
+ const collection = await createCollection(ctx, deps, {
25216
+ id: readOption(parsed, "id", "id"),
25217
+ name,
25218
+ description: nullableOption(parsed, "description", "description")
25219
+ });
25220
+ const items = await upsertStyleReferenceItems(ctx, deps, collection.id, parsed, false);
25221
+ printCollectionMutation("Created", collection, items, deps.print, parsed.options.json === "true");
25222
+ return {
25223
+ type: "collection",
25224
+ collection,
25225
+ items
25226
+ };
25227
+ }
25228
+ if (action === "update") {
25229
+ const collectionId = parsed.positionals[2] || readRequiredOption(parsed, "id", "id");
25230
+ const changes = {};
25231
+ const name = readOption(parsed, "name", "name");
25232
+ const description = nullableOption(parsed, "description", "description");
25233
+ if (name !== void 0) changes.name = name;
25234
+ if (description !== void 0) changes.description = description;
25235
+ let collection;
25236
+ if (Object.keys(changes).length > 0) collection = await updateCollection(ctx, deps, collectionId, changes);
25237
+ const items = hasReferenceOptions(parsed) ? await upsertStyleReferenceItems(ctx, deps, collectionId, parsed, parsed.options.append !== "true") : void 0;
25238
+ if (!collection) collection = (await listCollections(ctx, deps)).find((candidate) => candidate.id === collectionId);
25239
+ if (!collection) throw new Error(`Collection not found: ${collectionId}`);
25240
+ printCollectionMutation("Updated", collection, items, deps.print, parsed.options.json === "true");
25241
+ return {
25242
+ type: "collection",
25243
+ collection,
25244
+ items
25245
+ };
25246
+ }
25247
+ throw new Error(`Unknown styles collections command: ${action}`);
25248
+ }
25249
+ async function executePresets(parsed, deps) {
25250
+ const ctx = await buildContext$3(parsed, deps);
25251
+ const action = parsed.positionals[1] || "list";
25252
+ if (action === "list") {
25253
+ const presets = await listStylePresets(ctx, deps);
25254
+ if (parsed.options.json === "true") deps.print(JSON.stringify(presets, null, 2));
25255
+ else printPresets(presets, deps.print);
25256
+ return {
25257
+ type: "presets",
25258
+ presets
25259
+ };
25260
+ }
25261
+ if (action === "create") {
25262
+ const name = parsed.positionals[2] || readRequiredOption(parsed, "name", "name");
25263
+ const response = await createStylePreset(ctx, deps, {
25264
+ id: readOption(parsed, "id", "id"),
25265
+ name,
25266
+ description: nullableOption(parsed, "description", "description"),
25267
+ stylePrompt: readOption(parsed, "prompt", "stylePrompt") ?? "",
25268
+ collectionId: nullableOption(parsed, "collection", "collectionId"),
25269
+ enabled: parsed.options.disable === "true" ? false : true,
25270
+ isDefault: parsed.options.default === "true"
25271
+ });
25272
+ printPresetMutation("Created", response.preset, deps.print, parsed.options.json === "true");
25273
+ return {
25274
+ type: "preset",
25275
+ preset: response.preset
25276
+ };
25277
+ }
25278
+ if (action === "update") {
25279
+ const response = await updateStylePreset(ctx, deps, parsed.positionals[2] || readRequiredOption(parsed, "id", "id"), buildPresetUpdate(parsed));
25280
+ printPresetMutation("Updated", response.preset, deps.print, parsed.options.json === "true");
25281
+ return {
25282
+ type: "preset",
25283
+ preset: response.preset
25284
+ };
25285
+ }
25286
+ if (action === "enable" || action === "disable") {
25287
+ const response = await updateStylePreset(ctx, deps, parsed.positionals[2] || readRequiredOption(parsed, "id", "id"), { enabled: action === "enable" });
25288
+ printPresetMutation(action === "enable" ? "Enabled" : "Disabled", response.preset, deps.print, parsed.options.json === "true");
25289
+ return {
25290
+ type: "preset",
25291
+ preset: response.preset
25292
+ };
25293
+ }
25294
+ if (action === "delete" || action === "remove") {
25295
+ const presetId = parsed.positionals[2] || readRequiredOption(parsed, "id", "id");
25296
+ await deleteStylePreset(ctx, deps, presetId);
25297
+ if (parsed.options.json === "true") deps.print(JSON.stringify({
25298
+ success: true,
25299
+ presetId
25300
+ }, null, 2));
25301
+ else deps.print(`Deleted style preset ${presetId}`);
25302
+ return {
25303
+ type: "delete-preset",
25304
+ presetId
25305
+ };
25306
+ }
25307
+ throw new Error(`Unknown styles presets command: ${action}`);
25308
+ }
25309
+ async function buildContext$3(parsed, deps) {
25310
+ const projectConfig = await deps.loadProjectConfig();
25311
+ const env = resolveCommandEnvironment(parsed, projectConfig);
25312
+ const spaceId = resolveCommandSpace(parsed, projectConfig);
25313
+ if (!spaceId) throw new Error("--space is required, or run: makefx init --space <id>");
25314
+ const config = await deps.loadConfig(env);
25315
+ if (!config) throw new Error(`Not logged in to ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
25316
+ if (config.token.expiresAt < Date.now()) throw new Error(`Token expired for ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
25317
+ if (env === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
25318
+ return {
25319
+ env,
25320
+ spaceId,
25321
+ baseUrl: deps.resolveBaseUrl(env),
25322
+ accessToken: config.token.accessToken
25323
+ };
25324
+ }
25325
+ async function listAssets(ctx, deps) {
25326
+ return (await apiFetch("GET /api/spaces/:id/assets", {
25327
+ baseUrl: ctx.baseUrl,
25328
+ fetch: deps.fetch,
25329
+ params: { id: ctx.spaceId },
25330
+ headers: authHeaders(ctx)
25331
+ })).assets;
25332
+ }
25333
+ async function listCollections(ctx, deps) {
25334
+ return (await apiFetch("GET /api/spaces/:id/collections", {
25335
+ baseUrl: ctx.baseUrl,
25336
+ fetch: deps.fetch,
25337
+ params: { id: ctx.spaceId },
25338
+ headers: authHeaders(ctx)
25339
+ })).collections;
25340
+ }
25341
+ async function listStyleReferenceCollections(ctx, deps) {
25342
+ return (await apiFetch("GET /api/spaces/:id/style-reference-collections", {
25343
+ baseUrl: ctx.baseUrl,
25344
+ fetch: deps.fetch,
25345
+ params: { id: ctx.spaceId },
25346
+ headers: authHeaders(ctx)
25347
+ })).collections;
25348
+ }
25349
+ async function listCollectionItems(ctx, deps, collectionId) {
25350
+ return (await apiFetch("GET /api/spaces/:id/collections/:collectionId/items", {
25351
+ baseUrl: ctx.baseUrl,
25352
+ fetch: deps.fetch,
25353
+ params: {
25354
+ id: ctx.spaceId,
25355
+ collectionId
25356
+ },
25357
+ headers: authHeaders(ctx)
25358
+ })).items;
25359
+ }
25360
+ async function createCollection(ctx, deps, json) {
25361
+ return (await apiFetch("POST /api/spaces/:id/collections", {
25362
+ baseUrl: ctx.baseUrl,
25363
+ fetch: deps.fetch,
25364
+ params: { id: ctx.spaceId },
25365
+ json,
25366
+ headers: authHeaders(ctx)
25367
+ })).collection;
25368
+ }
25369
+ async function updateCollection(ctx, deps, collectionId, json) {
25370
+ return (await apiFetch("PATCH /api/spaces/:id/collections/:collectionId", {
25371
+ baseUrl: ctx.baseUrl,
25372
+ fetch: deps.fetch,
25373
+ params: {
25374
+ id: ctx.spaceId,
25375
+ collectionId
25376
+ },
25377
+ json,
25378
+ headers: authHeaders(ctx)
25379
+ })).collection;
25380
+ }
25381
+ async function createCollectionItem(ctx, deps, collectionId, json) {
25382
+ return (await apiFetch("POST /api/spaces/:id/collections/:collectionId/items", {
25383
+ baseUrl: ctx.baseUrl,
25384
+ fetch: deps.fetch,
25385
+ params: {
25386
+ id: ctx.spaceId,
25387
+ collectionId
25388
+ },
25389
+ json,
25390
+ headers: authHeaders(ctx)
25391
+ })).item;
25392
+ }
25393
+ async function deleteCollectionItem(ctx, deps, collectionId, itemId) {
25394
+ await apiFetch("DELETE /api/spaces/:id/collections/:collectionId/items/:itemId", {
25395
+ baseUrl: ctx.baseUrl,
25396
+ fetch: deps.fetch,
25397
+ params: {
25398
+ id: ctx.spaceId,
25399
+ collectionId,
25400
+ itemId
25401
+ },
25402
+ headers: authHeaders(ctx)
25403
+ });
25404
+ }
25405
+ async function listStylePresets(ctx, deps) {
25406
+ return (await apiFetch("GET /api/spaces/:id/style-presets", {
25407
+ baseUrl: ctx.baseUrl,
25408
+ fetch: deps.fetch,
25409
+ params: { id: ctx.spaceId },
25410
+ headers: authHeaders(ctx)
25411
+ })).presets;
25412
+ }
25413
+ async function createStylePreset(ctx, deps, json) {
25414
+ return apiFetch("POST /api/spaces/:id/style-presets", {
25415
+ baseUrl: ctx.baseUrl,
25416
+ fetch: deps.fetch,
25417
+ params: { id: ctx.spaceId },
25418
+ json,
25419
+ headers: authHeaders(ctx)
25420
+ });
25421
+ }
25422
+ async function updateStylePreset(ctx, deps, presetId, json) {
25423
+ return apiFetch("PATCH /api/spaces/:id/style-presets/:presetId", {
25424
+ baseUrl: ctx.baseUrl,
25425
+ fetch: deps.fetch,
25426
+ params: {
25427
+ id: ctx.spaceId,
25428
+ presetId
25429
+ },
25430
+ json,
25431
+ headers: authHeaders(ctx)
25432
+ });
25433
+ }
25434
+ async function deleteStylePreset(ctx, deps, presetId) {
25435
+ await apiFetch("DELETE /api/spaces/:id/style-presets/:presetId", {
25436
+ baseUrl: ctx.baseUrl,
25437
+ fetch: deps.fetch,
25438
+ params: {
25439
+ id: ctx.spaceId,
25440
+ presetId
25441
+ },
25442
+ headers: authHeaders(ctx)
25443
+ });
25444
+ }
25445
+ async function upsertStyleReferenceItems(ctx, deps, collectionId, parsed, replaceExisting) {
25446
+ const refs = await buildStyleReferenceItemRequests(ctx, deps, parsed);
25447
+ if (refs.length === 0) return [];
25448
+ if (replaceExisting) {
25449
+ const existing = await listCollectionItems(ctx, deps, collectionId);
25450
+ await Promise.all(existing.filter((item) => item.role === "style_ref").map((item) => deleteCollectionItem(ctx, deps, collectionId, item.id)));
25451
+ }
25452
+ const created = [];
25453
+ for (let index = 0; index < refs.length; index += 1) created.push(await createCollectionItem(ctx, deps, collectionId, {
25454
+ ...refs[index],
25455
+ role: "style_ref",
25456
+ sortIndex: index
25457
+ }));
25458
+ return created;
25459
+ }
25460
+ async function buildStyleReferenceItemRequests(ctx, deps, parsed) {
25461
+ const assets = parseCsvOptions(parsed, ["assets", "asset"]);
25462
+ const variants = parseCsvOptions(parsed, ["variants", "variant"]);
25463
+ const refs = parseCsvOptions(parsed, ["refs", "ref"]);
25464
+ if (assets.length === 0 && variants.length === 0 && refs.length === 0) return [];
25465
+ const allAssets = await listAssets(ctx, deps);
25466
+ const assetById = new Map(allAssets.map((asset) => [asset.id, asset]));
25467
+ const requests = [];
25468
+ for (const assetId of [...assets, ...refs.filter((ref) => assetById.has(ref))]) {
25469
+ const asset = assetById.get(assetId);
25470
+ if (!asset) throw new Error(`Asset not found in space ${ctx.spaceId}: ${assetId}`);
25471
+ if (!asset.active_variant_id) throw new Error(`Asset ${assetId} has no active variant to pin as a style reference`);
25472
+ requests.push({
25473
+ subjectType: "asset",
25474
+ assetId,
25475
+ pinnedVariantId: asset.active_variant_id
25476
+ });
25477
+ }
25478
+ for (const variantId of [...variants, ...refs.filter((ref) => !assetById.has(ref))]) requests.push({
25479
+ subjectType: "variant",
25480
+ variantId
25481
+ });
25482
+ return dedupeItemRequests(requests);
25483
+ }
25484
+ function dedupeItemRequests(requests) {
25485
+ const seen = /* @__PURE__ */ new Set();
25486
+ return requests.filter((request) => {
25487
+ const key = request.subjectType === "asset" ? `asset:${request.assetId}:${request.pinnedVariantId ?? ""}` : `variant:${request.variantId}`;
25488
+ if (seen.has(key)) return false;
25489
+ seen.add(key);
25490
+ return true;
25491
+ });
25492
+ }
25493
+ function buildPresetUpdate(parsed) {
25494
+ const update = {};
25495
+ const name = readOption(parsed, "name", "name");
25496
+ const description = nullableOption(parsed, "description", "description");
25497
+ const stylePrompt = readOption(parsed, "prompt", "stylePrompt");
25498
+ const collectionId = nullableOption(parsed, "collection", "collectionId");
25499
+ if (name !== void 0) update.name = name;
25500
+ if (description !== void 0) update.description = description;
25501
+ if (stylePrompt !== void 0) update.stylePrompt = stylePrompt;
25502
+ if (collectionId !== void 0) update.collectionId = collectionId;
25503
+ if (parsed.options.enable === "true") update.enabled = true;
25504
+ if (parsed.options.disable === "true") update.enabled = false;
25505
+ if (parsed.options.default === "true") update.isDefault = true;
25506
+ if (parsed.options["no-default"] === "true") update.isDefault = false;
25507
+ if (Object.keys(update).length === 0) throw new Error("No preset updates provided");
25508
+ return update;
25509
+ }
25510
+ function authHeaders(ctx) {
25511
+ return {
25512
+ "Authorization": `Bearer ${ctx.accessToken}`,
25513
+ "Accept": "application/json"
25514
+ };
25515
+ }
25516
+ function hasReferenceOptions(parsed) {
25517
+ return [
25518
+ "refs",
25519
+ "ref",
25520
+ "assets",
25521
+ "asset",
25522
+ "variants",
25523
+ "variant"
25524
+ ].some((key) => Boolean(readRawOption(parsed, key)));
25525
+ }
25526
+ function parseCsvOptions(parsed, keys) {
25527
+ return keys.flatMap((key) => parseCsv(readRawOption(parsed, key)));
25528
+ }
25529
+ function parseCsv(value) {
25530
+ if (!value || value === "true") return [];
25531
+ return value.split(",").map((item) => item.trim()).filter(Boolean);
25532
+ }
25533
+ function readRequiredOption(parsed, kebabName, camelName) {
25534
+ const value = readOption(parsed, kebabName, camelName);
25535
+ if (value === void 0) throw new Error(`--${kebabName} is required`);
25536
+ return value;
25537
+ }
25538
+ function readOption(parsed, kebabName, camelName) {
25539
+ const value = readRawOption(parsed, kebabName) ?? readRawOption(parsed, camelName);
25540
+ return !value || value === "true" ? void 0 : value;
25541
+ }
25542
+ function readRawOption(parsed, key) {
25543
+ return parsed.options[key];
25544
+ }
25545
+ function nullableOption(parsed, kebabName, camelName) {
25546
+ if (parsed.options["no-collection"] === "true" && (kebabName === "collection" || camelName === "collectionId")) return null;
25547
+ const value = readOption(parsed, kebabName, camelName);
25548
+ if (value === void 0) return void 0;
25549
+ return value === "null" || value === "-" ? null : value;
25550
+ }
25551
+ function isEnabled(value) {
25552
+ return value === true || value === 1;
25553
+ }
25554
+ function printReferences(references, print) {
25555
+ if (references.length === 0) {
25556
+ print("No style reference assets found.");
25557
+ return;
25558
+ }
25559
+ print(`Found ${references.length} style reference asset(s):\n`);
25560
+ print("Collection".padEnd(28) + "Subject".padEnd(10) + "Asset".padEnd(28) + "Variant".padEnd(28) + "Item");
25561
+ print("-".repeat(108));
25562
+ for (const reference of references) {
25563
+ const item = reference.item;
25564
+ print(truncate(reference.collectionName, 26).padEnd(28) + item.subject_type.padEnd(10) + truncate(item.asset_id || "-", 26).padEnd(28) + truncate(item.pinned_variant_id || item.variant_id || "-", 26).padEnd(28) + truncate(item.id, 26));
25565
+ }
25566
+ }
25567
+ function printCollections(collections, print) {
25568
+ if (collections.length === 0) {
25569
+ print("No style reference collections found.");
25570
+ return;
25571
+ }
25572
+ print(`Found ${collections.length} style reference collection(s):\n`);
25573
+ print("References".padEnd(12) + "Presets".padEnd(10) + "Collection".padEnd(34) + "Name");
25574
+ print("-".repeat(88));
25575
+ for (const collection of collections) print(String(collection.reference_count).padEnd(12) + String(collection.preset_count).padEnd(10) + truncate(collection.id, 32).padEnd(34) + truncate(collection.name, 40));
25576
+ }
25577
+ function printPresets(presets, print) {
25578
+ if (presets.length === 0) {
25579
+ print("No style presets found.");
25580
+ return;
25581
+ }
25582
+ print(`Found ${presets.length} style preset(s):\n`);
25583
+ print("State".padEnd(14) + "References".padEnd(12) + "Preset".padEnd(30) + "Collection".padEnd(28) + "Name");
25584
+ print("-".repeat(104));
25585
+ for (const preset of presets) print(truncate(`${isEnabled(preset.enabled) ? "enabled" : "disabled"}${isEnabled(preset.is_default) ? ",default" : ""}`, 12).padEnd(14) + String(preset.reference_count).padEnd(12) + truncate(preset.id, 28).padEnd(30) + truncate(preset.collection_name || preset.collection_id || "-", 26).padEnd(28) + truncate(preset.name, 34));
25586
+ }
25587
+ function printCollectionMutation(verb, collection, items, print, asJson) {
25588
+ if (asJson) {
25589
+ print(JSON.stringify({
25590
+ collection,
25591
+ items
25592
+ }, null, 2));
25593
+ return;
25594
+ }
25595
+ print(`${verb} style reference collection ${collection.id}`);
25596
+ print(` Name: ${collection.name}`);
25597
+ if (items) print(` References: ${items.filter((item) => item.role === "style_ref").length}`);
25598
+ }
25599
+ function printPresetMutation(verb, preset, print, asJson) {
25600
+ if (asJson) {
25601
+ print(JSON.stringify(preset, null, 2));
25602
+ return;
25603
+ }
25604
+ print(`${verb} style preset ${preset.id}`);
25605
+ print(` Name: ${preset.name}`);
25606
+ print(` Enabled: ${isEnabled(preset.enabled) ? "yes" : "no"}`);
25607
+ print(` Default: ${isEnabled(preset.is_default) ? "yes" : "no"}`);
25608
+ print(` Collection: ${preset.collection_name || preset.collection_id || "-"}`);
25609
+ print(` References: ${preset.reference_count}`);
25610
+ }
25611
+ function printUsage$2() {
25612
+ console.log(`
25613
+ Usage:
25614
+ makefx styles references [--collection <id-or-name>] [--json]
25615
+ makefx styles collections list [--json]
25616
+ makefx styles collections create <name> --refs <asset_or_variant,...>
25617
+ makefx styles collections update <collection-id> [--name <name>] [--refs <asset_or_variant,...>] [--append]
25618
+ makefx styles presets list [--json]
25619
+ makefx styles presets create <name> --collection <collection-id> --prompt "style prompt" [--default]
25620
+ makefx styles presets update <preset-id> [--name <name>] [--collection <collection-id>] [--prompt "style prompt"]
25621
+ makefx styles presets enable <preset-id>
25622
+ makefx styles presets disable <preset-id>
25623
+ makefx styles presets delete <preset-id>
25624
+
25625
+ Options:
25626
+ --space <id> Target space ID; defaults from the initialized project
25627
+ --refs <ids> Comma-separated asset IDs or variant IDs to use as style references
25628
+ --assets <ids> Comma-separated asset IDs; active variants are pinned
25629
+ --variants <ids> Comma-separated variant IDs
25630
+ --json Print machine-readable output
25631
+ --env <env> Environment (production|stage|local)
25632
+ --local Shortcut for --env local
25633
+ `);
25634
+ }
25635
+ //#endregion
25636
+ //#region src/cli/commands/usage.ts
25637
+ var defaultDeps$2 = {
25638
+ loadConfig: loadStoredConfig,
25639
+ loadProjectConfig,
25640
+ resolveBaseUrl,
25641
+ fetch,
25642
+ print: console.log
25643
+ };
25644
+ async function handleUsage(parsed) {
25645
+ try {
25646
+ await executeUsage(parsed);
25647
+ } catch (error) {
25648
+ console.error("Error:", error instanceof Error ? error.message : error);
25649
+ printUsage$1();
25650
+ process$1.exitCode = 1;
25651
+ }
25652
+ }
25653
+ async function executeUsage(parsed, deps = defaultDeps$2) {
25654
+ const subcommand = parsed.positionals[0] || "summary";
25655
+ if (subcommand !== "summary") throw new Error(`Unknown usage command: ${subcommand}`);
25656
+ const summary = await fetchUsageSummary(await buildContext$2(parsed, deps), deps, {
25657
+ from: optionValue$2(parsed.options.from),
25658
+ to: optionValue$2(parsed.options.to)
25659
+ });
25660
+ if (parsed.options.json === "true") deps.print(JSON.stringify(summary, null, 2));
25661
+ else printUsageSummary(summary, deps.print);
25662
+ return {
25663
+ type: "summary",
25664
+ summary
25665
+ };
25666
+ }
25667
+ async function buildContext$2(parsed, deps) {
25668
+ const projectConfig = await deps.loadProjectConfig();
25669
+ const env = resolveCommandEnvironment(parsed, projectConfig);
25670
+ const spaceId = resolveCommandSpace(parsed, projectConfig);
25671
+ if (!spaceId) throw new Error("--space is required, or run: makefx init --space <id>");
25672
+ const config = await deps.loadConfig(env);
25673
+ if (!config) throw new Error(`Not logged in to ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
25674
+ if (config.token.expiresAt < Date.now()) throw new Error(`Token expired for ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
25675
+ if (env === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
25676
+ return {
25677
+ env,
25678
+ spaceId,
25679
+ baseUrl: deps.resolveBaseUrl(env),
25680
+ accessToken: config.token.accessToken
25681
+ };
25682
+ }
25683
+ async function fetchUsageSummary(ctx, deps, options) {
25684
+ const params = new URLSearchParams();
25685
+ if (options.from) params.set("from", options.from);
25686
+ if (options.to) params.set("to", options.to);
25687
+ const query = params.toString();
25688
+ const response = await deps.fetch(`${ctx.baseUrl}/api/spaces/${encodeURIComponent(ctx.spaceId)}/usage/summary${query ? `?${query}` : ""}`, { headers: {
25689
+ "Authorization": `Bearer ${ctx.accessToken}`,
25690
+ "Accept": "application/json"
25691
+ } });
25692
+ if (!response.ok) {
25693
+ const text = await response.text();
25694
+ throw new Error(`Request failed (${response.status}): ${text || response.statusText}`);
25695
+ }
25696
+ return response.json();
25697
+ }
25698
+ function optionValue$2(value) {
25699
+ return !value || value === "true" ? void 0 : value;
25700
+ }
25701
+ function printUsageSummary(summary, print) {
25702
+ print(`\nUsage summary for ${summary.spaceId}\n`);
25703
+ print(` Period: ${formatPeriod$1(summary.period)}`);
25704
+ print(` Storage: ${formatBytes(summary.totals.storageBytes)}`);
25705
+ print(` Workflow runs: ${summary.totals.workflowRuns}`);
25706
+ print(` Delivery: ${formatBytes(summary.totals.deliveryBytes)}`);
25707
+ if (summary.byMediaKind.length > 0) {
25708
+ print("\nBy media kind:");
25709
+ print("Media".padEnd(10) + "Storage".padEnd(14) + "Workflows".padEnd(12) + "Delivery".padEnd(14) + "Events");
25710
+ print("-".repeat(58));
25711
+ for (const row of summary.byMediaKind) print((row.mediaKind || "-").padEnd(10) + formatBytes(row.storageBytes).padEnd(14) + String(row.workflowRuns).padEnd(12) + formatBytes(row.deliveryBytes).padEnd(14) + String(row.events));
25712
+ }
25713
+ }
25714
+ function formatPeriod$1(period) {
25715
+ if (!period.from && !period.to) return "all time";
25716
+ if (period.from && period.to) return `${period.from} to ${period.to}`;
25717
+ if (period.from) return `from ${period.from}`;
25718
+ return `through ${period.to}`;
25719
+ }
25720
+ function formatBytes(bytes) {
25721
+ const sign = bytes < 0 ? "-" : "";
25722
+ let value = Math.abs(bytes);
25723
+ const units = [
25724
+ "B",
25725
+ "KiB",
25726
+ "MiB",
25727
+ "GiB",
25728
+ "TiB"
25729
+ ];
25730
+ let unitIndex = 0;
25731
+ while (value >= 1024 && unitIndex < units.length - 1) {
25732
+ value /= 1024;
25733
+ unitIndex += 1;
25734
+ }
25735
+ return `${sign}${unitIndex === 0 ? String(value) : value.toFixed(value >= 10 ? 1 : 2)} ${units[unitIndex]}`;
25736
+ }
25737
+ function printUsage$1() {
25738
+ console.log(`
25739
+ Usage:
25740
+ makefx usage [summary] [--space <id>] [--from <date>] [--to <date>]
25741
+ makefx usage --json
25742
+
25743
+ Options:
25744
+ --space <id> Target space ID; defaults from the initialized project
25745
+ --from <date> Include usage at or after this date or ISO timestamp
25746
+ --to <date> Include usage at or before this date or ISO timestamp
25747
+ --json Print machine-readable output
25748
+ --env <env> Environment (production|stage|local)
25749
+ --local Shortcut for --env local
25750
+ `);
25751
+ }
25752
+ //#endregion
25753
+ //#region src/cli/commands/spend.ts
25754
+ var defaultDeps$1 = {
25755
+ loadConfig: loadStoredConfig,
25756
+ loadProjectConfig,
25757
+ resolveBaseUrl,
25758
+ fetch,
25759
+ print: console.log
25760
+ };
25761
+ async function handleSpend(parsed) {
25762
+ try {
25763
+ await executeSpend(parsed);
25764
+ } catch (error) {
25765
+ console.error("Error:", error instanceof Error ? error.message : error);
25766
+ printSpend();
25767
+ process$1.exitCode = 1;
25768
+ }
25769
+ }
25770
+ async function executeSpend(parsed, deps = defaultDeps$1) {
25771
+ const subcommand = parsed.positionals[0] || "summary";
25772
+ if (subcommand !== "summary") throw new Error(`Unknown spend command: ${subcommand}`);
25773
+ const summary = await fetchSpendSummary(await buildContext$1(parsed, deps), deps, {
25774
+ from: optionValue$1(parsed.options.from),
25775
+ to: optionValue$1(parsed.options.to),
25776
+ userId: optionValue$1(parsed.options["user-id"] ?? parsed.options.userId),
25777
+ spaceId: optionValue$1(parsed.options["space-id"] ?? parsed.options.spaceId ?? parsed.options.space),
25778
+ provider: optionValue$1(parsed.options.provider),
25779
+ mediaKind: optionValue$1(parsed.options["media-kind"] ?? parsed.options.mediaKind)
25780
+ });
25781
+ if (parsed.options.json === "true") deps.print(JSON.stringify(summary, null, 2));
25782
+ else printSpendSummary(summary, deps.print);
25783
+ return {
25784
+ type: "summary",
25785
+ summary
25786
+ };
25787
+ }
25788
+ async function buildContext$1(parsed, deps) {
25789
+ const env = resolveCommandEnvironment(parsed, await deps.loadProjectConfig());
25790
+ const config = await deps.loadConfig(env);
25791
+ if (!config) throw new Error(`Not logged in to ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
25792
+ if (config.token.expiresAt < Date.now()) throw new Error(`Token expired for ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
25793
+ if (env === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
25794
+ return {
25795
+ env,
25796
+ baseUrl: deps.resolveBaseUrl(env),
25797
+ accessToken: config.token.accessToken
25798
+ };
25799
+ }
25800
+ async function fetchSpendSummary(ctx, deps, options) {
25801
+ const params = new URLSearchParams();
25802
+ if (options.from) params.set("from", options.from);
25803
+ if (options.to) params.set("to", options.to);
25804
+ if (options.userId) params.set("user_id", options.userId);
25805
+ if (options.spaceId) params.set("space_id", options.spaceId);
25806
+ if (options.provider) params.set("provider", options.provider);
25807
+ if (options.mediaKind) params.set("media_kind", options.mediaKind);
25808
+ const query = params.toString();
25809
+ const response = await deps.fetch(`${ctx.baseUrl}/api/billing/spend/summary${query ? `?${query}` : ""}`, { headers: {
25810
+ "Authorization": `Bearer ${ctx.accessToken}`,
25811
+ "Accept": "application/json"
25812
+ } });
25813
+ if (!response.ok) {
25814
+ const text = await response.text();
25815
+ throw new Error(`Request failed (${response.status}): ${text || response.statusText}`);
25816
+ }
25817
+ return response.json();
25818
+ }
25819
+ function optionValue$1(value) {
25820
+ return !value || value === "true" ? void 0 : value;
25821
+ }
25822
+ function printSpendSummary(summary, print) {
25823
+ print("\nProvider cost summary\n");
25824
+ print(` Period: ${formatPeriod(summary.period)}`);
25825
+ print(` Filters: ${formatFilters(summary.filters)}`);
25826
+ print(` Provider cost: ${formatUsd(summary.totals.amountMicroUsd)}`);
25827
+ print(` Entries: ${summary.totals.entries}`);
25828
+ print(` Unpriced: ${summary.totals.unpricedEntries}`);
25829
+ print(` Quantity: ${formatNumber(summary.totals.quantity)}`);
25830
+ if (summary.byProvider.length > 0) printSpendTable("\nBy provider:", [
25831
+ "Provider",
25832
+ "Cost",
25833
+ "Entries",
25834
+ "Unpriced",
25835
+ "Quantity"
25836
+ ], summary.byProvider.map((row) => [
25837
+ row.provider,
25838
+ formatUsd(row.amountMicroUsd),
25839
+ String(row.entries),
25840
+ String(row.unpricedEntries),
25841
+ formatNumber(row.quantity)
25842
+ ]), print);
25843
+ if (summary.byModel.length > 0) printSpendTable("\nBy model:", [
25844
+ "Provider",
25845
+ "Model",
25846
+ "Cost",
25847
+ "Entries",
25848
+ "Unpriced"
25849
+ ], summary.byModel.map((row) => [
25850
+ row.provider,
25851
+ row.providerModel,
25852
+ formatUsd(row.amountMicroUsd),
25853
+ String(row.entries),
25854
+ String(row.unpricedEntries)
25855
+ ]), print);
25856
+ if (summary.byMediaKind.length > 0) printSpendTable("\nBy media kind:", [
25857
+ "Media",
25858
+ "Cost",
25859
+ "Entries",
25860
+ "Unpriced",
25861
+ "Quantity"
25862
+ ], summary.byMediaKind.map((row) => [
25863
+ row.mediaKind || "-",
25864
+ formatUsd(row.amountMicroUsd),
25865
+ String(row.entries),
25866
+ String(row.unpricedEntries),
25867
+ formatNumber(row.quantity)
25868
+ ]), print);
25869
+ if (summary.byMeterEventName.length > 0) printSpendTable("\nBy meter:", [
25870
+ "Meter",
25871
+ "Cost",
25872
+ "Entries",
25873
+ "Unpriced",
25874
+ "Quantity"
25875
+ ], summary.byMeterEventName.map((row) => [
25876
+ row.meterEventName || "-",
25877
+ formatUsd(row.amountMicroUsd),
25878
+ String(row.entries),
25879
+ String(row.unpricedEntries),
25880
+ formatNumber(row.quantity)
25881
+ ]), print);
25882
+ }
25883
+ function printSpendTable(title, headers, rows, print) {
25884
+ print(title);
25885
+ const widths = headers.map((header, index) => Math.max(header.length, ...rows.map((row) => row[index]?.length ?? 0)));
25886
+ print(headers.map((header, index) => header.padEnd(widths[index] + 2)).join("").trimEnd());
25887
+ print(widths.map((width) => "-".repeat(width)).join(" "));
25888
+ for (const row of rows) print(row.map((value, index) => value.padEnd(widths[index] + 2)).join("").trimEnd());
25889
+ }
25890
+ function formatPeriod(period) {
25891
+ if (!period.from && !period.to) return "all time";
25892
+ if (period.from && period.to) return `${period.from} to ${period.to}`;
25893
+ if (period.from) return `from ${period.from}`;
25894
+ return `through ${period.to}`;
25895
+ }
25896
+ function formatFilters(filters) {
25897
+ const parts = [
25898
+ filters.userId !== null ? `user=${filters.userId}` : null,
25899
+ filters.spaceId ? `space=${filters.spaceId}` : null,
25900
+ filters.provider ? `provider=${filters.provider}` : null,
25901
+ filters.mediaKind ? `media=${filters.mediaKind}` : null
25902
+ ].filter((part) => part !== null);
25903
+ return parts.length > 0 ? parts.join(", ") : "none";
25904
+ }
25905
+ function formatUsd(amountMicroUsd) {
25906
+ let trimmed = (amountMicroUsd / 1e6).toFixed(6).replace(/0+$/, "").replace(/\.$/, "");
25907
+ if (!trimmed.includes(".")) trimmed = `${trimmed}.00`;
25908
+ else if (trimmed.split(".")[1].length === 1) trimmed = `${trimmed}0`;
25909
+ return `$${trimmed}`;
25910
+ }
25911
+ function formatNumber(value) {
25912
+ return Number.isInteger(value) ? String(value) : value.toFixed(3).replace(/0+$/, "").replace(/\.$/, "");
25913
+ }
25914
+ function printSpend() {
25915
+ console.log(`
25916
+ Usage:
25917
+ makefx spend [summary] [--from <date>] [--to <date>]
25918
+ makefx spend --user-id <id> --provider <name> --media-kind <image|audio|video>
25919
+ makefx spend --json
25920
+
25921
+ Options:
25922
+ --from <date> Include provider cost at or after this date or ISO timestamp
25923
+ --to <date> Include provider cost at or before this date or ISO timestamp
25924
+ --user-id <id> Filter to one user ID
25925
+ --space-id <id> Filter to one space ID
25926
+ --space <id> Alias for --space-id
25927
+ --provider <name> Filter to one provider
25928
+ --media-kind <kind> Filter to image, audio, or video provider cost
25929
+ --json Print machine-readable output
25930
+ --env <env> Environment (production|stage|local)
25931
+ --local Shortcut for --env local
25932
+ `);
25933
+ }
25934
+ //#endregion
25935
+ //#region src/shared/featureFlags.ts
25936
+ var TRUE_VALUES = new Set([
25937
+ "1",
25938
+ "true",
25939
+ "yes",
25940
+ "on"
25941
+ ]);
25942
+ var ROTATION_FEATURE_FLAG = "MAKEFX_ROTATION_ENABLED";
25943
+ function isFeatureFlagEnabled(value) {
25944
+ if (typeof value === "boolean") return value;
25945
+ if (typeof value === "number") return value === 1;
25946
+ if (typeof value !== "string") return false;
25947
+ return TRUE_VALUES.has(value.trim().toLowerCase());
25948
+ }
25949
+ //#endregion
25950
+ //#region src/cli/lib/feature-flags.ts
25951
+ function isCliRotationEnabled(env = process.env) {
25952
+ return isFeatureFlagEnabled(env[ROTATION_FEATURE_FLAG]);
25953
+ }
25954
+ function rotationDisabledMessage() {
25955
+ return `Rotation features are disabled. Set ${ROTATION_FEATURE_FLAG}=true to enable this experimental surface.`;
25956
+ }
25957
+ //#endregion
23330
25958
  //#region src/cli/commands/pipelines.ts
23331
25959
  var ROTATION_CONFIGS = [
23332
25960
  "4-directional",
@@ -23345,6 +25973,7 @@ var defaultDeps = {
23345
25973
  loadProjectConfig,
23346
25974
  resolveBaseUrl,
23347
25975
  createClient: (env, spaceId) => WebSocketClient.create(env, spaceId),
25976
+ isRotationEnabled: isCliRotationEnabled,
23348
25977
  print: console.log
23349
25978
  };
23350
25979
  async function handleRotation(parsed) {
@@ -23358,12 +25987,15 @@ async function handlePipelineCommand(command, parsed) {
23358
25987
  const result = await executePipelineCommand(command, parsed, defaultDeps);
23359
25988
  if ("status" in result && (result.status === "failed" || result.status === "cancelled")) process$1.exitCode = 1;
23360
25989
  } catch (error) {
23361
- console.error("Error:", error instanceof Error ? error.message : error);
23362
- printUsage(command);
25990
+ const message = error instanceof Error ? error.message : String(error);
25991
+ console.error("Error:", message);
25992
+ if (message !== rotationDisabledMessage()) printUsage(command);
23363
25993
  process$1.exitCode = 1;
23364
25994
  }
23365
25995
  }
23366
25996
  async function executePipelineCommand(command, parsed, deps = defaultDeps) {
25997
+ const rotationEnabled = deps.isRotationEnabled ?? isCliRotationEnabled;
25998
+ if (command === "rotation" && !rotationEnabled()) throw new Error(rotationDisabledMessage());
23367
25999
  const ctx = await buildContext(parsed, deps);
23368
26000
  const client = await deps.createClient(ctx.env, ctx.spaceId);
23369
26001
  try {
@@ -23565,6 +26197,10 @@ function printJsonOrText(json, result, text, deps) {
23565
26197
  }
23566
26198
  function printUsage(command) {
23567
26199
  if (command === "rotation") {
26200
+ if (!isCliRotationEnabled()) {
26201
+ console.log(rotationDisabledMessage());
26202
+ return;
26203
+ }
23568
26204
  console.log(`
23569
26205
  Usage:
23570
26206
  makefx rotation --variant <variant-id> [--config 4-directional|8-directional|turnaround]
@@ -23577,7 +26213,7 @@ Options:
23577
26213
  --subject <text> Optional subject description for consistency prompts
23578
26214
  --aspect <ratio> Optional generation aspect ratio
23579
26215
  --mode <mode> sequential or single-shot (default: sequential)
23580
- --no-style Disable the space style anchor
26216
+ --no-style Disable style preset injection for this pipeline
23581
26217
  --detach Return after the pipeline starts instead of waiting for completion
23582
26218
  --timeout <sec> Override the pipeline wait timeout
23583
26219
  --json Print machine-readable output
@@ -23599,7 +26235,7 @@ Options:
23599
26235
  --seed-variant <id> Optional completed image variant to place at the center (sequential mode only)
23600
26236
  --aspect <ratio> Optional generation aspect ratio
23601
26237
  --mode <mode> sequential or single-shot (default: sequential)
23602
- --no-style Disable the space style anchor
26238
+ --no-style Disable style preset injection for this pipeline
23603
26239
  --detach Return after the pipeline starts instead of waiting for completion
23604
26240
  --timeout <sec> Override the pipeline wait timeout
23605
26241
  --json Print machine-readable output
@@ -23607,7 +26243,7 @@ Options:
23607
26243
  }
23608
26244
  //#endregion
23609
26245
  //#region src/cli/index.ts
23610
- var CLI_VERSION = "0.1.2+2907a84228d9";
26246
+ var CLI_VERSION = "0.2.0+a98a786097bf";
23611
26247
  async function main() {
23612
26248
  const argv = process$1.argv.slice(2);
23613
26249
  if (argv[0] === "--") argv.shift();
@@ -23716,6 +26352,9 @@ function printCommandHelp(command, positionals) {
23716
26352
  case "upload":
23717
26353
  printUploadHelp();
23718
26354
  return;
26355
+ case "import":
26356
+ printImportHelp();
26357
+ return;
23719
26358
  case "generate":
23720
26359
  case "refine":
23721
26360
  case "derive":
@@ -23734,10 +26373,20 @@ function printCommandHelp(command, positionals) {
23734
26373
  case "assets":
23735
26374
  printAssetsHelp();
23736
26375
  return;
26376
+ case "usage":
26377
+ printUsageHelp();
26378
+ return;
26379
+ case "spend":
26380
+ printSpendHelp();
26381
+ return;
23737
26382
  case "variants":
23738
26383
  case "variant":
23739
26384
  printVariantsHelp();
23740
26385
  return;
26386
+ case "styles":
26387
+ case "style":
26388
+ printStylesHelp();
26389
+ return;
23741
26390
  case "rotation":
23742
26391
  printRotationHelp();
23743
26392
  return;
@@ -23756,6 +26405,11 @@ function printCommandHelp(command, positionals) {
23756
26405
  }
23757
26406
  }
23758
26407
  function printHelp() {
26408
+ const rotationHelp = isCliRotationEnabled() ? ` rotation --variant <variant-id>
26409
+ Generate rotation views from a completed image variant
26410
+ rotation cancel <rotation-set-id>
26411
+ Cancel an active rotation pipeline` : "";
26412
+ const rotationExample = isCliRotationEnabled() ? " makefx rotation --variant variant_456 --config 8-directional\n" : "";
23759
26413
  console.log(`
23760
26414
  Make Effects CLI
23761
26415
 
@@ -23783,10 +26437,10 @@ Project:
23783
26437
  variants star <variant-id> Star a variant (unstar to clear)
23784
26438
  variants rate <variant-id> approved|rejected
23785
26439
  Rate a variant for quality curation
23786
- rotation --variant <variant-id>
23787
- Generate rotation views from a completed image variant
23788
- rotation cancel <rotation-set-id>
23789
- Cancel an active rotation pipeline
26440
+ styles presets List style presets
26441
+ styles collections List style reference collections
26442
+ styles references List style reference assets
26443
+ ${rotationHelp}
23790
26444
  tileset "prompt" --type terrain --grid 3x3
23791
26445
  Generate a consistent tile set
23792
26446
  tileset cancel <tile-set-id> Cancel an active tile-set pipeline
@@ -23794,12 +26448,14 @@ Project:
23794
26448
  List Space-backed production placements
23795
26449
  productions export --production-id <id>
23796
26450
  Export production scene args from Space records
26451
+ usage [summary] [--space <id>] Show platform storage and workflow consumption
26452
+ spend [summary] Show admin provider cost summary
23797
26453
 
23798
26454
  Billing (Polar.sh):
23799
26455
  billing status Show sync status (pending, failed, synced events)
23800
26456
  billing check Run operational checks for workers, meters, and sync health
23801
26457
  billing reconcile --user-id <id>
23802
- Compare local billable usage with Polar usage
26458
+ Reconcile Polar, charge, provider, and platform usage
23803
26459
  billing retry-failed Retry all failed events
23804
26460
 
23805
26461
  Spaces:
@@ -23816,6 +26472,7 @@ Listen:
23816
26472
  Upload:
23817
26473
  upload <file> --asset <id> [--space <id>] Upload image, audio, or video to existing asset
23818
26474
  upload <file> --name <name> [--space <id>] Upload media and create new asset
26475
+ import <manifest.json> [--space <id>] Import media with provenance, lineage, and organization metadata
23819
26476
 
23820
26477
  Forge:
23821
26478
  generate "prompt" --name <name> --type <type> -o <file>
@@ -23832,10 +26489,10 @@ Audio:
23832
26489
  audio sfx generate "prompt" --name <name> -o <file>
23833
26490
 
23834
26491
  Video:
23835
- video generate "prompt" --name <name> --type <type> -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio|--no-audio]
26492
+ video generate "prompt" --name <name> --type <type> -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio]
23836
26493
  video generate --follow <variant_id> -o <file>
23837
- video refine --variant <variant_id> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio|--no-audio]
23838
- video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio|--no-audio]
26494
+ video refine --variant <variant_id> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio]
26495
+ video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio]
23839
26496
 
23840
26497
  Options:
23841
26498
  --env <environment> Target environment (production|stage|local), default: production
@@ -23857,14 +26514,20 @@ Examples:
23857
26514
  makefx audio sfx generate "A short brass victory sting" --name "Victory Sting" -o victory.wav
23858
26515
  makefx video generate "A looping idle animation" --name "Idle Animation" --type animation --duration 6 --resolution 1080p --tier fast -o idle.mp4
23859
26516
  makefx productions export --production-id s01e01-a2
26517
+ makefx import import-manifest.json --dry-run --json
26518
+ makefx import external-renders.json --space space_123
23860
26519
  makefx assets
26520
+ makefx usage --from 2026-06-01
26521
+ makefx spend --from 2026-06-01 --provider gemini
23861
26522
  makefx assets download variant_123 -o variant.mp4
23862
26523
  makefx assets rename asset_123 "Hero (moving)"
23863
26524
  makefx assets set-active asset_123 variant_456
23864
26525
  makefx variants retry variant_456
23865
26526
  makefx variants delete variant_456
23866
- makefx rotation --variant variant_456 --config 8-directional
23867
- makefx tileset "grass and stone path tiles" --type terrain --grid 3x3
26527
+ makefx styles collections create "Painterly refs" --refs asset_123,variant_456
26528
+ makefx styles presets create "Painterly" --collection collection_123 --prompt "Painterly adventure game" --default
26529
+ makefx generate "A market background" --style-preset Painterly --name "Market" --type scene -o market.png
26530
+ ${rotationExample} makefx tileset "grass and stone path tiles" --type terrain --grid 3x3
23868
26531
  `);
23869
26532
  }
23870
26533
  function printInitHelp() {
@@ -23899,7 +26562,7 @@ Usage:
23899
26562
  Subcommands:
23900
26563
  status Show sync status (pending, failed, synced events)
23901
26564
  check Run operational checks for workers, Polar meters, and sync health
23902
- reconcile Compare local billable usage with Polar usage for one user
26565
+ reconcile Reconcile Polar, charge, provider, and platform usage for one user
23903
26566
  retry-failed Reset failed events for retry (next cron will sync them)
23904
26567
 
23905
26568
  Options:
@@ -23937,11 +26600,35 @@ Options:
23937
26600
  --name <name> New asset name (creates asset + variant)
23938
26601
  --type <type> Asset type for new assets (default: character)
23939
26602
  --media-kind <k> Optional explicit kind: image, audio, or video
23940
- --parent <id> Parent asset ID for new assets
23941
26603
  --env <env> Environment (production|stage|local)
23942
26604
  --local Shortcut for --env local
23943
26605
  `);
23944
26606
  }
26607
+ function printImportHelp() {
26608
+ console.log(`
26609
+ Usage:
26610
+ makefx import <manifest.json> [--space <id>]
26611
+ makefx import <manifest.json> --dry-run [--json]
26612
+
26613
+ Options:
26614
+ --space <id> Target space ID; defaults from initialized project
26615
+ --dry-run Validate manifest, files, targets, membership, lineage, and organization references
26616
+ --json Print machine-readable import or dry-run output
26617
+ --env <env> Environment (production|stage|local)
26618
+ --local Shortcut for --env local
26619
+
26620
+ Manifest:
26621
+ Records import files with prompt, model, provider, providerMetadata, and
26622
+ generationProvenance. Lineage entries record immutable source provenance using
26623
+ sourceFile or sourceVariantId; use collections, relations, and compositions
26624
+ for editable organization metadata. Style references are normal assets grouped
26625
+ into collections and selected through style presets.
26626
+
26627
+ Examples:
26628
+ makefx import external-renders.json --dry-run --json
26629
+ makefx import external-renders.json --space space_123
26630
+ `);
26631
+ }
23945
26632
  function printForgeHelp(command) {
23946
26633
  if (command === "generate") {
23947
26634
  console.log(`
@@ -23951,6 +26638,10 @@ Usage:
23951
26638
 
23952
26639
  ${imageCapabilityHelp()}
23953
26640
 
26641
+ Style:
26642
+ --style-preset <id-or-name> Use an enabled style preset for this generation
26643
+ --no-style Disable style preset injection for this generation
26644
+
23954
26645
  Production metadata:
23955
26646
  --scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
23956
26647
  --shot-id <id> --production-id <id>
@@ -23965,6 +26656,10 @@ Usage:
23965
26656
 
23966
26657
  ${imageCapabilityHelp()}
23967
26658
 
26659
+ Style:
26660
+ --style-preset <id-or-name> Use an enabled style preset for this refinement
26661
+ --no-style Disable style preset injection for this refinement
26662
+
23968
26663
  Production metadata:
23969
26664
  --scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
23970
26665
  --shot-id <id> --production-id <id>
@@ -23977,6 +26672,10 @@ Usage:
23977
26672
  makefx batch "prompt" --name <name> --type <type> --count <2-8> --output-dir <dir> [--model ${optionValues(IMAGE_MODEL_SELECTIONS)}] [--size ${imageSizeValues()}] [--aspect <ratio>]
23978
26673
 
23979
26674
  ${imageCapabilityHelp()}
26675
+
26676
+ Style:
26677
+ --style-preset <id-or-name> Use an enabled style preset for this batch
26678
+ --no-style Disable style preset injection for this batch
23980
26679
  `);
23981
26680
  return;
23982
26681
  }
@@ -23987,6 +26686,10 @@ Usage:
23987
26686
 
23988
26687
  ${imageCapabilityHelp()}
23989
26688
 
26689
+ Style:
26690
+ --style-preset <id-or-name> Use an enabled style preset for this derivation
26691
+ --no-style Disable style preset injection for this derivation
26692
+
23990
26693
  Production metadata:
23991
26694
  --scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
23992
26695
  --shot-id <id> --production-id <id>
@@ -24084,13 +26787,13 @@ function printVideoHelp(positionals) {
24084
26787
  if (subcommand === "generate") {
24085
26788
  console.log(`
24086
26789
  Usage:
24087
- makefx video generate "prompt" --name <name> --type <type> -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio|--no-audio] [--space <id>]
26790
+ makefx video generate "prompt" --name <name> --type <type> -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
24088
26791
  makefx video generate --follow <variant_id> -o <file> [--space <id>]
24089
26792
 
24090
26793
  ${videoCapabilityHelp()}
24091
26794
 
24092
26795
  Audio:
24093
- Video defaults to generated audio. Use --no-audio to record a silent-video request and add a silent-video instruction.
26796
+ Video defaults to generated audio. Current Veo models do not support --no-audio; the CLI rejects it before creating a job.
24094
26797
 
24095
26798
  Production metadata:
24096
26799
  --scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
@@ -24101,13 +26804,13 @@ Production metadata:
24101
26804
  if (subcommand === "refine") {
24102
26805
  console.log(`
24103
26806
  Usage:
24104
- makefx video refine --variant <variant_id> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio|--no-audio] [--space <id>]
26807
+ makefx video refine --variant <variant_id> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
24105
26808
  makefx video refine --follow <variant_id> -o <file> [--space <id>]
24106
26809
 
24107
26810
  ${videoCapabilityHelp()}
24108
26811
 
24109
26812
  Audio:
24110
- Video defaults to generated audio. Use --no-audio to record a silent-video request and add a silent-video instruction.
26813
+ Video defaults to generated audio. Current Veo models do not support --no-audio; the CLI rejects it before creating a job.
24111
26814
 
24112
26815
  Production metadata:
24113
26816
  --scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
@@ -24118,13 +26821,13 @@ Production metadata:
24118
26821
  if (subcommand === "derive") {
24119
26822
  console.log(`
24120
26823
  Usage:
24121
- makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio|--no-audio] [--space <id>]
26824
+ makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
24122
26825
  makefx video derive --follow <variant_id> -o <file> [--space <id>]
24123
26826
 
24124
26827
  ${videoCapabilityHelp()}
24125
26828
 
24126
26829
  Audio:
24127
- Video defaults to generated audio. Use --no-audio to record a silent-video request and add a silent-video instruction.
26830
+ Video defaults to generated audio. Current Veo models do not support --no-audio; the CLI rejects it before creating a job.
24128
26831
 
24129
26832
  Production metadata:
24130
26833
  --scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
@@ -24134,15 +26837,15 @@ Production metadata:
24134
26837
  }
24135
26838
  console.log(`
24136
26839
  Usage:
24137
- makefx video generate "prompt" --name <name> --type <type> -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio|--no-audio] [--space <id>]
26840
+ makefx video generate "prompt" --name <name> --type <type> -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
24138
26841
  makefx video generate --follow <variant_id> -o <file> [--space <id>]
24139
- makefx video refine --variant <variant_id> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio|--no-audio] [--space <id>]
24140
- makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio|--no-audio] [--space <id>]
26842
+ makefx video refine --variant <variant_id> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
26843
+ makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
24141
26844
 
24142
26845
  ${videoCapabilityHelp()}
24143
26846
 
24144
26847
  Audio:
24145
- Video defaults to generated audio. Use --no-audio to record a silent-video request and add a silent-video instruction.
26848
+ Video defaults to generated audio. Current Veo models do not support --no-audio; the CLI rejects it before creating a job.
24146
26849
 
24147
26850
  Production metadata:
24148
26851
  --scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
@@ -24184,7 +26887,43 @@ Options:
24184
26887
  --local Shortcut for --env local
24185
26888
  `);
24186
26889
  }
26890
+ function printStylesHelp() {
26891
+ console.log(`
26892
+ Usage:
26893
+ makefx styles references [--collection <id-or-name>] [--json]
26894
+ makefx styles collections list [--json]
26895
+ makefx styles collections create <name> --refs <asset_or_variant,...>
26896
+ makefx styles collections update <collection-id> [--name <name>] [--refs <asset_or_variant,...>] [--append]
26897
+ makefx styles presets list [--json]
26898
+ makefx styles presets create <name> --collection <collection-id> --prompt "style prompt" [--default]
26899
+ makefx styles presets update <preset-id> [--name <name>] [--collection <collection-id>] [--prompt "style prompt"]
26900
+ makefx styles presets enable <preset-id>
26901
+ makefx styles presets disable <preset-id>
26902
+ makefx styles presets delete <preset-id>
26903
+
26904
+ Generation:
26905
+ makefx generate "prompt" --style-preset <id-or-name> --name <name> --type <type> -o <file>
26906
+ makefx generate "prompt" --no-style --name <name> --type <type> -o <file>
26907
+
26908
+ Model:
26909
+ Style references are normal Space assets or exact variants grouped into style
26910
+ collections. Style presets point to those collections plus a style prompt.
26911
+
26912
+ Options:
26913
+ --space <id> Target space ID; defaults from the initialized project
26914
+ --refs <ids> Comma-separated asset IDs or variant IDs to use as style references
26915
+ --assets <ids> Comma-separated asset IDs; active variants are pinned
26916
+ --variants <ids> Comma-separated variant IDs
26917
+ --json Print machine-readable output
26918
+ --env <env> Environment (production|stage|local)
26919
+ --local Shortcut for --env local
26920
+ `);
26921
+ }
24187
26922
  function printRotationHelp() {
26923
+ if (!isCliRotationEnabled()) {
26924
+ console.log(rotationDisabledMessage());
26925
+ return;
26926
+ }
24188
26927
  console.log(`
24189
26928
  Usage:
24190
26929
  makefx rotation --variant <variant-id> [--config 4-directional|8-directional|turnaround]
@@ -24197,7 +26936,7 @@ Options:
24197
26936
  --subject <text> Optional subject description for consistency prompts
24198
26937
  --aspect <ratio> Optional generation aspect ratio
24199
26938
  --mode <mode> sequential or single-shot (default: sequential)
24200
- --no-style Disable the space style anchor
26939
+ --no-style Disable style preset injection for this pipeline
24201
26940
  --detach Return after the pipeline starts instead of waiting for completion
24202
26941
  --timeout <sec> Override the pipeline wait timeout
24203
26942
  --json Print machine-readable output
@@ -24219,7 +26958,7 @@ Options:
24219
26958
  --seed-variant <id> Optional completed image variant to place at the center (sequential mode only)
24220
26959
  --aspect <ratio> Optional generation aspect ratio
24221
26960
  --mode <mode> sequential or single-shot (default: sequential)
24222
- --no-style Disable the space style anchor
26961
+ --no-style Disable style preset injection for this pipeline
24223
26962
  --detach Return after the pipeline starts instead of waiting for completion
24224
26963
  --timeout <sec> Override the pipeline wait timeout
24225
26964
  --json Print machine-readable output
@@ -24247,6 +26986,41 @@ Usage:
24247
26986
  makefx assets download <variant-id|legacy-image-key> -o output-file
24248
26987
  `);
24249
26988
  }
26989
+ function printUsageHelp() {
26990
+ console.log(`
26991
+ Usage:
26992
+ makefx usage [summary] [--space <id>] [--from <date>] [--to <date>]
26993
+ makefx usage --json
26994
+
26995
+ Options:
26996
+ --space <id> Target space ID; defaults from the initialized project
26997
+ --from <date> Include usage at or after this date or ISO timestamp
26998
+ --to <date> Include usage at or before this date or ISO timestamp
26999
+ --json Print machine-readable output
27000
+ --env <env> Environment (production|stage|local)
27001
+ --local Shortcut for --env local
27002
+ `);
27003
+ }
27004
+ function printSpendHelp() {
27005
+ console.log(`
27006
+ Usage:
27007
+ makefx spend [summary] [--from <date>] [--to <date>]
27008
+ makefx spend --user-id <id> --provider <name> --media-kind <image|audio|video>
27009
+ makefx spend --json
27010
+
27011
+ Options:
27012
+ --from <date> Include provider cost at or after this date or ISO timestamp
27013
+ --to <date> Include provider cost at or before this date or ISO timestamp
27014
+ --user-id <id> Filter to one user ID
27015
+ --space-id <id> Filter to one space ID
27016
+ --space <id> Alias for --space-id
27017
+ --provider <name> Filter to one provider
27018
+ --media-kind <kind> Filter to image, audio, or video provider cost
27019
+ --json Print machine-readable output
27020
+ --env <env> Environment (production|stage|local)
27021
+ --local Shortcut for --env local
27022
+ `);
27023
+ }
24250
27024
  async function dispatchCommand(command, parsed) {
24251
27025
  switch (command) {
24252
27026
  case "init":
@@ -24270,6 +27044,9 @@ async function dispatchCommand(command, parsed) {
24270
27044
  case "upload":
24271
27045
  await handleUpload(parsed);
24272
27046
  break;
27047
+ case "import":
27048
+ await handleImport(parsed);
27049
+ break;
24273
27050
  case "generate":
24274
27051
  await handleGenerate(parsed);
24275
27052
  break;
@@ -24294,10 +27071,20 @@ async function dispatchCommand(command, parsed) {
24294
27071
  case "assets":
24295
27072
  await handleAssets(parsed);
24296
27073
  break;
27074
+ case "usage":
27075
+ await handleUsage(parsed);
27076
+ break;
27077
+ case "spend":
27078
+ await handleSpend(parsed);
27079
+ break;
24297
27080
  case "variants":
24298
27081
  case "variant":
24299
27082
  await handleVariants(parsed);
24300
27083
  break;
27084
+ case "styles":
27085
+ case "style":
27086
+ await handleStyles(parsed);
27087
+ break;
24301
27088
  case "rotation":
24302
27089
  await handleRotation(parsed);
24303
27090
  break;