makefx 0.1.3 → 0.2.1

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 +4 -2
  2. package/makefx.mjs +2424 -187
  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$12 = {
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$12) {
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,28 @@ 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
+ function resolveMediaType(ext, requestedMediaKind) {
5060
+ const mediaType = EXT_TO_MEDIA_TYPE[ext];
5061
+ if (!mediaType) throw new Error(`Invalid file type "${ext}". Allowed types: ${ALLOWED_EXTENSIONS$1.join(", ")}`);
5062
+ if (requestedMediaKind !== void 0 && requestedMediaKind !== "image" && requestedMediaKind !== "audio" && requestedMediaKind !== "video") throw new Error("Invalid --media-kind. Expected image, audio, or video");
5063
+ if (ext === ".webm" && requestedMediaKind === "audio") return {
5064
+ mediaKind: "audio",
5065
+ mimeType: "audio/webm"
5066
+ };
5067
+ if (requestedMediaKind && requestedMediaKind !== mediaType.mediaKind) throw new Error(`--media-kind ${requestedMediaKind} does not match ${ext} (${mediaType.mediaKind})`);
5068
+ return mediaType;
5069
+ }
5070
+ //#endregion
5071
+ //#region src/cli/commands/upload.ts
5072
+ /**
5073
+ * Upload Command - Upload one media file to create variants
5074
+ *
5075
+ * Usage:
5076
+ * makefx upload <file> --space <id> --asset <id> Upload to existing asset
5077
+ * makefx upload <file> --space <id> --name <name> Upload as new asset
5078
+ * makefx upload <file> --space <id> --name <name> --type <type>
5079
+ */
5080
+ var defaultDeps$11 = {
5041
5081
  loadConfig: loadStoredConfig,
5042
5082
  loadProjectConfig,
5043
5083
  resolveBaseUrl,
@@ -5052,50 +5092,111 @@ async function handleUpload(parsed) {
5052
5092
  await executeUpload(parsed);
5053
5093
  } catch (error) {
5054
5094
  console.error(error instanceof Error ? `Error: ${error.message}` : "Error: Upload failed");
5055
- if (error instanceof UploadUsageError) printUsage$9();
5095
+ if (error instanceof UploadUsageError) printUsage$11();
5056
5096
  process$1.exitCode = 1;
5057
5097
  }
5058
5098
  }
5059
- async function executeUpload(parsed, deps = defaultDeps$8) {
5099
+ async function executeUpload(parsed, deps = defaultDeps$11) {
5100
+ const filePath = parsed.positionals[0];
5101
+ if (!filePath) throw new UploadUsageError("File path is required");
5060
5102
  const projectConfig = await deps.loadProjectConfig();
5061
5103
  const env = resolveCommandEnvironment(parsed, projectConfig);
5062
5104
  const spaceId = resolveCommandSpace(parsed, projectConfig);
5063
5105
  const assetId = parsed.options.asset;
5064
5106
  const assetName = parsed.options.name;
5065
5107
  const assetType = parsed.options.type || "character";
5066
- const parentAssetId = parsed.options.parent;
5067
5108
  const requestedMediaKind = parsed.options["media-kind"] || parsed.options.mediaKind;
5068
- const filePath = parsed.positionals[0];
5069
- if (!filePath) throw new UploadUsageError("File path is required");
5109
+ const prompt = parsed.options.prompt;
5110
+ const model = parsed.options.model;
5111
+ const provider = parsed.options.provider;
5112
+ const rawProviderMetadata = parsed.options["provider-metadata"] ?? parsed.options.providerMetadata ?? parsed.options.provider_metadata;
5113
+ const rawGenerationProvenance = parsed.options["generation-provenance"] ?? parsed.options.generationProvenance ?? parsed.options.generation_provenance;
5114
+ const sourceVariantId = parsed.options["source-variant"] ?? parsed.options.sourceVariantId ?? parsed.options.parentVariantId;
5115
+ const rawRelationType = parsed.options["relation-type"] ?? parsed.options.relationType;
5116
+ const rawActiveVariantBehavior = parsed.options["active-variant-behavior"] ?? parsed.options.activeVariantBehavior;
5117
+ const rawCollectionIds = parsed.options.collection ?? parsed.options.collections;
5118
+ const rawCollectionNames = parsed.options["collection-name"] ?? parsed.options.collectionName;
5119
+ const rawCollectionRole = parsed.options["collection-role"] ?? parsed.options.collectionRole;
5120
+ const rawCollectionSubject = parsed.options["collection-subject"] ?? parsed.options.collectionSubject;
5121
+ const rawCollectionPinnedVariant = parsed.options["collection-pinned-variant"] ?? parsed.options.collectionPinnedVariant;
5122
+ const rawManualRelation = parsed.options["manual-relation"] ?? parsed.options.manualRelation;
5123
+ const rawManualRelationSubject = parsed.options["manual-relation-subject"] ?? parsed.options.manualRelationSubject;
5124
+ const rawManualRelationLabel = parsed.options["manual-relation-label"] ?? parsed.options.manualRelationLabel;
5125
+ const rawManualRelationContext = parsed.options["manual-relation-context"] ?? parsed.options.manualRelationContext;
5126
+ const rawManualRelationMetadata = parsed.options["manual-relation-metadata"] ?? parsed.options.manualRelationMetadata;
5127
+ const jsonOutput = parsed.options.json === "true";
5128
+ if (parsed.options["dry-run"] === "true" || parsed.options.dryRun === "true") throw new UploadUsageError("--dry-run is not supported for direct file upload");
5070
5129
  if (!spaceId) throw new UploadUsageError("--space is required, or run: makefx init --space <id>");
5071
5130
  if (!assetId && !assetName) throw new UploadUsageError("Either --asset or --name is required");
5131
+ if (!sourceVariantId && (parsed.options["relation-type"] || parsed.options.relationType)) throw new UploadUsageError("--relation-type requires --source-variant");
5132
+ const providerMetadata = parseJsonObjectOption(rawProviderMetadata, "--provider-metadata");
5133
+ const generationProvenance = parseJsonObjectOption(rawGenerationProvenance, "--generation-provenance");
5134
+ const relationType = normalizeRelationType(rawRelationType);
5135
+ const activeVariantBehavior = normalizeActiveVariantBehavior(rawActiveVariantBehavior);
5136
+ const collectionPlacements = parseCollectionPlacements({
5137
+ collectionIds: rawCollectionIds,
5138
+ collectionNames: rawCollectionNames,
5139
+ role: rawCollectionRole,
5140
+ subjectType: rawCollectionSubject,
5141
+ pinnedVariant: rawCollectionPinnedVariant
5142
+ });
5143
+ const manualRelations = parseManualRelations({
5144
+ relations: rawManualRelation,
5145
+ subjectType: rawManualRelationSubject,
5146
+ label: rawManualRelationLabel,
5147
+ context: rawManualRelationContext,
5148
+ metadata: rawManualRelationMetadata
5149
+ });
5072
5150
  const mediaType = resolveMediaType(path.extname(filePath).toLowerCase(), requestedMediaKind);
5073
5151
  const config = await deps.loadConfig(env);
5074
5152
  if (!config) throw new Error(`Not logged in to ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
5075
5153
  if (config.token.expiresAt < Date.now()) throw new Error(`Token expired for ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
5076
5154
  const baseUrl = deps.resolveBaseUrl(env);
5077
5155
  const accessToken = config.token.accessToken;
5156
+ const ctx = {
5157
+ spaceId,
5158
+ baseUrl,
5159
+ accessToken
5160
+ };
5078
5161
  if (env === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
5079
5162
  try {
5080
5163
  const fileStat = await deps.stat(filePath);
5081
5164
  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`);
5165
+ if (fileStat.size > 10485760) throw new Error(`File too large (${(fileStat.size / 1024 / 1024).toFixed(2)}MB). Maximum size: 10MB`);
5166
+ await preflightUploadOrganization(ctx, deps, {
5167
+ assetId,
5168
+ sourceVariantId,
5169
+ collectionPlacements,
5170
+ manualRelations
5171
+ });
5083
5172
  const fileBuffer = await deps.readFile(filePath);
5084
5173
  const fileName = path.basename(filePath);
5085
5174
  const formData = new FormData();
5086
5175
  const blob = new Blob([fileBuffer], { type: mediaType.mimeType });
5087
5176
  formData.append("file", blob, fileName);
5088
5177
  formData.append("mediaKind", mediaType.mediaKind);
5178
+ formData.append("activeVariantBehavior", activeVariantBehavior);
5089
5179
  if (assetId) formData.append("assetId", assetId);
5090
5180
  else {
5091
5181
  formData.append("assetName", assetName);
5092
5182
  formData.append("assetType", assetType);
5093
- if (parentAssetId) formData.append("parentAssetId", parentAssetId);
5094
5183
  }
5095
- deps.print(`\nUploading "${fileName}" to space ${spaceId}...`);
5096
- deps.print(` Media kind: ${mediaType.mediaKind}`);
5097
- if (assetId) deps.print(` Target asset: ${assetId}`);
5098
- else deps.print(` Creating asset: "${assetName}" (${assetType})`);
5184
+ if (prompt) formData.append("prompt", prompt);
5185
+ if (model) formData.append("model", model);
5186
+ if (provider) formData.append("provider", provider);
5187
+ if (providerMetadata) formData.append("providerMetadata", JSON.stringify(providerMetadata));
5188
+ if (generationProvenance) formData.append("generationProvenance", JSON.stringify(generationProvenance));
5189
+ if (sourceVariantId) formData.append("lineage", JSON.stringify([{
5190
+ parentVariantId: sourceVariantId,
5191
+ relationType
5192
+ }]));
5193
+ if (!jsonOutput) {
5194
+ deps.print(`\nUploading "${fileName}" to space ${spaceId}...`);
5195
+ deps.print(` Media kind: ${mediaType.mediaKind}`);
5196
+ if (assetId) deps.print(` Target asset: ${assetId}`);
5197
+ else deps.print(` Creating asset: "${assetName}" (${assetType})`);
5198
+ if (sourceVariantId) deps.print(` Source variant: ${sourceVariantId} (${relationType})`);
5199
+ }
5099
5200
  const response = await deps.fetch(`${baseUrl}/api/spaces/${spaceId}/upload`, {
5100
5201
  method: "POST",
5101
5202
  headers: { "Authorization": `Bearer ${accessToken}` },
@@ -5104,6 +5205,29 @@ async function executeUpload(parsed, deps = defaultDeps$8) {
5104
5205
  const data = await response.json();
5105
5206
  if (!response.ok) throw new Error(`Upload failed: ${"error" in data ? data.error : response.statusText}`);
5106
5207
  const upload = data;
5208
+ let organization = {
5209
+ collectionItemIds: [],
5210
+ relationIds: []
5211
+ };
5212
+ try {
5213
+ organization = await applyUploadOrganization(ctx, deps, upload, {
5214
+ collectionPlacements,
5215
+ manualRelations
5216
+ });
5217
+ } catch (error) {
5218
+ const message = error instanceof Error ? error.message : String(error);
5219
+ throw new Error(`Upload created asset ${upload.variant.asset_id} and variant ${upload.variant.id}, but organization failed: ${message}`);
5220
+ }
5221
+ const result = {
5222
+ asset: upload.asset,
5223
+ variant: upload.variant,
5224
+ lineage: upload.lineage,
5225
+ organization
5226
+ };
5227
+ if (jsonOutput) {
5228
+ deps.print(JSON.stringify(result, null, 2));
5229
+ return result;
5230
+ }
5107
5231
  deps.print("\nUpload successful!\n");
5108
5232
  if (upload.asset) {
5109
5233
  deps.print("New Asset:");
@@ -5121,6 +5245,11 @@ async function executeUpload(parsed, deps = defaultDeps$8) {
5121
5245
  if (upload.variant.image_key) deps.print(` Image: ${upload.variant.image_key}`);
5122
5246
  if (upload.variant.thumb_key) deps.print(` Thumb: ${upload.variant.thumb_key}`);
5123
5247
  if (upload.variant.media_mime_type) deps.print(` MIME: ${upload.variant.media_mime_type}`);
5248
+ if (organization.collectionItemIds.length > 0 || organization.relationIds.length > 0) {
5249
+ deps.print("\nOrganization:");
5250
+ if (organization.collectionItemIds.length > 0) deps.print(` Collection items: ${organization.collectionItemIds.join(", ")}`);
5251
+ if (organization.relationIds.length > 0) deps.print(` Relations: ${organization.relationIds.join(", ")}`);
5252
+ }
5124
5253
  if (upload.variant.recipe) try {
5125
5254
  const recipe = JSON.parse(upload.variant.recipe);
5126
5255
  deps.print("\nRecipe:");
@@ -5130,31 +5259,235 @@ async function executeUpload(parsed, deps = defaultDeps$8) {
5130
5259
  } catch {}
5131
5260
  deps.print("\nTo inspect:");
5132
5261
  deps.print(` makefx assets show ${upload.variant.asset_id} --space ${spaceId}`);
5133
- return {
5134
- asset: upload.asset,
5135
- variant: upload.variant
5136
- };
5262
+ return result;
5137
5263
  } catch (error) {
5138
5264
  if (error.code === "ENOENT") throw new Error(`File not found: ${filePath}`);
5139
5265
  throw error;
5140
5266
  }
5141
5267
  }
5142
- function resolveMediaType(ext, requestedMediaKind) {
5143
- const mediaType = EXT_TO_MEDIA_TYPE[ext];
5144
- if (!mediaType) throw new Error(`Invalid file type "${ext}". Allowed types: ${ALLOWED_EXTENSIONS$1.join(", ")}`);
5145
- if (requestedMediaKind !== void 0 && requestedMediaKind !== "image" && requestedMediaKind !== "audio" && requestedMediaKind !== "video") throw new Error("Invalid --media-kind. Expected image, audio, or video");
5146
- if (ext === ".webm" && requestedMediaKind === "audio") return {
5147
- mediaKind: "audio",
5148
- mimeType: "audio/webm"
5268
+ function parseJsonObjectOption(value, optionName) {
5269
+ if (value === void 0) return void 0;
5270
+ let parsed;
5271
+ try {
5272
+ parsed = JSON.parse(value);
5273
+ } catch {
5274
+ throw new UploadUsageError(`${optionName} must be valid JSON`);
5275
+ }
5276
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new UploadUsageError(`${optionName} must be a JSON object`);
5277
+ return parsed;
5278
+ }
5279
+ function parseJsonObjectOrStringOption(value, optionName) {
5280
+ if (value === void 0) return void 0;
5281
+ if (!value.trim().startsWith("{")) return value;
5282
+ return parseJsonObjectOption(value, optionName);
5283
+ }
5284
+ function normalizeRelationType(value) {
5285
+ if (!value) return "derived";
5286
+ if (value === "derived" || value === "refined" || value === "forked") return value;
5287
+ throw new UploadUsageError("--relation-type must be derived, refined, or forked");
5288
+ }
5289
+ function normalizeActiveVariantBehavior(value) {
5290
+ if (!value || value === "if-missing" || value === "if_missing") return "if-missing";
5291
+ if (value === "set-active" || value === "set_active") return "set-active";
5292
+ if (value === "keep") return "keep";
5293
+ throw new UploadUsageError("--active-variant-behavior must be if-missing, set-active, or keep");
5294
+ }
5295
+ function normalizeSpaceSubjectType(value, optionName, defaultValue) {
5296
+ if (!value) return defaultValue;
5297
+ if (value === "asset" || value === "variant") return value;
5298
+ throw new UploadUsageError(`${optionName} must be asset or variant`);
5299
+ }
5300
+ function normalizeManualRelationType(value, optionName) {
5301
+ if ([
5302
+ "appears_in",
5303
+ "background_for",
5304
+ "style_reference_for",
5305
+ "thumbnail_for",
5306
+ "alternate_of",
5307
+ "prop_in",
5308
+ "map_for",
5309
+ "part_of",
5310
+ "reference_for",
5311
+ "custom"
5312
+ ].includes(value)) return value;
5313
+ throw new UploadUsageError(`${optionName} relation type is invalid`);
5314
+ }
5315
+ function parseCsvOption$1(value, optionName) {
5316
+ if (!value) return [];
5317
+ if (value === "true") throw new UploadUsageError(`${optionName} requires a value`);
5318
+ return value.split(",").map((entry) => entry.trim()).filter(Boolean);
5319
+ }
5320
+ function parseCollectionPlacements(input) {
5321
+ const collectionIds = parseCsvOption$1(input.collectionIds, "--collection");
5322
+ const collectionNames = parseCsvOption$1(input.collectionNames, "--collection-name");
5323
+ if (collectionIds.length === 0 && collectionNames.length === 0) return [];
5324
+ const subjectType = normalizeSpaceSubjectType(input.subjectType, "--collection-subject", "asset");
5325
+ if (subjectType === "variant" && input.pinnedVariant && input.pinnedVariant !== "true") throw new UploadUsageError("--collection-pinned-variant can only be used when --collection-subject is asset");
5326
+ const pinnedVariantId = normalizeCollectionPinnedVariant(input.pinnedVariant);
5327
+ const placement = {
5328
+ role: input.role && input.role !== "true" ? input.role : "member",
5329
+ subjectType,
5330
+ pinnedVariantId
5331
+ };
5332
+ return [...collectionIds.map((collectionId) => ({
5333
+ ...placement,
5334
+ collectionId
5335
+ })), ...collectionNames.map((collectionName) => ({
5336
+ ...placement,
5337
+ collectionName
5338
+ }))];
5339
+ }
5340
+ function normalizeCollectionPinnedVariant(value) {
5341
+ if (!value || value === "true" || value === "uploaded") return void 0;
5342
+ if (value === "none" || value === "unpin") return null;
5343
+ return value;
5344
+ }
5345
+ function parseManualRelations(input) {
5346
+ const relationSpecs = parseCsvOption$1(input.relations, "--manual-relation");
5347
+ if (relationSpecs.length === 0) return [];
5348
+ const subjectType = normalizeSpaceSubjectType(input.subjectType, "--manual-relation-subject", "variant");
5349
+ const context = parseJsonObjectOrStringOption(input.context, "--manual-relation-context");
5350
+ const metadata = parseJsonObjectOption(input.metadata, "--manual-relation-metadata");
5351
+ return relationSpecs.map((spec) => {
5352
+ const parts = spec.split(":");
5353
+ if (parts.length !== 3) throw new UploadUsageError("--manual-relation entries must use <relation-type>:asset:<asset-id> or <relation-type>:variant:<variant-id>");
5354
+ const [relationTypeValue, objectTypeValue, objectId] = parts;
5355
+ const objectType = normalizeSpaceSubjectType(objectTypeValue, "--manual-relation object type", "asset");
5356
+ if (!objectId) throw new UploadUsageError("--manual-relation object id is required");
5357
+ return {
5358
+ relationType: normalizeManualRelationType(relationTypeValue, "--manual-relation"),
5359
+ object: objectType === "asset" ? {
5360
+ subjectType: "asset",
5361
+ assetId: objectId
5362
+ } : {
5363
+ subjectType: "variant",
5364
+ variantId: objectId
5365
+ },
5366
+ subjectType,
5367
+ label: input.label && input.label !== "true" ? input.label : void 0,
5368
+ context,
5369
+ metadata
5370
+ };
5371
+ });
5372
+ }
5373
+ async function preflightUploadOrganization(ctx, deps, options) {
5374
+ const needsCollections = options.collectionPlacements.length > 0;
5375
+ const needsAssetState = Boolean(options.sourceVariantId) || options.manualRelations.length > 0 || options.collectionPlacements.some((placement) => placement.pinnedVariantId);
5376
+ const [collections, state] = await Promise.all([needsCollections ? fetchJson$1(ctx, deps, `/api/spaces/${ctx.spaceId}/collections`) : void 0, needsAssetState ? fetchAssetState(ctx, deps) : void 0]);
5377
+ if (collections) {
5378
+ const collectionList = collections.collections ?? [];
5379
+ const collectionIds = new Set(collectionList.map((collection) => collection.id));
5380
+ for (const placement of options.collectionPlacements) {
5381
+ if (placement.collectionId && !collectionIds.has(placement.collectionId)) throw new Error(`Collection not found: ${placement.collectionId}`);
5382
+ if (!placement.collectionName) continue;
5383
+ const matches = collectionList.filter((collection) => collection.name === placement.collectionName);
5384
+ if (matches.length === 0) throw new Error(`Collection not found by exact name: ${placement.collectionName}`);
5385
+ if (matches.length > 1) throw new Error(`Collection name is ambiguous: ${placement.collectionName}; use --collection <id>`);
5386
+ placement.collectionId = matches[0].id;
5387
+ }
5388
+ }
5389
+ if (!state) return;
5390
+ if (options.sourceVariantId && !state.variantsById.has(options.sourceVariantId)) throw new Error(`Source variant not found in space: ${options.sourceVariantId}`);
5391
+ for (const placement of options.collectionPlacements) {
5392
+ if (!placement.pinnedVariantId) continue;
5393
+ const pinned = state.variantsById.get(placement.pinnedVariantId);
5394
+ if (!pinned) throw new Error(`Collection pinned variant not found: ${placement.pinnedVariantId}`);
5395
+ if (placement.subjectType === "asset") {
5396
+ if (!options.assetId) throw new Error("--collection-pinned-variant cannot reference an existing variant when creating a new asset");
5397
+ if (pinned.asset_id !== options.assetId) throw new Error("--collection-pinned-variant must reference a variant on the target asset");
5398
+ }
5399
+ }
5400
+ for (const relation of options.manualRelations) if (relation.object.subjectType === "asset") {
5401
+ if (!relation.object.assetId || !state.assetsById.has(relation.object.assetId)) throw new Error(`Manual relation object asset not found: ${relation.object.assetId ?? ""}`);
5402
+ } else if (!relation.object.variantId || !state.variantsById.has(relation.object.variantId)) throw new Error(`Manual relation object variant not found: ${relation.object.variantId ?? ""}`);
5403
+ }
5404
+ async function fetchAssetState(ctx, deps) {
5405
+ const assets = (await fetchJson$1(ctx, deps, `/api/spaces/${ctx.spaceId}/assets`)).assets ?? [];
5406
+ const variantsById = /* @__PURE__ */ new Map();
5407
+ await Promise.all(assets.map(async (asset) => {
5408
+ const details = await fetchJson$1(ctx, deps, `/api/spaces/${ctx.spaceId}/assets/${encodeURIComponent(asset.id)}`);
5409
+ for (const variant of details.variants ?? []) variantsById.set(variant.id, variant);
5410
+ }));
5411
+ return {
5412
+ assetsById: new Map(assets.map((asset) => [asset.id, asset])),
5413
+ variantsById
5414
+ };
5415
+ }
5416
+ async function applyUploadOrganization(ctx, deps, upload, options) {
5417
+ const collectionItemIds = [];
5418
+ const relationIds = [];
5419
+ const uploadedSubject = {
5420
+ assetId: upload.variant.asset_id,
5421
+ variantId: upload.variant.id
5422
+ };
5423
+ for (const placement of options.collectionPlacements) {
5424
+ if (!placement.collectionId) throw new Error(`Collection name was not resolved: ${placement.collectionName ?? ""}`);
5425
+ const body = placement.subjectType === "asset" ? {
5426
+ subjectType: "asset",
5427
+ assetId: uploadedSubject.assetId,
5428
+ role: placement.role,
5429
+ pinnedVariantId: placement.pinnedVariantId === void 0 ? uploadedSubject.variantId : placement.pinnedVariantId
5430
+ } : {
5431
+ subjectType: "variant",
5432
+ variantId: uploadedSubject.variantId,
5433
+ role: placement.role
5434
+ };
5435
+ const created = await postJson(ctx, deps, `/api/spaces/${ctx.spaceId}/collections/${encodeURIComponent(placement.collectionId)}/items`, body);
5436
+ collectionItemIds.push(created.item.id);
5437
+ }
5438
+ for (const relation of options.manualRelations) {
5439
+ const created = await postJson(ctx, deps, `/api/spaces/${ctx.spaceId}/relations`, {
5440
+ subject: relation.subjectType === "asset" ? {
5441
+ subjectType: "asset",
5442
+ assetId: uploadedSubject.assetId
5443
+ } : {
5444
+ subjectType: "variant",
5445
+ variantId: uploadedSubject.variantId
5446
+ },
5447
+ object: relation.object,
5448
+ relationType: relation.relationType,
5449
+ label: relation.label,
5450
+ context: relation.context,
5451
+ metadata: relation.metadata
5452
+ });
5453
+ relationIds.push(created.relation.id);
5454
+ }
5455
+ return {
5456
+ collectionItemIds,
5457
+ relationIds
5149
5458
  };
5150
- if (requestedMediaKind && requestedMediaKind !== mediaType.mediaKind) throw new Error(`--media-kind ${requestedMediaKind} does not match ${ext} (${mediaType.mediaKind})`);
5151
- return mediaType;
5152
5459
  }
5153
- function printUsage$9() {
5460
+ async function postJson(ctx, deps, requestPath, json) {
5461
+ const response = await deps.fetch(`${ctx.baseUrl}${requestPath}`, {
5462
+ method: "POST",
5463
+ headers: {
5464
+ Authorization: `Bearer ${ctx.accessToken}`,
5465
+ Accept: "application/json",
5466
+ "Content-Type": "application/json"
5467
+ },
5468
+ body: JSON.stringify(stripUndefined(json))
5469
+ });
5470
+ const data = await response.json().catch(() => ({}));
5471
+ if (!response.ok) throw new Error("error" in data ? data.error : `Request failed: ${response.status}`);
5472
+ return data;
5473
+ }
5474
+ async function fetchJson$1(ctx, deps, requestPath) {
5475
+ const response = await deps.fetch(`${ctx.baseUrl}${requestPath}`, { headers: {
5476
+ Authorization: `Bearer ${ctx.accessToken}`,
5477
+ Accept: "application/json"
5478
+ } });
5479
+ const data = await response.json().catch(() => ({}));
5480
+ if (!response.ok) throw new Error("error" in data ? data.error : `Request failed: ${response.status}`);
5481
+ return data;
5482
+ }
5483
+ function stripUndefined(value) {
5484
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
5485
+ }
5486
+ function printUsage$11() {
5154
5487
  console.log(`
5155
5488
  Usage:
5156
5489
  makefx upload <file> --asset <id> [--space <id>] Upload media to existing asset
5157
- makefx upload <file> --name <name> [--space <id>] Create new asset
5490
+ makefx upload <file> --name <name> [--space <id>] Upload media as a new asset
5158
5491
 
5159
5492
  Options:
5160
5493
  --space <id> Target space ID; defaults from initialized project
@@ -5162,16 +5495,43 @@ Options:
5162
5495
  --name <name> New asset name (creates asset + variant)
5163
5496
  --type <type> Asset type for new assets (default: character)
5164
5497
  --media-kind <k> Optional explicit kind: image, audio, or video
5165
- --parent <id> Parent asset ID for new assets
5498
+ --prompt <text> Prompt provenance for uploaded media
5499
+ --model <model> Model provenance for uploaded media
5500
+ --provider <name> Provider provenance for uploaded media
5501
+ --provider-metadata <json> Provider metadata JSON object
5502
+ --generation-provenance <json> Extra provenance JSON object
5503
+ --source-variant <id> Existing source variant for upload lineage
5504
+ --relation-type <type> Lineage type: derived, refined, or forked (default: derived)
5505
+ --active-variant-behavior <b> if-missing, set-active, or keep
5506
+ --collection <ids> Comma-separated collection IDs for the uploaded asset or variant
5507
+ --collection-name <names> Comma-separated exact collection names for lookup
5508
+ --collection-role <role> Collection item role (default: member)
5509
+ --collection-subject <type> Collection subject: asset or variant (default: asset)
5510
+ --collection-pinned-variant <id|uploaded|none>
5511
+ Pin an asset collection item to the uploaded variant by default
5512
+ --manual-relation <spec> Comma-separated <type>:asset:<id> or <type>:variant:<id>
5513
+ --manual-relation-subject <type>
5514
+ Relation subject: uploaded asset or variant (default: variant)
5515
+ --manual-relation-label <text> Optional manual relation label
5516
+ --manual-relation-context <json|string>
5517
+ Optional manual relation context
5518
+ --manual-relation-metadata <json>
5519
+ Optional manual relation metadata object
5520
+ --json Print machine-readable upload output with Space IDs
5166
5521
  --env <env> Environment (production|stage|local)
5167
5522
  --local Shortcut for --env local
5168
5523
 
5169
5524
  Examples:
5170
5525
  makefx upload hero.png --space abc123 --name "Hero Character"
5526
+ makefx upload hero.png --space abc123 --name "Hero" --prompt "external render" --provider blender
5527
+ makefx upload paintover.png --space abc123 --asset def456 --source-variant var123 --relation-type refined
5528
+ makefx upload hero.png --space abc123 --name "Hero" --collection collection_cast --collection-role character
5529
+ makefx upload hero.png --space abc123 --name "Hero" --collection-name "Cast" --collection-role character
5530
+ makefx upload thumbnail.png --space abc123 --asset asset_thumb --manual-relation thumbnail_for:asset:asset_target
5171
5531
  makefx upload theme.mp3 --space abc123 --name "Theme Music" --type audio
5172
5532
  makefx upload cutscene.mp4 --space abc123 --name "Opening Cutscene" --type video
5173
5533
  makefx upload variant.jpg --space abc123 --asset def456
5174
- makefx upload sword.png --space abc123 --name "Sword" --type item --parent abc789
5534
+ makefx upload hero.png --space abc123 --name "Hero" --json
5175
5535
  `);
5176
5536
  }
5177
5537
  //#endregion
@@ -19110,7 +19470,8 @@ var UserProfileSchema = object({
19110
19470
  }).openapi("UserProfile");
19111
19471
  var SessionConfigSchema = object({
19112
19472
  googleClientId: string$1(),
19113
- environment: string$1()
19473
+ environment: string$1(),
19474
+ features: object({ rotation: boolean$1() })
19114
19475
  }).openapi("SessionConfig");
19115
19476
  var AuthSessionResponseSchema = object({
19116
19477
  user: ApiUserSchema.nullable(),
@@ -19138,6 +19499,33 @@ var UserSettingsResponseSchema = object({
19138
19499
  success: literal(true),
19139
19500
  user: ApiUserSchema
19140
19501
  }).openapi("UserSettingsResponse");
19502
+ var ProviderKeyProviderSchema = _enum([
19503
+ "google_ai",
19504
+ "anthropic",
19505
+ "elevenlabs",
19506
+ "lyria"
19507
+ ]).openapi("ProviderKeyProvider");
19508
+ var ProviderKeyParamsSchema = object({ provider: ProviderKeyProviderSchema.openapi({ param: {
19509
+ name: "provider",
19510
+ in: "path"
19511
+ } }) });
19512
+ var ProviderKeySummarySchema = object({
19513
+ provider: ProviderKeyProviderSchema,
19514
+ label: string$1(),
19515
+ configured: boolean$1(),
19516
+ keyHint: string$1().nullable(),
19517
+ updatedAt: string$1().nullable(),
19518
+ platformConfigured: boolean$1()
19519
+ }).openapi("ProviderKeySummary");
19520
+ var ListProviderKeysResponseSchema = object({
19521
+ success: literal(true),
19522
+ providers: array(ProviderKeySummarySchema)
19523
+ }).openapi("ListProviderKeysResponse");
19524
+ var UpsertProviderKeyRequestSchema = object({ apiKey: string$1() }).openapi("UpsertProviderKeyRequest");
19525
+ var ProviderKeyResponseSchema = object({
19526
+ success: literal(true),
19527
+ provider: ProviderKeySummarySchema
19528
+ }).openapi("ProviderKeyResponse");
19141
19529
  var SpaceRoleSchema = _enum([
19142
19530
  "owner",
19143
19531
  "editor",
@@ -19191,6 +19579,12 @@ var VariantStatusSchema = _enum([
19191
19579
  "completed",
19192
19580
  "failed"
19193
19581
  ]);
19582
+ var PlatformUsageTypeSchema = _enum([
19583
+ "storage",
19584
+ "workflow",
19585
+ "delivery"
19586
+ ]);
19587
+ var PlatformUsageUnitSchema = _enum(["byte", "run"]);
19194
19588
  var BooleanFromSqliteSchema = union([
19195
19589
  boolean$1(),
19196
19590
  literal(0),
@@ -19240,10 +19634,454 @@ var VariantSchema = object({
19240
19634
  created_at: number$1(),
19241
19635
  updated_at: number$1().nullable()
19242
19636
  }).passthrough().openapi("Variant");
19637
+ var LineageSchema = object({
19638
+ id: string$1(),
19639
+ parent_variant_id: string$1(),
19640
+ child_variant_id: string$1(),
19641
+ relation_type: _enum([
19642
+ "derived",
19643
+ "refined",
19644
+ "forked"
19645
+ ]),
19646
+ severed: BooleanFromSqliteSchema.optional(),
19647
+ created_at: number$1().optional()
19648
+ }).passthrough().openapi("Lineage");
19243
19649
  var ListSpaceAssetsResponseSchema = object({
19244
19650
  success: literal(true),
19245
19651
  assets: array(AssetSchema)
19246
19652
  }).openapi("ListSpaceAssetsResponse");
19653
+ var SpaceSubjectTypeSchema = _enum(["asset", "variant"]);
19654
+ var CollectionKindSchema = _enum([
19655
+ "cast",
19656
+ "style_refs",
19657
+ "backgrounds",
19658
+ "scenes",
19659
+ "thumbnails",
19660
+ "maps",
19661
+ "deliverables",
19662
+ "custom"
19663
+ ]);
19664
+ var SpaceRelationTypeSchema = _enum([
19665
+ "appears_in",
19666
+ "background_for",
19667
+ "style_reference_for",
19668
+ "thumbnail_for",
19669
+ "alternate_of",
19670
+ "prop_in",
19671
+ "map_for",
19672
+ "part_of",
19673
+ "reference_for",
19674
+ "custom"
19675
+ ]);
19676
+ var CompositionItemRoleSchema = _enum([
19677
+ "output",
19678
+ "background",
19679
+ "character",
19680
+ "prop",
19681
+ "style_ref",
19682
+ "overlay",
19683
+ "map",
19684
+ "thumbnail",
19685
+ "custom"
19686
+ ]);
19687
+ var CompositionStatusSchema = _enum(["draft", "final"]);
19688
+ var CollectionIdParamsSchema = SpaceIdParamsSchema.extend({ collectionId: string$1().openapi({ param: {
19689
+ name: "collectionId",
19690
+ in: "path"
19691
+ } }) });
19692
+ var CollectionItemParamsSchema = CollectionIdParamsSchema.extend({ itemId: string$1().openapi({ param: {
19693
+ name: "itemId",
19694
+ in: "path"
19695
+ } }) });
19696
+ var StylePresetParamsSchema = SpaceIdParamsSchema.extend({ presetId: string$1().openapi({ param: {
19697
+ name: "presetId",
19698
+ in: "path"
19699
+ } }) });
19700
+ var RelationParamsSchema = SpaceIdParamsSchema.extend({ relationId: string$1().openapi({ param: {
19701
+ name: "relationId",
19702
+ in: "path"
19703
+ } }) });
19704
+ var CompositionIdParamsSchema = SpaceIdParamsSchema.extend({ compositionId: string$1().openapi({ param: {
19705
+ name: "compositionId",
19706
+ in: "path"
19707
+ } }) });
19708
+ var CompositionItemParamsSchema = CompositionIdParamsSchema.extend({ itemId: string$1().openapi({ param: {
19709
+ name: "itemId",
19710
+ in: "path"
19711
+ } }) });
19712
+ var SpaceSubjectSchema = object({
19713
+ subjectType: SpaceSubjectTypeSchema,
19714
+ assetId: string$1().optional(),
19715
+ variantId: string$1().optional()
19716
+ }).openapi("SpaceSubject");
19717
+ var SpaceCollectionSchema = object({
19718
+ id: string$1(),
19719
+ name: string$1(),
19720
+ kind: CollectionKindSchema,
19721
+ color: string$1().nullable(),
19722
+ description: string$1().nullable(),
19723
+ sort_index: number$1().int(),
19724
+ created_by: string$1(),
19725
+ created_at: number$1(),
19726
+ updated_at: number$1()
19727
+ }).openapi("SpaceCollection");
19728
+ var CollectionItemSchema = object({
19729
+ id: string$1(),
19730
+ collection_id: string$1(),
19731
+ subject_type: SpaceSubjectTypeSchema,
19732
+ asset_id: string$1().nullable(),
19733
+ variant_id: string$1().nullable(),
19734
+ role: string$1(),
19735
+ pinned_variant_id: string$1().nullable(),
19736
+ sort_index: number$1().int(),
19737
+ created_by: string$1(),
19738
+ created_at: number$1(),
19739
+ updated_at: number$1()
19740
+ }).openapi("CollectionItem");
19741
+ var StyleReferenceCollectionSchema = SpaceCollectionSchema.extend({
19742
+ reference_count: number$1().int(),
19743
+ preset_count: number$1().int()
19744
+ }).openapi("StyleReferenceCollection");
19745
+ var StylePresetSchema = object({
19746
+ id: string$1(),
19747
+ name: string$1(),
19748
+ description: string$1().nullable(),
19749
+ style_prompt: string$1(),
19750
+ collection_id: string$1().nullable(),
19751
+ enabled: BooleanFromSqliteSchema,
19752
+ is_default: BooleanFromSqliteSchema,
19753
+ created_by: string$1(),
19754
+ created_at: number$1(),
19755
+ updated_at: number$1(),
19756
+ collection_name: string$1().nullable(),
19757
+ reference_count: number$1().int(),
19758
+ style_reference_variant_ids: array(string$1()),
19759
+ style_reference_image_keys: array(string$1())
19760
+ }).openapi("StylePreset");
19761
+ var SpaceRelationSchema = object({
19762
+ id: string$1(),
19763
+ subject_type: SpaceSubjectTypeSchema,
19764
+ subject_asset_id: string$1().nullable(),
19765
+ subject_variant_id: string$1().nullable(),
19766
+ object_type: SpaceSubjectTypeSchema,
19767
+ object_asset_id: string$1().nullable(),
19768
+ object_variant_id: string$1().nullable(),
19769
+ relation_type: SpaceRelationTypeSchema,
19770
+ label: string$1().nullable(),
19771
+ context: string$1().nullable(),
19772
+ metadata: string$1(),
19773
+ sort_index: number$1().int(),
19774
+ created_by: string$1(),
19775
+ created_at: number$1(),
19776
+ updated_at: number$1()
19777
+ }).openapi("SpaceRelation");
19778
+ var CompositionSchema = object({
19779
+ id: string$1(),
19780
+ name: string$1(),
19781
+ description: string$1().nullable(),
19782
+ status: CompositionStatusSchema,
19783
+ output_asset_id: string$1().nullable(),
19784
+ output_variant_id: string$1().nullable(),
19785
+ metadata: string$1(),
19786
+ sort_index: number$1().int(),
19787
+ created_by: string$1(),
19788
+ created_at: number$1(),
19789
+ updated_at: number$1()
19790
+ }).openapi("Composition");
19791
+ var CompositionItemSchema = object({
19792
+ id: string$1(),
19793
+ composition_id: string$1(),
19794
+ role: CompositionItemRoleSchema,
19795
+ label: string$1().nullable(),
19796
+ asset_id: string$1().nullable(),
19797
+ variant_id: string$1(),
19798
+ metadata: string$1(),
19799
+ sort_index: number$1().int(),
19800
+ created_by: string$1(),
19801
+ created_at: number$1(),
19802
+ updated_at: number$1()
19803
+ }).openapi("CompositionItem");
19804
+ var UpsertCollectionRequestSchema = object({
19805
+ id: string$1().optional(),
19806
+ name: string$1().min(1),
19807
+ kind: CollectionKindSchema.optional(),
19808
+ color: string$1().nullable().optional(),
19809
+ description: string$1().nullable().optional(),
19810
+ sortIndex: number$1().int().optional()
19811
+ }).openapi("UpsertCollectionRequest");
19812
+ var UpdateCollectionRequestSchema = UpsertCollectionRequestSchema.omit({ id: true }).partial().openapi("UpdateCollectionRequest");
19813
+ var UpsertCollectionItemRequestSchema = object({
19814
+ id: string$1().optional(),
19815
+ subjectType: SpaceSubjectTypeSchema,
19816
+ assetId: string$1().optional(),
19817
+ variantId: string$1().optional(),
19818
+ role: string$1().optional(),
19819
+ pinnedVariantId: string$1().nullable().optional(),
19820
+ sortIndex: number$1().int().optional()
19821
+ }).openapi("UpsertCollectionItemRequest");
19822
+ var UpsertStylePresetRequestSchema = object({
19823
+ id: string$1().optional(),
19824
+ name: string$1().min(1),
19825
+ description: string$1().nullable().optional(),
19826
+ stylePrompt: string$1().optional(),
19827
+ collectionId: string$1().nullable().optional(),
19828
+ enabled: boolean$1().optional(),
19829
+ isDefault: boolean$1().optional()
19830
+ }).openapi("UpsertStylePresetRequest");
19831
+ var UpdateStylePresetRequestSchema = UpsertStylePresetRequestSchema.omit({
19832
+ id: true,
19833
+ name: true
19834
+ }).extend({ name: string$1().min(1).optional() }).openapi("UpdateStylePresetRequest");
19835
+ var UpdateCollectionItemRequestSchema = object({
19836
+ role: string$1().optional(),
19837
+ pinnedVariantId: string$1().nullable().optional(),
19838
+ sortIndex: number$1().int().optional()
19839
+ }).openapi("UpdateCollectionItemRequest");
19840
+ var ReorderItemsRequestSchema = object({ itemIds: array(string$1()) }).openapi("ReorderItemsRequest");
19841
+ var UpsertRelationRequestSchema = object({
19842
+ id: string$1().optional(),
19843
+ subject: SpaceSubjectSchema,
19844
+ object: SpaceSubjectSchema,
19845
+ relationType: SpaceRelationTypeSchema,
19846
+ label: string$1().nullable().optional(),
19847
+ context: union([string$1(), record(string$1(), unknown())]).nullable().optional(),
19848
+ metadata: record(string$1(), unknown()).optional(),
19849
+ sortIndex: number$1().int().optional()
19850
+ }).openapi("UpsertRelationRequest");
19851
+ var UpdateRelationRequestSchema = object({
19852
+ relationType: SpaceRelationTypeSchema.optional(),
19853
+ label: string$1().nullable().optional(),
19854
+ context: union([string$1(), record(string$1(), unknown())]).nullable().optional(),
19855
+ metadata: record(string$1(), unknown()).optional(),
19856
+ sortIndex: number$1().int().optional()
19857
+ }).openapi("UpdateRelationRequest");
19858
+ var UpsertCompositionRequestSchema = object({
19859
+ id: string$1().optional(),
19860
+ name: string$1().min(1),
19861
+ description: string$1().nullable().optional(),
19862
+ status: CompositionStatusSchema.optional(),
19863
+ outputAssetId: string$1().nullable().optional(),
19864
+ outputVariantId: string$1().nullable().optional(),
19865
+ metadata: record(string$1(), unknown()).optional(),
19866
+ sortIndex: number$1().int().optional()
19867
+ }).openapi("UpsertCompositionRequest");
19868
+ var UpdateCompositionRequestSchema = UpsertCompositionRequestSchema.omit({
19869
+ id: true,
19870
+ name: true
19871
+ }).extend({ name: string$1().min(1).optional() }).openapi("UpdateCompositionRequest");
19872
+ var UpsertCompositionItemRequestSchema = object({
19873
+ id: string$1().optional(),
19874
+ role: CompositionItemRoleSchema,
19875
+ label: string$1().nullable().optional(),
19876
+ assetId: string$1().nullable().optional(),
19877
+ variantId: string$1().min(1),
19878
+ metadata: record(string$1(), unknown()).optional(),
19879
+ sortIndex: number$1().int().optional()
19880
+ }).openapi("UpsertCompositionItemRequest");
19881
+ var UpdateCompositionItemRequestSchema = object({
19882
+ role: CompositionItemRoleSchema.optional(),
19883
+ label: string$1().nullable().optional(),
19884
+ assetId: string$1().nullable().optional(),
19885
+ variantId: string$1().optional(),
19886
+ metadata: record(string$1(), unknown()).optional(),
19887
+ sortIndex: number$1().int().optional()
19888
+ }).openapi("UpdateCompositionItemRequest");
19889
+ var ListCollectionsResponseSchema = object({
19890
+ success: literal(true),
19891
+ collections: array(SpaceCollectionSchema)
19892
+ }).openapi("ListCollectionsResponse");
19893
+ var CollectionResponseSchema = object({
19894
+ success: literal(true),
19895
+ collection: SpaceCollectionSchema
19896
+ }).openapi("CollectionResponse");
19897
+ var ListCollectionItemsResponseSchema = object({
19898
+ success: literal(true),
19899
+ items: array(CollectionItemSchema)
19900
+ }).openapi("ListCollectionItemsResponse");
19901
+ var CollectionItemResponseSchema = object({
19902
+ success: literal(true),
19903
+ item: CollectionItemSchema
19904
+ }).openapi("CollectionItemResponse");
19905
+ var ListStyleReferenceCollectionsResponseSchema = object({
19906
+ success: literal(true),
19907
+ collections: array(StyleReferenceCollectionSchema)
19908
+ }).openapi("ListStyleReferenceCollectionsResponse");
19909
+ var ListStylePresetsResponseSchema = object({
19910
+ success: literal(true),
19911
+ presets: array(StylePresetSchema)
19912
+ }).openapi("ListStylePresetsResponse");
19913
+ var StylePresetResponseSchema = object({
19914
+ success: literal(true),
19915
+ preset: StylePresetSchema
19916
+ }).openapi("StylePresetResponse");
19917
+ var ListRelationsResponseSchema = object({
19918
+ success: literal(true),
19919
+ relations: array(SpaceRelationSchema)
19920
+ }).openapi("ListRelationsResponse");
19921
+ var RelationResponseSchema = object({
19922
+ success: literal(true),
19923
+ relation: SpaceRelationSchema
19924
+ }).openapi("RelationResponse");
19925
+ var ListCompositionsResponseSchema = object({
19926
+ success: literal(true),
19927
+ compositions: array(CompositionSchema)
19928
+ }).openapi("ListCompositionsResponse");
19929
+ var CompositionResponseSchema = object({
19930
+ success: literal(true),
19931
+ composition: CompositionSchema
19932
+ }).openapi("CompositionResponse");
19933
+ var ListCompositionItemsResponseSchema = object({
19934
+ success: literal(true),
19935
+ items: array(CompositionItemSchema)
19936
+ }).openapi("ListCompositionItemsResponse");
19937
+ var CompositionItemResponseSchema = object({
19938
+ success: literal(true),
19939
+ item: CompositionItemSchema
19940
+ }).openapi("CompositionItemResponse");
19941
+ var UsageSummaryQuerySchema = object({
19942
+ from: string$1().optional(),
19943
+ to: string$1().optional()
19944
+ });
19945
+ var PlatformUsageTypeSummarySchema = object({
19946
+ usageType: PlatformUsageTypeSchema,
19947
+ unit: PlatformUsageUnitSchema,
19948
+ quantity: number$1().int(),
19949
+ events: number$1().int().nonnegative()
19950
+ }).openapi("PlatformUsageTypeSummary");
19951
+ var PlatformUsageMediaKindSummarySchema = object({
19952
+ mediaKind: MediaKindSchema.nullable(),
19953
+ storageBytes: number$1().int(),
19954
+ workflowRuns: number$1().int(),
19955
+ deliveryBytes: number$1().int(),
19956
+ events: number$1().int().nonnegative()
19957
+ }).openapi("PlatformUsageMediaKindSummary");
19958
+ var PlatformUsageSummaryResponseSchema = object({
19959
+ success: literal(true),
19960
+ spaceId: string$1(),
19961
+ period: object({
19962
+ from: string$1().nullable(),
19963
+ to: string$1().nullable()
19964
+ }),
19965
+ totals: object({
19966
+ storageBytes: number$1().int(),
19967
+ workflowRuns: number$1().int(),
19968
+ deliveryBytes: number$1().int()
19969
+ }),
19970
+ byType: array(PlatformUsageTypeSummarySchema),
19971
+ byMediaKind: array(PlatformUsageMediaKindSummarySchema)
19972
+ }).openapi("PlatformUsageSummaryResponse");
19973
+ var ProviderSpendSummaryQuerySchema = object({
19974
+ from: string$1().optional(),
19975
+ to: string$1().optional(),
19976
+ user_id: string$1().optional(),
19977
+ userId: string$1().optional(),
19978
+ space_id: string$1().optional(),
19979
+ spaceId: string$1().optional(),
19980
+ provider: string$1().optional(),
19981
+ media_kind: MediaKindSchema.optional(),
19982
+ mediaKind: MediaKindSchema.optional()
19983
+ });
19984
+ var ProviderSpendAggregateSchema = object({
19985
+ amountMicroUsd: number$1().int(),
19986
+ amountUsd: number$1(),
19987
+ quantity: number$1(),
19988
+ entries: number$1().int().nonnegative(),
19989
+ unpricedEntries: number$1().int().nonnegative()
19990
+ }).openapi("ProviderSpendAggregate");
19991
+ var ProviderSpendSummaryResponseSchema = object({
19992
+ success: literal(true),
19993
+ period: object({
19994
+ from: string$1().nullable(),
19995
+ to: string$1().nullable()
19996
+ }),
19997
+ filters: object({
19998
+ userId: number$1().int().nullable(),
19999
+ spaceId: string$1().nullable(),
20000
+ provider: string$1().nullable(),
20001
+ mediaKind: MediaKindSchema.nullable()
20002
+ }),
20003
+ totals: ProviderSpendAggregateSchema,
20004
+ byProvider: array(ProviderSpendAggregateSchema.extend({ provider: string$1() })),
20005
+ byModel: array(ProviderSpendAggregateSchema.extend({
20006
+ provider: string$1(),
20007
+ providerModel: string$1()
20008
+ })),
20009
+ byMediaKind: array(ProviderSpendAggregateSchema.extend({ mediaKind: MediaKindSchema.nullable() })),
20010
+ byMeterEventName: array(ProviderSpendAggregateSchema.extend({ meterEventName: string$1().nullable() })),
20011
+ bySpace: array(ProviderSpendAggregateSchema.extend({ spaceId: string$1().nullable() })),
20012
+ byAsset: array(ProviderSpendAggregateSchema.extend({
20013
+ spaceId: string$1().nullable(),
20014
+ assetId: string$1().nullable()
20015
+ }))
20016
+ }).openapi("ProviderSpendSummaryResponse");
20017
+ var BillingEntitlementSchema = _enum([
20018
+ "none",
20019
+ "paid",
20020
+ "internal"
20021
+ ]).openapi("BillingEntitlement");
20022
+ var BillingPlanStatusSchema = _enum([
20023
+ "inactive",
20024
+ "active",
20025
+ "internal"
20026
+ ]).openapi("BillingPlanStatus");
20027
+ var BillingPlanStatusResponseSchema = object({
20028
+ key: literal("paid_generation"),
20029
+ displayName: string$1(),
20030
+ status: BillingPlanStatusSchema,
20031
+ checkoutAvailable: boolean$1(),
20032
+ portalAvailable: boolean$1()
20033
+ }).openapi("BillingPlanStatusResponse");
20034
+ var BillingMeterStatusSchema = object({
20035
+ name: string$1(),
20036
+ consumed: number$1(),
20037
+ credited: number$1(),
20038
+ remaining: number$1(),
20039
+ percentUsed: number$1(),
20040
+ hasLimit: boolean$1(),
20041
+ status: _enum([
20042
+ "ok",
20043
+ "warning",
20044
+ "critical",
20045
+ "exceeded"
20046
+ ])
20047
+ }).openapi("BillingMeterStatus");
20048
+ var BillingStatusResponseSchema = object({
20049
+ configured: boolean$1(),
20050
+ available: boolean$1(),
20051
+ hasSubscription: boolean$1(),
20052
+ entitlement: BillingEntitlementSchema,
20053
+ plan: BillingPlanStatusResponseSchema,
20054
+ meters: array(BillingMeterStatusSchema),
20055
+ subscription: object({
20056
+ status: string$1(),
20057
+ periodStart: string$1().nullable().optional(),
20058
+ renewsAt: string$1().nullable()
20059
+ }).nullable(),
20060
+ portalUrl: string$1().nullable(),
20061
+ error: string$1().optional()
20062
+ }).openapi("BillingStatusResponse");
20063
+ var BillingUsageMeterSchema = object({
20064
+ used: number$1(),
20065
+ limit: number$1().nullable(),
20066
+ remaining: number$1().nullable(),
20067
+ costUsd: number$1().optional()
20068
+ }).openapi("BillingUsageMeter");
20069
+ var BillingUsageResponseSchema = object({
20070
+ period: object({
20071
+ start: string$1(),
20072
+ end: string$1()
20073
+ }),
20074
+ usage: record(string$1(), BillingUsageMeterSchema),
20075
+ estimatedCost: object({
20076
+ amount: number$1(),
20077
+ currency: string$1()
20078
+ }).optional()
20079
+ }).openapi("BillingUsageResponse");
20080
+ var BillingUrlResponseSchema = object({ url: string$1() }).openapi("BillingUrlResponse");
20081
+ var BillingUrlQuerySchema = object({
20082
+ return_url: string$1().optional(),
20083
+ success_url: string$1().optional()
20084
+ });
19247
20085
  var ProductionRecordSchema = object({
19248
20086
  id: string$1(),
19249
20087
  production_id: string$1(),
@@ -19413,7 +20251,14 @@ var UploadMediaRequestSchema = object({
19413
20251
  assetName: string$1().optional(),
19414
20252
  assetType: string$1().optional(),
19415
20253
  mediaKind: MediaKindSchema.optional(),
19416
- parentAssetId: string$1().optional(),
20254
+ operation: string$1().optional(),
20255
+ prompt: string$1().optional(),
20256
+ model: string$1().optional(),
20257
+ provider: string$1().optional(),
20258
+ providerMetadata: string$1().optional(),
20259
+ generationProvenance: string$1().optional(),
20260
+ lineage: string$1().optional(),
20261
+ activeVariantBehavior: string$1().optional(),
19417
20262
  transcript: UploadFileSchema.optional(),
19418
20263
  wordTimings: UploadFileSchema.optional(),
19419
20264
  renderMetadata: UploadFileSchema.optional()
@@ -19421,14 +20266,9 @@ var UploadMediaRequestSchema = object({
19421
20266
  var UploadMediaResponseSchema = object({
19422
20267
  success: literal(true),
19423
20268
  variant: VariantSchema,
19424
- asset: AssetSchema.optional()
20269
+ asset: AssetSchema.optional(),
20270
+ lineage: array(LineageSchema).optional()
19425
20271
  }).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
20272
  var VariantMediaParamsSchema = object({
19433
20273
  spaceId: string$1().openapi({ param: {
19434
20274
  name: "spaceId",
@@ -19479,6 +20319,24 @@ var apiEndpoints = {
19479
20319
  jsonSchema: UpdateUserProfileRequestSchema,
19480
20320
  responseSchema: UserProfileUpdateResponseSchema
19481
20321
  },
20322
+ "GET /api/user/provider-keys": {
20323
+ method: "GET",
20324
+ path: "/api/user/provider-keys",
20325
+ responseSchema: ListProviderKeysResponseSchema
20326
+ },
20327
+ "PUT /api/user/provider-keys/:provider": {
20328
+ method: "PUT",
20329
+ path: "/api/user/provider-keys/:provider",
20330
+ paramsSchema: ProviderKeyParamsSchema,
20331
+ jsonSchema: UpsertProviderKeyRequestSchema,
20332
+ responseSchema: ProviderKeyResponseSchema
20333
+ },
20334
+ "DELETE /api/user/provider-keys/:provider": {
20335
+ method: "DELETE",
20336
+ path: "/api/user/provider-keys/:provider",
20337
+ paramsSchema: ProviderKeyParamsSchema,
20338
+ responseSchema: ProviderKeyResponseSchema
20339
+ },
19482
20340
  "POST /api/spaces": {
19483
20341
  method: "POST",
19484
20342
  path: "/api/spaces",
@@ -19502,73 +20360,284 @@ var apiEndpoints = {
19502
20360
  paramsSchema: SpaceIdParamsSchema,
19503
20361
  responseSchema: ListSpaceAssetsResponseSchema
19504
20362
  },
19505
- "GET /api/spaces/:id/productions": {
20363
+ "GET /api/spaces/:id/collections": {
19506
20364
  method: "GET",
19507
- path: "/api/spaces/:id/productions",
20365
+ path: "/api/spaces/:id/collections",
19508
20366
  paramsSchema: SpaceIdParamsSchema,
19509
- responseSchema: ListProductionsResponseSchema
20367
+ responseSchema: ListCollectionsResponseSchema
19510
20368
  },
19511
- "POST /api/spaces/:id/productions": {
20369
+ "POST /api/spaces/:id/collections": {
19512
20370
  method: "POST",
19513
- path: "/api/spaces/:id/productions",
20371
+ path: "/api/spaces/:id/collections",
19514
20372
  paramsSchema: SpaceIdParamsSchema,
19515
- jsonSchema: UpsertProductionRequestSchema,
19516
- responseSchema: ProductionResponseSchema
20373
+ jsonSchema: UpsertCollectionRequestSchema,
20374
+ responseSchema: CollectionResponseSchema
19517
20375
  },
19518
- "GET /api/spaces/:id/productions/:productionId": {
19519
- method: "GET",
19520
- path: "/api/spaces/:id/productions/:productionId",
19521
- paramsSchema: ProductionIdParamsSchema,
19522
- responseSchema: ProductionDetailResponseSchema
20376
+ "PATCH /api/spaces/:id/collections/:collectionId": {
20377
+ method: "PATCH",
20378
+ path: "/api/spaces/:id/collections/:collectionId",
20379
+ paramsSchema: CollectionIdParamsSchema,
20380
+ jsonSchema: UpdateCollectionRequestSchema,
20381
+ responseSchema: CollectionResponseSchema
19523
20382
  },
19524
- "DELETE /api/spaces/:id/productions/:productionId": {
20383
+ "DELETE /api/spaces/:id/collections/:collectionId": {
19525
20384
  method: "DELETE",
19526
- path: "/api/spaces/:id/productions/:productionId",
19527
- paramsSchema: ProductionIdParamsSchema,
20385
+ path: "/api/spaces/:id/collections/:collectionId",
20386
+ paramsSchema: CollectionIdParamsSchema,
19528
20387
  responseSchema: SuccessResponseSchema
19529
20388
  },
19530
- "POST /api/spaces/:id/productions/:productionId/shots": {
19531
- method: "POST",
19532
- path: "/api/spaces/:id/productions/:productionId/shots",
19533
- paramsSchema: ProductionIdParamsSchema,
19534
- jsonSchema: UpsertProductionShotRequestSchema,
19535
- responseSchema: ProductionShotResponseSchema
19536
- },
19537
- "DELETE /api/spaces/:id/productions/:productionId/shots/:childId": {
19538
- method: "DELETE",
19539
- path: "/api/spaces/:id/productions/:productionId/shots/:childId",
19540
- paramsSchema: ProductionChildParamsSchema,
19541
- responseSchema: SuccessResponseSchema
20389
+ "GET /api/spaces/:id/collections/:collectionId/items": {
20390
+ method: "GET",
20391
+ path: "/api/spaces/:id/collections/:collectionId/items",
20392
+ paramsSchema: CollectionIdParamsSchema,
20393
+ responseSchema: ListCollectionItemsResponseSchema
19542
20394
  },
19543
- "POST /api/spaces/:id/productions/:productionId/cues": {
20395
+ "POST /api/spaces/:id/collections/:collectionId/items": {
19544
20396
  method: "POST",
19545
- path: "/api/spaces/:id/productions/:productionId/cues",
19546
- paramsSchema: ProductionIdParamsSchema,
19547
- jsonSchema: UpsertProductionCueRequestSchema,
19548
- responseSchema: ProductionCueResponseSchema
20397
+ path: "/api/spaces/:id/collections/:collectionId/items",
20398
+ paramsSchema: CollectionIdParamsSchema,
20399
+ jsonSchema: UpsertCollectionItemRequestSchema,
20400
+ responseSchema: CollectionItemResponseSchema
19549
20401
  },
19550
- "DELETE /api/spaces/:id/productions/:productionId/cues/:childId": {
19551
- method: "DELETE",
19552
- path: "/api/spaces/:id/productions/:productionId/cues/:childId",
19553
- paramsSchema: ProductionChildParamsSchema,
19554
- responseSchema: SuccessResponseSchema
20402
+ "PATCH /api/spaces/:id/collections/:collectionId/items/:itemId": {
20403
+ method: "PATCH",
20404
+ path: "/api/spaces/:id/collections/:collectionId/items/:itemId",
20405
+ paramsSchema: CollectionItemParamsSchema,
20406
+ jsonSchema: UpdateCollectionItemRequestSchema,
20407
+ responseSchema: CollectionItemResponseSchema
19555
20408
  },
19556
- "POST /api/spaces/:id/productions/:productionId/placements": {
20409
+ "POST /api/spaces/:id/collections/:collectionId/items/reorder": {
19557
20410
  method: "POST",
19558
- path: "/api/spaces/:id/productions/:productionId/placements",
19559
- paramsSchema: ProductionIdParamsSchema,
19560
- jsonSchema: UpsertProductionPlacementRequestSchema,
19561
- responseSchema: ProductionPlacementResponseSchema
20411
+ path: "/api/spaces/:id/collections/:collectionId/items/reorder",
20412
+ paramsSchema: CollectionIdParamsSchema,
20413
+ jsonSchema: ReorderItemsRequestSchema,
20414
+ responseSchema: ListCollectionItemsResponseSchema
19562
20415
  },
19563
- "DELETE /api/spaces/:id/productions/:productionId/placements/:childId": {
20416
+ "DELETE /api/spaces/:id/collections/:collectionId/items/:itemId": {
19564
20417
  method: "DELETE",
19565
- path: "/api/spaces/:id/productions/:productionId/placements/:childId",
19566
- paramsSchema: ProductionChildParamsSchema,
20418
+ path: "/api/spaces/:id/collections/:collectionId/items/:itemId",
20419
+ paramsSchema: CollectionItemParamsSchema,
19567
20420
  responseSchema: SuccessResponseSchema
19568
20421
  },
19569
- "GET /api/spaces/:id/productions/:productionId/records": {
20422
+ "GET /api/spaces/:id/style-reference-collections": {
19570
20423
  method: "GET",
19571
- path: "/api/spaces/:id/productions/:productionId/records",
20424
+ path: "/api/spaces/:id/style-reference-collections",
20425
+ paramsSchema: SpaceIdParamsSchema,
20426
+ responseSchema: ListStyleReferenceCollectionsResponseSchema
20427
+ },
20428
+ "GET /api/spaces/:id/style-presets": {
20429
+ method: "GET",
20430
+ path: "/api/spaces/:id/style-presets",
20431
+ paramsSchema: SpaceIdParamsSchema,
20432
+ responseSchema: ListStylePresetsResponseSchema
20433
+ },
20434
+ "POST /api/spaces/:id/style-presets": {
20435
+ method: "POST",
20436
+ path: "/api/spaces/:id/style-presets",
20437
+ paramsSchema: SpaceIdParamsSchema,
20438
+ jsonSchema: UpsertStylePresetRequestSchema,
20439
+ responseSchema: StylePresetResponseSchema
20440
+ },
20441
+ "PATCH /api/spaces/:id/style-presets/:presetId": {
20442
+ method: "PATCH",
20443
+ path: "/api/spaces/:id/style-presets/:presetId",
20444
+ paramsSchema: StylePresetParamsSchema,
20445
+ jsonSchema: UpdateStylePresetRequestSchema,
20446
+ responseSchema: StylePresetResponseSchema
20447
+ },
20448
+ "DELETE /api/spaces/:id/style-presets/:presetId": {
20449
+ method: "DELETE",
20450
+ path: "/api/spaces/:id/style-presets/:presetId",
20451
+ paramsSchema: StylePresetParamsSchema,
20452
+ responseSchema: SuccessResponseSchema
20453
+ },
20454
+ "GET /api/spaces/:id/relations": {
20455
+ method: "GET",
20456
+ path: "/api/spaces/:id/relations",
20457
+ paramsSchema: SpaceIdParamsSchema,
20458
+ responseSchema: ListRelationsResponseSchema
20459
+ },
20460
+ "POST /api/spaces/:id/relations": {
20461
+ method: "POST",
20462
+ path: "/api/spaces/:id/relations",
20463
+ paramsSchema: SpaceIdParamsSchema,
20464
+ jsonSchema: UpsertRelationRequestSchema,
20465
+ responseSchema: RelationResponseSchema
20466
+ },
20467
+ "PATCH /api/spaces/:id/relations/:relationId": {
20468
+ method: "PATCH",
20469
+ path: "/api/spaces/:id/relations/:relationId",
20470
+ paramsSchema: RelationParamsSchema,
20471
+ jsonSchema: UpdateRelationRequestSchema,
20472
+ responseSchema: RelationResponseSchema
20473
+ },
20474
+ "DELETE /api/spaces/:id/relations/:relationId": {
20475
+ method: "DELETE",
20476
+ path: "/api/spaces/:id/relations/:relationId",
20477
+ paramsSchema: RelationParamsSchema,
20478
+ responseSchema: SuccessResponseSchema
20479
+ },
20480
+ "GET /api/spaces/:id/compositions": {
20481
+ method: "GET",
20482
+ path: "/api/spaces/:id/compositions",
20483
+ paramsSchema: SpaceIdParamsSchema,
20484
+ responseSchema: ListCompositionsResponseSchema
20485
+ },
20486
+ "POST /api/spaces/:id/compositions": {
20487
+ method: "POST",
20488
+ path: "/api/spaces/:id/compositions",
20489
+ paramsSchema: SpaceIdParamsSchema,
20490
+ jsonSchema: UpsertCompositionRequestSchema,
20491
+ responseSchema: CompositionResponseSchema
20492
+ },
20493
+ "PATCH /api/spaces/:id/compositions/:compositionId": {
20494
+ method: "PATCH",
20495
+ path: "/api/spaces/:id/compositions/:compositionId",
20496
+ paramsSchema: CompositionIdParamsSchema,
20497
+ jsonSchema: UpdateCompositionRequestSchema,
20498
+ responseSchema: CompositionResponseSchema
20499
+ },
20500
+ "DELETE /api/spaces/:id/compositions/:compositionId": {
20501
+ method: "DELETE",
20502
+ path: "/api/spaces/:id/compositions/:compositionId",
20503
+ paramsSchema: CompositionIdParamsSchema,
20504
+ responseSchema: SuccessResponseSchema
20505
+ },
20506
+ "GET /api/spaces/:id/compositions/:compositionId/items": {
20507
+ method: "GET",
20508
+ path: "/api/spaces/:id/compositions/:compositionId/items",
20509
+ paramsSchema: CompositionIdParamsSchema,
20510
+ responseSchema: ListCompositionItemsResponseSchema
20511
+ },
20512
+ "POST /api/spaces/:id/compositions/:compositionId/items": {
20513
+ method: "POST",
20514
+ path: "/api/spaces/:id/compositions/:compositionId/items",
20515
+ paramsSchema: CompositionIdParamsSchema,
20516
+ jsonSchema: UpsertCompositionItemRequestSchema,
20517
+ responseSchema: CompositionItemResponseSchema
20518
+ },
20519
+ "PATCH /api/spaces/:id/compositions/:compositionId/items/:itemId": {
20520
+ method: "PATCH",
20521
+ path: "/api/spaces/:id/compositions/:compositionId/items/:itemId",
20522
+ paramsSchema: CompositionItemParamsSchema,
20523
+ jsonSchema: UpdateCompositionItemRequestSchema,
20524
+ responseSchema: CompositionItemResponseSchema
20525
+ },
20526
+ "POST /api/spaces/:id/compositions/:compositionId/items/reorder": {
20527
+ method: "POST",
20528
+ path: "/api/spaces/:id/compositions/:compositionId/items/reorder",
20529
+ paramsSchema: CompositionIdParamsSchema,
20530
+ jsonSchema: ReorderItemsRequestSchema,
20531
+ responseSchema: ListCompositionItemsResponseSchema
20532
+ },
20533
+ "DELETE /api/spaces/:id/compositions/:compositionId/items/:itemId": {
20534
+ method: "DELETE",
20535
+ path: "/api/spaces/:id/compositions/:compositionId/items/:itemId",
20536
+ paramsSchema: CompositionItemParamsSchema,
20537
+ responseSchema: SuccessResponseSchema
20538
+ },
20539
+ "GET /api/spaces/:id/usage/summary": {
20540
+ method: "GET",
20541
+ path: "/api/spaces/:id/usage/summary",
20542
+ paramsSchema: SpaceIdParamsSchema,
20543
+ querySchema: UsageSummaryQuerySchema,
20544
+ responseSchema: PlatformUsageSummaryResponseSchema
20545
+ },
20546
+ "GET /api/billing/status": {
20547
+ method: "GET",
20548
+ path: "/api/billing/status",
20549
+ responseSchema: BillingStatusResponseSchema
20550
+ },
20551
+ "GET /api/billing/usage": {
20552
+ method: "GET",
20553
+ path: "/api/billing/usage",
20554
+ responseSchema: BillingUsageResponseSchema
20555
+ },
20556
+ "GET /api/billing/checkout": {
20557
+ method: "GET",
20558
+ path: "/api/billing/checkout",
20559
+ querySchema: BillingUrlQuerySchema,
20560
+ responseSchema: BillingUrlResponseSchema
20561
+ },
20562
+ "GET /api/billing/portal": {
20563
+ method: "GET",
20564
+ path: "/api/billing/portal",
20565
+ querySchema: BillingUrlQuerySchema,
20566
+ responseSchema: BillingUrlResponseSchema
20567
+ },
20568
+ "GET /api/billing/spend/summary": {
20569
+ method: "GET",
20570
+ path: "/api/billing/spend/summary",
20571
+ querySchema: ProviderSpendSummaryQuerySchema,
20572
+ responseSchema: ProviderSpendSummaryResponseSchema
20573
+ },
20574
+ "GET /api/spaces/:id/productions": {
20575
+ method: "GET",
20576
+ path: "/api/spaces/:id/productions",
20577
+ paramsSchema: SpaceIdParamsSchema,
20578
+ responseSchema: ListProductionsResponseSchema
20579
+ },
20580
+ "POST /api/spaces/:id/productions": {
20581
+ method: "POST",
20582
+ path: "/api/spaces/:id/productions",
20583
+ paramsSchema: SpaceIdParamsSchema,
20584
+ jsonSchema: UpsertProductionRequestSchema,
20585
+ responseSchema: ProductionResponseSchema
20586
+ },
20587
+ "GET /api/spaces/:id/productions/:productionId": {
20588
+ method: "GET",
20589
+ path: "/api/spaces/:id/productions/:productionId",
20590
+ paramsSchema: ProductionIdParamsSchema,
20591
+ responseSchema: ProductionDetailResponseSchema
20592
+ },
20593
+ "DELETE /api/spaces/:id/productions/:productionId": {
20594
+ method: "DELETE",
20595
+ path: "/api/spaces/:id/productions/:productionId",
20596
+ paramsSchema: ProductionIdParamsSchema,
20597
+ responseSchema: SuccessResponseSchema
20598
+ },
20599
+ "POST /api/spaces/:id/productions/:productionId/shots": {
20600
+ method: "POST",
20601
+ path: "/api/spaces/:id/productions/:productionId/shots",
20602
+ paramsSchema: ProductionIdParamsSchema,
20603
+ jsonSchema: UpsertProductionShotRequestSchema,
20604
+ responseSchema: ProductionShotResponseSchema
20605
+ },
20606
+ "DELETE /api/spaces/:id/productions/:productionId/shots/:childId": {
20607
+ method: "DELETE",
20608
+ path: "/api/spaces/:id/productions/:productionId/shots/:childId",
20609
+ paramsSchema: ProductionChildParamsSchema,
20610
+ responseSchema: SuccessResponseSchema
20611
+ },
20612
+ "POST /api/spaces/:id/productions/:productionId/cues": {
20613
+ method: "POST",
20614
+ path: "/api/spaces/:id/productions/:productionId/cues",
20615
+ paramsSchema: ProductionIdParamsSchema,
20616
+ jsonSchema: UpsertProductionCueRequestSchema,
20617
+ responseSchema: ProductionCueResponseSchema
20618
+ },
20619
+ "DELETE /api/spaces/:id/productions/:productionId/cues/:childId": {
20620
+ method: "DELETE",
20621
+ path: "/api/spaces/:id/productions/:productionId/cues/:childId",
20622
+ paramsSchema: ProductionChildParamsSchema,
20623
+ responseSchema: SuccessResponseSchema
20624
+ },
20625
+ "POST /api/spaces/:id/productions/:productionId/placements": {
20626
+ method: "POST",
20627
+ path: "/api/spaces/:id/productions/:productionId/placements",
20628
+ paramsSchema: ProductionIdParamsSchema,
20629
+ jsonSchema: UpsertProductionPlacementRequestSchema,
20630
+ responseSchema: ProductionPlacementResponseSchema
20631
+ },
20632
+ "DELETE /api/spaces/:id/productions/:productionId/placements/:childId": {
20633
+ method: "DELETE",
20634
+ path: "/api/spaces/:id/productions/:productionId/placements/:childId",
20635
+ paramsSchema: ProductionChildParamsSchema,
20636
+ responseSchema: SuccessResponseSchema
20637
+ },
20638
+ "GET /api/spaces/:id/productions/:productionId/records": {
20639
+ method: "GET",
20640
+ path: "/api/spaces/:id/productions/:productionId/records",
19572
20641
  paramsSchema: ProductionIdParamsSchema,
19573
20642
  responseSchema: ListProductionRecordsResponseSchema
19574
20643
  },
@@ -19598,13 +20667,6 @@ var apiEndpoints = {
19598
20667
  formSchema: UploadMediaRequestSchema,
19599
20668
  responseSchema: UploadMediaResponseSchema
19600
20669
  },
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
20670
  "GET /api/spaces/:spaceId/variants/:variantId/media": {
19609
20671
  method: "GET",
19610
20672
  path: "/api/spaces/:spaceId/variants/:variantId/media",
@@ -19648,6 +20710,17 @@ function resolveUrl(path, baseUrl) {
19648
20710
  if (baseUrl) return new URL(path, baseUrl).toString();
19649
20711
  return path;
19650
20712
  }
20713
+ function appendQuery(path, query) {
20714
+ if (!query) return path;
20715
+ const params = new URLSearchParams();
20716
+ for (const [key, value] of Object.entries(query)) {
20717
+ if (value === void 0 || value === null) continue;
20718
+ params.set(key, String(value));
20719
+ }
20720
+ const search = params.toString();
20721
+ if (!search) return path;
20722
+ return `${path}${path.includes("?") ? "&" : "?"}${search}`;
20723
+ }
19651
20724
  function buildFormData(form) {
19652
20725
  const formData = new FormData();
19653
20726
  for (const [key, value] of Object.entries(form)) {
@@ -19679,8 +20752,9 @@ async function apiFetch(key, ...args) {
19679
20752
  const fetchImpl = options.fetch ?? fetch;
19680
20753
  const params = "paramsSchema" in endpoint ? endpoint.paramsSchema.parse(options.params) : void 0;
19681
20754
  const json = "jsonSchema" in endpoint ? endpoint.jsonSchema.parse(options.json) : void 0;
20755
+ const query = "querySchema" in endpoint ? endpoint.querySchema.parse(options.query ?? {}) : void 0;
19682
20756
  const form = "formSchema" in endpoint ? endpoint.formSchema.parse(options.form) : void 0;
19683
- const path = buildPath(endpoint.path, params);
20757
+ const path = appendQuery(buildPath(endpoint.path, params), query);
19684
20758
  const headers = new Headers(options.headers);
19685
20759
  const init = {
19686
20760
  ...options,
@@ -19691,6 +20765,7 @@ async function apiFetch(key, ...args) {
19691
20765
  delete init.baseUrl;
19692
20766
  delete init.fetch;
19693
20767
  delete init.params;
20768
+ delete init.query;
19694
20769
  delete init.json;
19695
20770
  delete init.form;
19696
20771
  if (json !== void 0) {
@@ -19710,7 +20785,7 @@ async function apiFetch(key, ...args) {
19710
20785
  }
19711
20786
  //#endregion
19712
20787
  //#region src/cli/commands/productions.ts
19713
- var defaultDeps$7 = {
20788
+ var defaultDeps$10 = {
19714
20789
  loadConfig: loadStoredConfig,
19715
20790
  loadProjectConfig,
19716
20791
  resolveBaseUrl,
@@ -19724,12 +20799,12 @@ async function handleProductions(parsed) {
19724
20799
  await executeProductions(parsed);
19725
20800
  } catch (error) {
19726
20801
  console.error("Error:", error instanceof Error ? error.message : error);
19727
- printUsage$8();
20802
+ printUsage$10();
19728
20803
  process$1.exitCode = 1;
19729
20804
  }
19730
20805
  }
19731
- async function executeProductions(parsed, deps = defaultDeps$7) {
19732
- const ctx = await buildContext$4(parsed, deps);
20806
+ async function executeProductions(parsed, deps = defaultDeps$10) {
20807
+ const ctx = await buildContext$7(parsed, deps);
19733
20808
  const subcommand = parsed.positionals[0] || "list";
19734
20809
  if (subcommand === "list") {
19735
20810
  const records = await listProductionRecords(ctx, deps, readProductionId(parsed, 1));
@@ -19802,7 +20877,7 @@ async function placeProductionRecordForCli(input) {
19802
20877
  }
19803
20878
  })).record;
19804
20879
  }
19805
- async function buildContext$4(parsed, deps) {
20880
+ async function buildContext$7(parsed, deps) {
19806
20881
  const projectConfig = await deps.loadProjectConfig();
19807
20882
  const env = resolveCommandEnvironment(parsed, projectConfig);
19808
20883
  const spaceId = resolveCommandSpace(parsed, projectConfig);
@@ -19861,10 +20936,10 @@ function readProductionId(parsed, positionalIndex) {
19861
20936
  return productionId;
19862
20937
  }
19863
20938
  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");
20939
+ const productionId = readRequiredOption$1(parsed, "production-id", "productionId");
20940
+ const variantId = readRequiredOption$1(parsed, "variant", "variantId");
20941
+ const sceneLabel = readRequiredOption$1(parsed, "scene-label", "sceneLabel");
20942
+ const timelineStartMs = parseNonNegativeInteger$1(readRequiredOption$1(parsed, "timeline-start-ms", "timelineStartMs"), "--timeline-start-ms");
19868
20943
  const durationValue = readOptionalOption$1(parsed, "duration-ms", "durationMs");
19869
20944
  return {
19870
20945
  id: readOptionalOption$1(parsed, "id", "id"),
@@ -19880,7 +20955,7 @@ function parsePlaceRequest(parsed) {
19880
20955
  metadata: parseMetadataJson(readOptionalOption$1(parsed, "metadata-json", "metadataJson"))
19881
20956
  };
19882
20957
  }
19883
- function readRequiredOption(parsed, kebabName, camelName) {
20958
+ function readRequiredOption$1(parsed, kebabName, camelName) {
19884
20959
  const value = readOptionalOption$1(parsed, kebabName, camelName);
19885
20960
  if (value === void 0) throw new Error(`--${kebabName} is required`);
19886
20961
  return value;
@@ -20025,7 +21100,7 @@ function parseJsonObject$1(value) {
20025
21100
  function shellQuote$1(value) {
20026
21101
  return `'${value.replace(/'/g, "'\\''")}'`;
20027
21102
  }
20028
- function printUsage$8() {
21103
+ function printUsage$10() {
20029
21104
  console.log(`
20030
21105
  Usage:
20031
21106
  makefx productions list --production-id <id>
@@ -20230,6 +21305,7 @@ var WebSocketClient = class WebSocketClient {
20230
21305
  chatHandlers = /* @__PURE__ */ new Map();
20231
21306
  generateHandlers = /* @__PURE__ */ new Map();
20232
21307
  batchHandlers = /* @__PURE__ */ new Map();
21308
+ estimateHandlers = /* @__PURE__ */ new Map();
20233
21309
  batchVariantToRequestId = /* @__PURE__ */ new Map();
20234
21310
  variantCompletionHandlers = /* @__PURE__ */ new Map();
20235
21311
  describeHandlers = /* @__PURE__ */ new Map();
@@ -20430,6 +21506,16 @@ var WebSocketClient = class WebSocketClient {
20430
21506
  }
20431
21507
  break;
20432
21508
  }
21509
+ case "generation:estimate": {
21510
+ const estimateMsg = message;
21511
+ const handler = this.estimateHandlers.get(estimateMsg.requestId);
21512
+ if (handler) {
21513
+ this.estimateHandlers.delete(estimateMsg.requestId);
21514
+ clearTimeout(handler.timeout);
21515
+ handler.resolve(estimateMsg);
21516
+ }
21517
+ break;
21518
+ }
20433
21519
  case "variant:updated": {
20434
21520
  const variant = message.variant;
20435
21521
  const batchRequestId = this.batchVariantToRequestId.get(variant.id);
@@ -20519,7 +21605,8 @@ var WebSocketClient = class WebSocketClient {
20519
21605
  const error = /* @__PURE__ */ new Error(`${errorMsg.code}: ${errorMsg.message}`);
20520
21606
  const mutationConsumed = this.failMutationWaiters(error);
20521
21607
  const pipelineConsumed = this.failPipelineHandlers(error);
20522
- if (!(mutationConsumed || pipelineConsumed)) {
21608
+ const estimateConsumed = this.failEstimateHandlers(error);
21609
+ if (!(mutationConsumed || pipelineConsumed || estimateConsumed)) {
20523
21610
  console.error(`[WebSocketClient] Server error: ${errorMsg.code} - ${errorMsg.message}`);
20524
21611
  this.onError?.(new Error(errorMsg.message));
20525
21612
  }
@@ -20616,6 +21703,15 @@ var WebSocketClient = class WebSocketClient {
20616
21703
  this.tileSetToRequestId.clear();
20617
21704
  return true;
20618
21705
  }
21706
+ failEstimateHandlers(error) {
21707
+ if (this.estimateHandlers.size === 0) return false;
21708
+ for (const [requestId, handler] of this.estimateHandlers) {
21709
+ clearTimeout(handler.timeout);
21710
+ this.estimateHandlers.delete(requestId);
21711
+ handler.reject(error);
21712
+ }
21713
+ return true;
21714
+ }
20619
21715
  handleRotationPipelineMessage(message) {
20620
21716
  if (message.type === "rotation:started") {
20621
21717
  const handler = this.rotationHandlers.get(message.requestId);
@@ -20874,6 +21970,8 @@ var WebSocketClient = class WebSocketClient {
20874
21970
  subjectDescription: params.subjectDescription,
20875
21971
  aspectRatio: params.aspectRatio,
20876
21972
  disableStyle: params.disableStyle,
21973
+ stylePresetId: params.stylePresetId,
21974
+ styleVariantIds: params.styleVariantIds,
20877
21975
  generationMode: params.generationMode
20878
21976
  });
20879
21977
  } catch (err) {
@@ -20921,6 +22019,8 @@ var WebSocketClient = class WebSocketClient {
20921
22019
  seedVariantId: params.seedVariantId,
20922
22020
  aspectRatio: params.aspectRatio,
20923
22021
  disableStyle: params.disableStyle,
22022
+ stylePresetId: params.stylePresetId,
22023
+ styleVariantIds: params.styleVariantIds,
20924
22024
  generationMode: params.generationMode
20925
22025
  });
20926
22026
  } catch (err) {
@@ -20975,6 +22075,46 @@ var WebSocketClient = class WebSocketClient {
20975
22075
  }, 12e4);
20976
22076
  });
20977
22077
  }
22078
+ async sendGenerationEstimateRequest(params) {
22079
+ const requestId = crypto.randomUUID();
22080
+ return new Promise((resolve, reject) => {
22081
+ const timeout = setTimeout(() => {
22082
+ if (this.estimateHandlers.has(requestId)) {
22083
+ this.estimateHandlers.delete(requestId);
22084
+ reject(/* @__PURE__ */ new Error("Generation estimate request timed out"));
22085
+ }
22086
+ }, 3e4);
22087
+ this.estimateHandlers.set(requestId, {
22088
+ resolve,
22089
+ reject,
22090
+ timeout
22091
+ });
22092
+ const message = {
22093
+ type: "generation:estimate",
22094
+ requestId,
22095
+ operation: params.operation,
22096
+ assetId: params.assetId,
22097
+ assetType: params.assetType,
22098
+ mediaKind: params.mediaKind,
22099
+ prompt: params.prompt,
22100
+ count: params.count,
22101
+ model: params.model,
22102
+ imageSize: params.imageSize,
22103
+ musicProvider: params.musicProvider,
22104
+ generateAudio: params.generateAudio,
22105
+ videoResolution: params.videoResolution,
22106
+ videoDurationSeconds: params.videoDurationSeconds,
22107
+ videoTier: params.videoTier
22108
+ };
22109
+ try {
22110
+ this.send(message);
22111
+ } catch (err) {
22112
+ this.estimateHandlers.delete(requestId);
22113
+ clearTimeout(timeout);
22114
+ reject(err);
22115
+ }
22116
+ });
22117
+ }
20978
22118
  /**
20979
22119
  * Send a generate request and wait for result
20980
22120
  */
@@ -21011,8 +22151,9 @@ var WebSocketClient = class WebSocketClient {
21011
22151
  model: params.model,
21012
22152
  aspectRatio: params.aspectRatio,
21013
22153
  imageSize: params.imageSize,
21014
- parentAssetId: params.parentAssetId,
21015
22154
  disableStyle: params.disableStyle,
22155
+ stylePresetId: params.stylePresetId,
22156
+ styleVariantIds: params.styleVariantIds,
21016
22157
  mediaKind: params.mediaKind,
21017
22158
  voiceId: params.voiceId,
21018
22159
  dialogueVoiceIds: params.dialogueVoiceIds,
@@ -21096,6 +22237,8 @@ var WebSocketClient = class WebSocketClient {
21096
22237
  aspectRatio: params.aspectRatio,
21097
22238
  imageSize: params.imageSize,
21098
22239
  disableStyle: params.disableStyle,
22240
+ stylePresetId: params.stylePresetId,
22241
+ styleVariantIds: params.styleVariantIds,
21099
22242
  mediaKind: params.mediaKind,
21100
22243
  voiceId: params.voiceId,
21101
22244
  dialogueVoiceIds: params.dialogueVoiceIds,
@@ -21148,8 +22291,9 @@ var WebSocketClient = class WebSocketClient {
21148
22291
  model: params.model,
21149
22292
  aspectRatio: params.aspectRatio,
21150
22293
  imageSize: params.imageSize,
21151
- parentAssetId: params.parentAssetId,
21152
22294
  disableStyle: params.disableStyle,
22295
+ stylePresetId: params.stylePresetId,
22296
+ styleVariantIds: params.styleVariantIds,
21153
22297
  mediaKind: params.mediaKind,
21154
22298
  voiceId: params.voiceId,
21155
22299
  dialogueVoiceIds: params.dialogueVoiceIds,
@@ -21575,7 +22719,7 @@ function cliGenerationSupportsRefs(namespace) {
21575
22719
  //#endregion
21576
22720
  //#region src/cli/commands/forge.ts
21577
22721
  var CLI_GENERATION_MEDIA_KIND = getCliGenerationMediaKind("top-level");
21578
- var defaultDeps$6 = {
22722
+ var defaultDeps$9 = {
21579
22723
  loadConfig: loadStoredConfig,
21580
22724
  loadProjectConfig,
21581
22725
  resolveBaseUrl,
@@ -21585,6 +22729,7 @@ var defaultDeps$6 = {
21585
22729
  downloadFile,
21586
22730
  saveRunManifest,
21587
22731
  placeProductionRecord: placeProductionRecordForCli,
22732
+ fetch,
21588
22733
  createRunId,
21589
22734
  getWorkingDir: () => process$1.cwd(),
21590
22735
  fileExists: async (filePath) => {
@@ -21596,6 +22741,43 @@ var defaultDeps$6 = {
21596
22741
  }
21597
22742
  }
21598
22743
  };
22744
+ var ESTIMATE_METER_LABELS = {
22745
+ gemini_images: "Gemini image",
22746
+ gemini_videos: "Veo video unit",
22747
+ gemini_audio: "Lyria generation",
22748
+ elevenlabs_audio: "ElevenLabs unit"
22749
+ };
22750
+ function formatEstimatedUsd(microUsd) {
22751
+ if (!Number.isFinite(microUsd) || microUsd <= 0) return "$0.00";
22752
+ if (microUsd < 1e4) return "<$0.01";
22753
+ return `$${(microUsd / 1e6).toFixed(2)}`;
22754
+ }
22755
+ function formatEstimateQuantity(quantity, singular) {
22756
+ const normalized = Number.isFinite(quantity) ? quantity : 0;
22757
+ const suffix = normalized === 1 ? singular : `${singular}s`;
22758
+ return `${normalized.toLocaleString()} ${suffix}`;
22759
+ }
22760
+ async function printPreflightEstimate(client, params) {
22761
+ let result;
22762
+ try {
22763
+ result = await client.sendGenerationEstimateRequest(params);
22764
+ } catch (error) {
22765
+ console.warn(`Preflight estimate unavailable: ${error instanceof Error ? error.message : String(error)}`);
22766
+ return;
22767
+ }
22768
+ if (!result.success || !result.estimate) {
22769
+ console.warn(`Preflight estimate unavailable: ${result.error || "unknown error"}`);
22770
+ return;
22771
+ }
22772
+ const estimate = result.estimate;
22773
+ const meterLabel = ESTIMATE_METER_LABELS[estimate.meterEventName] ?? estimate.meterEventName;
22774
+ const quotaLine = estimate.quota?.limit === null || estimate.quota?.limit === void 0 ? void 0 : `${estimate.quota.used.toLocaleString()} used / ${estimate.quota.limit.toLocaleString()} limit`;
22775
+ console.log("Preflight estimate:");
22776
+ console.log(` Usage: ${formatEstimateQuantity(estimate.quotaQuantity, meterLabel)}, ${formatEstimateQuantity(estimate.platformWorkflowRuns, "workflow")}`);
22777
+ console.log(` Estimated provider cost: ${formatEstimatedUsd(estimate.providerCostMicroUsd)}${estimate.billingMode === "byok" ? " (BYOK)" : ""}`);
22778
+ if (quotaLine) console.log(` Quota: ${quotaLine}`);
22779
+ if (!estimate.allowed) throw new Error(estimate.denyMessage || "Preflight check denied this generation request");
22780
+ }
21599
22781
  async function handleGenerate(parsed) {
21600
22782
  await handleForgeCommand("generate", parsed);
21601
22783
  }
@@ -21610,18 +22792,18 @@ async function handleBatch(parsed) {
21610
22792
  }
21611
22793
  async function handleForgeCommand(command, parsed) {
21612
22794
  try {
21613
- await executeForgeCommand(command, parsed, defaultDeps$6);
22795
+ await executeForgeCommand(command, parsed, defaultDeps$9);
21614
22796
  } catch (error) {
21615
22797
  console.error("Error:", error instanceof Error ? error.message : error);
21616
- printUsage$7(command);
22798
+ printUsage$9(command);
21617
22799
  process$1.exitCode = 1;
21618
22800
  }
21619
22801
  }
21620
- async function executeForgeCommand(command, parsed, deps = defaultDeps$6, options = {}) {
22802
+ async function executeForgeCommand(command, parsed, deps = defaultDeps$9, options = {}) {
21621
22803
  const mediaKind = options.mediaKind || CLI_GENERATION_MEDIA_KIND;
21622
22804
  if (parsed.options.follow) {
21623
22805
  if (command === "batch") throw new Error("--follow is only supported for single-output generation commands");
21624
- const ctx = await buildContext$3(parsed, deps);
22806
+ const ctx = await buildContext$6(parsed, deps);
21625
22807
  const client = await deps.createClient(ctx.env, ctx.spaceId);
21626
22808
  try {
21627
22809
  await client.connect();
@@ -21635,7 +22817,7 @@ async function executeForgeCommand(command, parsed, deps = defaultDeps$6, option
21635
22817
  validateVideoAudioOptions(parsed, mediaKind);
21636
22818
  parseVideoGenerationOptions(parsed, mediaKind);
21637
22819
  if (command !== "batch") validateProductionMetadataOptions(parsed);
21638
- const ctx = await buildContext$3(parsed, deps);
22820
+ const ctx = await buildContext$6(parsed, deps);
21639
22821
  const client = await deps.createClient(ctx.env, ctx.spaceId);
21640
22822
  try {
21641
22823
  await client.connect();
@@ -21649,7 +22831,7 @@ async function executeForgeCommand(command, parsed, deps = defaultDeps$6, option
21649
22831
  client.disconnect();
21650
22832
  }
21651
22833
  }
21652
- async function executeAudioCommand(command, parsed, deps = defaultDeps$6, options = {}) {
22834
+ async function executeAudioCommand(command, parsed, deps = defaultDeps$9, options = {}) {
21653
22835
  const audioProfile = getCliGenerationProfile("audio");
21654
22836
  if (!audioProfile.commands.includes(command)) throw new Error(`Audio generation does not support ${command}`);
21655
22837
  const modeEntry = options.mode ? getMediaOperationEntry(options.mode) : void 0;
@@ -21662,7 +22844,7 @@ async function executeAudioCommand(command, parsed, deps = defaultDeps$6, option
21662
22844
  audioMode: options.mode
21663
22845
  });
21664
22846
  }
21665
- async function executeVideoCommand(command, parsed, deps = defaultDeps$6) {
22847
+ async function executeVideoCommand(command, parsed, deps = defaultDeps$9) {
21666
22848
  const videoProfile = getCliGenerationProfile("video");
21667
22849
  if (!videoProfile.commands.includes(command)) throw new Error(`Video generation does not support ${command}`);
21668
22850
  return executeForgeCommand(command, parsed, deps, {
@@ -21708,6 +22890,20 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
21708
22890
  const imageOptions = parseImageGenerationOptions(parsed, mediaKind);
21709
22891
  const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
21710
22892
  const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
22893
+ const styleSelection = await resolveStyleSelection(parsed, ctx, deps);
22894
+ await printPreflightEstimate(client, {
22895
+ operation: "generate",
22896
+ assetType,
22897
+ mediaKind,
22898
+ prompt,
22899
+ count: 1,
22900
+ model: imageOptions.model,
22901
+ imageSize: imageOptions.imageSize,
22902
+ ...musicProvider ? { musicProvider } : {},
22903
+ ...videoAudioOptions,
22904
+ ...videoOptions
22905
+ });
22906
+ printStyleSelection(styleSelection);
21711
22907
  console.log(`Generating "${name}" in space ${ctx.spaceId}...`);
21712
22908
  const audioVoiceOptions = mediaKind === "audio" ? parseAudioVoiceOptions(parsed) : {};
21713
22909
  const result = await client.sendGenerateRequest({
@@ -21716,8 +22912,8 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
21716
22912
  prompt,
21717
22913
  ...imageOptions,
21718
22914
  aspectRatio: imageOptions.aspectRatio ?? videoOptions.aspectRatio,
21719
- parentAssetId: parsed.options.parent,
21720
22915
  disableStyle: parsed.options["no-style"] === "true",
22916
+ ...styleSelection.stylePresetId ? { stylePresetId: styleSelection.stylePresetId } : {},
21721
22917
  mediaKind,
21722
22918
  ...audioVoiceOptions,
21723
22919
  ...musicProvider ? { musicProvider } : {},
@@ -21785,6 +22981,20 @@ async function executeRefine(parsed, ctx, client, deps, mediaKind) {
21785
22981
  const imageOptions = parseImageGenerationOptions(parsed, mediaKind);
21786
22982
  const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
21787
22983
  const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
22984
+ const styleSelection = await resolveStyleSelection(parsed, ctx, deps);
22985
+ await printPreflightEstimate(client, {
22986
+ operation: "refine",
22987
+ assetId: sourceVariant.asset_id,
22988
+ assetType: sourceAsset?.type || void 0,
22989
+ mediaKind,
22990
+ prompt,
22991
+ count: 1,
22992
+ model: imageOptions.model,
22993
+ imageSize: imageOptions.imageSize,
22994
+ ...videoAudioOptions,
22995
+ ...videoOptions
22996
+ });
22997
+ printStyleSelection(styleSelection);
21788
22998
  console.log(`Refining variant ${sourceVariantId}...`);
21789
22999
  const result = await client.sendRefineRequest({
21790
23000
  assetId: sourceVariant.asset_id,
@@ -21793,6 +23003,7 @@ async function executeRefine(parsed, ctx, client, deps, mediaKind) {
21793
23003
  ...imageOptions,
21794
23004
  aspectRatio: imageOptions.aspectRatio ?? videoOptions.aspectRatio,
21795
23005
  disableStyle: parsed.options["no-style"] === "true",
23006
+ ...styleSelection.stylePresetId ? { stylePresetId: styleSelection.stylePresetId } : {},
21796
23007
  mediaKind,
21797
23008
  ...videoAudioOptions,
21798
23009
  ...videoOptions,
@@ -21843,6 +23054,19 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
21843
23054
  });
21844
23055
  const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
21845
23056
  const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
23057
+ const styleSelection = await resolveStyleSelection(parsed, ctx, deps);
23058
+ await printPreflightEstimate(client, {
23059
+ operation: "derive",
23060
+ assetType,
23061
+ mediaKind,
23062
+ prompt,
23063
+ count: 1,
23064
+ model: imageOptions.model,
23065
+ imageSize: imageOptions.imageSize,
23066
+ ...videoAudioOptions,
23067
+ ...videoOptions
23068
+ });
23069
+ printStyleSelection(styleSelection);
21846
23070
  console.log(`Deriving "${name}" from ${referenceVariantIds.length} reference(s)...`);
21847
23071
  const result = await client.sendGenerateRequest({
21848
23072
  name,
@@ -21851,8 +23075,8 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
21851
23075
  referenceVariantIds,
21852
23076
  ...imageOptions,
21853
23077
  aspectRatio: imageOptions.aspectRatio ?? videoOptions.aspectRatio,
21854
- parentAssetId: parsed.options.parent,
21855
23078
  disableStyle: parsed.options["no-style"] === "true",
23079
+ ...styleSelection.stylePresetId ? { stylePresetId: styleSelection.stylePresetId } : {},
21856
23080
  mediaKind,
21857
23081
  ...videoAudioOptions,
21858
23082
  ...videoOptions,
@@ -22047,7 +23271,20 @@ async function executeBatch(parsed, ctx, client, deps, mediaKind, saveBatchManif
22047
23271
  const referenceVariantIds = refs.length > 0 ? await resolveReferenceVariantIds(refs, ctx, deps, state.variants, mediaKind) : void 0;
22048
23272
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
22049
23273
  const runId = deps.createRunId();
22050
- console.log(`Batch generating ${count} ${mediaKind === "image" ? "image" : mediaKind === "video" ? "video" : "audio file"}(s) for "${name}"...`);
23274
+ const styleSelection = await resolveStyleSelection(parsed, ctx, deps);
23275
+ await printPreflightEstimate(client, {
23276
+ operation: "batch",
23277
+ assetType,
23278
+ mediaKind,
23279
+ prompt,
23280
+ count,
23281
+ model: imageOptions.model,
23282
+ imageSize: imageOptions.imageSize,
23283
+ ...musicProvider ? { musicProvider } : {}
23284
+ });
23285
+ const mediaLabel = mediaKind === "image" ? "image" : mediaKind === "video" ? "video" : "audio file";
23286
+ printStyleSelection(styleSelection);
23287
+ console.log(`Batch generating ${count} ${mediaLabel}(s) for "${name}"...`);
22051
23288
  const audioVoiceOptions = mediaKind === "audio" ? parseAudioVoiceOptions(parsed) : {};
22052
23289
  const result = await client.sendBatchRequest({
22053
23290
  name,
@@ -22058,8 +23295,8 @@ async function executeBatch(parsed, ctx, client, deps, mediaKind, saveBatchManif
22058
23295
  referenceVariantIds,
22059
23296
  ...imageOptions,
22060
23297
  aspectRatio: imageOptions.aspectRatio,
22061
- parentAssetId: parsed.options.parent,
22062
23298
  disableStyle: parsed.options["no-style"] === "true",
23299
+ ...styleSelection.stylePresetId ? { stylePresetId: styleSelection.stylePresetId } : {},
22063
23300
  mediaKind,
22064
23301
  ...audioVoiceOptions,
22065
23302
  ...musicProvider ? { musicProvider } : {}
@@ -22177,7 +23414,7 @@ async function placeProductionRecordFromScene(input) {
22177
23414
  record
22178
23415
  });
22179
23416
  }
22180
- async function buildContext$3(parsed, deps) {
23417
+ async function buildContext$6(parsed, deps) {
22181
23418
  const projectConfig = await deps.loadProjectConfig();
22182
23419
  const env = resolveCommandEnvironment(parsed, projectConfig);
22183
23420
  const spaceId = resolveCommandSpace(parsed, projectConfig);
@@ -22243,6 +23480,51 @@ function requestSpaceState(client) {
22243
23480
  client.requestSync();
22244
23481
  });
22245
23482
  }
23483
+ async function resolveStyleSelection(parsed, ctx, deps) {
23484
+ const stylePresetRef = readStylePresetOption(parsed);
23485
+ if (parsed.options["no-style"] === "true") {
23486
+ if (stylePresetRef) throw new Error("--style-preset cannot be used with --no-style");
23487
+ return {};
23488
+ }
23489
+ if (!stylePresetRef) return {};
23490
+ const presets = (await apiFetch("GET /api/spaces/:id/style-presets", {
23491
+ baseUrl: ctx.baseUrl,
23492
+ fetch: deps.fetch ?? fetch,
23493
+ params: { id: ctx.spaceId },
23494
+ headers: {
23495
+ "Authorization": `Bearer ${ctx.accessToken}`,
23496
+ "Accept": "application/json"
23497
+ }
23498
+ })).presets;
23499
+ const byId = presets.find((preset) => preset.id === stylePresetRef);
23500
+ const byName = presets.filter((preset) => preset.name === stylePresetRef);
23501
+ const preset = byId ?? (byName.length === 1 ? byName[0] : void 0);
23502
+ if (!preset) {
23503
+ if (byName.length > 1) throw new Error(`Style preset name is ambiguous: ${stylePresetRef}. Use a preset ID.`);
23504
+ throw new Error(`Style preset not found: ${stylePresetRef}`);
23505
+ }
23506
+ if (!isTruthyFlag(preset.enabled)) throw new Error(`Style preset is disabled: ${preset.name} (${preset.id})`);
23507
+ return {
23508
+ stylePresetId: preset.id,
23509
+ preset
23510
+ };
23511
+ }
23512
+ function readStylePresetOption(parsed) {
23513
+ return readOptionalOption(parsed, "style-preset", "stylePreset") ?? readOptionalOption(parsed, "preset", "preset");
23514
+ }
23515
+ function printStyleSelection(selection) {
23516
+ if (selection.preset) {
23517
+ const preset = selection.preset;
23518
+ const defaultLabel = isTruthyFlag(preset.is_default) ? ", default" : "";
23519
+ console.log(`Style preset: ${preset.name} (${preset.id}${defaultLabel})`);
23520
+ console.log(` References: ${preset.reference_count}`);
23521
+ console.log(` Collection: ${preset.collection_name || "-"}`);
23522
+ return;
23523
+ }
23524
+ }
23525
+ function isTruthyFlag(value) {
23526
+ return value === true || value === 1;
23527
+ }
22246
23528
  async function downloadResult(result, outputPath, ctx, deps) {
22247
23529
  const variant = result.variant;
22248
23530
  if (!result.success || !variant) throw new Error(result.error || "Generation failed without a completed variant");
@@ -22528,7 +23810,7 @@ function cliImageSizeValues() {
22528
23810
  function cliImageAspectValues() {
22529
23811
  return cliOptionValues(getImageModelCapabilities().supportedAspectRatios);
22530
23812
  }
22531
- function printUsage$7(command) {
23813
+ function printUsage$9(command) {
22532
23814
  if (command === "generate") {
22533
23815
  console.log(`
22534
23816
  Usage:
@@ -22581,7 +23863,7 @@ function printBatchResult(result, outputDir, manifestPath, ctx, mediaKind) {
22581
23863
  }
22582
23864
  //#endregion
22583
23865
  //#region src/cli/commands/audio.ts
22584
- var defaultDeps$5 = {
23866
+ var defaultDeps$8 = {
22585
23867
  loadConfig: loadStoredConfig,
22586
23868
  loadProjectConfig,
22587
23869
  resolveBaseUrl,
@@ -22594,11 +23876,11 @@ async function handleAudio(parsed) {
22594
23876
  await executeAudio(parsed);
22595
23877
  } catch (error) {
22596
23878
  console.error("Error:", error instanceof Error ? error.message : error);
22597
- printUsage$6();
23879
+ printUsage$8();
22598
23880
  process$1.exitCode = 1;
22599
23881
  }
22600
23882
  }
22601
- async function executeAudio(parsed, deps = defaultDeps$5) {
23883
+ async function executeAudio(parsed, deps = defaultDeps$8) {
22602
23884
  const invocation = parseAudioInvocation(parsed.positionals);
22603
23885
  if (invocation.command === "voices") return executeAudioVoices({
22604
23886
  ...parsed,
@@ -22671,7 +23953,7 @@ function printVoices(response, print) {
22671
23953
  function formatLabels(labels) {
22672
23954
  return Object.entries(labels).map(([key, value]) => `${key}:${value}`).join(", ");
22673
23955
  }
22674
- function printUsage$6() {
23956
+ function printUsage$8() {
22675
23957
  const modes = AUDIO_FORGE_MEDIA_MODES.join("|");
22676
23958
  console.log(`
22677
23959
  Usage:
@@ -22700,7 +23982,7 @@ async function handleVideo(parsed) {
22700
23982
  });
22701
23983
  } catch (error) {
22702
23984
  console.error("Error:", error instanceof Error ? error.message : error);
22703
- printUsage$5();
23985
+ printUsage$7();
22704
23986
  process$1.exitCode = 1;
22705
23987
  }
22706
23988
  }
@@ -22709,7 +23991,7 @@ function parseVideoCommand(value) {
22709
23991
  if (value && commands.includes(value)) return value;
22710
23992
  throw new Error("Video command is required: generate, refine, or derive");
22711
23993
  }
22712
- function printUsage$5() {
23994
+ function printUsage$7() {
22713
23995
  const aspectValues = VIDEO_GENERATION_ASPECT_RATIOS.join("|");
22714
23996
  const resolutionValues = Array.from(new Set(VIDEO_GENERATION_TIERS.flatMap((tier) => getVideoGenerationResolutionsForTier(tier)))).join("|");
22715
23997
  const durationValues = VIDEO_GENERATION_DURATION_SECONDS.join("|");
@@ -22741,17 +24023,17 @@ Production metadata:
22741
24023
  }
22742
24024
  //#endregion
22743
24025
  //#region src/cli/commands/init.ts
22744
- var defaultDeps$4 = { saveProjectConfig };
24026
+ var defaultDeps$7 = { saveProjectConfig };
22745
24027
  async function handleInit(parsed) {
22746
24028
  try {
22747
24029
  await executeInit(parsed);
22748
24030
  } catch (error) {
22749
24031
  console.error("Error:", error instanceof Error ? error.message : error);
22750
- printUsage$4();
24032
+ printUsage$6();
22751
24033
  process$1.exitCode = 1;
22752
24034
  }
22753
24035
  }
22754
- async function executeInit(parsed, deps = defaultDeps$4) {
24036
+ async function executeInit(parsed, deps = defaultDeps$7) {
22755
24037
  const environment = resolveCommandEnvironment(parsed);
22756
24038
  const spaceId = resolveCommandSpace(parsed);
22757
24039
  if (!spaceId) throw new Error("--space is required");
@@ -22777,7 +24059,7 @@ async function executeInit(parsed, deps = defaultDeps$4) {
22777
24059
  spaceId
22778
24060
  };
22779
24061
  }
22780
- function printUsage$4() {
24062
+ function printUsage$6() {
22781
24063
  console.log(`
22782
24064
  Usage:
22783
24065
  makefx init --space <id> [--env production|stage|local]
@@ -22786,7 +24068,7 @@ Usage:
22786
24068
  }
22787
24069
  //#endregion
22788
24070
  //#region src/cli/commands/runs.ts
22789
- var defaultDeps$3 = {
24071
+ var defaultDeps$6 = {
22790
24072
  loadProjectConfig,
22791
24073
  listRunManifests,
22792
24074
  readRunManifest,
@@ -22799,11 +24081,11 @@ async function handleRuns(parsed) {
22799
24081
  await executeRuns(parsed);
22800
24082
  } catch (error) {
22801
24083
  console.error("Error:", error instanceof Error ? error.message : error);
22802
- printUsage$3();
24084
+ printUsage$5();
22803
24085
  process$1.exitCode = 1;
22804
24086
  }
22805
24087
  }
22806
- async function executeRuns(parsed, deps = defaultDeps$3) {
24088
+ async function executeRuns(parsed, deps = defaultDeps$6) {
22807
24089
  const projectConfig = await deps.loadProjectConfig();
22808
24090
  if (!projectConfig?.projectRoot) throw new Error("Make Effects project config not found. Run: makefx init --space <id>");
22809
24091
  requireDebugAcknowledgement(parsed);
@@ -22921,7 +24203,7 @@ function formatCreated(value) {
22921
24203
  if (Number.isNaN(date.getTime())) return value;
22922
24204
  return value.replace("T", " ").replace(/\.\d{3}Z$/, "Z").slice(0, 20);
22923
24205
  }
22924
- function printUsage$3() {
24206
+ function printUsage$5() {
22925
24207
  console.log(`
22926
24208
  Usage:
22927
24209
  makefx runs --debug
@@ -22939,7 +24221,7 @@ For timed scene assembly, use:
22939
24221
  }
22940
24222
  //#endregion
22941
24223
  //#region src/cli/commands/assets.ts
22942
- var defaultDeps$2 = {
24224
+ var defaultDeps$5 = {
22943
24225
  loadConfig: loadStoredConfig,
22944
24226
  loadProjectConfig,
22945
24227
  resolveBaseUrl,
@@ -22962,15 +24244,15 @@ async function handleAssets(parsed) {
22962
24244
  await executeAssets(parsed);
22963
24245
  } catch (error) {
22964
24246
  console.error("Error:", error instanceof Error ? error.message : error);
22965
- printUsage$2();
24247
+ printUsage$4();
22966
24248
  process$1.exitCode = 1;
22967
24249
  }
22968
24250
  }
22969
- async function executeAssets(parsed, deps = defaultDeps$2) {
22970
- const ctx = await buildContext$2(parsed, deps);
24251
+ async function executeAssets(parsed, deps = defaultDeps$5) {
24252
+ const ctx = await buildContext$5(parsed, deps);
22971
24253
  const subcommand = parsed.positionals[0] || "list";
22972
24254
  if (subcommand === "list") {
22973
- const assets = await listAssets(ctx, deps);
24255
+ const assets = await listAssets$1(ctx, deps);
22974
24256
  if (parsed.options.json === "true") deps.print(JSON.stringify(assets.map(toAssetJson), null, 2));
22975
24257
  else printAssetList(assets, deps.print);
22976
24258
  return {
@@ -23046,7 +24328,7 @@ async function executeAssets(parsed, deps = defaultDeps$2) {
23046
24328
  function normalizeOption(value) {
23047
24329
  return !value || value === "true" ? void 0 : value;
23048
24330
  }
23049
- async function buildContext$2(parsed, deps) {
24331
+ async function buildContext$5(parsed, deps) {
23050
24332
  const projectConfig = await deps.loadProjectConfig();
23051
24333
  const env = resolveCommandEnvironment(parsed, projectConfig);
23052
24334
  const spaceId = resolveCommandSpace(parsed, projectConfig);
@@ -23063,7 +24345,7 @@ async function buildContext$2(parsed, deps) {
23063
24345
  force: parsed.options.force === "true"
23064
24346
  };
23065
24347
  }
23066
- async function listAssets(ctx, deps) {
24348
+ async function listAssets$1(ctx, deps) {
23067
24349
  return (await fetchJson(ctx, deps, `/api/spaces/${ctx.spaceId}/assets`)).assets || [];
23068
24350
  }
23069
24351
  async function getAssetDetails(ctx, deps, assetId) {
@@ -23088,7 +24370,7 @@ async function resolveDownloadRef(ref, ctx, deps) {
23088
24370
  requestPath: `/api/images/${ref}`
23089
24371
  };
23090
24372
  }
23091
- const assets = await listAssets(ctx, deps);
24373
+ const assets = await listAssets$1(ctx, deps);
23092
24374
  for (const asset of assets) {
23093
24375
  const variant = (await getAssetDetails(ctx, deps, asset.id)).variants.find((candidate) => candidate.id === ref);
23094
24376
  if (!variant) continue;
@@ -23146,7 +24428,6 @@ function printAssetDetails(details, ctx, print) {
23146
24428
  print(` Type: ${asset.type || "unknown"}`);
23147
24429
  print(` Media: ${asset.media_kind || "-"}`);
23148
24430
  print(` Active: ${asset.active_variant_id || "-"}`);
23149
- print(` Parent: ${asset.parent_asset_id || "-"}`);
23150
24431
  print(` Created: ${formatTimestamp(asset.created_at)}`);
23151
24432
  print(` Updated: ${formatTimestamp(asset.updated_at)}`);
23152
24433
  print(` Web: ${ctx.baseUrl}/spaces/${ctx.spaceId}/assets/${asset.id}`);
@@ -23195,7 +24476,6 @@ function toAssetJson(asset) {
23195
24476
  type: asset.type,
23196
24477
  media_kind: asset.media_kind || null,
23197
24478
  activeVariantId: asset.active_variant_id,
23198
- parentAssetId: asset.parent_asset_id || null,
23199
24479
  createdAt: asset.created_at || null,
23200
24480
  updatedAt: asset.updated_at || null
23201
24481
  };
@@ -23227,7 +24507,7 @@ function formatTimestamp(value) {
23227
24507
  if (Number.isNaN(date.getTime())) return String(value);
23228
24508
  return date.toISOString().replace("T", " ").replace(/\.\d{3}Z$/, "Z").slice(0, 20);
23229
24509
  }
23230
- function printUsage$2() {
24510
+ function printUsage$4() {
23231
24511
  console.log(`
23232
24512
  Usage:
23233
24513
  makefx assets
@@ -23242,7 +24522,7 @@ Usage:
23242
24522
  }
23243
24523
  //#endregion
23244
24524
  //#region src/cli/commands/variants.ts
23245
- var defaultDeps$1 = {
24525
+ var defaultDeps$4 = {
23246
24526
  loadConfig: loadStoredConfig,
23247
24527
  loadProjectConfig,
23248
24528
  resolveBaseUrl,
@@ -23254,12 +24534,12 @@ async function handleVariants(parsed) {
23254
24534
  await executeVariants(parsed);
23255
24535
  } catch (error) {
23256
24536
  console.error("Error:", error instanceof Error ? error.message : error);
23257
- printUsage$1();
24537
+ printUsage$3();
23258
24538
  process$1.exitCode = 1;
23259
24539
  }
23260
24540
  }
23261
- async function executeVariants(parsed, deps = defaultDeps$1) {
23262
- const ctx = await buildContext$1(parsed, deps);
24541
+ async function executeVariants(parsed, deps = defaultDeps$4) {
24542
+ const ctx = await buildContext$4(parsed, deps);
23263
24543
  const subcommand = parsed.positionals[0];
23264
24544
  if (subcommand === "delete") {
23265
24545
  const variantId = requireVariantId(parsed, "delete");
@@ -23307,7 +24587,7 @@ function requireVariantId(parsed, verb) {
23307
24587
  if (!variantId) throw new Error(`Variant ID is required: makefx variants ${verb} <variant-id>`);
23308
24588
  return variantId;
23309
24589
  }
23310
- async function buildContext$1(parsed, deps) {
24590
+ async function buildContext$4(parsed, deps) {
23311
24591
  const projectConfig = await deps.loadProjectConfig();
23312
24592
  const env = resolveCommandEnvironment(parsed, projectConfig);
23313
24593
  const spaceId = resolveCommandSpace(parsed, projectConfig);
@@ -23330,7 +24610,7 @@ async function withVariantClient(ctx, deps, run) {
23330
24610
  client.disconnect();
23331
24611
  }
23332
24612
  }
23333
- function printUsage$1() {
24613
+ function printUsage$3() {
23334
24614
  console.log(`
23335
24615
  Usage:
23336
24616
  makefx variants delete <variant-id>
@@ -23346,6 +24626,809 @@ Options:
23346
24626
  `);
23347
24627
  }
23348
24628
  //#endregion
24629
+ //#region src/cli/commands/styles.ts
24630
+ var defaultDeps$3 = {
24631
+ loadConfig: loadStoredConfig,
24632
+ loadProjectConfig,
24633
+ resolveBaseUrl,
24634
+ fetch,
24635
+ print: console.log
24636
+ };
24637
+ async function handleStyles(parsed) {
24638
+ try {
24639
+ await executeStyles(parsed);
24640
+ } catch (error) {
24641
+ console.error("Error:", error instanceof Error ? error.message : error);
24642
+ printUsage$2();
24643
+ process$1.exitCode = 1;
24644
+ }
24645
+ }
24646
+ async function executeStyles(parsed, deps = defaultDeps$3) {
24647
+ const namespace = parsed.positionals[0] || "presets";
24648
+ if (namespace === "references" || namespace === "refs") return executeReferences(parsed, deps);
24649
+ if (namespace === "collections" || namespace === "collection") return executeCollections(parsed, deps);
24650
+ if (namespace === "presets" || namespace === "preset") return executePresets(parsed, deps);
24651
+ throw new Error(`Unknown styles command: ${namespace}`);
24652
+ }
24653
+ async function executeReferences(parsed, deps) {
24654
+ const ctx = await buildContext$3(parsed, deps);
24655
+ const collectionFilter = readOption(parsed, "collection", "collectionId") || parsed.positionals[1];
24656
+ const collections = await listStyleReferenceCollections(ctx, deps);
24657
+ const selected = collectionFilter ? collections.filter((collection) => collection.id === collectionFilter || collection.name === collectionFilter) : collections;
24658
+ if (collectionFilter && selected.length === 0) throw new Error(`Style reference collection not found: ${collectionFilter}`);
24659
+ const references = [];
24660
+ for (const collection of selected) {
24661
+ const items = await listCollectionItems(ctx, deps, collection.id);
24662
+ for (const item of items.filter((candidate) => candidate.role === "style_ref")) references.push({
24663
+ collectionId: collection.id,
24664
+ collectionName: collection.name,
24665
+ item
24666
+ });
24667
+ }
24668
+ if (parsed.options.json === "true") deps.print(JSON.stringify(references, null, 2));
24669
+ else printReferences(references, deps.print);
24670
+ return {
24671
+ type: "references",
24672
+ references
24673
+ };
24674
+ }
24675
+ async function executeCollections(parsed, deps) {
24676
+ const ctx = await buildContext$3(parsed, deps);
24677
+ const action = parsed.positionals[1] || "list";
24678
+ if (action === "list") {
24679
+ const collections = await listStyleReferenceCollections(ctx, deps);
24680
+ if (parsed.options.json === "true") deps.print(JSON.stringify(collections, null, 2));
24681
+ else printCollections(collections, deps.print);
24682
+ return {
24683
+ type: "collections",
24684
+ collections
24685
+ };
24686
+ }
24687
+ if (action === "create") {
24688
+ const name = parsed.positionals[2] || readRequiredOption(parsed, "name", "name");
24689
+ const collection = await createCollection(ctx, deps, {
24690
+ id: readOption(parsed, "id", "id"),
24691
+ name,
24692
+ description: nullableOption(parsed, "description", "description")
24693
+ });
24694
+ const items = await upsertStyleReferenceItems(ctx, deps, collection.id, parsed, false);
24695
+ printCollectionMutation("Created", collection, items, deps.print, parsed.options.json === "true");
24696
+ return {
24697
+ type: "collection",
24698
+ collection,
24699
+ items
24700
+ };
24701
+ }
24702
+ if (action === "update") {
24703
+ const collectionId = parsed.positionals[2] || readRequiredOption(parsed, "id", "id");
24704
+ const changes = {};
24705
+ const name = readOption(parsed, "name", "name");
24706
+ const description = nullableOption(parsed, "description", "description");
24707
+ if (name !== void 0) changes.name = name;
24708
+ if (description !== void 0) changes.description = description;
24709
+ let collection;
24710
+ if (Object.keys(changes).length > 0) collection = await updateCollection(ctx, deps, collectionId, changes);
24711
+ const items = hasReferenceOptions(parsed) ? await upsertStyleReferenceItems(ctx, deps, collectionId, parsed, parsed.options.append !== "true") : void 0;
24712
+ if (!collection) collection = (await listCollections(ctx, deps)).find((candidate) => candidate.id === collectionId);
24713
+ if (!collection) throw new Error(`Collection not found: ${collectionId}`);
24714
+ printCollectionMutation("Updated", collection, items, deps.print, parsed.options.json === "true");
24715
+ return {
24716
+ type: "collection",
24717
+ collection,
24718
+ items
24719
+ };
24720
+ }
24721
+ throw new Error(`Unknown styles collections command: ${action}`);
24722
+ }
24723
+ async function executePresets(parsed, deps) {
24724
+ const ctx = await buildContext$3(parsed, deps);
24725
+ const action = parsed.positionals[1] || "list";
24726
+ if (action === "list") {
24727
+ const presets = await listStylePresets(ctx, deps);
24728
+ if (parsed.options.json === "true") deps.print(JSON.stringify(presets, null, 2));
24729
+ else printPresets(presets, deps.print);
24730
+ return {
24731
+ type: "presets",
24732
+ presets
24733
+ };
24734
+ }
24735
+ if (action === "create") {
24736
+ const name = parsed.positionals[2] || readRequiredOption(parsed, "name", "name");
24737
+ const response = await createStylePreset(ctx, deps, {
24738
+ id: readOption(parsed, "id", "id"),
24739
+ name,
24740
+ description: nullableOption(parsed, "description", "description"),
24741
+ stylePrompt: readOption(parsed, "prompt", "stylePrompt") ?? "",
24742
+ collectionId: nullableOption(parsed, "collection", "collectionId"),
24743
+ enabled: parsed.options.disable === "true" ? false : true,
24744
+ isDefault: parsed.options.default === "true"
24745
+ });
24746
+ printPresetMutation("Created", response.preset, deps.print, parsed.options.json === "true");
24747
+ return {
24748
+ type: "preset",
24749
+ preset: response.preset
24750
+ };
24751
+ }
24752
+ if (action === "update") {
24753
+ const response = await updateStylePreset(ctx, deps, parsed.positionals[2] || readRequiredOption(parsed, "id", "id"), buildPresetUpdate(parsed));
24754
+ printPresetMutation("Updated", response.preset, deps.print, parsed.options.json === "true");
24755
+ return {
24756
+ type: "preset",
24757
+ preset: response.preset
24758
+ };
24759
+ }
24760
+ if (action === "enable" || action === "disable") {
24761
+ const response = await updateStylePreset(ctx, deps, parsed.positionals[2] || readRequiredOption(parsed, "id", "id"), { enabled: action === "enable" });
24762
+ printPresetMutation(action === "enable" ? "Enabled" : "Disabled", response.preset, deps.print, parsed.options.json === "true");
24763
+ return {
24764
+ type: "preset",
24765
+ preset: response.preset
24766
+ };
24767
+ }
24768
+ if (action === "delete" || action === "remove") {
24769
+ const presetId = parsed.positionals[2] || readRequiredOption(parsed, "id", "id");
24770
+ await deleteStylePreset(ctx, deps, presetId);
24771
+ if (parsed.options.json === "true") deps.print(JSON.stringify({
24772
+ success: true,
24773
+ presetId
24774
+ }, null, 2));
24775
+ else deps.print(`Deleted style preset ${presetId}`);
24776
+ return {
24777
+ type: "delete-preset",
24778
+ presetId
24779
+ };
24780
+ }
24781
+ throw new Error(`Unknown styles presets command: ${action}`);
24782
+ }
24783
+ async function buildContext$3(parsed, deps) {
24784
+ const projectConfig = await deps.loadProjectConfig();
24785
+ const env = resolveCommandEnvironment(parsed, projectConfig);
24786
+ const spaceId = resolveCommandSpace(parsed, projectConfig);
24787
+ if (!spaceId) throw new Error("--space is required, or run: makefx init --space <id>");
24788
+ const config = await deps.loadConfig(env);
24789
+ if (!config) throw new Error(`Not logged in to ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
24790
+ if (config.token.expiresAt < Date.now()) throw new Error(`Token expired for ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
24791
+ if (env === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
24792
+ return {
24793
+ env,
24794
+ spaceId,
24795
+ baseUrl: deps.resolveBaseUrl(env),
24796
+ accessToken: config.token.accessToken
24797
+ };
24798
+ }
24799
+ async function listAssets(ctx, deps) {
24800
+ return (await apiFetch("GET /api/spaces/:id/assets", {
24801
+ baseUrl: ctx.baseUrl,
24802
+ fetch: deps.fetch,
24803
+ params: { id: ctx.spaceId },
24804
+ headers: authHeaders(ctx)
24805
+ })).assets;
24806
+ }
24807
+ async function listCollections(ctx, deps) {
24808
+ return (await apiFetch("GET /api/spaces/:id/collections", {
24809
+ baseUrl: ctx.baseUrl,
24810
+ fetch: deps.fetch,
24811
+ params: { id: ctx.spaceId },
24812
+ headers: authHeaders(ctx)
24813
+ })).collections;
24814
+ }
24815
+ async function listStyleReferenceCollections(ctx, deps) {
24816
+ return (await apiFetch("GET /api/spaces/:id/style-reference-collections", {
24817
+ baseUrl: ctx.baseUrl,
24818
+ fetch: deps.fetch,
24819
+ params: { id: ctx.spaceId },
24820
+ headers: authHeaders(ctx)
24821
+ })).collections;
24822
+ }
24823
+ async function listCollectionItems(ctx, deps, collectionId) {
24824
+ return (await apiFetch("GET /api/spaces/:id/collections/:collectionId/items", {
24825
+ baseUrl: ctx.baseUrl,
24826
+ fetch: deps.fetch,
24827
+ params: {
24828
+ id: ctx.spaceId,
24829
+ collectionId
24830
+ },
24831
+ headers: authHeaders(ctx)
24832
+ })).items;
24833
+ }
24834
+ async function createCollection(ctx, deps, json) {
24835
+ return (await apiFetch("POST /api/spaces/:id/collections", {
24836
+ baseUrl: ctx.baseUrl,
24837
+ fetch: deps.fetch,
24838
+ params: { id: ctx.spaceId },
24839
+ json,
24840
+ headers: authHeaders(ctx)
24841
+ })).collection;
24842
+ }
24843
+ async function updateCollection(ctx, deps, collectionId, json) {
24844
+ return (await apiFetch("PATCH /api/spaces/:id/collections/:collectionId", {
24845
+ baseUrl: ctx.baseUrl,
24846
+ fetch: deps.fetch,
24847
+ params: {
24848
+ id: ctx.spaceId,
24849
+ collectionId
24850
+ },
24851
+ json,
24852
+ headers: authHeaders(ctx)
24853
+ })).collection;
24854
+ }
24855
+ async function createCollectionItem(ctx, deps, collectionId, json) {
24856
+ return (await apiFetch("POST /api/spaces/:id/collections/:collectionId/items", {
24857
+ baseUrl: ctx.baseUrl,
24858
+ fetch: deps.fetch,
24859
+ params: {
24860
+ id: ctx.spaceId,
24861
+ collectionId
24862
+ },
24863
+ json,
24864
+ headers: authHeaders(ctx)
24865
+ })).item;
24866
+ }
24867
+ async function deleteCollectionItem(ctx, deps, collectionId, itemId) {
24868
+ await apiFetch("DELETE /api/spaces/:id/collections/:collectionId/items/:itemId", {
24869
+ baseUrl: ctx.baseUrl,
24870
+ fetch: deps.fetch,
24871
+ params: {
24872
+ id: ctx.spaceId,
24873
+ collectionId,
24874
+ itemId
24875
+ },
24876
+ headers: authHeaders(ctx)
24877
+ });
24878
+ }
24879
+ async function listStylePresets(ctx, deps) {
24880
+ return (await apiFetch("GET /api/spaces/:id/style-presets", {
24881
+ baseUrl: ctx.baseUrl,
24882
+ fetch: deps.fetch,
24883
+ params: { id: ctx.spaceId },
24884
+ headers: authHeaders(ctx)
24885
+ })).presets;
24886
+ }
24887
+ async function createStylePreset(ctx, deps, json) {
24888
+ return apiFetch("POST /api/spaces/:id/style-presets", {
24889
+ baseUrl: ctx.baseUrl,
24890
+ fetch: deps.fetch,
24891
+ params: { id: ctx.spaceId },
24892
+ json,
24893
+ headers: authHeaders(ctx)
24894
+ });
24895
+ }
24896
+ async function updateStylePreset(ctx, deps, presetId, json) {
24897
+ return apiFetch("PATCH /api/spaces/:id/style-presets/:presetId", {
24898
+ baseUrl: ctx.baseUrl,
24899
+ fetch: deps.fetch,
24900
+ params: {
24901
+ id: ctx.spaceId,
24902
+ presetId
24903
+ },
24904
+ json,
24905
+ headers: authHeaders(ctx)
24906
+ });
24907
+ }
24908
+ async function deleteStylePreset(ctx, deps, presetId) {
24909
+ await apiFetch("DELETE /api/spaces/:id/style-presets/:presetId", {
24910
+ baseUrl: ctx.baseUrl,
24911
+ fetch: deps.fetch,
24912
+ params: {
24913
+ id: ctx.spaceId,
24914
+ presetId
24915
+ },
24916
+ headers: authHeaders(ctx)
24917
+ });
24918
+ }
24919
+ async function upsertStyleReferenceItems(ctx, deps, collectionId, parsed, replaceExisting) {
24920
+ const refs = await buildStyleReferenceItemRequests(ctx, deps, parsed);
24921
+ if (refs.length === 0) return [];
24922
+ if (replaceExisting) {
24923
+ const existing = await listCollectionItems(ctx, deps, collectionId);
24924
+ await Promise.all(existing.filter((item) => item.role === "style_ref").map((item) => deleteCollectionItem(ctx, deps, collectionId, item.id)));
24925
+ }
24926
+ const created = [];
24927
+ for (let index = 0; index < refs.length; index += 1) created.push(await createCollectionItem(ctx, deps, collectionId, {
24928
+ ...refs[index],
24929
+ role: "style_ref",
24930
+ sortIndex: index
24931
+ }));
24932
+ return created;
24933
+ }
24934
+ async function buildStyleReferenceItemRequests(ctx, deps, parsed) {
24935
+ const assets = parseCsvOptions(parsed, ["assets", "asset"]);
24936
+ const variants = parseCsvOptions(parsed, ["variants", "variant"]);
24937
+ const refs = parseCsvOptions(parsed, ["refs", "ref"]);
24938
+ if (assets.length === 0 && variants.length === 0 && refs.length === 0) return [];
24939
+ const allAssets = await listAssets(ctx, deps);
24940
+ const assetById = new Map(allAssets.map((asset) => [asset.id, asset]));
24941
+ const requests = [];
24942
+ for (const assetId of [...assets, ...refs.filter((ref) => assetById.has(ref))]) {
24943
+ const asset = assetById.get(assetId);
24944
+ if (!asset) throw new Error(`Asset not found in space ${ctx.spaceId}: ${assetId}`);
24945
+ if (!asset.active_variant_id) throw new Error(`Asset ${assetId} has no active variant to pin as a style reference`);
24946
+ requests.push({
24947
+ subjectType: "asset",
24948
+ assetId,
24949
+ pinnedVariantId: asset.active_variant_id
24950
+ });
24951
+ }
24952
+ for (const variantId of [...variants, ...refs.filter((ref) => !assetById.has(ref))]) requests.push({
24953
+ subjectType: "variant",
24954
+ variantId
24955
+ });
24956
+ return dedupeItemRequests(requests);
24957
+ }
24958
+ function dedupeItemRequests(requests) {
24959
+ const seen = /* @__PURE__ */ new Set();
24960
+ return requests.filter((request) => {
24961
+ const key = request.subjectType === "asset" ? `asset:${request.assetId}:${request.pinnedVariantId ?? ""}` : `variant:${request.variantId}`;
24962
+ if (seen.has(key)) return false;
24963
+ seen.add(key);
24964
+ return true;
24965
+ });
24966
+ }
24967
+ function buildPresetUpdate(parsed) {
24968
+ const update = {};
24969
+ const name = readOption(parsed, "name", "name");
24970
+ const description = nullableOption(parsed, "description", "description");
24971
+ const stylePrompt = readOption(parsed, "prompt", "stylePrompt");
24972
+ const collectionId = nullableOption(parsed, "collection", "collectionId");
24973
+ if (name !== void 0) update.name = name;
24974
+ if (description !== void 0) update.description = description;
24975
+ if (stylePrompt !== void 0) update.stylePrompt = stylePrompt;
24976
+ if (collectionId !== void 0) update.collectionId = collectionId;
24977
+ if (parsed.options.enable === "true") update.enabled = true;
24978
+ if (parsed.options.disable === "true") update.enabled = false;
24979
+ if (parsed.options.default === "true") update.isDefault = true;
24980
+ if (parsed.options["no-default"] === "true") update.isDefault = false;
24981
+ if (Object.keys(update).length === 0) throw new Error("No preset updates provided");
24982
+ return update;
24983
+ }
24984
+ function authHeaders(ctx) {
24985
+ return {
24986
+ "Authorization": `Bearer ${ctx.accessToken}`,
24987
+ "Accept": "application/json"
24988
+ };
24989
+ }
24990
+ function hasReferenceOptions(parsed) {
24991
+ return [
24992
+ "refs",
24993
+ "ref",
24994
+ "assets",
24995
+ "asset",
24996
+ "variants",
24997
+ "variant"
24998
+ ].some((key) => Boolean(readRawOption(parsed, key)));
24999
+ }
25000
+ function parseCsvOptions(parsed, keys) {
25001
+ return keys.flatMap((key) => parseCsv(readRawOption(parsed, key)));
25002
+ }
25003
+ function parseCsv(value) {
25004
+ if (!value || value === "true") return [];
25005
+ return value.split(",").map((item) => item.trim()).filter(Boolean);
25006
+ }
25007
+ function readRequiredOption(parsed, kebabName, camelName) {
25008
+ const value = readOption(parsed, kebabName, camelName);
25009
+ if (value === void 0) throw new Error(`--${kebabName} is required`);
25010
+ return value;
25011
+ }
25012
+ function readOption(parsed, kebabName, camelName) {
25013
+ const value = readRawOption(parsed, kebabName) ?? readRawOption(parsed, camelName);
25014
+ return !value || value === "true" ? void 0 : value;
25015
+ }
25016
+ function readRawOption(parsed, key) {
25017
+ return parsed.options[key];
25018
+ }
25019
+ function nullableOption(parsed, kebabName, camelName) {
25020
+ if (parsed.options["no-collection"] === "true" && (kebabName === "collection" || camelName === "collectionId")) return null;
25021
+ const value = readOption(parsed, kebabName, camelName);
25022
+ if (value === void 0) return void 0;
25023
+ return value === "null" || value === "-" ? null : value;
25024
+ }
25025
+ function isEnabled(value) {
25026
+ return value === true || value === 1;
25027
+ }
25028
+ function printReferences(references, print) {
25029
+ if (references.length === 0) {
25030
+ print("No style reference assets found.");
25031
+ return;
25032
+ }
25033
+ print(`Found ${references.length} style reference asset(s):\n`);
25034
+ print("Collection".padEnd(28) + "Subject".padEnd(10) + "Asset".padEnd(28) + "Variant".padEnd(28) + "Item");
25035
+ print("-".repeat(108));
25036
+ for (const reference of references) {
25037
+ const item = reference.item;
25038
+ 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));
25039
+ }
25040
+ }
25041
+ function printCollections(collections, print) {
25042
+ if (collections.length === 0) {
25043
+ print("No style reference collections found.");
25044
+ return;
25045
+ }
25046
+ print(`Found ${collections.length} style reference collection(s):\n`);
25047
+ print("References".padEnd(12) + "Presets".padEnd(10) + "Collection".padEnd(34) + "Name");
25048
+ print("-".repeat(88));
25049
+ 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));
25050
+ }
25051
+ function printPresets(presets, print) {
25052
+ if (presets.length === 0) {
25053
+ print("No style presets found.");
25054
+ return;
25055
+ }
25056
+ print(`Found ${presets.length} style preset(s):\n`);
25057
+ print("State".padEnd(14) + "References".padEnd(12) + "Preset".padEnd(30) + "Collection".padEnd(28) + "Name");
25058
+ print("-".repeat(104));
25059
+ 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));
25060
+ }
25061
+ function printCollectionMutation(verb, collection, items, print, asJson) {
25062
+ if (asJson) {
25063
+ print(JSON.stringify({
25064
+ collection,
25065
+ items
25066
+ }, null, 2));
25067
+ return;
25068
+ }
25069
+ print(`${verb} style reference collection ${collection.id}`);
25070
+ print(` Name: ${collection.name}`);
25071
+ if (items) print(` References: ${items.filter((item) => item.role === "style_ref").length}`);
25072
+ }
25073
+ function printPresetMutation(verb, preset, print, asJson) {
25074
+ if (asJson) {
25075
+ print(JSON.stringify(preset, null, 2));
25076
+ return;
25077
+ }
25078
+ print(`${verb} style preset ${preset.id}`);
25079
+ print(` Name: ${preset.name}`);
25080
+ print(` Enabled: ${isEnabled(preset.enabled) ? "yes" : "no"}`);
25081
+ print(` Default: ${isEnabled(preset.is_default) ? "yes" : "no"}`);
25082
+ print(` Collection: ${preset.collection_name || preset.collection_id || "-"}`);
25083
+ print(` References: ${preset.reference_count}`);
25084
+ }
25085
+ function printUsage$2() {
25086
+ console.log(`
25087
+ Usage:
25088
+ makefx styles references [--collection <id-or-name>] [--json]
25089
+ makefx styles collections list [--json]
25090
+ makefx styles collections create <name> --refs <asset_or_variant,...>
25091
+ makefx styles collections update <collection-id> [--name <name>] [--refs <asset_or_variant,...>] [--append]
25092
+ makefx styles presets list [--json]
25093
+ makefx styles presets create <name> --collection <collection-id> --prompt "style prompt" [--default]
25094
+ makefx styles presets update <preset-id> [--name <name>] [--collection <collection-id>] [--prompt "style prompt"]
25095
+ makefx styles presets enable <preset-id>
25096
+ makefx styles presets disable <preset-id>
25097
+ makefx styles presets delete <preset-id>
25098
+
25099
+ Options:
25100
+ --space <id> Target space ID; defaults from the initialized project
25101
+ --refs <ids> Comma-separated asset IDs or variant IDs to use as style references
25102
+ --assets <ids> Comma-separated asset IDs; active variants are pinned
25103
+ --variants <ids> Comma-separated variant IDs
25104
+ --json Print machine-readable output
25105
+ --env <env> Environment (production|stage|local)
25106
+ --local Shortcut for --env local
25107
+ `);
25108
+ }
25109
+ //#endregion
25110
+ //#region src/cli/commands/usage.ts
25111
+ var defaultDeps$2 = {
25112
+ loadConfig: loadStoredConfig,
25113
+ loadProjectConfig,
25114
+ resolveBaseUrl,
25115
+ fetch,
25116
+ print: console.log
25117
+ };
25118
+ async function handleUsage(parsed) {
25119
+ try {
25120
+ await executeUsage(parsed);
25121
+ } catch (error) {
25122
+ console.error("Error:", error instanceof Error ? error.message : error);
25123
+ printUsage$1();
25124
+ process$1.exitCode = 1;
25125
+ }
25126
+ }
25127
+ async function executeUsage(parsed, deps = defaultDeps$2) {
25128
+ const subcommand = parsed.positionals[0] || "summary";
25129
+ if (subcommand !== "summary") throw new Error(`Unknown usage command: ${subcommand}`);
25130
+ const summary = await fetchUsageSummary(await buildContext$2(parsed, deps), deps, {
25131
+ from: optionValue$2(parsed.options.from),
25132
+ to: optionValue$2(parsed.options.to)
25133
+ });
25134
+ if (parsed.options.json === "true") deps.print(JSON.stringify(summary, null, 2));
25135
+ else printUsageSummary(summary, deps.print);
25136
+ return {
25137
+ type: "summary",
25138
+ summary
25139
+ };
25140
+ }
25141
+ async function buildContext$2(parsed, deps) {
25142
+ const projectConfig = await deps.loadProjectConfig();
25143
+ const env = resolveCommandEnvironment(parsed, projectConfig);
25144
+ const spaceId = resolveCommandSpace(parsed, projectConfig);
25145
+ if (!spaceId) throw new Error("--space is required, or run: makefx init --space <id>");
25146
+ const config = await deps.loadConfig(env);
25147
+ if (!config) throw new Error(`Not logged in to ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
25148
+ if (config.token.expiresAt < Date.now()) throw new Error(`Token expired for ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
25149
+ if (env === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
25150
+ return {
25151
+ env,
25152
+ spaceId,
25153
+ baseUrl: deps.resolveBaseUrl(env),
25154
+ accessToken: config.token.accessToken
25155
+ };
25156
+ }
25157
+ async function fetchUsageSummary(ctx, deps, options) {
25158
+ const params = new URLSearchParams();
25159
+ if (options.from) params.set("from", options.from);
25160
+ if (options.to) params.set("to", options.to);
25161
+ const query = params.toString();
25162
+ const response = await deps.fetch(`${ctx.baseUrl}/api/spaces/${encodeURIComponent(ctx.spaceId)}/usage/summary${query ? `?${query}` : ""}`, { headers: {
25163
+ "Authorization": `Bearer ${ctx.accessToken}`,
25164
+ "Accept": "application/json"
25165
+ } });
25166
+ if (!response.ok) {
25167
+ const text = await response.text();
25168
+ throw new Error(`Request failed (${response.status}): ${text || response.statusText}`);
25169
+ }
25170
+ return response.json();
25171
+ }
25172
+ function optionValue$2(value) {
25173
+ return !value || value === "true" ? void 0 : value;
25174
+ }
25175
+ function printUsageSummary(summary, print) {
25176
+ print(`\nUsage summary for ${summary.spaceId}\n`);
25177
+ print(` Period: ${formatPeriod$1(summary.period)}`);
25178
+ print(` Storage: ${formatBytes(summary.totals.storageBytes)}`);
25179
+ print(` Workflow runs: ${summary.totals.workflowRuns}`);
25180
+ print(` Delivery: ${formatBytes(summary.totals.deliveryBytes)}`);
25181
+ if (summary.byMediaKind.length > 0) {
25182
+ print("\nBy media kind:");
25183
+ print("Media".padEnd(10) + "Storage".padEnd(14) + "Workflows".padEnd(12) + "Delivery".padEnd(14) + "Events");
25184
+ print("-".repeat(58));
25185
+ 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));
25186
+ }
25187
+ }
25188
+ function formatPeriod$1(period) {
25189
+ if (!period.from && !period.to) return "all time";
25190
+ if (period.from && period.to) return `${period.from} to ${period.to}`;
25191
+ if (period.from) return `from ${period.from}`;
25192
+ return `through ${period.to}`;
25193
+ }
25194
+ function formatBytes(bytes) {
25195
+ const sign = bytes < 0 ? "-" : "";
25196
+ let value = Math.abs(bytes);
25197
+ const units = [
25198
+ "B",
25199
+ "KiB",
25200
+ "MiB",
25201
+ "GiB",
25202
+ "TiB"
25203
+ ];
25204
+ let unitIndex = 0;
25205
+ while (value >= 1024 && unitIndex < units.length - 1) {
25206
+ value /= 1024;
25207
+ unitIndex += 1;
25208
+ }
25209
+ return `${sign}${unitIndex === 0 ? String(value) : value.toFixed(value >= 10 ? 1 : 2)} ${units[unitIndex]}`;
25210
+ }
25211
+ function printUsage$1() {
25212
+ console.log(`
25213
+ Usage:
25214
+ makefx usage [summary] [--space <id>] [--from <date>] [--to <date>]
25215
+ makefx usage --json
25216
+
25217
+ Options:
25218
+ --space <id> Target space ID; defaults from the initialized project
25219
+ --from <date> Include usage at or after this date or ISO timestamp
25220
+ --to <date> Include usage at or before this date or ISO timestamp
25221
+ --json Print machine-readable output
25222
+ --env <env> Environment (production|stage|local)
25223
+ --local Shortcut for --env local
25224
+ `);
25225
+ }
25226
+ //#endregion
25227
+ //#region src/cli/commands/spend.ts
25228
+ var defaultDeps$1 = {
25229
+ loadConfig: loadStoredConfig,
25230
+ loadProjectConfig,
25231
+ resolveBaseUrl,
25232
+ fetch,
25233
+ print: console.log
25234
+ };
25235
+ async function handleSpend(parsed) {
25236
+ try {
25237
+ await executeSpend(parsed);
25238
+ } catch (error) {
25239
+ console.error("Error:", error instanceof Error ? error.message : error);
25240
+ printSpend();
25241
+ process$1.exitCode = 1;
25242
+ }
25243
+ }
25244
+ async function executeSpend(parsed, deps = defaultDeps$1) {
25245
+ const subcommand = parsed.positionals[0] || "summary";
25246
+ if (subcommand !== "summary") throw new Error(`Unknown spend command: ${subcommand}`);
25247
+ const summary = await fetchSpendSummary(await buildContext$1(parsed, deps), deps, {
25248
+ from: optionValue$1(parsed.options.from),
25249
+ to: optionValue$1(parsed.options.to),
25250
+ userId: optionValue$1(parsed.options["user-id"] ?? parsed.options.userId),
25251
+ spaceId: optionValue$1(parsed.options["space-id"] ?? parsed.options.spaceId ?? parsed.options.space),
25252
+ provider: optionValue$1(parsed.options.provider),
25253
+ mediaKind: optionValue$1(parsed.options["media-kind"] ?? parsed.options.mediaKind)
25254
+ });
25255
+ if (parsed.options.json === "true") deps.print(JSON.stringify(summary, null, 2));
25256
+ else printSpendSummary(summary, deps.print);
25257
+ return {
25258
+ type: "summary",
25259
+ summary
25260
+ };
25261
+ }
25262
+ async function buildContext$1(parsed, deps) {
25263
+ const env = resolveCommandEnvironment(parsed, await deps.loadProjectConfig());
25264
+ const config = await deps.loadConfig(env);
25265
+ if (!config) throw new Error(`Not logged in to ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
25266
+ if (config.token.expiresAt < Date.now()) throw new Error(`Token expired for ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
25267
+ if (env === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
25268
+ return {
25269
+ env,
25270
+ baseUrl: deps.resolveBaseUrl(env),
25271
+ accessToken: config.token.accessToken
25272
+ };
25273
+ }
25274
+ async function fetchSpendSummary(ctx, deps, options) {
25275
+ const params = new URLSearchParams();
25276
+ if (options.from) params.set("from", options.from);
25277
+ if (options.to) params.set("to", options.to);
25278
+ if (options.userId) params.set("user_id", options.userId);
25279
+ if (options.spaceId) params.set("space_id", options.spaceId);
25280
+ if (options.provider) params.set("provider", options.provider);
25281
+ if (options.mediaKind) params.set("media_kind", options.mediaKind);
25282
+ const query = params.toString();
25283
+ const response = await deps.fetch(`${ctx.baseUrl}/api/billing/spend/summary${query ? `?${query}` : ""}`, { headers: {
25284
+ "Authorization": `Bearer ${ctx.accessToken}`,
25285
+ "Accept": "application/json"
25286
+ } });
25287
+ if (!response.ok) {
25288
+ const text = await response.text();
25289
+ throw new Error(`Request failed (${response.status}): ${text || response.statusText}`);
25290
+ }
25291
+ return response.json();
25292
+ }
25293
+ function optionValue$1(value) {
25294
+ return !value || value === "true" ? void 0 : value;
25295
+ }
25296
+ function printSpendSummary(summary, print) {
25297
+ print("\nProvider cost summary\n");
25298
+ print(` Period: ${formatPeriod(summary.period)}`);
25299
+ print(` Filters: ${formatFilters(summary.filters)}`);
25300
+ print(` Provider cost: ${formatUsd(summary.totals.amountMicroUsd)}`);
25301
+ print(` Entries: ${summary.totals.entries}`);
25302
+ print(` Unpriced: ${summary.totals.unpricedEntries}`);
25303
+ print(` Quantity: ${formatNumber(summary.totals.quantity)}`);
25304
+ if (summary.byProvider.length > 0) printSpendTable("\nBy provider:", [
25305
+ "Provider",
25306
+ "Cost",
25307
+ "Entries",
25308
+ "Unpriced",
25309
+ "Quantity"
25310
+ ], summary.byProvider.map((row) => [
25311
+ row.provider,
25312
+ formatUsd(row.amountMicroUsd),
25313
+ String(row.entries),
25314
+ String(row.unpricedEntries),
25315
+ formatNumber(row.quantity)
25316
+ ]), print);
25317
+ if (summary.byModel.length > 0) printSpendTable("\nBy model:", [
25318
+ "Provider",
25319
+ "Model",
25320
+ "Cost",
25321
+ "Entries",
25322
+ "Unpriced"
25323
+ ], summary.byModel.map((row) => [
25324
+ row.provider,
25325
+ row.providerModel,
25326
+ formatUsd(row.amountMicroUsd),
25327
+ String(row.entries),
25328
+ String(row.unpricedEntries)
25329
+ ]), print);
25330
+ if (summary.byMediaKind.length > 0) printSpendTable("\nBy media kind:", [
25331
+ "Media",
25332
+ "Cost",
25333
+ "Entries",
25334
+ "Unpriced",
25335
+ "Quantity"
25336
+ ], summary.byMediaKind.map((row) => [
25337
+ row.mediaKind || "-",
25338
+ formatUsd(row.amountMicroUsd),
25339
+ String(row.entries),
25340
+ String(row.unpricedEntries),
25341
+ formatNumber(row.quantity)
25342
+ ]), print);
25343
+ if (summary.byMeterEventName.length > 0) printSpendTable("\nBy meter:", [
25344
+ "Meter",
25345
+ "Cost",
25346
+ "Entries",
25347
+ "Unpriced",
25348
+ "Quantity"
25349
+ ], summary.byMeterEventName.map((row) => [
25350
+ row.meterEventName || "-",
25351
+ formatUsd(row.amountMicroUsd),
25352
+ String(row.entries),
25353
+ String(row.unpricedEntries),
25354
+ formatNumber(row.quantity)
25355
+ ]), print);
25356
+ }
25357
+ function printSpendTable(title, headers, rows, print) {
25358
+ print(title);
25359
+ const widths = headers.map((header, index) => Math.max(header.length, ...rows.map((row) => row[index]?.length ?? 0)));
25360
+ print(headers.map((header, index) => header.padEnd(widths[index] + 2)).join("").trimEnd());
25361
+ print(widths.map((width) => "-".repeat(width)).join(" "));
25362
+ for (const row of rows) print(row.map((value, index) => value.padEnd(widths[index] + 2)).join("").trimEnd());
25363
+ }
25364
+ function formatPeriod(period) {
25365
+ if (!period.from && !period.to) return "all time";
25366
+ if (period.from && period.to) return `${period.from} to ${period.to}`;
25367
+ if (period.from) return `from ${period.from}`;
25368
+ return `through ${period.to}`;
25369
+ }
25370
+ function formatFilters(filters) {
25371
+ const parts = [
25372
+ filters.userId !== null ? `user=${filters.userId}` : null,
25373
+ filters.spaceId ? `space=${filters.spaceId}` : null,
25374
+ filters.provider ? `provider=${filters.provider}` : null,
25375
+ filters.mediaKind ? `media=${filters.mediaKind}` : null
25376
+ ].filter((part) => part !== null);
25377
+ return parts.length > 0 ? parts.join(", ") : "none";
25378
+ }
25379
+ function formatUsd(amountMicroUsd) {
25380
+ let trimmed = (amountMicroUsd / 1e6).toFixed(6).replace(/0+$/, "").replace(/\.$/, "");
25381
+ if (!trimmed.includes(".")) trimmed = `${trimmed}.00`;
25382
+ else if (trimmed.split(".")[1].length === 1) trimmed = `${trimmed}0`;
25383
+ return `$${trimmed}`;
25384
+ }
25385
+ function formatNumber(value) {
25386
+ return Number.isInteger(value) ? String(value) : value.toFixed(3).replace(/0+$/, "").replace(/\.$/, "");
25387
+ }
25388
+ function printSpend() {
25389
+ console.log(`
25390
+ Usage:
25391
+ makefx spend [summary] [--from <date>] [--to <date>]
25392
+ makefx spend --user-id <id> --provider <name> --media-kind <image|audio|video>
25393
+ makefx spend --json
25394
+
25395
+ Options:
25396
+ --from <date> Include provider cost at or after this date or ISO timestamp
25397
+ --to <date> Include provider cost at or before this date or ISO timestamp
25398
+ --user-id <id> Filter to one user ID
25399
+ --space-id <id> Filter to one space ID
25400
+ --space <id> Alias for --space-id
25401
+ --provider <name> Filter to one provider
25402
+ --media-kind <kind> Filter to image, audio, or video provider cost
25403
+ --json Print machine-readable output
25404
+ --env <env> Environment (production|stage|local)
25405
+ --local Shortcut for --env local
25406
+ `);
25407
+ }
25408
+ //#endregion
25409
+ //#region src/shared/featureFlags.ts
25410
+ var TRUE_VALUES = new Set([
25411
+ "1",
25412
+ "true",
25413
+ "yes",
25414
+ "on"
25415
+ ]);
25416
+ var ROTATION_FEATURE_FLAG = "MAKEFX_ROTATION_ENABLED";
25417
+ function isFeatureFlagEnabled(value) {
25418
+ if (typeof value === "boolean") return value;
25419
+ if (typeof value === "number") return value === 1;
25420
+ if (typeof value !== "string") return false;
25421
+ return TRUE_VALUES.has(value.trim().toLowerCase());
25422
+ }
25423
+ //#endregion
25424
+ //#region src/cli/lib/feature-flags.ts
25425
+ function isCliRotationEnabled(env = process.env) {
25426
+ return isFeatureFlagEnabled(env[ROTATION_FEATURE_FLAG]);
25427
+ }
25428
+ function rotationDisabledMessage() {
25429
+ return `Rotation features are disabled. Set ${ROTATION_FEATURE_FLAG}=true to enable this experimental surface.`;
25430
+ }
25431
+ //#endregion
23349
25432
  //#region src/cli/commands/pipelines.ts
23350
25433
  var ROTATION_CONFIGS = [
23351
25434
  "4-directional",
@@ -23364,6 +25447,7 @@ var defaultDeps = {
23364
25447
  loadProjectConfig,
23365
25448
  resolveBaseUrl,
23366
25449
  createClient: (env, spaceId) => WebSocketClient.create(env, spaceId),
25450
+ isRotationEnabled: isCliRotationEnabled,
23367
25451
  print: console.log
23368
25452
  };
23369
25453
  async function handleRotation(parsed) {
@@ -23377,12 +25461,15 @@ async function handlePipelineCommand(command, parsed) {
23377
25461
  const result = await executePipelineCommand(command, parsed, defaultDeps);
23378
25462
  if ("status" in result && (result.status === "failed" || result.status === "cancelled")) process$1.exitCode = 1;
23379
25463
  } catch (error) {
23380
- console.error("Error:", error instanceof Error ? error.message : error);
23381
- printUsage(command);
25464
+ const message = error instanceof Error ? error.message : String(error);
25465
+ console.error("Error:", message);
25466
+ if (message !== rotationDisabledMessage()) printUsage(command);
23382
25467
  process$1.exitCode = 1;
23383
25468
  }
23384
25469
  }
23385
25470
  async function executePipelineCommand(command, parsed, deps = defaultDeps) {
25471
+ const rotationEnabled = deps.isRotationEnabled ?? isCliRotationEnabled;
25472
+ if (command === "rotation" && !rotationEnabled()) throw new Error(rotationDisabledMessage());
23386
25473
  const ctx = await buildContext(parsed, deps);
23387
25474
  const client = await deps.createClient(ctx.env, ctx.spaceId);
23388
25475
  try {
@@ -23584,6 +25671,10 @@ function printJsonOrText(json, result, text, deps) {
23584
25671
  }
23585
25672
  function printUsage(command) {
23586
25673
  if (command === "rotation") {
25674
+ if (!isCliRotationEnabled()) {
25675
+ console.log(rotationDisabledMessage());
25676
+ return;
25677
+ }
23587
25678
  console.log(`
23588
25679
  Usage:
23589
25680
  makefx rotation --variant <variant-id> [--config 4-directional|8-directional|turnaround]
@@ -23596,7 +25687,7 @@ Options:
23596
25687
  --subject <text> Optional subject description for consistency prompts
23597
25688
  --aspect <ratio> Optional generation aspect ratio
23598
25689
  --mode <mode> sequential or single-shot (default: sequential)
23599
- --no-style Disable the space style anchor
25690
+ --no-style Disable style preset injection for this pipeline
23600
25691
  --detach Return after the pipeline starts instead of waiting for completion
23601
25692
  --timeout <sec> Override the pipeline wait timeout
23602
25693
  --json Print machine-readable output
@@ -23618,7 +25709,7 @@ Options:
23618
25709
  --seed-variant <id> Optional completed image variant to place at the center (sequential mode only)
23619
25710
  --aspect <ratio> Optional generation aspect ratio
23620
25711
  --mode <mode> sequential or single-shot (default: sequential)
23621
- --no-style Disable the space style anchor
25712
+ --no-style Disable style preset injection for this pipeline
23622
25713
  --detach Return after the pipeline starts instead of waiting for completion
23623
25714
  --timeout <sec> Override the pipeline wait timeout
23624
25715
  --json Print machine-readable output
@@ -23626,7 +25717,7 @@ Options:
23626
25717
  }
23627
25718
  //#endregion
23628
25719
  //#region src/cli/index.ts
23629
- var CLI_VERSION = "0.1.3+21fbf493922f";
25720
+ var CLI_VERSION = "0.2.1+2f99bf2b725b";
23630
25721
  async function main() {
23631
25722
  const argv = process$1.argv.slice(2);
23632
25723
  if (argv[0] === "--") argv.shift();
@@ -23753,10 +25844,20 @@ function printCommandHelp(command, positionals) {
23753
25844
  case "assets":
23754
25845
  printAssetsHelp();
23755
25846
  return;
25847
+ case "usage":
25848
+ printUsageHelp();
25849
+ return;
25850
+ case "spend":
25851
+ printSpendHelp();
25852
+ return;
23756
25853
  case "variants":
23757
25854
  case "variant":
23758
25855
  printVariantsHelp();
23759
25856
  return;
25857
+ case "styles":
25858
+ case "style":
25859
+ printStylesHelp();
25860
+ return;
23760
25861
  case "rotation":
23761
25862
  printRotationHelp();
23762
25863
  return;
@@ -23775,6 +25876,11 @@ function printCommandHelp(command, positionals) {
23775
25876
  }
23776
25877
  }
23777
25878
  function printHelp() {
25879
+ const rotationHelp = isCliRotationEnabled() ? ` rotation --variant <variant-id>
25880
+ Generate rotation views from a completed image variant
25881
+ rotation cancel <rotation-set-id>
25882
+ Cancel an active rotation pipeline` : "";
25883
+ const rotationExample = isCliRotationEnabled() ? " makefx rotation --variant variant_456 --config 8-directional\n" : "";
23778
25884
  console.log(`
23779
25885
  Make Effects CLI
23780
25886
 
@@ -23802,10 +25908,10 @@ Project:
23802
25908
  variants star <variant-id> Star a variant (unstar to clear)
23803
25909
  variants rate <variant-id> approved|rejected
23804
25910
  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
25911
+ styles presets List style presets
25912
+ styles collections List style reference collections
25913
+ styles references List style reference assets
25914
+ ${rotationHelp}
23809
25915
  tileset "prompt" --type terrain --grid 3x3
23810
25916
  Generate a consistent tile set
23811
25917
  tileset cancel <tile-set-id> Cancel an active tile-set pipeline
@@ -23813,12 +25919,14 @@ Project:
23813
25919
  List Space-backed production placements
23814
25920
  productions export --production-id <id>
23815
25921
  Export production scene args from Space records
25922
+ usage [summary] [--space <id>] Show platform storage and workflow consumption
25923
+ spend [summary] Show admin provider cost summary
23816
25924
 
23817
25925
  Billing (Polar.sh):
23818
25926
  billing status Show sync status (pending, failed, synced events)
23819
25927
  billing check Run operational checks for workers, meters, and sync health
23820
25928
  billing reconcile --user-id <id>
23821
- Compare local billable usage with Polar usage
25929
+ Reconcile Polar, charge, provider, and platform usage
23822
25930
  billing retry-failed Retry all failed events
23823
25931
 
23824
25932
  Spaces:
@@ -23834,7 +25942,10 @@ Listen:
23834
25942
 
23835
25943
  Upload:
23836
25944
  upload <file> --asset <id> [--space <id>] Upload image, audio, or video to existing asset
23837
- upload <file> --name <name> [--space <id>] Upload media and create new asset
25945
+ upload <file> --name <name> [--space <id>] Upload image, audio, or video as a new asset
25946
+ upload <file> --collection <id> Place uploaded media in a collection
25947
+ upload <file> --collection-name <name> Place uploaded media in an exact-name collection
25948
+ upload <file> --manual-relation <spec> Create a manual relation from uploaded media
23838
25949
 
23839
25950
  Forge:
23840
25951
  generate "prompt" --name <name> --type <type> -o <file>
@@ -23876,14 +25987,21 @@ Examples:
23876
25987
  makefx audio sfx generate "A short brass victory sting" --name "Victory Sting" -o victory.wav
23877
25988
  makefx video generate "A looping idle animation" --name "Idle Animation" --type animation --duration 6 --resolution 1080p --tier fast -o idle.mp4
23878
25989
  makefx productions export --production-id s01e01-a2
25990
+ makefx upload hero.png --name "Hero" --collection collection_cast
25991
+ makefx upload hero.png --name "Hero" --collection-name "Cast" --json
25992
+ makefx upload thumbnail.png --asset asset_thumb --manual-relation thumbnail_for:asset:asset_target
23879
25993
  makefx assets
25994
+ makefx usage --from 2026-06-01
25995
+ makefx spend --from 2026-06-01 --provider gemini
23880
25996
  makefx assets download variant_123 -o variant.mp4
23881
25997
  makefx assets rename asset_123 "Hero (moving)"
23882
25998
  makefx assets set-active asset_123 variant_456
23883
25999
  makefx variants retry variant_456
23884
26000
  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
26001
+ makefx styles collections create "Painterly refs" --refs asset_123,variant_456
26002
+ makefx styles presets create "Painterly" --collection collection_123 --prompt "Painterly adventure game" --default
26003
+ makefx generate "A market background" --style-preset Painterly --name "Market" --type scene -o market.png
26004
+ ${rotationExample} makefx tileset "grass and stone path tiles" --type terrain --grid 3x3
23887
26005
  `);
23888
26006
  }
23889
26007
  function printInitHelp() {
@@ -23918,7 +26036,7 @@ Usage:
23918
26036
  Subcommands:
23919
26037
  status Show sync status (pending, failed, synced events)
23920
26038
  check Run operational checks for workers, Polar meters, and sync health
23921
- reconcile Compare local billable usage with Polar usage for one user
26039
+ reconcile Reconcile Polar, charge, provider, and platform usage for one user
23922
26040
  retry-failed Reset failed events for retry (next cron will sync them)
23923
26041
 
23924
26042
  Options:
@@ -23948,7 +26066,7 @@ function printUploadHelp() {
23948
26066
  console.log(`
23949
26067
  Usage:
23950
26068
  makefx upload <file> --asset <id> [--space <id>] Upload media to existing asset
23951
- makefx upload <file> --name <name> [--space <id>] Create new asset
26069
+ makefx upload <file> --name <name> [--space <id>] Upload media as a new asset
23952
26070
 
23953
26071
  Options:
23954
26072
  --space <id> Target space ID; defaults from initialized project
@@ -23956,7 +26074,29 @@ Options:
23956
26074
  --name <name> New asset name (creates asset + variant)
23957
26075
  --type <type> Asset type for new assets (default: character)
23958
26076
  --media-kind <k> Optional explicit kind: image, audio, or video
23959
- --parent <id> Parent asset ID for new assets
26077
+ --prompt <text> Prompt provenance for uploaded media
26078
+ --model <model> Model provenance for uploaded media
26079
+ --provider <name> Provider provenance for uploaded media
26080
+ --provider-metadata <json> Provider metadata JSON object
26081
+ --generation-provenance <json> Extra provenance JSON object
26082
+ --source-variant <id> Existing source variant for upload lineage
26083
+ --relation-type <type> Lineage type: derived, refined, or forked (default: derived)
26084
+ --active-variant-behavior <b> if-missing, set-active, or keep
26085
+ --collection <ids> Comma-separated collection IDs for the uploaded asset or variant
26086
+ --collection-name <names> Comma-separated exact collection names for lookup
26087
+ --collection-role <role> Collection item role (default: member)
26088
+ --collection-subject <type> Collection subject: asset or variant (default: asset)
26089
+ --collection-pinned-variant <id|uploaded|none>
26090
+ Pin an asset collection item to the uploaded variant by default
26091
+ --manual-relation <spec> Comma-separated <type>:asset:<id> or <type>:variant:<id>
26092
+ --manual-relation-subject <type>
26093
+ Relation subject: uploaded asset or variant (default: variant)
26094
+ --manual-relation-label <text> Optional manual relation label
26095
+ --manual-relation-context <json|string>
26096
+ Optional manual relation context
26097
+ --manual-relation-metadata <json>
26098
+ Optional manual relation metadata object
26099
+ --json Print machine-readable upload output with Space IDs
23960
26100
  --env <env> Environment (production|stage|local)
23961
26101
  --local Shortcut for --env local
23962
26102
  `);
@@ -23970,6 +26110,10 @@ Usage:
23970
26110
 
23971
26111
  ${imageCapabilityHelp()}
23972
26112
 
26113
+ Style:
26114
+ --style-preset <id-or-name> Use an enabled style preset for this generation
26115
+ --no-style Disable style preset injection for this generation
26116
+
23973
26117
  Production metadata:
23974
26118
  --scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
23975
26119
  --shot-id <id> --production-id <id>
@@ -23984,6 +26128,10 @@ Usage:
23984
26128
 
23985
26129
  ${imageCapabilityHelp()}
23986
26130
 
26131
+ Style:
26132
+ --style-preset <id-or-name> Use an enabled style preset for this refinement
26133
+ --no-style Disable style preset injection for this refinement
26134
+
23987
26135
  Production metadata:
23988
26136
  --scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
23989
26137
  --shot-id <id> --production-id <id>
@@ -23996,6 +26144,10 @@ Usage:
23996
26144
  makefx batch "prompt" --name <name> --type <type> --count <2-8> --output-dir <dir> [--model ${optionValues(IMAGE_MODEL_SELECTIONS)}] [--size ${imageSizeValues()}] [--aspect <ratio>]
23997
26145
 
23998
26146
  ${imageCapabilityHelp()}
26147
+
26148
+ Style:
26149
+ --style-preset <id-or-name> Use an enabled style preset for this batch
26150
+ --no-style Disable style preset injection for this batch
23999
26151
  `);
24000
26152
  return;
24001
26153
  }
@@ -24006,6 +26158,10 @@ Usage:
24006
26158
 
24007
26159
  ${imageCapabilityHelp()}
24008
26160
 
26161
+ Style:
26162
+ --style-preset <id-or-name> Use an enabled style preset for this derivation
26163
+ --no-style Disable style preset injection for this derivation
26164
+
24009
26165
  Production metadata:
24010
26166
  --scene-label <label> --timeline-start-ms <ms> --duration-ms <ms>
24011
26167
  --shot-id <id> --production-id <id>
@@ -24203,7 +26359,43 @@ Options:
24203
26359
  --local Shortcut for --env local
24204
26360
  `);
24205
26361
  }
26362
+ function printStylesHelp() {
26363
+ console.log(`
26364
+ Usage:
26365
+ makefx styles references [--collection <id-or-name>] [--json]
26366
+ makefx styles collections list [--json]
26367
+ makefx styles collections create <name> --refs <asset_or_variant,...>
26368
+ makefx styles collections update <collection-id> [--name <name>] [--refs <asset_or_variant,...>] [--append]
26369
+ makefx styles presets list [--json]
26370
+ makefx styles presets create <name> --collection <collection-id> --prompt "style prompt" [--default]
26371
+ makefx styles presets update <preset-id> [--name <name>] [--collection <collection-id>] [--prompt "style prompt"]
26372
+ makefx styles presets enable <preset-id>
26373
+ makefx styles presets disable <preset-id>
26374
+ makefx styles presets delete <preset-id>
26375
+
26376
+ Generation:
26377
+ makefx generate "prompt" --style-preset <id-or-name> --name <name> --type <type> -o <file>
26378
+ makefx generate "prompt" --no-style --name <name> --type <type> -o <file>
26379
+
26380
+ Model:
26381
+ Style references are normal Space assets or exact variants grouped into style
26382
+ collections. Style presets point to those collections plus a style prompt.
26383
+
26384
+ Options:
26385
+ --space <id> Target space ID; defaults from the initialized project
26386
+ --refs <ids> Comma-separated asset IDs or variant IDs to use as style references
26387
+ --assets <ids> Comma-separated asset IDs; active variants are pinned
26388
+ --variants <ids> Comma-separated variant IDs
26389
+ --json Print machine-readable output
26390
+ --env <env> Environment (production|stage|local)
26391
+ --local Shortcut for --env local
26392
+ `);
26393
+ }
24206
26394
  function printRotationHelp() {
26395
+ if (!isCliRotationEnabled()) {
26396
+ console.log(rotationDisabledMessage());
26397
+ return;
26398
+ }
24207
26399
  console.log(`
24208
26400
  Usage:
24209
26401
  makefx rotation --variant <variant-id> [--config 4-directional|8-directional|turnaround]
@@ -24216,7 +26408,7 @@ Options:
24216
26408
  --subject <text> Optional subject description for consistency prompts
24217
26409
  --aspect <ratio> Optional generation aspect ratio
24218
26410
  --mode <mode> sequential or single-shot (default: sequential)
24219
- --no-style Disable the space style anchor
26411
+ --no-style Disable style preset injection for this pipeline
24220
26412
  --detach Return after the pipeline starts instead of waiting for completion
24221
26413
  --timeout <sec> Override the pipeline wait timeout
24222
26414
  --json Print machine-readable output
@@ -24238,7 +26430,7 @@ Options:
24238
26430
  --seed-variant <id> Optional completed image variant to place at the center (sequential mode only)
24239
26431
  --aspect <ratio> Optional generation aspect ratio
24240
26432
  --mode <mode> sequential or single-shot (default: sequential)
24241
- --no-style Disable the space style anchor
26433
+ --no-style Disable style preset injection for this pipeline
24242
26434
  --detach Return after the pipeline starts instead of waiting for completion
24243
26435
  --timeout <sec> Override the pipeline wait timeout
24244
26436
  --json Print machine-readable output
@@ -24266,6 +26458,41 @@ Usage:
24266
26458
  makefx assets download <variant-id|legacy-image-key> -o output-file
24267
26459
  `);
24268
26460
  }
26461
+ function printUsageHelp() {
26462
+ console.log(`
26463
+ Usage:
26464
+ makefx usage [summary] [--space <id>] [--from <date>] [--to <date>]
26465
+ makefx usage --json
26466
+
26467
+ Options:
26468
+ --space <id> Target space ID; defaults from the initialized project
26469
+ --from <date> Include usage at or after this date or ISO timestamp
26470
+ --to <date> Include usage at or before this date or ISO timestamp
26471
+ --json Print machine-readable output
26472
+ --env <env> Environment (production|stage|local)
26473
+ --local Shortcut for --env local
26474
+ `);
26475
+ }
26476
+ function printSpendHelp() {
26477
+ console.log(`
26478
+ Usage:
26479
+ makefx spend [summary] [--from <date>] [--to <date>]
26480
+ makefx spend --user-id <id> --provider <name> --media-kind <image|audio|video>
26481
+ makefx spend --json
26482
+
26483
+ Options:
26484
+ --from <date> Include provider cost at or after this date or ISO timestamp
26485
+ --to <date> Include provider cost at or before this date or ISO timestamp
26486
+ --user-id <id> Filter to one user ID
26487
+ --space-id <id> Filter to one space ID
26488
+ --space <id> Alias for --space-id
26489
+ --provider <name> Filter to one provider
26490
+ --media-kind <kind> Filter to image, audio, or video provider cost
26491
+ --json Print machine-readable output
26492
+ --env <env> Environment (production|stage|local)
26493
+ --local Shortcut for --env local
26494
+ `);
26495
+ }
24269
26496
  async function dispatchCommand(command, parsed) {
24270
26497
  switch (command) {
24271
26498
  case "init":
@@ -24313,10 +26540,20 @@ async function dispatchCommand(command, parsed) {
24313
26540
  case "assets":
24314
26541
  await handleAssets(parsed);
24315
26542
  break;
26543
+ case "usage":
26544
+ await handleUsage(parsed);
26545
+ break;
26546
+ case "spend":
26547
+ await handleSpend(parsed);
26548
+ break;
24316
26549
  case "variants":
24317
26550
  case "variant":
24318
26551
  await handleVariants(parsed);
24319
26552
  break;
26553
+ case "styles":
26554
+ case "style":
26555
+ await handleStyles(parsed);
26556
+ break;
24320
26557
  case "rotation":
24321
26558
  await handleRotation(parsed);
24322
26559
  break;