makefx 0.1.3 → 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 +2898 -130
  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,
@@ -21575,7 +23245,7 @@ function cliGenerationSupportsRefs(namespace) {
21575
23245
  //#endregion
21576
23246
  //#region src/cli/commands/forge.ts
21577
23247
  var CLI_GENERATION_MEDIA_KIND = getCliGenerationMediaKind("top-level");
21578
- var defaultDeps$6 = {
23248
+ var defaultDeps$9 = {
21579
23249
  loadConfig: loadStoredConfig,
21580
23250
  loadProjectConfig,
21581
23251
  resolveBaseUrl,
@@ -21585,6 +23255,7 @@ var defaultDeps$6 = {
21585
23255
  downloadFile,
21586
23256
  saveRunManifest,
21587
23257
  placeProductionRecord: placeProductionRecordForCli,
23258
+ fetch,
21588
23259
  createRunId,
21589
23260
  getWorkingDir: () => process$1.cwd(),
21590
23261
  fileExists: async (filePath) => {
@@ -21596,6 +23267,43 @@ var defaultDeps$6 = {
21596
23267
  }
21597
23268
  }
21598
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
+ }
21599
23307
  async function handleGenerate(parsed) {
21600
23308
  await handleForgeCommand("generate", parsed);
21601
23309
  }
@@ -21610,18 +23318,18 @@ async function handleBatch(parsed) {
21610
23318
  }
21611
23319
  async function handleForgeCommand(command, parsed) {
21612
23320
  try {
21613
- await executeForgeCommand(command, parsed, defaultDeps$6);
23321
+ await executeForgeCommand(command, parsed, defaultDeps$9);
21614
23322
  } catch (error) {
21615
23323
  console.error("Error:", error instanceof Error ? error.message : error);
21616
- printUsage$7(command);
23324
+ printUsage$9(command);
21617
23325
  process$1.exitCode = 1;
21618
23326
  }
21619
23327
  }
21620
- async function executeForgeCommand(command, parsed, deps = defaultDeps$6, options = {}) {
23328
+ async function executeForgeCommand(command, parsed, deps = defaultDeps$9, options = {}) {
21621
23329
  const mediaKind = options.mediaKind || CLI_GENERATION_MEDIA_KIND;
21622
23330
  if (parsed.options.follow) {
21623
23331
  if (command === "batch") throw new Error("--follow is only supported for single-output generation commands");
21624
- const ctx = await buildContext$3(parsed, deps);
23332
+ const ctx = await buildContext$6(parsed, deps);
21625
23333
  const client = await deps.createClient(ctx.env, ctx.spaceId);
21626
23334
  try {
21627
23335
  await client.connect();
@@ -21635,7 +23343,7 @@ async function executeForgeCommand(command, parsed, deps = defaultDeps$6, option
21635
23343
  validateVideoAudioOptions(parsed, mediaKind);
21636
23344
  parseVideoGenerationOptions(parsed, mediaKind);
21637
23345
  if (command !== "batch") validateProductionMetadataOptions(parsed);
21638
- const ctx = await buildContext$3(parsed, deps);
23346
+ const ctx = await buildContext$6(parsed, deps);
21639
23347
  const client = await deps.createClient(ctx.env, ctx.spaceId);
21640
23348
  try {
21641
23349
  await client.connect();
@@ -21649,7 +23357,7 @@ async function executeForgeCommand(command, parsed, deps = defaultDeps$6, option
21649
23357
  client.disconnect();
21650
23358
  }
21651
23359
  }
21652
- async function executeAudioCommand(command, parsed, deps = defaultDeps$6, options = {}) {
23360
+ async function executeAudioCommand(command, parsed, deps = defaultDeps$9, options = {}) {
21653
23361
  const audioProfile = getCliGenerationProfile("audio");
21654
23362
  if (!audioProfile.commands.includes(command)) throw new Error(`Audio generation does not support ${command}`);
21655
23363
  const modeEntry = options.mode ? getMediaOperationEntry(options.mode) : void 0;
@@ -21662,7 +23370,7 @@ async function executeAudioCommand(command, parsed, deps = defaultDeps$6, option
21662
23370
  audioMode: options.mode
21663
23371
  });
21664
23372
  }
21665
- async function executeVideoCommand(command, parsed, deps = defaultDeps$6) {
23373
+ async function executeVideoCommand(command, parsed, deps = defaultDeps$9) {
21666
23374
  const videoProfile = getCliGenerationProfile("video");
21667
23375
  if (!videoProfile.commands.includes(command)) throw new Error(`Video generation does not support ${command}`);
21668
23376
  return executeForgeCommand(command, parsed, deps, {
@@ -21708,6 +23416,20 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
21708
23416
  const imageOptions = parseImageGenerationOptions(parsed, mediaKind);
21709
23417
  const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
21710
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);
21711
23433
  console.log(`Generating "${name}" in space ${ctx.spaceId}...`);
21712
23434
  const audioVoiceOptions = mediaKind === "audio" ? parseAudioVoiceOptions(parsed) : {};
21713
23435
  const result = await client.sendGenerateRequest({
@@ -21716,8 +23438,8 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
21716
23438
  prompt,
21717
23439
  ...imageOptions,
21718
23440
  aspectRatio: imageOptions.aspectRatio ?? videoOptions.aspectRatio,
21719
- parentAssetId: parsed.options.parent,
21720
23441
  disableStyle: parsed.options["no-style"] === "true",
23442
+ ...styleSelection.stylePresetId ? { stylePresetId: styleSelection.stylePresetId } : {},
21721
23443
  mediaKind,
21722
23444
  ...audioVoiceOptions,
21723
23445
  ...musicProvider ? { musicProvider } : {},
@@ -21785,6 +23507,20 @@ async function executeRefine(parsed, ctx, client, deps, mediaKind) {
21785
23507
  const imageOptions = parseImageGenerationOptions(parsed, mediaKind);
21786
23508
  const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
21787
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);
21788
23524
  console.log(`Refining variant ${sourceVariantId}...`);
21789
23525
  const result = await client.sendRefineRequest({
21790
23526
  assetId: sourceVariant.asset_id,
@@ -21793,6 +23529,7 @@ async function executeRefine(parsed, ctx, client, deps, mediaKind) {
21793
23529
  ...imageOptions,
21794
23530
  aspectRatio: imageOptions.aspectRatio ?? videoOptions.aspectRatio,
21795
23531
  disableStyle: parsed.options["no-style"] === "true",
23532
+ ...styleSelection.stylePresetId ? { stylePresetId: styleSelection.stylePresetId } : {},
21796
23533
  mediaKind,
21797
23534
  ...videoAudioOptions,
21798
23535
  ...videoOptions,
@@ -21843,6 +23580,19 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
21843
23580
  });
21844
23581
  const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
21845
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);
21846
23596
  console.log(`Deriving "${name}" from ${referenceVariantIds.length} reference(s)...`);
21847
23597
  const result = await client.sendGenerateRequest({
21848
23598
  name,
@@ -21851,8 +23601,8 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
21851
23601
  referenceVariantIds,
21852
23602
  ...imageOptions,
21853
23603
  aspectRatio: imageOptions.aspectRatio ?? videoOptions.aspectRatio,
21854
- parentAssetId: parsed.options.parent,
21855
23604
  disableStyle: parsed.options["no-style"] === "true",
23605
+ ...styleSelection.stylePresetId ? { stylePresetId: styleSelection.stylePresetId } : {},
21856
23606
  mediaKind,
21857
23607
  ...videoAudioOptions,
21858
23608
  ...videoOptions,
@@ -22047,7 +23797,20 @@ async function executeBatch(parsed, ctx, client, deps, mediaKind, saveBatchManif
22047
23797
  const referenceVariantIds = refs.length > 0 ? await resolveReferenceVariantIds(refs, ctx, deps, state.variants, mediaKind) : void 0;
22048
23798
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
22049
23799
  const runId = deps.createRunId();
22050
- 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}"...`);
22051
23814
  const audioVoiceOptions = mediaKind === "audio" ? parseAudioVoiceOptions(parsed) : {};
22052
23815
  const result = await client.sendBatchRequest({
22053
23816
  name,
@@ -22058,8 +23821,8 @@ async function executeBatch(parsed, ctx, client, deps, mediaKind, saveBatchManif
22058
23821
  referenceVariantIds,
22059
23822
  ...imageOptions,
22060
23823
  aspectRatio: imageOptions.aspectRatio,
22061
- parentAssetId: parsed.options.parent,
22062
23824
  disableStyle: parsed.options["no-style"] === "true",
23825
+ ...styleSelection.stylePresetId ? { stylePresetId: styleSelection.stylePresetId } : {},
22063
23826
  mediaKind,
22064
23827
  ...audioVoiceOptions,
22065
23828
  ...musicProvider ? { musicProvider } : {}
@@ -22177,7 +23940,7 @@ async function placeProductionRecordFromScene(input) {
22177
23940
  record
22178
23941
  });
22179
23942
  }
22180
- async function buildContext$3(parsed, deps) {
23943
+ async function buildContext$6(parsed, deps) {
22181
23944
  const projectConfig = await deps.loadProjectConfig();
22182
23945
  const env = resolveCommandEnvironment(parsed, projectConfig);
22183
23946
  const spaceId = resolveCommandSpace(parsed, projectConfig);
@@ -22243,6 +24006,51 @@ function requestSpaceState(client) {
22243
24006
  client.requestSync();
22244
24007
  });
22245
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
+ }
22246
24054
  async function downloadResult(result, outputPath, ctx, deps) {
22247
24055
  const variant = result.variant;
22248
24056
  if (!result.success || !variant) throw new Error(result.error || "Generation failed without a completed variant");
@@ -22528,7 +24336,7 @@ function cliImageSizeValues() {
22528
24336
  function cliImageAspectValues() {
22529
24337
  return cliOptionValues(getImageModelCapabilities().supportedAspectRatios);
22530
24338
  }
22531
- function printUsage$7(command) {
24339
+ function printUsage$9(command) {
22532
24340
  if (command === "generate") {
22533
24341
  console.log(`
22534
24342
  Usage:
@@ -22581,7 +24389,7 @@ function printBatchResult(result, outputDir, manifestPath, ctx, mediaKind) {
22581
24389
  }
22582
24390
  //#endregion
22583
24391
  //#region src/cli/commands/audio.ts
22584
- var defaultDeps$5 = {
24392
+ var defaultDeps$8 = {
22585
24393
  loadConfig: loadStoredConfig,
22586
24394
  loadProjectConfig,
22587
24395
  resolveBaseUrl,
@@ -22594,11 +24402,11 @@ async function handleAudio(parsed) {
22594
24402
  await executeAudio(parsed);
22595
24403
  } catch (error) {
22596
24404
  console.error("Error:", error instanceof Error ? error.message : error);
22597
- printUsage$6();
24405
+ printUsage$8();
22598
24406
  process$1.exitCode = 1;
22599
24407
  }
22600
24408
  }
22601
- async function executeAudio(parsed, deps = defaultDeps$5) {
24409
+ async function executeAudio(parsed, deps = defaultDeps$8) {
22602
24410
  const invocation = parseAudioInvocation(parsed.positionals);
22603
24411
  if (invocation.command === "voices") return executeAudioVoices({
22604
24412
  ...parsed,
@@ -22671,7 +24479,7 @@ function printVoices(response, print) {
22671
24479
  function formatLabels(labels) {
22672
24480
  return Object.entries(labels).map(([key, value]) => `${key}:${value}`).join(", ");
22673
24481
  }
22674
- function printUsage$6() {
24482
+ function printUsage$8() {
22675
24483
  const modes = AUDIO_FORGE_MEDIA_MODES.join("|");
22676
24484
  console.log(`
22677
24485
  Usage:
@@ -22700,7 +24508,7 @@ async function handleVideo(parsed) {
22700
24508
  });
22701
24509
  } catch (error) {
22702
24510
  console.error("Error:", error instanceof Error ? error.message : error);
22703
- printUsage$5();
24511
+ printUsage$7();
22704
24512
  process$1.exitCode = 1;
22705
24513
  }
22706
24514
  }
@@ -22709,7 +24517,7 @@ function parseVideoCommand(value) {
22709
24517
  if (value && commands.includes(value)) return value;
22710
24518
  throw new Error("Video command is required: generate, refine, or derive");
22711
24519
  }
22712
- function printUsage$5() {
24520
+ function printUsage$7() {
22713
24521
  const aspectValues = VIDEO_GENERATION_ASPECT_RATIOS.join("|");
22714
24522
  const resolutionValues = Array.from(new Set(VIDEO_GENERATION_TIERS.flatMap((tier) => getVideoGenerationResolutionsForTier(tier)))).join("|");
22715
24523
  const durationValues = VIDEO_GENERATION_DURATION_SECONDS.join("|");
@@ -22741,17 +24549,17 @@ Production metadata:
22741
24549
  }
22742
24550
  //#endregion
22743
24551
  //#region src/cli/commands/init.ts
22744
- var defaultDeps$4 = { saveProjectConfig };
24552
+ var defaultDeps$7 = { saveProjectConfig };
22745
24553
  async function handleInit(parsed) {
22746
24554
  try {
22747
24555
  await executeInit(parsed);
22748
24556
  } catch (error) {
22749
24557
  console.error("Error:", error instanceof Error ? error.message : error);
22750
- printUsage$4();
24558
+ printUsage$6();
22751
24559
  process$1.exitCode = 1;
22752
24560
  }
22753
24561
  }
22754
- async function executeInit(parsed, deps = defaultDeps$4) {
24562
+ async function executeInit(parsed, deps = defaultDeps$7) {
22755
24563
  const environment = resolveCommandEnvironment(parsed);
22756
24564
  const spaceId = resolveCommandSpace(parsed);
22757
24565
  if (!spaceId) throw new Error("--space is required");
@@ -22777,7 +24585,7 @@ async function executeInit(parsed, deps = defaultDeps$4) {
22777
24585
  spaceId
22778
24586
  };
22779
24587
  }
22780
- function printUsage$4() {
24588
+ function printUsage$6() {
22781
24589
  console.log(`
22782
24590
  Usage:
22783
24591
  makefx init --space <id> [--env production|stage|local]
@@ -22786,7 +24594,7 @@ Usage:
22786
24594
  }
22787
24595
  //#endregion
22788
24596
  //#region src/cli/commands/runs.ts
22789
- var defaultDeps$3 = {
24597
+ var defaultDeps$6 = {
22790
24598
  loadProjectConfig,
22791
24599
  listRunManifests,
22792
24600
  readRunManifest,
@@ -22799,11 +24607,11 @@ async function handleRuns(parsed) {
22799
24607
  await executeRuns(parsed);
22800
24608
  } catch (error) {
22801
24609
  console.error("Error:", error instanceof Error ? error.message : error);
22802
- printUsage$3();
24610
+ printUsage$5();
22803
24611
  process$1.exitCode = 1;
22804
24612
  }
22805
24613
  }
22806
- async function executeRuns(parsed, deps = defaultDeps$3) {
24614
+ async function executeRuns(parsed, deps = defaultDeps$6) {
22807
24615
  const projectConfig = await deps.loadProjectConfig();
22808
24616
  if (!projectConfig?.projectRoot) throw new Error("Make Effects project config not found. Run: makefx init --space <id>");
22809
24617
  requireDebugAcknowledgement(parsed);
@@ -22921,7 +24729,7 @@ function formatCreated(value) {
22921
24729
  if (Number.isNaN(date.getTime())) return value;
22922
24730
  return value.replace("T", " ").replace(/\.\d{3}Z$/, "Z").slice(0, 20);
22923
24731
  }
22924
- function printUsage$3() {
24732
+ function printUsage$5() {
22925
24733
  console.log(`
22926
24734
  Usage:
22927
24735
  makefx runs --debug
@@ -22939,7 +24747,7 @@ For timed scene assembly, use:
22939
24747
  }
22940
24748
  //#endregion
22941
24749
  //#region src/cli/commands/assets.ts
22942
- var defaultDeps$2 = {
24750
+ var defaultDeps$5 = {
22943
24751
  loadConfig: loadStoredConfig,
22944
24752
  loadProjectConfig,
22945
24753
  resolveBaseUrl,
@@ -22962,15 +24770,15 @@ async function handleAssets(parsed) {
22962
24770
  await executeAssets(parsed);
22963
24771
  } catch (error) {
22964
24772
  console.error("Error:", error instanceof Error ? error.message : error);
22965
- printUsage$2();
24773
+ printUsage$4();
22966
24774
  process$1.exitCode = 1;
22967
24775
  }
22968
24776
  }
22969
- async function executeAssets(parsed, deps = defaultDeps$2) {
22970
- const ctx = await buildContext$2(parsed, deps);
24777
+ async function executeAssets(parsed, deps = defaultDeps$5) {
24778
+ const ctx = await buildContext$5(parsed, deps);
22971
24779
  const subcommand = parsed.positionals[0] || "list";
22972
24780
  if (subcommand === "list") {
22973
- const assets = await listAssets(ctx, deps);
24781
+ const assets = await listAssets$1(ctx, deps);
22974
24782
  if (parsed.options.json === "true") deps.print(JSON.stringify(assets.map(toAssetJson), null, 2));
22975
24783
  else printAssetList(assets, deps.print);
22976
24784
  return {
@@ -23046,7 +24854,7 @@ async function executeAssets(parsed, deps = defaultDeps$2) {
23046
24854
  function normalizeOption(value) {
23047
24855
  return !value || value === "true" ? void 0 : value;
23048
24856
  }
23049
- async function buildContext$2(parsed, deps) {
24857
+ async function buildContext$5(parsed, deps) {
23050
24858
  const projectConfig = await deps.loadProjectConfig();
23051
24859
  const env = resolveCommandEnvironment(parsed, projectConfig);
23052
24860
  const spaceId = resolveCommandSpace(parsed, projectConfig);
@@ -23063,7 +24871,7 @@ async function buildContext$2(parsed, deps) {
23063
24871
  force: parsed.options.force === "true"
23064
24872
  };
23065
24873
  }
23066
- async function listAssets(ctx, deps) {
24874
+ async function listAssets$1(ctx, deps) {
23067
24875
  return (await fetchJson(ctx, deps, `/api/spaces/${ctx.spaceId}/assets`)).assets || [];
23068
24876
  }
23069
24877
  async function getAssetDetails(ctx, deps, assetId) {
@@ -23088,7 +24896,7 @@ async function resolveDownloadRef(ref, ctx, deps) {
23088
24896
  requestPath: `/api/images/${ref}`
23089
24897
  };
23090
24898
  }
23091
- const assets = await listAssets(ctx, deps);
24899
+ const assets = await listAssets$1(ctx, deps);
23092
24900
  for (const asset of assets) {
23093
24901
  const variant = (await getAssetDetails(ctx, deps, asset.id)).variants.find((candidate) => candidate.id === ref);
23094
24902
  if (!variant) continue;
@@ -23146,7 +24954,6 @@ function printAssetDetails(details, ctx, print) {
23146
24954
  print(` Type: ${asset.type || "unknown"}`);
23147
24955
  print(` Media: ${asset.media_kind || "-"}`);
23148
24956
  print(` Active: ${asset.active_variant_id || "-"}`);
23149
- print(` Parent: ${asset.parent_asset_id || "-"}`);
23150
24957
  print(` Created: ${formatTimestamp(asset.created_at)}`);
23151
24958
  print(` Updated: ${formatTimestamp(asset.updated_at)}`);
23152
24959
  print(` Web: ${ctx.baseUrl}/spaces/${ctx.spaceId}/assets/${asset.id}`);
@@ -23195,7 +25002,6 @@ function toAssetJson(asset) {
23195
25002
  type: asset.type,
23196
25003
  media_kind: asset.media_kind || null,
23197
25004
  activeVariantId: asset.active_variant_id,
23198
- parentAssetId: asset.parent_asset_id || null,
23199
25005
  createdAt: asset.created_at || null,
23200
25006
  updatedAt: asset.updated_at || null
23201
25007
  };
@@ -23227,7 +25033,7 @@ function formatTimestamp(value) {
23227
25033
  if (Number.isNaN(date.getTime())) return String(value);
23228
25034
  return date.toISOString().replace("T", " ").replace(/\.\d{3}Z$/, "Z").slice(0, 20);
23229
25035
  }
23230
- function printUsage$2() {
25036
+ function printUsage$4() {
23231
25037
  console.log(`
23232
25038
  Usage:
23233
25039
  makefx assets
@@ -23242,7 +25048,7 @@ Usage:
23242
25048
  }
23243
25049
  //#endregion
23244
25050
  //#region src/cli/commands/variants.ts
23245
- var defaultDeps$1 = {
25051
+ var defaultDeps$4 = {
23246
25052
  loadConfig: loadStoredConfig,
23247
25053
  loadProjectConfig,
23248
25054
  resolveBaseUrl,
@@ -23254,12 +25060,12 @@ async function handleVariants(parsed) {
23254
25060
  await executeVariants(parsed);
23255
25061
  } catch (error) {
23256
25062
  console.error("Error:", error instanceof Error ? error.message : error);
23257
- printUsage$1();
25063
+ printUsage$3();
23258
25064
  process$1.exitCode = 1;
23259
25065
  }
23260
25066
  }
23261
- async function executeVariants(parsed, deps = defaultDeps$1) {
23262
- const ctx = await buildContext$1(parsed, deps);
25067
+ async function executeVariants(parsed, deps = defaultDeps$4) {
25068
+ const ctx = await buildContext$4(parsed, deps);
23263
25069
  const subcommand = parsed.positionals[0];
23264
25070
  if (subcommand === "delete") {
23265
25071
  const variantId = requireVariantId(parsed, "delete");
@@ -23307,7 +25113,7 @@ function requireVariantId(parsed, verb) {
23307
25113
  if (!variantId) throw new Error(`Variant ID is required: makefx variants ${verb} <variant-id>`);
23308
25114
  return variantId;
23309
25115
  }
23310
- async function buildContext$1(parsed, deps) {
25116
+ async function buildContext$4(parsed, deps) {
23311
25117
  const projectConfig = await deps.loadProjectConfig();
23312
25118
  const env = resolveCommandEnvironment(parsed, projectConfig);
23313
25119
  const spaceId = resolveCommandSpace(parsed, projectConfig);
@@ -23330,7 +25136,7 @@ async function withVariantClient(ctx, deps, run) {
23330
25136
  client.disconnect();
23331
25137
  }
23332
25138
  }
23333
- function printUsage$1() {
25139
+ function printUsage$3() {
23334
25140
  console.log(`
23335
25141
  Usage:
23336
25142
  makefx variants delete <variant-id>
@@ -23346,6 +25152,809 @@ Options:
23346
25152
  `);
23347
25153
  }
23348
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
23349
25958
  //#region src/cli/commands/pipelines.ts
23350
25959
  var ROTATION_CONFIGS = [
23351
25960
  "4-directional",
@@ -23364,6 +25973,7 @@ var defaultDeps = {
23364
25973
  loadProjectConfig,
23365
25974
  resolveBaseUrl,
23366
25975
  createClient: (env, spaceId) => WebSocketClient.create(env, spaceId),
25976
+ isRotationEnabled: isCliRotationEnabled,
23367
25977
  print: console.log
23368
25978
  };
23369
25979
  async function handleRotation(parsed) {
@@ -23377,12 +25987,15 @@ async function handlePipelineCommand(command, parsed) {
23377
25987
  const result = await executePipelineCommand(command, parsed, defaultDeps);
23378
25988
  if ("status" in result && (result.status === "failed" || result.status === "cancelled")) process$1.exitCode = 1;
23379
25989
  } catch (error) {
23380
- console.error("Error:", error instanceof Error ? error.message : error);
23381
- printUsage(command);
25990
+ const message = error instanceof Error ? error.message : String(error);
25991
+ console.error("Error:", message);
25992
+ if (message !== rotationDisabledMessage()) printUsage(command);
23382
25993
  process$1.exitCode = 1;
23383
25994
  }
23384
25995
  }
23385
25996
  async function executePipelineCommand(command, parsed, deps = defaultDeps) {
25997
+ const rotationEnabled = deps.isRotationEnabled ?? isCliRotationEnabled;
25998
+ if (command === "rotation" && !rotationEnabled()) throw new Error(rotationDisabledMessage());
23386
25999
  const ctx = await buildContext(parsed, deps);
23387
26000
  const client = await deps.createClient(ctx.env, ctx.spaceId);
23388
26001
  try {
@@ -23584,6 +26197,10 @@ function printJsonOrText(json, result, text, deps) {
23584
26197
  }
23585
26198
  function printUsage(command) {
23586
26199
  if (command === "rotation") {
26200
+ if (!isCliRotationEnabled()) {
26201
+ console.log(rotationDisabledMessage());
26202
+ return;
26203
+ }
23587
26204
  console.log(`
23588
26205
  Usage:
23589
26206
  makefx rotation --variant <variant-id> [--config 4-directional|8-directional|turnaround]
@@ -23596,7 +26213,7 @@ Options:
23596
26213
  --subject <text> Optional subject description for consistency prompts
23597
26214
  --aspect <ratio> Optional generation aspect ratio
23598
26215
  --mode <mode> sequential or single-shot (default: sequential)
23599
- --no-style Disable the space style anchor
26216
+ --no-style Disable style preset injection for this pipeline
23600
26217
  --detach Return after the pipeline starts instead of waiting for completion
23601
26218
  --timeout <sec> Override the pipeline wait timeout
23602
26219
  --json Print machine-readable output
@@ -23618,7 +26235,7 @@ Options:
23618
26235
  --seed-variant <id> Optional completed image variant to place at the center (sequential mode only)
23619
26236
  --aspect <ratio> Optional generation aspect ratio
23620
26237
  --mode <mode> sequential or single-shot (default: sequential)
23621
- --no-style Disable the space style anchor
26238
+ --no-style Disable style preset injection for this pipeline
23622
26239
  --detach Return after the pipeline starts instead of waiting for completion
23623
26240
  --timeout <sec> Override the pipeline wait timeout
23624
26241
  --json Print machine-readable output
@@ -23626,7 +26243,7 @@ Options:
23626
26243
  }
23627
26244
  //#endregion
23628
26245
  //#region src/cli/index.ts
23629
- var CLI_VERSION = "0.1.3+21fbf493922f";
26246
+ var CLI_VERSION = "0.2.0+a98a786097bf";
23630
26247
  async function main() {
23631
26248
  const argv = process$1.argv.slice(2);
23632
26249
  if (argv[0] === "--") argv.shift();
@@ -23735,6 +26352,9 @@ function printCommandHelp(command, positionals) {
23735
26352
  case "upload":
23736
26353
  printUploadHelp();
23737
26354
  return;
26355
+ case "import":
26356
+ printImportHelp();
26357
+ return;
23738
26358
  case "generate":
23739
26359
  case "refine":
23740
26360
  case "derive":
@@ -23753,10 +26373,20 @@ function printCommandHelp(command, positionals) {
23753
26373
  case "assets":
23754
26374
  printAssetsHelp();
23755
26375
  return;
26376
+ case "usage":
26377
+ printUsageHelp();
26378
+ return;
26379
+ case "spend":
26380
+ printSpendHelp();
26381
+ return;
23756
26382
  case "variants":
23757
26383
  case "variant":
23758
26384
  printVariantsHelp();
23759
26385
  return;
26386
+ case "styles":
26387
+ case "style":
26388
+ printStylesHelp();
26389
+ return;
23760
26390
  case "rotation":
23761
26391
  printRotationHelp();
23762
26392
  return;
@@ -23775,6 +26405,11 @@ function printCommandHelp(command, positionals) {
23775
26405
  }
23776
26406
  }
23777
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" : "";
23778
26413
  console.log(`
23779
26414
  Make Effects CLI
23780
26415
 
@@ -23802,10 +26437,10 @@ Project:
23802
26437
  variants star <variant-id> Star a variant (unstar to clear)
23803
26438
  variants rate <variant-id> approved|rejected
23804
26439
  Rate a variant for quality curation
23805
- rotation --variant <variant-id>
23806
- Generate rotation views from a completed image variant
23807
- rotation cancel <rotation-set-id>
23808
- 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}
23809
26444
  tileset "prompt" --type terrain --grid 3x3
23810
26445
  Generate a consistent tile set
23811
26446
  tileset cancel <tile-set-id> Cancel an active tile-set pipeline
@@ -23813,12 +26448,14 @@ Project:
23813
26448
  List Space-backed production placements
23814
26449
  productions export --production-id <id>
23815
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
23816
26453
 
23817
26454
  Billing (Polar.sh):
23818
26455
  billing status Show sync status (pending, failed, synced events)
23819
26456
  billing check Run operational checks for workers, meters, and sync health
23820
26457
  billing reconcile --user-id <id>
23821
- Compare local billable usage with Polar usage
26458
+ Reconcile Polar, charge, provider, and platform usage
23822
26459
  billing retry-failed Retry all failed events
23823
26460
 
23824
26461
  Spaces:
@@ -23835,6 +26472,7 @@ Listen:
23835
26472
  Upload:
23836
26473
  upload <file> --asset <id> [--space <id>] Upload image, audio, or video to existing asset
23837
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
23838
26476
 
23839
26477
  Forge:
23840
26478
  generate "prompt" --name <name> --type <type> -o <file>
@@ -23876,14 +26514,20 @@ Examples:
23876
26514
  makefx audio sfx generate "A short brass victory sting" --name "Victory Sting" -o victory.wav
23877
26515
  makefx video generate "A looping idle animation" --name "Idle Animation" --type animation --duration 6 --resolution 1080p --tier fast -o idle.mp4
23878
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
23879
26519
  makefx assets
26520
+ makefx usage --from 2026-06-01
26521
+ makefx spend --from 2026-06-01 --provider gemini
23880
26522
  makefx assets download variant_123 -o variant.mp4
23881
26523
  makefx assets rename asset_123 "Hero (moving)"
23882
26524
  makefx assets set-active asset_123 variant_456
23883
26525
  makefx variants retry variant_456
23884
26526
  makefx variants delete variant_456
23885
- makefx rotation --variant variant_456 --config 8-directional
23886
- 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
23887
26531
  `);
23888
26532
  }
23889
26533
  function printInitHelp() {
@@ -23918,7 +26562,7 @@ Usage:
23918
26562
  Subcommands:
23919
26563
  status Show sync status (pending, failed, synced events)
23920
26564
  check Run operational checks for workers, Polar meters, and sync health
23921
- reconcile Compare local billable usage with Polar usage for one user
26565
+ reconcile Reconcile Polar, charge, provider, and platform usage for one user
23922
26566
  retry-failed Reset failed events for retry (next cron will sync them)
23923
26567
 
23924
26568
  Options:
@@ -23956,11 +26600,35 @@ Options:
23956
26600
  --name <name> New asset name (creates asset + variant)
23957
26601
  --type <type> Asset type for new assets (default: character)
23958
26602
  --media-kind <k> Optional explicit kind: image, audio, or video
23959
- --parent <id> Parent asset ID for new assets
23960
26603
  --env <env> Environment (production|stage|local)
23961
26604
  --local Shortcut for --env local
23962
26605
  `);
23963
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
+ }
23964
26632
  function printForgeHelp(command) {
23965
26633
  if (command === "generate") {
23966
26634
  console.log(`
@@ -23970,6 +26638,10 @@ Usage:
23970
26638
 
23971
26639
  ${imageCapabilityHelp()}
23972
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
+
23973
26645
  Production metadata:
23974
26646
  --scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
23975
26647
  --shot-id <id> --production-id <id>
@@ -23984,6 +26656,10 @@ Usage:
23984
26656
 
23985
26657
  ${imageCapabilityHelp()}
23986
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
+
23987
26663
  Production metadata:
23988
26664
  --scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
23989
26665
  --shot-id <id> --production-id <id>
@@ -23996,6 +26672,10 @@ Usage:
23996
26672
  makefx batch "prompt" --name <name> --type <type> --count <2-8> --output-dir <dir> [--model ${optionValues(IMAGE_MODEL_SELECTIONS)}] [--size ${imageSizeValues()}] [--aspect <ratio>]
23997
26673
 
23998
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
23999
26679
  `);
24000
26680
  return;
24001
26681
  }
@@ -24006,6 +26686,10 @@ Usage:
24006
26686
 
24007
26687
  ${imageCapabilityHelp()}
24008
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
+
24009
26693
  Production metadata:
24010
26694
  --scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
24011
26695
  --shot-id <id> --production-id <id>
@@ -24203,7 +26887,43 @@ Options:
24203
26887
  --local Shortcut for --env local
24204
26888
  `);
24205
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
+ }
24206
26922
  function printRotationHelp() {
26923
+ if (!isCliRotationEnabled()) {
26924
+ console.log(rotationDisabledMessage());
26925
+ return;
26926
+ }
24207
26927
  console.log(`
24208
26928
  Usage:
24209
26929
  makefx rotation --variant <variant-id> [--config 4-directional|8-directional|turnaround]
@@ -24216,7 +26936,7 @@ Options:
24216
26936
  --subject <text> Optional subject description for consistency prompts
24217
26937
  --aspect <ratio> Optional generation aspect ratio
24218
26938
  --mode <mode> sequential or single-shot (default: sequential)
24219
- --no-style Disable the space style anchor
26939
+ --no-style Disable style preset injection for this pipeline
24220
26940
  --detach Return after the pipeline starts instead of waiting for completion
24221
26941
  --timeout <sec> Override the pipeline wait timeout
24222
26942
  --json Print machine-readable output
@@ -24238,7 +26958,7 @@ Options:
24238
26958
  --seed-variant <id> Optional completed image variant to place at the center (sequential mode only)
24239
26959
  --aspect <ratio> Optional generation aspect ratio
24240
26960
  --mode <mode> sequential or single-shot (default: sequential)
24241
- --no-style Disable the space style anchor
26961
+ --no-style Disable style preset injection for this pipeline
24242
26962
  --detach Return after the pipeline starts instead of waiting for completion
24243
26963
  --timeout <sec> Override the pipeline wait timeout
24244
26964
  --json Print machine-readable output
@@ -24266,6 +26986,41 @@ Usage:
24266
26986
  makefx assets download <variant-id|legacy-image-key> -o output-file
24267
26987
  `);
24268
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
+ }
24269
27024
  async function dispatchCommand(command, parsed) {
24270
27025
  switch (command) {
24271
27026
  case "init":
@@ -24289,6 +27044,9 @@ async function dispatchCommand(command, parsed) {
24289
27044
  case "upload":
24290
27045
  await handleUpload(parsed);
24291
27046
  break;
27047
+ case "import":
27048
+ await handleImport(parsed);
27049
+ break;
24292
27050
  case "generate":
24293
27051
  await handleGenerate(parsed);
24294
27052
  break;
@@ -24313,10 +27071,20 @@ async function dispatchCommand(command, parsed) {
24313
27071
  case "assets":
24314
27072
  await handleAssets(parsed);
24315
27073
  break;
27074
+ case "usage":
27075
+ await handleUsage(parsed);
27076
+ break;
27077
+ case "spend":
27078
+ await handleSpend(parsed);
27079
+ break;
24316
27080
  case "variants":
24317
27081
  case "variant":
24318
27082
  await handleVariants(parsed);
24319
27083
  break;
27084
+ case "styles":
27085
+ case "style":
27086
+ await handleStyles(parsed);
27087
+ break;
24320
27088
  case "rotation":
24321
27089
  await handleRotation(parsed);
24322
27090
  break;