makefx 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/makefx.mjs +1004 -884
- package/package.json +1 -1
package/makefx.mjs
CHANGED
|
@@ -8,9 +8,9 @@ import { mkdir, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/p
|
|
|
8
8
|
import os from "node:os";
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import { createReadStream, createWriteStream } from "node:fs";
|
|
11
|
+
import https from "node:https";
|
|
11
12
|
import { Readable } from "node:stream";
|
|
12
13
|
import { pipeline } from "node:stream/promises";
|
|
13
|
-
import https from "node:https";
|
|
14
14
|
//#region \0rolldown/runtime.js
|
|
15
15
|
var __create = Object.create;
|
|
16
16
|
var __defProp = Object.defineProperty;
|
|
@@ -831,6 +831,78 @@ function validateProjectConfig(config, configPath) {
|
|
|
831
831
|
if (!config.spaceId || typeof config.spaceId !== "string") throw new Error(`Make Effects project config is missing spaceId: ${configPath}`);
|
|
832
832
|
}
|
|
833
833
|
//#endregion
|
|
834
|
+
//#region src/shared/compact-references.ts
|
|
835
|
+
var COMPACT_ID_LENGTH = 8;
|
|
836
|
+
var CompactReferenceError = class extends Error {
|
|
837
|
+
code;
|
|
838
|
+
constructor(code, message) {
|
|
839
|
+
super(message);
|
|
840
|
+
this.code = code;
|
|
841
|
+
this.name = "CompactReferenceError";
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
function normalizeId(value) {
|
|
845
|
+
return value.toLowerCase().replaceAll(/[^a-z0-9]/gu, "");
|
|
846
|
+
}
|
|
847
|
+
function slugify$1(value) {
|
|
848
|
+
return value.normalize("NFKD").replaceAll(/\p{Mark}/gu, "").toLowerCase().replaceAll(/[^\p{Letter}\p{Number}]+/gu, "-").replaceAll(/^-+|-+$/gu, "").slice(0, 32).replaceAll(/-+$/gu, "") || "asset";
|
|
849
|
+
}
|
|
850
|
+
function compactIdPrefix(id) {
|
|
851
|
+
return normalizeId(id).slice(0, COMPACT_ID_LENGTH);
|
|
852
|
+
}
|
|
853
|
+
function createAssetRef(name, assetId) {
|
|
854
|
+
return `asset:${slugify$1(name)}~${compactIdPrefix(assetId)}`;
|
|
855
|
+
}
|
|
856
|
+
function createVariantRef(name, assetId, variantId) {
|
|
857
|
+
return `${createAssetRef(name, assetId)}@${compactIdPrefix(variantId)}`;
|
|
858
|
+
}
|
|
859
|
+
function parseAssetRef(value) {
|
|
860
|
+
const match = /^asset:[^~]+~([a-z0-9]{4,8})$/u.exec(value);
|
|
861
|
+
return match ? { idPrefix: match[1] } : null;
|
|
862
|
+
}
|
|
863
|
+
function parseVariantRef(value) {
|
|
864
|
+
const separator = value.lastIndexOf("@");
|
|
865
|
+
if (separator < 0) return null;
|
|
866
|
+
const assetRef = value.slice(0, separator);
|
|
867
|
+
const variant = value.slice(separator + 1);
|
|
868
|
+
if (!parseAssetRef(assetRef) || variant !== "active" && !/^[a-z0-9]{4,8}$/u.test(variant)) return null;
|
|
869
|
+
return {
|
|
870
|
+
assetRef,
|
|
871
|
+
variant
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
function idMatchesPrefix(id, prefix) {
|
|
875
|
+
return normalizeId(id).startsWith(prefix.toLowerCase());
|
|
876
|
+
}
|
|
877
|
+
function resolveAssetRef(identifier, assets) {
|
|
878
|
+
const parsed = parseAssetRef(identifier);
|
|
879
|
+
if (!parsed) {
|
|
880
|
+
if (identifier.startsWith("asset:")) throw new CompactReferenceError("MALFORMED_REFERENCE", `Asset reference ${identifier} is malformed`);
|
|
881
|
+
return identifier;
|
|
882
|
+
}
|
|
883
|
+
const matches = assets.filter((asset) => idMatchesPrefix(asset.id, parsed.idPrefix));
|
|
884
|
+
if (matches.length === 0) throw new CompactReferenceError("NOT_FOUND", `Asset reference ${identifier} was not found`);
|
|
885
|
+
if (matches.length > 1) throw new CompactReferenceError("AMBIGUOUS_REFERENCE", `Asset reference ${identifier} is ambiguous`);
|
|
886
|
+
return matches[0].id;
|
|
887
|
+
}
|
|
888
|
+
function resolveVariantRef(identifier, assets, variants) {
|
|
889
|
+
const parsed = parseVariantRef(identifier);
|
|
890
|
+
if (!parsed) {
|
|
891
|
+
if (identifier.startsWith("asset:")) throw new CompactReferenceError("MALFORMED_REFERENCE", `Variant reference ${identifier} is malformed`);
|
|
892
|
+
return identifier;
|
|
893
|
+
}
|
|
894
|
+
const assetId = resolveAssetRef(parsed.assetRef, assets);
|
|
895
|
+
const asset = assets.find((candidate) => candidate.id === assetId);
|
|
896
|
+
if (parsed.variant === "active") {
|
|
897
|
+
if (!asset?.active_variant_id) throw new CompactReferenceError("NOT_FOUND", `Asset reference ${parsed.assetRef} has no active variant`);
|
|
898
|
+
return asset.active_variant_id;
|
|
899
|
+
}
|
|
900
|
+
const matches = variants.filter((variant) => variant.asset_id === assetId && idMatchesPrefix(variant.id, parsed.variant));
|
|
901
|
+
if (matches.length === 0) throw new CompactReferenceError("NOT_FOUND", `Variant reference ${identifier} was not found`);
|
|
902
|
+
if (matches.length > 1) throw new CompactReferenceError("AMBIGUOUS_REFERENCE", `Variant reference ${identifier} is ambiguous`);
|
|
903
|
+
return matches[0].id;
|
|
904
|
+
}
|
|
905
|
+
//#endregion
|
|
834
906
|
//#region src/cli/commands/spaces.ts
|
|
835
907
|
/**
|
|
836
908
|
* Spaces Command - List and manage user's spaces
|
|
@@ -933,7 +1005,14 @@ async function executeSpaces(parsed, deps = defaultDeps$11) {
|
|
|
933
1005
|
}
|
|
934
1006
|
if (spaceId) {
|
|
935
1007
|
const details = await getSpaceDetails(ctx, deps, spaceId);
|
|
936
|
-
if (jsonOutput) deps.print(JSON.stringify(
|
|
1008
|
+
if (jsonOutput) deps.print(JSON.stringify({
|
|
1009
|
+
...details,
|
|
1010
|
+
assets: details.assets.map((asset) => ({
|
|
1011
|
+
...asset,
|
|
1012
|
+
assetRef: createAssetRef(asset.name, asset.id),
|
|
1013
|
+
variantRef: asset.active_variant_id ? createVariantRef(asset.name, asset.id, asset.active_variant_id) : null
|
|
1014
|
+
}))
|
|
1015
|
+
}, null, 2));
|
|
937
1016
|
else printSpaceDetails(details, deps.print);
|
|
938
1017
|
return {
|
|
939
1018
|
type: "show",
|
|
@@ -1144,8 +1223,8 @@ function printSpaceDetails(details, print) {
|
|
|
1144
1223
|
for (const [type, typeAssets] of byType) {
|
|
1145
1224
|
print(`${type.charAt(0).toUpperCase() + type.slice(1)}s (${typeAssets.length}):`);
|
|
1146
1225
|
for (const asset of typeAssets) {
|
|
1147
|
-
print(` ${asset.active_variant_id ? "✓" : "○"} ${asset.name}`);
|
|
1148
|
-
print(`
|
|
1226
|
+
print(` ${asset.active_variant_id ? "✓" : "○"} ${createAssetRef(asset.name, asset.id)} — ${asset.name}`);
|
|
1227
|
+
if (asset.active_variant_id) print(` Active: ${createVariantRef(asset.name, asset.id, asset.active_variant_id)}`);
|
|
1149
1228
|
}
|
|
1150
1229
|
print("");
|
|
1151
1230
|
}
|
|
@@ -5377,553 +5456,42 @@ function isMirrorEntry(value) {
|
|
|
5377
5456
|
return entry.version === MIRROR_REGISTRY_VERSION && typeof entry.baseUrl === "string" && (entry.environment === void 0 || typeof entry.environment === "string") && typeof entry.spaceId === "string" && typeof entry.sha256 === "string" && typeof entry.sizeBytes === "number" && Array.isArray(entry.paths) && entry.paths.every((item) => typeof item === "string") && typeof entry.assetId === "string" && typeof entry.variantId === "string" && typeof entry.mediaKind === "string" && (entry.mediaKey === void 0 || entry.mediaKey === null || typeof entry.mediaKey === "string") && typeof entry.updatedAt === "string";
|
|
5378
5457
|
}
|
|
5379
5458
|
//#endregion
|
|
5380
|
-
//#region src/cli/
|
|
5459
|
+
//#region src/cli/lib/websocket-client.ts
|
|
5381
5460
|
/**
|
|
5382
|
-
*
|
|
5461
|
+
* WebSocket Client for CLI
|
|
5383
5462
|
*
|
|
5384
|
-
*
|
|
5385
|
-
*
|
|
5386
|
-
* makefx upload <file> --space <id> --name <name> Upload as new asset
|
|
5387
|
-
* makefx upload <file> --space <id> --name <name> --type <type>
|
|
5463
|
+
* Provides WebSocket-based communication with the Space Durable Object.
|
|
5464
|
+
* Replaces HTTP API calls with WebSocket messages for chat and generation.
|
|
5388
5465
|
*/
|
|
5389
|
-
var
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
fetch,
|
|
5394
|
-
readFile,
|
|
5395
|
-
stat,
|
|
5396
|
-
recordMirrorForFile,
|
|
5397
|
-
print: console.log
|
|
5398
|
-
};
|
|
5399
|
-
var UploadUsageError = class extends Error {};
|
|
5400
|
-
var RETIRED_UPLOAD_ORGANIZATION_OPTIONS = [
|
|
5401
|
-
["collection", "--collection"],
|
|
5402
|
-
["collection-name", "--collection-name"],
|
|
5403
|
-
["collectionName", "--collection-name"],
|
|
5404
|
-
["collection-role", "--collection-role"],
|
|
5405
|
-
["collectionRole", "--collection-role"],
|
|
5406
|
-
["collection-subject", "--collection-subject"],
|
|
5407
|
-
["collectionSubject", "--collection-subject"],
|
|
5408
|
-
["manual-relation", "--manual-relation"],
|
|
5409
|
-
["manualRelation", "--manual-relation"],
|
|
5410
|
-
["manual-relation-context", "--manual-relation-context"],
|
|
5411
|
-
["manualRelationContext", "--manual-relation-context"]
|
|
5412
|
-
];
|
|
5413
|
-
async function handleUpload(parsed) {
|
|
5414
|
-
try {
|
|
5415
|
-
await executeUpload(parsed);
|
|
5416
|
-
} catch (error) {
|
|
5417
|
-
console.error(error instanceof Error ? `Error: ${error.message}` : "Error: Upload failed");
|
|
5418
|
-
if (error instanceof UploadUsageError) printUsage$10();
|
|
5419
|
-
process$1.exitCode = 1;
|
|
5420
|
-
}
|
|
5421
|
-
}
|
|
5422
|
-
async function executeUpload(parsed, deps = defaultDeps$10) {
|
|
5423
|
-
const filePath = parsed.positionals[0];
|
|
5424
|
-
if (!filePath) throw new UploadUsageError("File path is required");
|
|
5425
|
-
rejectRetiredUploadOrganizationOptions(parsed);
|
|
5426
|
-
const projectConfig = await deps.loadProjectConfig();
|
|
5427
|
-
const env = resolveCommandEnvironment(parsed, projectConfig);
|
|
5428
|
-
const spaceId = resolveCommandSpace(parsed, projectConfig);
|
|
5429
|
-
const assetId = parsed.options.asset;
|
|
5430
|
-
const assetName = parsed.options.name;
|
|
5431
|
-
const assetType = parsed.options.type || "character";
|
|
5432
|
-
const requestedMediaKind = parsed.options["media-kind"] || parsed.options.mediaKind;
|
|
5433
|
-
const prompt = parsed.options.prompt;
|
|
5434
|
-
const model = parsed.options.model;
|
|
5435
|
-
const provider = parsed.options.provider;
|
|
5436
|
-
const rawProviderMetadata = parsed.options["provider-metadata"] ?? parsed.options.providerMetadata ?? parsed.options.provider_metadata;
|
|
5437
|
-
const rawGenerationProvenance = parsed.options["generation-provenance"] ?? parsed.options.generationProvenance ?? parsed.options.generation_provenance;
|
|
5438
|
-
const rawSourceVariantIds = parsed.options["source-variants"] ?? parsed.options.sourceVariants ?? parsed.options.sourceVariantIds ?? parsed.options["source-variant"] ?? parsed.options.sourceVariantId ?? parsed.options.parentVariantId;
|
|
5439
|
-
const rawRelationType = parsed.options["relation-type"] ?? parsed.options.relationType;
|
|
5440
|
-
const rawActiveVariantBehavior = parsed.options["active-variant-behavior"] ?? parsed.options.activeVariantBehavior;
|
|
5441
|
-
const jsonOutput = parsed.options.json === "true";
|
|
5442
|
-
if (parsed.options["dry-run"] === "true" || parsed.options.dryRun === "true") throw new UploadUsageError("--dry-run is not supported for direct file upload");
|
|
5443
|
-
if (!spaceId) throw new UploadUsageError("--space is required, or run: makefx init --space <id>");
|
|
5444
|
-
if (!assetId && !assetName) throw new UploadUsageError("Either --asset or --name is required");
|
|
5445
|
-
const providerMetadata = parseJsonObjectOption(rawProviderMetadata, "--provider-metadata");
|
|
5446
|
-
const generationProvenance = parseJsonObjectOption(rawGenerationProvenance, "--generation-provenance");
|
|
5447
|
-
const sourceVariantIds = parseCsvOption(rawSourceVariantIds, "--source-variant");
|
|
5448
|
-
const relationType = normalizeRelationType(rawRelationType);
|
|
5449
|
-
const activeVariantBehavior = normalizeActiveVariantBehavior(rawActiveVariantBehavior);
|
|
5450
|
-
if (sourceVariantIds.length === 0 && (parsed.options["relation-type"] || parsed.options.relationType)) throw new UploadUsageError("--relation-type requires --source-variant or --source-variants");
|
|
5451
|
-
const mediaType = resolveMediaType(path.extname(filePath).toLowerCase(), requestedMediaKind);
|
|
5452
|
-
const config = await deps.loadConfig(env);
|
|
5453
|
-
if (!config) throw new Error(`Not logged in to ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
|
|
5454
|
-
if (config.token.expiresAt < Date.now()) throw new Error(`Token expired for ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
|
|
5455
|
-
const baseUrl = deps.resolveBaseUrl(env);
|
|
5456
|
-
const accessToken = config.token.accessToken;
|
|
5457
|
-
if (env === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
5458
|
-
try {
|
|
5459
|
-
const fileStat = await deps.stat(filePath);
|
|
5460
|
-
if (!fileStat.isFile()) throw new Error(`"${filePath}" is not a file`);
|
|
5461
|
-
if (fileStat.size > 10485760) throw new Error(`File too large (${(fileStat.size / 1024 / 1024).toFixed(2)}MB). Maximum size: 10MB`);
|
|
5462
|
-
const fileBuffer = await deps.readFile(filePath);
|
|
5463
|
-
const fileName = path.basename(filePath);
|
|
5464
|
-
const formData = new FormData();
|
|
5465
|
-
const blob = new Blob([fileBuffer], { type: mediaType.mimeType });
|
|
5466
|
-
formData.append("file", blob, fileName);
|
|
5467
|
-
formData.append("mediaKind", mediaType.mediaKind);
|
|
5468
|
-
formData.append("activeVariantBehavior", activeVariantBehavior);
|
|
5469
|
-
if (assetId) formData.append("assetId", assetId);
|
|
5470
|
-
else {
|
|
5471
|
-
formData.append("assetName", assetName);
|
|
5472
|
-
formData.append("assetType", assetType);
|
|
5473
|
-
}
|
|
5474
|
-
if (prompt) formData.append("prompt", prompt);
|
|
5475
|
-
if (model) formData.append("model", model);
|
|
5476
|
-
if (provider) formData.append("provider", provider);
|
|
5477
|
-
if (providerMetadata) formData.append("providerMetadata", JSON.stringify(providerMetadata));
|
|
5478
|
-
if (generationProvenance) formData.append("generationProvenance", JSON.stringify(generationProvenance));
|
|
5479
|
-
if (sourceVariantIds.length > 0) formData.append("lineage", JSON.stringify(sourceVariantIds.map((parentVariantId) => ({
|
|
5480
|
-
parentVariantId,
|
|
5481
|
-
relationType
|
|
5482
|
-
}))));
|
|
5483
|
-
if (!jsonOutput) {
|
|
5484
|
-
deps.print(`\nUploading "${fileName}" to space ${spaceId}...`);
|
|
5485
|
-
deps.print(` Media kind: ${mediaType.mediaKind}`);
|
|
5486
|
-
if (assetId) deps.print(` Target asset: ${assetId}`);
|
|
5487
|
-
else deps.print(` Creating asset: "${assetName}" (${assetType})`);
|
|
5488
|
-
if (sourceVariantIds.length === 1) deps.print(` Source variant: ${sourceVariantIds[0]} (${relationType})`);
|
|
5489
|
-
else if (sourceVariantIds.length > 1) deps.print(` Source variants: ${sourceVariantIds.join(", ")} (${relationType})`);
|
|
5490
|
-
}
|
|
5491
|
-
const response = await deps.fetch(`${baseUrl}/api/spaces/${spaceId}/upload`, {
|
|
5492
|
-
method: "POST",
|
|
5493
|
-
headers: { "Authorization": `Bearer ${accessToken}` },
|
|
5494
|
-
body: formData
|
|
5495
|
-
});
|
|
5496
|
-
const data = await response.json();
|
|
5497
|
-
if (!response.ok) throw new Error(`Upload failed: ${"error" in data ? data.error : response.statusText}`);
|
|
5498
|
-
const upload = data;
|
|
5499
|
-
const result = {
|
|
5500
|
-
asset: upload.asset,
|
|
5501
|
-
variant: upload.variant,
|
|
5502
|
-
lineage: upload.lineage
|
|
5503
|
-
};
|
|
5504
|
-
await recordUploadMirror({
|
|
5505
|
-
deps,
|
|
5506
|
-
projectRoot: projectConfig?.projectRoot,
|
|
5507
|
-
env,
|
|
5508
|
-
baseUrl,
|
|
5509
|
-
spaceId,
|
|
5510
|
-
filePath,
|
|
5511
|
-
assetId: upload.asset?.id ?? upload.variant.asset_id,
|
|
5512
|
-
variantId: upload.variant.id,
|
|
5513
|
-
mediaKind: upload.variant.media_kind || mediaType.mediaKind,
|
|
5514
|
-
mediaKey: upload.variant.media_key || upload.variant.image_key
|
|
5515
|
-
});
|
|
5516
|
-
if (jsonOutput) {
|
|
5517
|
-
deps.print(JSON.stringify(result, null, 2));
|
|
5518
|
-
return result;
|
|
5519
|
-
}
|
|
5520
|
-
deps.print("\nUpload successful!\n");
|
|
5521
|
-
if (upload.asset) {
|
|
5522
|
-
deps.print("New Asset:");
|
|
5523
|
-
deps.print(` ID: ${upload.asset.id}`);
|
|
5524
|
-
deps.print(` Name: ${upload.asset.name}`);
|
|
5525
|
-
deps.print(` Type: ${upload.asset.type}`);
|
|
5526
|
-
deps.print("");
|
|
5527
|
-
}
|
|
5528
|
-
deps.print("Variant:");
|
|
5529
|
-
deps.print(` ID: ${upload.variant.id}`);
|
|
5530
|
-
deps.print(` Asset: ${upload.variant.asset_id}`);
|
|
5531
|
-
deps.print(` Status: ${upload.variant.status}`);
|
|
5532
|
-
deps.print(` Media: ${upload.variant.media_kind || mediaType.mediaKind}`);
|
|
5533
|
-
deps.print(` File: ${upload.variant.media_key || upload.variant.image_key || "-"}`);
|
|
5534
|
-
if (upload.variant.image_key) deps.print(` Image: ${upload.variant.image_key}`);
|
|
5535
|
-
if (upload.variant.thumb_key) deps.print(` Thumb: ${upload.variant.thumb_key}`);
|
|
5536
|
-
if (upload.variant.media_mime_type) deps.print(` MIME: ${upload.variant.media_mime_type}`);
|
|
5537
|
-
if (upload.variant.recipe) try {
|
|
5538
|
-
const recipe = JSON.parse(upload.variant.recipe);
|
|
5539
|
-
deps.print("\nRecipe:");
|
|
5540
|
-
deps.print(` Operation: ${recipe.operation}`);
|
|
5541
|
-
deps.print(` Original: ${recipe.originalFilename}`);
|
|
5542
|
-
deps.print(` Uploaded: ${recipe.uploadedAt}`);
|
|
5543
|
-
} catch {}
|
|
5544
|
-
deps.print("\nTo inspect:");
|
|
5545
|
-
deps.print(` makefx assets show ${upload.variant.asset_id} --space ${spaceId}`);
|
|
5546
|
-
return result;
|
|
5547
|
-
} catch (error) {
|
|
5548
|
-
if (error.code === "ENOENT") throw new Error(`File not found: ${filePath}`);
|
|
5549
|
-
throw error;
|
|
5550
|
-
}
|
|
5551
|
-
}
|
|
5552
|
-
async function recordUploadMirror(input) {
|
|
5553
|
-
if (!input.deps.recordMirrorForFile) return;
|
|
5554
|
-
try {
|
|
5555
|
-
await input.deps.recordMirrorForFile({
|
|
5556
|
-
projectRoot: input.projectRoot,
|
|
5557
|
-
baseUrl: input.baseUrl,
|
|
5558
|
-
environment: input.env,
|
|
5559
|
-
spaceId: input.spaceId,
|
|
5560
|
-
filePath: input.filePath,
|
|
5561
|
-
assetId: input.assetId,
|
|
5562
|
-
variantId: input.variantId,
|
|
5563
|
-
mediaKind: input.mediaKind,
|
|
5564
|
-
mediaKey: input.mediaKey
|
|
5565
|
-
});
|
|
5566
|
-
} catch (error) {
|
|
5567
|
-
console.warn(`Warning: upload succeeded but mirror registry was not updated: ${error instanceof Error ? error.message : String(error)}`);
|
|
5568
|
-
}
|
|
5466
|
+
var GENERATION_REQUEST_TIMEOUT_MS = 3e5;
|
|
5467
|
+
var VIDEO_GENERATION_REQUEST_TIMEOUT_MS = 72e4;
|
|
5468
|
+
function getGenerationRequestTimeoutMs(mediaKind) {
|
|
5469
|
+
return mediaKind === "video" ? VIDEO_GENERATION_REQUEST_TIMEOUT_MS : GENERATION_REQUEST_TIMEOUT_MS;
|
|
5569
5470
|
}
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5471
|
+
/**
|
|
5472
|
+
* Thrown when a mutation's confirmation broadcast does not arrive within the
|
|
5473
|
+
* timeout. The server write may still have landed — callers can re-read state
|
|
5474
|
+
* to confirm. Distinct from server-rejection errors (PERMISSION_DENIED,
|
|
5475
|
+
* VALIDATION_ERROR, …), which reject with their own message and must not be
|
|
5476
|
+
* treated as a missing confirmation.
|
|
5477
|
+
*/
|
|
5478
|
+
var ServerConfirmationTimeoutError = class extends Error {
|
|
5479
|
+
constructor(message = "Timed out waiting for server confirmation") {
|
|
5480
|
+
super(message);
|
|
5481
|
+
this.name = "ServerConfirmationTimeoutError";
|
|
5577
5482
|
}
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
function normalizeRelationType(value) {
|
|
5582
|
-
if (!value) return "derived";
|
|
5583
|
-
if (value === "derived" || value === "refined" || value === "forked") return value;
|
|
5584
|
-
throw new UploadUsageError("--relation-type must be derived, refined, or forked");
|
|
5585
|
-
}
|
|
5586
|
-
function normalizeActiveVariantBehavior(value) {
|
|
5587
|
-
if (!value || value === "if-missing" || value === "if_missing") return "if-missing";
|
|
5588
|
-
if (value === "set-active" || value === "set_active") return "set-active";
|
|
5589
|
-
if (value === "keep") return "keep";
|
|
5590
|
-
throw new UploadUsageError("--active-variant-behavior must be if-missing, set-active, or keep");
|
|
5483
|
+
};
|
|
5484
|
+
function booleanFromSqlite(value) {
|
|
5485
|
+
return value === true || value === 1;
|
|
5591
5486
|
}
|
|
5592
|
-
function
|
|
5593
|
-
|
|
5594
|
-
if (
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
if (
|
|
5599
|
-
|
|
5600
|
-
return value.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
5601
|
-
}
|
|
5602
|
-
function printUsage$10() {
|
|
5603
|
-
console.log(`
|
|
5604
|
-
Usage:
|
|
5605
|
-
makefx upload <file> --asset <id> [--space <id>] Upload media to existing asset
|
|
5606
|
-
makefx upload <file> --name <name> [--space <id>] Upload media as a new asset
|
|
5607
|
-
|
|
5608
|
-
Options:
|
|
5609
|
-
--space <id> Target space ID; defaults from initialized project
|
|
5610
|
-
--asset <id> Target asset ID (upload as new variant)
|
|
5611
|
-
--name <name> New asset name (creates asset + variant)
|
|
5612
|
-
--type <type> Asset type for new assets (default: character)
|
|
5613
|
-
--media-kind <k> Optional explicit kind: image, audio, or video
|
|
5614
|
-
--prompt <text> Prompt provenance for uploaded media
|
|
5615
|
-
--model <model> Model provenance for uploaded media
|
|
5616
|
-
--provider <name> Provider provenance for uploaded media
|
|
5617
|
-
--provider-metadata <json> Provider metadata JSON object
|
|
5618
|
-
--generation-provenance <json> Extra provenance JSON object
|
|
5619
|
-
--source-variant <ids> Comma-separated source variants for upload lineage
|
|
5620
|
-
--source-variants <ids> Alias for --source-variant
|
|
5621
|
-
--relation-type <type> Lineage type: derived, refined, or forked (default: derived)
|
|
5622
|
-
--active-variant-behavior <b> if-missing, set-active, or keep
|
|
5623
|
-
--json Print machine-readable upload output with Space IDs
|
|
5624
|
-
--env <env> Environment (production|stage|local)
|
|
5625
|
-
--local Shortcut for --env local
|
|
5626
|
-
|
|
5627
|
-
Examples:
|
|
5628
|
-
makefx upload hero.png --space abc123 --name "Hero Character"
|
|
5629
|
-
makefx upload hero.png --space abc123 --name "Hero" --prompt "external render" --provider blender
|
|
5630
|
-
makefx upload paintover.png --space abc123 --asset def456 --source-variant var123 --relation-type refined
|
|
5631
|
-
makefx upload scene.png --space abc123 --name "Cocina" --type scene --source-variants anna,roman,bg
|
|
5632
|
-
makefx upload theme.mp3 --space abc123 --name "Theme Music" --type audio
|
|
5633
|
-
makefx upload cutscene.mp4 --space abc123 --name "Opening Cutscene" --type video
|
|
5634
|
-
makefx upload variant.jpg --space abc123 --asset def456
|
|
5635
|
-
makefx upload hero.png --space abc123 --name "Hero" --json
|
|
5636
|
-
`);
|
|
5637
|
-
}
|
|
5638
|
-
//#endregion
|
|
5639
|
-
//#region src/cli/lib/run-manifest.ts
|
|
5640
|
-
function createRunId(date = /* @__PURE__ */ new Date()) {
|
|
5641
|
-
return `${date.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z")}-${crypto.randomUUID().slice(0, 8)}`;
|
|
5642
|
-
}
|
|
5643
|
-
async function saveRunManifest(manifest, cwd = process.cwd()) {
|
|
5644
|
-
const manifestPath = path.join(cwd, ".inventory", "runs", `${manifest.runId}.json`);
|
|
5645
|
-
await mkdir(path.dirname(manifestPath), { recursive: true });
|
|
5646
|
-
await writeFile(manifestPath, JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
5647
|
-
return manifestPath;
|
|
5648
|
-
}
|
|
5649
|
-
function getRunManifestDir(projectRoot = process.cwd()) {
|
|
5650
|
-
return path.join(projectRoot, ".inventory", "runs");
|
|
5651
|
-
}
|
|
5652
|
-
async function listRunManifests(projectRoot = process.cwd()) {
|
|
5653
|
-
const runsDir = getRunManifestDir(projectRoot);
|
|
5654
|
-
let entries;
|
|
5655
|
-
try {
|
|
5656
|
-
entries = await readdir(runsDir);
|
|
5657
|
-
} catch (error) {
|
|
5658
|
-
if (error.code === "ENOENT") return [];
|
|
5659
|
-
throw error;
|
|
5660
|
-
}
|
|
5661
|
-
return (await Promise.all(entries.filter((entry) => entry.endsWith(".json")).map((entry) => readRunManifest(path.join(runsDir, entry))))).sort((a, b) => {
|
|
5662
|
-
const byCreatedAt = Date.parse(b.manifest.createdAt) - Date.parse(a.manifest.createdAt);
|
|
5663
|
-
if (Number.isFinite(byCreatedAt) && byCreatedAt !== 0) return byCreatedAt;
|
|
5664
|
-
return b.manifestPath.localeCompare(a.manifestPath);
|
|
5665
|
-
});
|
|
5666
|
-
}
|
|
5667
|
-
async function readRunManifest(manifestPath) {
|
|
5668
|
-
const raw = await readFile(manifestPath, "utf8");
|
|
5669
|
-
return {
|
|
5670
|
-
manifest: normalizeRunManifest(JSON.parse(raw), manifestPath),
|
|
5671
|
-
manifestPath
|
|
5672
|
-
};
|
|
5673
|
-
}
|
|
5674
|
-
async function resolveRunManifest(input) {
|
|
5675
|
-
if (input.latest) {
|
|
5676
|
-
const manifests = await listRunManifests(input.projectRoot);
|
|
5677
|
-
if (manifests.length === 0) throw new Error(`No run manifests found in ${getRunManifestDir(input.projectRoot)}`);
|
|
5678
|
-
return manifests[0];
|
|
5679
|
-
}
|
|
5680
|
-
const selector = input.runIdOrPath;
|
|
5681
|
-
if (!selector) throw new Error("Run ID, manifest path, or --latest is required");
|
|
5682
|
-
return readRunManifest(looksLikeManifestPath(selector) ? path.resolve(selector) : path.join(getRunManifestDir(input.projectRoot), `${selector}.json`));
|
|
5683
|
-
}
|
|
5684
|
-
function createMediaRunExport(record, projectRoot) {
|
|
5685
|
-
const pathBase = record.manifest.workingDir || projectRoot;
|
|
5686
|
-
return {
|
|
5687
|
-
version: 1,
|
|
5688
|
-
format: "media-handoff",
|
|
5689
|
-
runId: record.manifest.runId,
|
|
5690
|
-
manifestPath: record.manifestPath,
|
|
5691
|
-
projectRoot,
|
|
5692
|
-
success: record.manifest.success,
|
|
5693
|
-
prompt: record.manifest.prompt,
|
|
5694
|
-
name: record.manifest.name,
|
|
5695
|
-
assetType: record.manifest.assetType,
|
|
5696
|
-
spaceId: record.manifest.spaceId,
|
|
5697
|
-
baseUrl: record.manifest.baseUrl,
|
|
5698
|
-
refs: record.manifest.refs,
|
|
5699
|
-
referenceVariantIds: record.manifest.referenceVariantIds,
|
|
5700
|
-
createdAt: record.manifest.createdAt,
|
|
5701
|
-
completedAt: record.manifest.completedAt,
|
|
5702
|
-
media: sortedMedia(record.manifest).map((media) => ({
|
|
5703
|
-
...media,
|
|
5704
|
-
absolutePath: path.resolve(pathBase, media.localPath)
|
|
5705
|
-
})),
|
|
5706
|
-
images: [...record.manifest.images].sort((a, b) => a.index - b.index).map((image) => ({
|
|
5707
|
-
...image,
|
|
5708
|
-
absolutePath: path.resolve(pathBase, image.localPath)
|
|
5709
|
-
})),
|
|
5710
|
-
failed: record.manifest.failed
|
|
5711
|
-
};
|
|
5712
|
-
}
|
|
5713
|
-
function createRemotionRunExport(record, projectRoot) {
|
|
5714
|
-
return {
|
|
5715
|
-
...createMediaRunExport(record, projectRoot),
|
|
5716
|
-
format: "remotion-keyframes"
|
|
5717
|
-
};
|
|
5718
|
-
}
|
|
5719
|
-
function manifestMediaFromVariant(input) {
|
|
5720
|
-
const mediaKind = input.variant.media_kind || "image";
|
|
5721
|
-
const mediaKey = input.variant.media_key || input.variant.image_key;
|
|
5722
|
-
if (!mediaKey) throw new Error(`Variant has no media key: ${input.variant.id}`);
|
|
5723
|
-
return {
|
|
5724
|
-
index: input.index,
|
|
5725
|
-
mediaKind,
|
|
5726
|
-
assetId: input.variant.asset_id,
|
|
5727
|
-
variantId: input.variant.id,
|
|
5728
|
-
mediaKey,
|
|
5729
|
-
imageKey: input.variant.image_key,
|
|
5730
|
-
thumbKey: input.variant.thumb_key,
|
|
5731
|
-
mimeType: input.variant.media_mime_type || null,
|
|
5732
|
-
sizeBytes: input.variant.media_size_bytes ?? null,
|
|
5733
|
-
width: input.variant.media_width ?? null,
|
|
5734
|
-
height: input.variant.media_height ?? null,
|
|
5735
|
-
durationMs: input.variant.media_duration_ms ?? null,
|
|
5736
|
-
localPath: input.localPath,
|
|
5737
|
-
webUrl: `${input.baseUrl}/spaces/${input.spaceId}/assets/${input.variant.asset_id}`
|
|
5738
|
-
};
|
|
5739
|
-
}
|
|
5740
|
-
function looksLikeManifestPath(value) {
|
|
5741
|
-
return path.isAbsolute(value) || value.endsWith(".json") || value.includes("/") || value.includes("\\");
|
|
5742
|
-
}
|
|
5743
|
-
function normalizeRunManifest(manifest, manifestPath) {
|
|
5744
|
-
if (manifest.version !== 1) throw new Error(`Unsupported run manifest version in ${manifestPath}`);
|
|
5745
|
-
if (!isSupportedCommand(manifest.command)) throw new Error(`Unsupported run manifest command in ${manifestPath}`);
|
|
5746
|
-
if (!manifest.runId || typeof manifest.runId !== "string") throw new Error(`Run manifest is missing runId: ${manifestPath}`);
|
|
5747
|
-
const media = Array.isArray(manifest.media) ? manifest.media : manifest.images;
|
|
5748
|
-
if (!Array.isArray(media)) throw new Error(`Run manifest is missing media: ${manifestPath}`);
|
|
5749
|
-
if (!Array.isArray(manifest.failed)) throw new Error(`Run manifest is missing failed entries: ${manifestPath}`);
|
|
5750
|
-
const normalizedMedia = media.map((entry) => normalizeManifestMedia(entry));
|
|
5751
|
-
return {
|
|
5752
|
-
...manifest,
|
|
5753
|
-
mediaKind: manifest.mediaKind || inferManifestMediaKind(normalizedMedia),
|
|
5754
|
-
media: normalizedMedia,
|
|
5755
|
-
images: normalizedMedia.filter(isRunManifestImage)
|
|
5756
|
-
};
|
|
5757
|
-
}
|
|
5758
|
-
function sortedMedia(manifest) {
|
|
5759
|
-
return [...manifest.media].sort((a, b) => a.index - b.index);
|
|
5760
|
-
}
|
|
5761
|
-
function isSupportedCommand(command) {
|
|
5762
|
-
return command === "generate" || command === "refine" || command === "derive" || command === "batch";
|
|
5763
|
-
}
|
|
5764
|
-
function normalizeManifestMedia(entry) {
|
|
5765
|
-
const legacyImageKey = "imageKey" in entry ? entry.imageKey : null;
|
|
5766
|
-
const mediaKey = "mediaKey" in entry ? entry.mediaKey : legacyImageKey;
|
|
5767
|
-
return {
|
|
5768
|
-
index: entry.index,
|
|
5769
|
-
mediaKind: entry.mediaKind || "image",
|
|
5770
|
-
assetId: entry.assetId,
|
|
5771
|
-
variantId: entry.variantId,
|
|
5772
|
-
mediaKey: mediaKey || "",
|
|
5773
|
-
imageKey: legacyImageKey,
|
|
5774
|
-
thumbKey: entry.thumbKey,
|
|
5775
|
-
mimeType: "mimeType" in entry ? entry.mimeType : null,
|
|
5776
|
-
sizeBytes: "sizeBytes" in entry ? entry.sizeBytes : null,
|
|
5777
|
-
width: "width" in entry ? entry.width : null,
|
|
5778
|
-
height: "height" in entry ? entry.height : null,
|
|
5779
|
-
durationMs: "durationMs" in entry ? entry.durationMs : null,
|
|
5780
|
-
localPath: entry.localPath,
|
|
5781
|
-
webUrl: entry.webUrl
|
|
5782
|
-
};
|
|
5783
|
-
}
|
|
5784
|
-
function isRunManifestImage(entry) {
|
|
5785
|
-
return entry.mediaKind === "image" && Boolean(entry.imageKey);
|
|
5786
|
-
}
|
|
5787
|
-
function inferManifestMediaKind(media) {
|
|
5788
|
-
return media[0]?.mediaKind || "image";
|
|
5789
|
-
}
|
|
5790
|
-
//#endregion
|
|
5791
|
-
//#region src/cli/lib/image-transfer.ts
|
|
5792
|
-
var MAX_FILE_SIZE_MB = 10;
|
|
5793
|
-
var MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024;
|
|
5794
|
-
var ALLOWED_EXTENSIONS = [
|
|
5795
|
-
".jpg",
|
|
5796
|
-
".jpeg",
|
|
5797
|
-
".png",
|
|
5798
|
-
".gif",
|
|
5799
|
-
".webp"
|
|
5800
|
-
];
|
|
5801
|
-
var EXT_TO_MIME = {
|
|
5802
|
-
".jpg": "image/jpeg",
|
|
5803
|
-
".jpeg": "image/jpeg",
|
|
5804
|
-
".png": "image/png",
|
|
5805
|
-
".gif": "image/gif",
|
|
5806
|
-
".webp": "image/webp"
|
|
5807
|
-
};
|
|
5808
|
-
function isSupportedImagePath(filePath) {
|
|
5809
|
-
return ALLOWED_EXTENSIONS.includes(path.extname(filePath).toLowerCase());
|
|
5810
|
-
}
|
|
5811
|
-
function looksLikeFilePath(value) {
|
|
5812
|
-
return value.startsWith(".") || value.includes("/") || value.includes("\\") || isSupportedImagePath(value);
|
|
5813
|
-
}
|
|
5814
|
-
async function uploadLocalImageAsReference(input) {
|
|
5815
|
-
const ext = path.extname(input.filePath).toLowerCase();
|
|
5816
|
-
if (!ALLOWED_EXTENSIONS.includes(ext)) throw new Error(`Invalid reference file type "${ext}". Allowed: ${ALLOWED_EXTENSIONS.join(", ")}`);
|
|
5817
|
-
const fileStat = await stat(input.filePath);
|
|
5818
|
-
if (!fileStat.isFile()) throw new Error(`Reference is not a file: ${input.filePath}`);
|
|
5819
|
-
if (fileStat.size > MAX_FILE_SIZE_BYTES) throw new Error(`Reference file too large (${(fileStat.size / 1024 / 1024).toFixed(2)}MB). Maximum size: ${MAX_FILE_SIZE_MB}MB`);
|
|
5820
|
-
const fileBuffer = await readFile(input.filePath);
|
|
5821
|
-
const filename = path.basename(input.filePath);
|
|
5822
|
-
const mimeType = EXT_TO_MIME[ext] || "image/png";
|
|
5823
|
-
const assetName = input.assetName || `Reference: ${filename.replace(/\.[^/.]+$/, "")}`;
|
|
5824
|
-
const formData = new FormData();
|
|
5825
|
-
formData.append("file", new Blob([fileBuffer], { type: mimeType }), filename);
|
|
5826
|
-
formData.append("assetName", assetName);
|
|
5827
|
-
formData.append("assetType", "reference");
|
|
5828
|
-
formData.append("mediaKind", DEFAULT_MEDIA_KIND);
|
|
5829
|
-
const response = await fetch(`${input.baseUrl}/api/spaces/${input.spaceId}/upload`, {
|
|
5830
|
-
method: "POST",
|
|
5831
|
-
headers: { "Authorization": `Bearer ${input.accessToken}` },
|
|
5832
|
-
body: formData
|
|
5833
|
-
});
|
|
5834
|
-
const data = await response.json();
|
|
5835
|
-
if (!response.ok || !data.success || !data.variant) throw new Error(`Failed to upload reference "${input.filePath}": ${data.error || response.statusText}`);
|
|
5836
|
-
return {
|
|
5837
|
-
asset: data.asset,
|
|
5838
|
-
variant: data.variant
|
|
5839
|
-
};
|
|
5840
|
-
}
|
|
5841
|
-
async function downloadFile(input) {
|
|
5842
|
-
if (!input.force) try {
|
|
5843
|
-
if ((await stat(input.outputPath)).isFile()) throw new Error(`Output file already exists: ${input.outputPath}. Pass --force to overwrite.`);
|
|
5844
|
-
} catch (error) {
|
|
5845
|
-
if (error.code !== "ENOENT") throw error;
|
|
5846
|
-
}
|
|
5847
|
-
const headers = {};
|
|
5848
|
-
if (input.accessToken) headers.Authorization = `Bearer ${input.accessToken}`;
|
|
5849
|
-
const requestUrl = `${input.baseUrl}${input.requestPath}`;
|
|
5850
|
-
let response;
|
|
5851
|
-
try {
|
|
5852
|
-
response = await fetch(requestUrl, { headers });
|
|
5853
|
-
} catch (error) {
|
|
5854
|
-
throw new Error(`Failed to download ${input.requestPath}: ${formatFetchError(error)}`);
|
|
5855
|
-
}
|
|
5856
|
-
if (!response.ok) {
|
|
5857
|
-
const errorText = await readErrorText(response);
|
|
5858
|
-
throw new Error(`Failed to download ${input.requestPath}: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ""}`);
|
|
5859
|
-
}
|
|
5860
|
-
await mkdir(path.dirname(input.outputPath), { recursive: true });
|
|
5861
|
-
if (!response.body) throw new Error(`Failed to download ${input.requestPath}: response body was empty`);
|
|
5862
|
-
try {
|
|
5863
|
-
await pipeline(Readable.fromWeb(response.body), createWriteStream(input.outputPath));
|
|
5864
|
-
} catch (error) {
|
|
5865
|
-
throw new Error(`Failed to write download ${input.requestPath} to ${input.outputPath}: ${formatFetchError(error)}`);
|
|
5866
|
-
}
|
|
5867
|
-
return {
|
|
5868
|
-
headers: response.headers,
|
|
5869
|
-
requestUrl
|
|
5870
|
-
};
|
|
5871
|
-
}
|
|
5872
|
-
async function readErrorText(response) {
|
|
5873
|
-
try {
|
|
5874
|
-
return (await response.text()).slice(0, 500).trim();
|
|
5875
|
-
} catch {
|
|
5876
|
-
return "";
|
|
5877
|
-
}
|
|
5878
|
-
}
|
|
5879
|
-
function formatFetchError(error) {
|
|
5880
|
-
if (!(error instanceof Error)) return String(error);
|
|
5881
|
-
const cause = error.cause instanceof Error ? ` (${error.cause.message})` : "";
|
|
5882
|
-
return `${error.message}${cause}`;
|
|
5883
|
-
}
|
|
5884
|
-
async function downloadImage(input) {
|
|
5885
|
-
await downloadFile({
|
|
5886
|
-
baseUrl: input.baseUrl,
|
|
5887
|
-
accessToken: input.accessToken,
|
|
5888
|
-
requestPath: `/api/images/${input.imageKey}`,
|
|
5889
|
-
outputPath: input.outputPath,
|
|
5890
|
-
force: input.force
|
|
5891
|
-
});
|
|
5892
|
-
}
|
|
5893
|
-
//#endregion
|
|
5894
|
-
//#region src/cli/lib/websocket-client.ts
|
|
5895
|
-
/**
|
|
5896
|
-
* WebSocket Client for CLI
|
|
5897
|
-
*
|
|
5898
|
-
* Provides WebSocket-based communication with the Space Durable Object.
|
|
5899
|
-
* Replaces HTTP API calls with WebSocket messages for chat and generation.
|
|
5900
|
-
*/
|
|
5901
|
-
var GENERATION_REQUEST_TIMEOUT_MS = 3e5;
|
|
5902
|
-
var VIDEO_GENERATION_REQUEST_TIMEOUT_MS = 72e4;
|
|
5903
|
-
function getGenerationRequestTimeoutMs(mediaKind) {
|
|
5904
|
-
return mediaKind === "video" ? VIDEO_GENERATION_REQUEST_TIMEOUT_MS : GENERATION_REQUEST_TIMEOUT_MS;
|
|
5905
|
-
}
|
|
5906
|
-
/**
|
|
5907
|
-
* Thrown when a mutation's confirmation broadcast does not arrive within the
|
|
5908
|
-
* timeout. The server write may still have landed — callers can re-read state
|
|
5909
|
-
* to confirm. Distinct from server-rejection errors (PERMISSION_DENIED,
|
|
5910
|
-
* VALIDATION_ERROR, …), which reject with their own message and must not be
|
|
5911
|
-
* treated as a missing confirmation.
|
|
5912
|
-
*/
|
|
5913
|
-
var ServerConfirmationTimeoutError = class extends Error {
|
|
5914
|
-
constructor(message = "Timed out waiting for server confirmation") {
|
|
5915
|
-
super(message);
|
|
5916
|
-
this.name = "ServerConfirmationTimeoutError";
|
|
5917
|
-
}
|
|
5918
|
-
};
|
|
5919
|
-
function collectionItemMatchesInput(item, input) {
|
|
5920
|
-
if (item.subject_type !== input.subjectType) return false;
|
|
5921
|
-
if (input.subjectType === "asset" && item.asset_id !== input.assetId) return false;
|
|
5922
|
-
if (input.subjectType === "variant" && item.variant_id !== input.variantId) return false;
|
|
5923
|
-
if (input.role !== void 0 && item.role !== input.role) return false;
|
|
5924
|
-
if (input.pinnedVariantId !== void 0 && item.pinned_variant_id !== input.pinnedVariantId) return false;
|
|
5925
|
-
if (input.sortIndex !== void 0 && item.sort_index !== input.sortIndex) return false;
|
|
5926
|
-
return true;
|
|
5487
|
+
function collectionItemMatchesInput(item, input) {
|
|
5488
|
+
if (item.subject_type !== input.subjectType) return false;
|
|
5489
|
+
if (input.subjectType === "asset" && item.asset_id !== input.assetId) return false;
|
|
5490
|
+
if (input.subjectType === "variant" && item.variant_id !== input.variantId) return false;
|
|
5491
|
+
if (input.role !== void 0 && item.role !== input.role) return false;
|
|
5492
|
+
if (input.pinnedVariantId !== void 0 && item.pinned_variant_id !== input.pinnedVariantId) return false;
|
|
5493
|
+
if (input.sortIndex !== void 0 && item.sort_index !== input.sortIndex) return false;
|
|
5494
|
+
return true;
|
|
5927
5495
|
}
|
|
5928
5496
|
var WebSocketClient = class WebSocketClient {
|
|
5929
5497
|
ws = null;
|
|
@@ -5935,7 +5503,6 @@ var WebSocketClient = class WebSocketClient {
|
|
|
5935
5503
|
chatHandlers = /* @__PURE__ */ new Map();
|
|
5936
5504
|
generateHandlers = /* @__PURE__ */ new Map();
|
|
5937
5505
|
batchHandlers = /* @__PURE__ */ new Map();
|
|
5938
|
-
estimateHandlers = /* @__PURE__ */ new Map();
|
|
5939
5506
|
batchVariantToRequestId = /* @__PURE__ */ new Map();
|
|
5940
5507
|
variantCompletionHandlers = /* @__PURE__ */ new Map();
|
|
5941
5508
|
describeHandlers = /* @__PURE__ */ new Map();
|
|
@@ -6131,16 +5698,6 @@ var WebSocketClient = class WebSocketClient {
|
|
|
6131
5698
|
}
|
|
6132
5699
|
break;
|
|
6133
5700
|
}
|
|
6134
|
-
case "generation:estimate": {
|
|
6135
|
-
const estimateMsg = message;
|
|
6136
|
-
const handler = this.estimateHandlers.get(estimateMsg.requestId);
|
|
6137
|
-
if (handler) {
|
|
6138
|
-
this.estimateHandlers.delete(estimateMsg.requestId);
|
|
6139
|
-
clearTimeout(handler.timeout);
|
|
6140
|
-
handler.resolve(estimateMsg);
|
|
6141
|
-
}
|
|
6142
|
-
break;
|
|
6143
|
-
}
|
|
6144
5701
|
case "variant:updated": {
|
|
6145
5702
|
const variant = message.variant;
|
|
6146
5703
|
const batchRequestId = this.batchVariantToRequestId.get(variant.id);
|
|
@@ -6296,13 +5853,6 @@ var WebSocketClient = class WebSocketClient {
|
|
|
6296
5853
|
return true;
|
|
6297
5854
|
}
|
|
6298
5855
|
failRequestHandler(requestId, error) {
|
|
6299
|
-
const estimateHandler = this.estimateHandlers.get(requestId);
|
|
6300
|
-
if (estimateHandler) {
|
|
6301
|
-
this.estimateHandlers.delete(requestId);
|
|
6302
|
-
clearTimeout(estimateHandler.timeout);
|
|
6303
|
-
estimateHandler.reject(error);
|
|
6304
|
-
return true;
|
|
6305
|
-
}
|
|
6306
5856
|
const generateHandler = this.generateHandlers.get(requestId);
|
|
6307
5857
|
if (generateHandler) {
|
|
6308
5858
|
this.generateHandlers.delete(requestId);
|
|
@@ -6395,11 +5945,15 @@ var WebSocketClient = class WebSocketClient {
|
|
|
6395
5945
|
}
|
|
6396
5946
|
/** Star or unstar a variant. Resolves with the updated variant. */
|
|
6397
5947
|
async starVariant(variantId, starred) {
|
|
6398
|
-
|
|
5948
|
+
const result = await this.awaitServerMessage({
|
|
6399
5949
|
type: "variant:star",
|
|
6400
5950
|
variantId,
|
|
6401
5951
|
starred
|
|
6402
|
-
}, (msg) => msg.type === "variant:updated" && msg.variant.id === variantId && msg.variant.starred === starred)
|
|
5952
|
+
}, (msg) => msg.type === "variant:updated" && msg.variant.id === variantId && booleanFromSqlite(msg.variant.starred) === starred);
|
|
5953
|
+
return {
|
|
5954
|
+
...result.variant,
|
|
5955
|
+
starred: booleanFromSqlite(result.variant.starred)
|
|
5956
|
+
};
|
|
6403
5957
|
}
|
|
6404
5958
|
/** Rate a variant (approved/rejected). Resolves with the updated variant. */
|
|
6405
5959
|
async rateVariant(variantId, rating) {
|
|
@@ -6460,69 +6014,28 @@ var WebSocketClient = class WebSocketClient {
|
|
|
6460
6014
|
return new Promise((resolve, reject) => {
|
|
6461
6015
|
this.chatHandlers.set(requestId, {
|
|
6462
6016
|
resolve,
|
|
6463
|
-
reject
|
|
6464
|
-
});
|
|
6465
|
-
const message = {
|
|
6466
|
-
type: "chat:request",
|
|
6467
|
-
requestId,
|
|
6468
|
-
message: params.message,
|
|
6469
|
-
mode: params.mode,
|
|
6470
|
-
forgeContext: params.forgeContext,
|
|
6471
|
-
viewingContext: params.viewingContext
|
|
6472
|
-
};
|
|
6473
|
-
try {
|
|
6474
|
-
this.send(message);
|
|
6475
|
-
} catch (err) {
|
|
6476
|
-
this.chatHandlers.delete(requestId);
|
|
6477
|
-
reject(err);
|
|
6478
|
-
}
|
|
6479
|
-
setTimeout(() => {
|
|
6480
|
-
if (this.chatHandlers.has(requestId)) {
|
|
6481
|
-
this.chatHandlers.delete(requestId);
|
|
6482
|
-
reject(/* @__PURE__ */ new Error("Chat request timed out"));
|
|
6483
|
-
}
|
|
6484
|
-
}, 12e4);
|
|
6485
|
-
});
|
|
6486
|
-
}
|
|
6487
|
-
async sendGenerationEstimateRequest(params) {
|
|
6488
|
-
const requestId = crypto.randomUUID();
|
|
6489
|
-
return new Promise((resolve, reject) => {
|
|
6490
|
-
const timeout = setTimeout(() => {
|
|
6491
|
-
if (this.estimateHandlers.has(requestId)) {
|
|
6492
|
-
this.estimateHandlers.delete(requestId);
|
|
6493
|
-
reject(/* @__PURE__ */ new Error("Generation estimate request timed out"));
|
|
6494
|
-
}
|
|
6495
|
-
}, 3e4);
|
|
6496
|
-
this.estimateHandlers.set(requestId, {
|
|
6497
|
-
resolve,
|
|
6498
|
-
reject,
|
|
6499
|
-
timeout
|
|
6017
|
+
reject
|
|
6500
6018
|
});
|
|
6501
6019
|
const message = {
|
|
6502
|
-
type: "
|
|
6020
|
+
type: "chat:request",
|
|
6503
6021
|
requestId,
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
prompt: params.prompt,
|
|
6509
|
-
count: params.count,
|
|
6510
|
-
model: params.model,
|
|
6511
|
-
aspectRatio: params.aspectRatio,
|
|
6512
|
-
imageSize: params.imageSize,
|
|
6513
|
-
musicProvider: params.musicProvider,
|
|
6514
|
-
generateAudio: params.generateAudio,
|
|
6515
|
-
videoResolution: params.videoResolution,
|
|
6516
|
-
videoDurationSeconds: params.videoDurationSeconds,
|
|
6517
|
-
videoTier: params.videoTier
|
|
6022
|
+
message: params.message,
|
|
6023
|
+
mode: params.mode,
|
|
6024
|
+
forgeContext: params.forgeContext,
|
|
6025
|
+
viewingContext: params.viewingContext
|
|
6518
6026
|
};
|
|
6519
6027
|
try {
|
|
6520
6028
|
this.send(message);
|
|
6521
6029
|
} catch (err) {
|
|
6522
|
-
this.
|
|
6523
|
-
clearTimeout(timeout);
|
|
6030
|
+
this.chatHandlers.delete(requestId);
|
|
6524
6031
|
reject(err);
|
|
6525
6032
|
}
|
|
6033
|
+
setTimeout(() => {
|
|
6034
|
+
if (this.chatHandlers.has(requestId)) {
|
|
6035
|
+
this.chatHandlers.delete(requestId);
|
|
6036
|
+
reject(/* @__PURE__ */ new Error("Chat request timed out"));
|
|
6037
|
+
}
|
|
6038
|
+
}, 12e4);
|
|
6526
6039
|
});
|
|
6527
6040
|
}
|
|
6528
6041
|
/**
|
|
@@ -6742,88 +6255,653 @@ var WebSocketClient = class WebSocketClient {
|
|
|
6742
6255
|
}, 6e4);
|
|
6743
6256
|
});
|
|
6744
6257
|
}
|
|
6745
|
-
/**
|
|
6746
|
-
* Send a compare images request and wait for response
|
|
6747
|
-
*/
|
|
6748
|
-
async sendCompareRequest(params) {
|
|
6749
|
-
const requestId = crypto.randomUUID();
|
|
6750
|
-
return new Promise((resolve, reject) => {
|
|
6751
|
-
this.compareHandlers.set(requestId, {
|
|
6752
|
-
resolve,
|
|
6753
|
-
reject
|
|
6754
|
-
});
|
|
6755
|
-
const message = {
|
|
6756
|
-
type: "compare:request",
|
|
6757
|
-
requestId,
|
|
6758
|
-
variantIds: params.variantIds,
|
|
6759
|
-
aspects: params.aspects
|
|
6760
|
-
};
|
|
6761
|
-
try {
|
|
6762
|
-
this.send(message);
|
|
6763
|
-
} catch (err) {
|
|
6764
|
-
this.compareHandlers.delete(requestId);
|
|
6765
|
-
reject(err);
|
|
6766
|
-
}
|
|
6767
|
-
setTimeout(() => {
|
|
6768
|
-
if (this.compareHandlers.has(requestId)) {
|
|
6769
|
-
this.compareHandlers.delete(requestId);
|
|
6770
|
-
reject(/* @__PURE__ */ new Error("Compare request timed out"));
|
|
6771
|
-
}
|
|
6772
|
-
}, 6e4);
|
|
6258
|
+
/**
|
|
6259
|
+
* Send a compare images request and wait for response
|
|
6260
|
+
*/
|
|
6261
|
+
async sendCompareRequest(params) {
|
|
6262
|
+
const requestId = crypto.randomUUID();
|
|
6263
|
+
return new Promise((resolve, reject) => {
|
|
6264
|
+
this.compareHandlers.set(requestId, {
|
|
6265
|
+
resolve,
|
|
6266
|
+
reject
|
|
6267
|
+
});
|
|
6268
|
+
const message = {
|
|
6269
|
+
type: "compare:request",
|
|
6270
|
+
requestId,
|
|
6271
|
+
variantIds: params.variantIds,
|
|
6272
|
+
aspects: params.aspects
|
|
6273
|
+
};
|
|
6274
|
+
try {
|
|
6275
|
+
this.send(message);
|
|
6276
|
+
} catch (err) {
|
|
6277
|
+
this.compareHandlers.delete(requestId);
|
|
6278
|
+
reject(err);
|
|
6279
|
+
}
|
|
6280
|
+
setTimeout(() => {
|
|
6281
|
+
if (this.compareHandlers.has(requestId)) {
|
|
6282
|
+
this.compareHandlers.delete(requestId);
|
|
6283
|
+
reject(/* @__PURE__ */ new Error("Compare request timed out"));
|
|
6284
|
+
}
|
|
6285
|
+
}, 6e4);
|
|
6286
|
+
});
|
|
6287
|
+
}
|
|
6288
|
+
/**
|
|
6289
|
+
* Request sync state (initial state load)
|
|
6290
|
+
*/
|
|
6291
|
+
requestSync() {
|
|
6292
|
+
this.send({ type: "sync:request" });
|
|
6293
|
+
}
|
|
6294
|
+
/**
|
|
6295
|
+
* Approve a pending approval
|
|
6296
|
+
*/
|
|
6297
|
+
approveApproval(approvalId) {
|
|
6298
|
+
this.send({
|
|
6299
|
+
type: "approval:approve",
|
|
6300
|
+
approvalId
|
|
6301
|
+
});
|
|
6302
|
+
}
|
|
6303
|
+
/**
|
|
6304
|
+
* Reject a pending approval
|
|
6305
|
+
*/
|
|
6306
|
+
rejectApproval(approvalId) {
|
|
6307
|
+
this.send({
|
|
6308
|
+
type: "approval:reject",
|
|
6309
|
+
approvalId
|
|
6310
|
+
});
|
|
6311
|
+
}
|
|
6312
|
+
/**
|
|
6313
|
+
* Request list of pending approvals
|
|
6314
|
+
*/
|
|
6315
|
+
listApprovals() {
|
|
6316
|
+
this.send({ type: "approval:list" });
|
|
6317
|
+
}
|
|
6318
|
+
/**
|
|
6319
|
+
* Get current session state
|
|
6320
|
+
*/
|
|
6321
|
+
getSession() {
|
|
6322
|
+
this.send({ type: "session:get" });
|
|
6323
|
+
}
|
|
6324
|
+
/**
|
|
6325
|
+
* Update session context (viewing, forge tray)
|
|
6326
|
+
*/
|
|
6327
|
+
updateSession(data) {
|
|
6328
|
+
this.send({
|
|
6329
|
+
type: "session:update",
|
|
6330
|
+
...data
|
|
6331
|
+
});
|
|
6332
|
+
}
|
|
6333
|
+
/**
|
|
6334
|
+
* Check if connected
|
|
6335
|
+
*/
|
|
6336
|
+
isConnected() {
|
|
6337
|
+
return this.ws !== null && this.ws.readyState === wrapper_default.OPEN;
|
|
6338
|
+
}
|
|
6339
|
+
};
|
|
6340
|
+
//#endregion
|
|
6341
|
+
//#region src/cli/lib/reference-resolver.ts
|
|
6342
|
+
async function resolveCliAssetIdentifier(identifier, createClient) {
|
|
6343
|
+
if (!identifier.startsWith("asset:")) return identifier;
|
|
6344
|
+
return resolveAssetRef(identifier, (await readReferenceSpaceState(createClient)).assets);
|
|
6345
|
+
}
|
|
6346
|
+
async function resolveCliVariantIdentifier(identifier, createClient) {
|
|
6347
|
+
if (!identifier.startsWith("asset:")) return identifier;
|
|
6348
|
+
const state = await readReferenceSpaceState(createClient);
|
|
6349
|
+
return resolveVariantRef(identifier, state.assets, state.variants);
|
|
6350
|
+
}
|
|
6351
|
+
async function resolveCliVariantIdentifiers(identifiers, createClient) {
|
|
6352
|
+
if (!identifiers.some((identifier) => identifier.startsWith("asset:"))) return [...identifiers];
|
|
6353
|
+
const state = await readReferenceSpaceState(createClient);
|
|
6354
|
+
return identifiers.map((identifier) => resolveVariantRef(identifier, state.assets, state.variants));
|
|
6355
|
+
}
|
|
6356
|
+
async function readReferenceSpaceState(createClient) {
|
|
6357
|
+
const client = await createClient();
|
|
6358
|
+
await client.connect();
|
|
6359
|
+
try {
|
|
6360
|
+
const syncClient = client;
|
|
6361
|
+
if (typeof syncClient.setOnSyncState !== "function" || typeof syncClient.requestSync !== "function") throw new Error("Space sync is not available");
|
|
6362
|
+
return await new Promise((resolve, reject) => {
|
|
6363
|
+
let settled = false;
|
|
6364
|
+
const finish = (callback) => {
|
|
6365
|
+
if (settled) return;
|
|
6366
|
+
settled = true;
|
|
6367
|
+
clearTimeout(timer);
|
|
6368
|
+
callback();
|
|
6369
|
+
};
|
|
6370
|
+
const timer = setTimeout(() => finish(() => reject(/* @__PURE__ */ new Error("Timed out waiting for space sync state"))), 3e4);
|
|
6371
|
+
syncClient.setOnSyncState?.((state) => finish(() => resolve(state)));
|
|
6372
|
+
try {
|
|
6373
|
+
syncClient.requestSync?.();
|
|
6374
|
+
} catch (error) {
|
|
6375
|
+
finish(() => reject(error));
|
|
6376
|
+
}
|
|
6377
|
+
});
|
|
6378
|
+
} finally {
|
|
6379
|
+
client.disconnect();
|
|
6380
|
+
}
|
|
6381
|
+
}
|
|
6382
|
+
//#endregion
|
|
6383
|
+
//#region src/cli/commands/upload.ts
|
|
6384
|
+
/**
|
|
6385
|
+
* Upload Command - Upload one media file to create variants
|
|
6386
|
+
*
|
|
6387
|
+
* Usage:
|
|
6388
|
+
* makefx upload <file> --space <id> --asset <id> Upload to existing asset
|
|
6389
|
+
* makefx upload <file> --space <id> --name <name> Upload as new asset
|
|
6390
|
+
* makefx upload <file> --space <id> --name <name> --type <type>
|
|
6391
|
+
*/
|
|
6392
|
+
var defaultDeps$10 = {
|
|
6393
|
+
loadConfig: loadStoredConfig,
|
|
6394
|
+
loadProjectConfig,
|
|
6395
|
+
resolveBaseUrl,
|
|
6396
|
+
fetch,
|
|
6397
|
+
readFile,
|
|
6398
|
+
stat,
|
|
6399
|
+
recordMirrorForFile,
|
|
6400
|
+
createStateClient: (env, spaceId) => WebSocketClient.create(env, spaceId),
|
|
6401
|
+
print: console.log
|
|
6402
|
+
};
|
|
6403
|
+
var UploadUsageError = class extends Error {};
|
|
6404
|
+
var RETIRED_UPLOAD_ORGANIZATION_OPTIONS = [
|
|
6405
|
+
["collection", "--collection"],
|
|
6406
|
+
["collection-name", "--collection-name"],
|
|
6407
|
+
["collectionName", "--collection-name"],
|
|
6408
|
+
["collection-role", "--collection-role"],
|
|
6409
|
+
["collectionRole", "--collection-role"],
|
|
6410
|
+
["collection-subject", "--collection-subject"],
|
|
6411
|
+
["collectionSubject", "--collection-subject"],
|
|
6412
|
+
["manual-relation", "--manual-relation"],
|
|
6413
|
+
["manualRelation", "--manual-relation"],
|
|
6414
|
+
["manual-relation-context", "--manual-relation-context"],
|
|
6415
|
+
["manualRelationContext", "--manual-relation-context"]
|
|
6416
|
+
];
|
|
6417
|
+
async function handleUpload(parsed) {
|
|
6418
|
+
try {
|
|
6419
|
+
await executeUpload(parsed);
|
|
6420
|
+
} catch (error) {
|
|
6421
|
+
console.error(error instanceof Error ? `Error: ${error.message}` : "Error: Upload failed");
|
|
6422
|
+
if (error instanceof UploadUsageError) printUsage$10();
|
|
6423
|
+
process$1.exitCode = 1;
|
|
6424
|
+
}
|
|
6425
|
+
}
|
|
6426
|
+
async function executeUpload(parsed, deps = defaultDeps$10) {
|
|
6427
|
+
const filePath = parsed.positionals[0];
|
|
6428
|
+
if (!filePath) throw new UploadUsageError("File path is required");
|
|
6429
|
+
rejectRetiredUploadOrganizationOptions(parsed);
|
|
6430
|
+
const projectConfig = await deps.loadProjectConfig();
|
|
6431
|
+
const env = resolveCommandEnvironment(parsed, projectConfig);
|
|
6432
|
+
const spaceId = resolveCommandSpace(parsed, projectConfig);
|
|
6433
|
+
let assetId = parsed.options.asset;
|
|
6434
|
+
const assetName = parsed.options.name;
|
|
6435
|
+
const assetType = parsed.options.type || "character";
|
|
6436
|
+
const requestedMediaKind = parsed.options["media-kind"] || parsed.options.mediaKind;
|
|
6437
|
+
const prompt = parsed.options.prompt;
|
|
6438
|
+
const model = parsed.options.model;
|
|
6439
|
+
const provider = parsed.options.provider;
|
|
6440
|
+
const rawProviderMetadata = parsed.options["provider-metadata"] ?? parsed.options.providerMetadata ?? parsed.options.provider_metadata;
|
|
6441
|
+
const rawGenerationProvenance = parsed.options["generation-provenance"] ?? parsed.options.generationProvenance ?? parsed.options.generation_provenance;
|
|
6442
|
+
const rawSourceVariantIds = parsed.options["source-variants"] ?? parsed.options.sourceVariants ?? parsed.options.sourceVariantIds ?? parsed.options["source-variant"] ?? parsed.options.sourceVariantId ?? parsed.options.parentVariantId;
|
|
6443
|
+
const rawRelationType = parsed.options["relation-type"] ?? parsed.options.relationType;
|
|
6444
|
+
const rawActiveVariantBehavior = parsed.options["active-variant-behavior"] ?? parsed.options.activeVariantBehavior;
|
|
6445
|
+
const jsonOutput = parsed.options.json === "true";
|
|
6446
|
+
if (parsed.options["dry-run"] === "true" || parsed.options.dryRun === "true") throw new UploadUsageError("--dry-run is not supported for direct file upload");
|
|
6447
|
+
if (!spaceId) throw new UploadUsageError("--space is required, or run: makefx init --space <id>");
|
|
6448
|
+
if (!assetId && !assetName) throw new UploadUsageError("Either --asset or --name is required");
|
|
6449
|
+
const providerMetadata = parseJsonObjectOption(rawProviderMetadata, "--provider-metadata");
|
|
6450
|
+
const generationProvenance = parseJsonObjectOption(rawGenerationProvenance, "--generation-provenance");
|
|
6451
|
+
let sourceVariantIds = parseCsvOption(rawSourceVariantIds, "--source-variant");
|
|
6452
|
+
const relationType = normalizeRelationType(rawRelationType);
|
|
6453
|
+
const activeVariantBehavior = normalizeActiveVariantBehavior(rawActiveVariantBehavior);
|
|
6454
|
+
if (sourceVariantIds.length === 0 && (parsed.options["relation-type"] || parsed.options.relationType)) throw new UploadUsageError("--relation-type requires --source-variant or --source-variants");
|
|
6455
|
+
const mediaType = resolveMediaType(path.extname(filePath).toLowerCase(), requestedMediaKind);
|
|
6456
|
+
const config = await deps.loadConfig(env);
|
|
6457
|
+
if (!config) throw new Error(`Not logged in to ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
|
|
6458
|
+
if (config.token.expiresAt < Date.now()) throw new Error(`Token expired for ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
|
|
6459
|
+
const baseUrl = deps.resolveBaseUrl(env);
|
|
6460
|
+
const accessToken = config.token.accessToken;
|
|
6461
|
+
const createStateClient = () => (deps.createStateClient ?? defaultDeps$10.createStateClient)(env, spaceId);
|
|
6462
|
+
if (assetId) assetId = await resolveCliAssetIdentifier(assetId, createStateClient);
|
|
6463
|
+
sourceVariantIds = await resolveCliVariantIdentifiers(sourceVariantIds, createStateClient);
|
|
6464
|
+
if (env === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
6465
|
+
try {
|
|
6466
|
+
const fileStat = await deps.stat(filePath);
|
|
6467
|
+
if (!fileStat.isFile()) throw new Error(`"${filePath}" is not a file`);
|
|
6468
|
+
if (fileStat.size > 10485760) throw new Error(`File too large (${(fileStat.size / 1024 / 1024).toFixed(2)}MB). Maximum size: 10MB`);
|
|
6469
|
+
const fileBuffer = await deps.readFile(filePath);
|
|
6470
|
+
const fileName = path.basename(filePath);
|
|
6471
|
+
const formData = new FormData();
|
|
6472
|
+
const blob = new Blob([fileBuffer], { type: mediaType.mimeType });
|
|
6473
|
+
formData.append("file", blob, fileName);
|
|
6474
|
+
formData.append("mediaKind", mediaType.mediaKind);
|
|
6475
|
+
formData.append("activeVariantBehavior", activeVariantBehavior);
|
|
6476
|
+
if (assetId) formData.append("assetId", assetId);
|
|
6477
|
+
else {
|
|
6478
|
+
formData.append("assetName", assetName);
|
|
6479
|
+
formData.append("assetType", assetType);
|
|
6480
|
+
}
|
|
6481
|
+
if (prompt) formData.append("prompt", prompt);
|
|
6482
|
+
if (model) formData.append("model", model);
|
|
6483
|
+
if (provider) formData.append("provider", provider);
|
|
6484
|
+
if (providerMetadata) formData.append("providerMetadata", JSON.stringify(providerMetadata));
|
|
6485
|
+
if (generationProvenance) formData.append("generationProvenance", JSON.stringify(generationProvenance));
|
|
6486
|
+
if (sourceVariantIds.length > 0) formData.append("lineage", JSON.stringify(sourceVariantIds.map((parentVariantId) => ({
|
|
6487
|
+
parentVariantId,
|
|
6488
|
+
relationType
|
|
6489
|
+
}))));
|
|
6490
|
+
if (!jsonOutput) {
|
|
6491
|
+
deps.print(`\nUploading "${fileName}" to space ${spaceId}...`);
|
|
6492
|
+
deps.print(` Media kind: ${mediaType.mediaKind}`);
|
|
6493
|
+
if (assetId) deps.print(` Target asset: ${assetId}`);
|
|
6494
|
+
else deps.print(` Creating asset: "${assetName}" (${assetType})`);
|
|
6495
|
+
if (sourceVariantIds.length === 1) deps.print(` Source variant: ${sourceVariantIds[0]} (${relationType})`);
|
|
6496
|
+
else if (sourceVariantIds.length > 1) deps.print(` Source variants: ${sourceVariantIds.join(", ")} (${relationType})`);
|
|
6497
|
+
}
|
|
6498
|
+
const response = await deps.fetch(`${baseUrl}/api/spaces/${spaceId}/upload`, {
|
|
6499
|
+
method: "POST",
|
|
6500
|
+
headers: { "Authorization": `Bearer ${accessToken}` },
|
|
6501
|
+
body: formData
|
|
6502
|
+
});
|
|
6503
|
+
const data = await response.json();
|
|
6504
|
+
if (!response.ok) throw new Error(`Upload failed: ${"error" in data ? data.error : response.statusText}`);
|
|
6505
|
+
const upload = data;
|
|
6506
|
+
const result = {
|
|
6507
|
+
asset: upload.asset,
|
|
6508
|
+
variant: upload.variant,
|
|
6509
|
+
lineage: upload.lineage
|
|
6510
|
+
};
|
|
6511
|
+
const resultAssetName = upload.asset?.name ?? assetName ?? "asset";
|
|
6512
|
+
result.assetRef = createAssetRef(resultAssetName, upload.asset?.id ?? upload.variant.asset_id);
|
|
6513
|
+
result.variantRef = createVariantRef(resultAssetName, upload.variant.asset_id, upload.variant.id);
|
|
6514
|
+
await recordUploadMirror({
|
|
6515
|
+
deps,
|
|
6516
|
+
projectRoot: projectConfig?.projectRoot,
|
|
6517
|
+
env,
|
|
6518
|
+
baseUrl,
|
|
6519
|
+
spaceId,
|
|
6520
|
+
filePath,
|
|
6521
|
+
assetId: upload.asset?.id ?? upload.variant.asset_id,
|
|
6522
|
+
variantId: upload.variant.id,
|
|
6523
|
+
mediaKind: upload.variant.media_kind || mediaType.mediaKind,
|
|
6524
|
+
mediaKey: upload.variant.media_key || upload.variant.image_key
|
|
6525
|
+
});
|
|
6526
|
+
if (jsonOutput) {
|
|
6527
|
+
deps.print(JSON.stringify(result, null, 2));
|
|
6528
|
+
return result;
|
|
6529
|
+
}
|
|
6530
|
+
deps.print("\nUpload successful!\n");
|
|
6531
|
+
if (upload.asset) {
|
|
6532
|
+
deps.print("New Asset:");
|
|
6533
|
+
deps.print(` Ref: ${result.assetRef}`);
|
|
6534
|
+
deps.print(` ID: ${upload.asset.id}`);
|
|
6535
|
+
deps.print(` Name: ${upload.asset.name}`);
|
|
6536
|
+
deps.print(` Type: ${upload.asset.type}`);
|
|
6537
|
+
deps.print("");
|
|
6538
|
+
}
|
|
6539
|
+
deps.print("Variant:");
|
|
6540
|
+
deps.print(` Ref: ${result.variantRef}`);
|
|
6541
|
+
deps.print(` ID: ${upload.variant.id}`);
|
|
6542
|
+
deps.print(` Asset: ${upload.variant.asset_id}`);
|
|
6543
|
+
deps.print(` Status: ${upload.variant.status}`);
|
|
6544
|
+
deps.print(` Media: ${upload.variant.media_kind || mediaType.mediaKind}`);
|
|
6545
|
+
deps.print(` File: ${upload.variant.media_key || upload.variant.image_key || "-"}`);
|
|
6546
|
+
if (upload.variant.image_key) deps.print(` Image: ${upload.variant.image_key}`);
|
|
6547
|
+
if (upload.variant.thumb_key) deps.print(` Thumb: ${upload.variant.thumb_key}`);
|
|
6548
|
+
if (upload.variant.media_mime_type) deps.print(` MIME: ${upload.variant.media_mime_type}`);
|
|
6549
|
+
if (upload.variant.recipe) try {
|
|
6550
|
+
const recipe = JSON.parse(upload.variant.recipe);
|
|
6551
|
+
deps.print("\nRecipe:");
|
|
6552
|
+
deps.print(` Operation: ${recipe.operation}`);
|
|
6553
|
+
deps.print(` Original: ${recipe.originalFilename}`);
|
|
6554
|
+
deps.print(` Uploaded: ${recipe.uploadedAt}`);
|
|
6555
|
+
} catch {}
|
|
6556
|
+
deps.print("\nTo inspect:");
|
|
6557
|
+
deps.print(` makefx assets show ${result.assetRef} --space ${spaceId}`);
|
|
6558
|
+
return result;
|
|
6559
|
+
} catch (error) {
|
|
6560
|
+
if (error.code === "ENOENT") throw new Error(`File not found: ${filePath}`);
|
|
6561
|
+
throw error;
|
|
6562
|
+
}
|
|
6563
|
+
}
|
|
6564
|
+
async function recordUploadMirror(input) {
|
|
6565
|
+
if (!input.deps.recordMirrorForFile) return;
|
|
6566
|
+
try {
|
|
6567
|
+
await input.deps.recordMirrorForFile({
|
|
6568
|
+
projectRoot: input.projectRoot,
|
|
6569
|
+
baseUrl: input.baseUrl,
|
|
6570
|
+
environment: input.env,
|
|
6571
|
+
spaceId: input.spaceId,
|
|
6572
|
+
filePath: input.filePath,
|
|
6573
|
+
assetId: input.assetId,
|
|
6574
|
+
variantId: input.variantId,
|
|
6575
|
+
mediaKind: input.mediaKind,
|
|
6576
|
+
mediaKey: input.mediaKey
|
|
6773
6577
|
});
|
|
6578
|
+
} catch (error) {
|
|
6579
|
+
console.warn(`Warning: upload succeeded but mirror registry was not updated: ${error instanceof Error ? error.message : String(error)}`);
|
|
6774
6580
|
}
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6581
|
+
}
|
|
6582
|
+
function parseJsonObjectOption(value, optionName) {
|
|
6583
|
+
if (value === void 0) return void 0;
|
|
6584
|
+
let parsed;
|
|
6585
|
+
try {
|
|
6586
|
+
parsed = JSON.parse(value);
|
|
6587
|
+
} catch {
|
|
6588
|
+
throw new UploadUsageError(`${optionName} must be valid JSON`);
|
|
6780
6589
|
}
|
|
6781
|
-
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
6590
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new UploadUsageError(`${optionName} must be a JSON object`);
|
|
6591
|
+
return parsed;
|
|
6592
|
+
}
|
|
6593
|
+
function normalizeRelationType(value) {
|
|
6594
|
+
if (!value) return "derived";
|
|
6595
|
+
if (value === "derived" || value === "refined" || value === "forked") return value;
|
|
6596
|
+
throw new UploadUsageError("--relation-type must be derived, refined, or forked");
|
|
6597
|
+
}
|
|
6598
|
+
function normalizeActiveVariantBehavior(value) {
|
|
6599
|
+
if (!value || value === "if-missing" || value === "if_missing") return "if-missing";
|
|
6600
|
+
if (value === "set-active" || value === "set_active") return "set-active";
|
|
6601
|
+
if (value === "keep") return "keep";
|
|
6602
|
+
throw new UploadUsageError("--active-variant-behavior must be if-missing, set-active, or keep");
|
|
6603
|
+
}
|
|
6604
|
+
function rejectRetiredUploadOrganizationOptions(parsed) {
|
|
6605
|
+
const usedOptions = RETIRED_UPLOAD_ORGANIZATION_OPTIONS.filter(([key]) => parsed.options[key] !== void 0).map(([, flag]) => flag);
|
|
6606
|
+
if (usedOptions.length === 0) return;
|
|
6607
|
+
throw new UploadUsageError(`${Array.from(new Set(usedOptions)).join(", ")} ${usedOptions.length === 1 ? "was" : "were"} removed. Upload creates assets or variants only; organize the result visually on the Space canvas. Use --source-variant for immutable lineage provenance.`);
|
|
6608
|
+
}
|
|
6609
|
+
function parseCsvOption(value, optionName) {
|
|
6610
|
+
if (!value) return [];
|
|
6611
|
+
if (value === "true") throw new UploadUsageError(`${optionName} requires a value`);
|
|
6612
|
+
return value.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
6613
|
+
}
|
|
6614
|
+
function printUsage$10() {
|
|
6615
|
+
console.log(`
|
|
6616
|
+
Usage:
|
|
6617
|
+
makefx upload <file> --asset <id> [--space <id>] Upload media to existing asset
|
|
6618
|
+
makefx upload <file> --name <name> [--space <id>] Upload media as a new asset
|
|
6619
|
+
|
|
6620
|
+
Options:
|
|
6621
|
+
--space <id> Target space ID; defaults from initialized project
|
|
6622
|
+
--asset <id> Target asset ID (upload as new variant)
|
|
6623
|
+
--name <name> New asset name (creates asset + variant)
|
|
6624
|
+
--type <type> Asset type for new assets (default: character)
|
|
6625
|
+
--media-kind <k> Optional explicit kind: image, audio, or video
|
|
6626
|
+
--prompt <text> Prompt provenance for uploaded media
|
|
6627
|
+
--model <model> Model provenance for uploaded media
|
|
6628
|
+
--provider <name> Provider provenance for uploaded media
|
|
6629
|
+
--provider-metadata <json> Provider metadata JSON object
|
|
6630
|
+
--generation-provenance <json> Extra provenance JSON object
|
|
6631
|
+
--source-variant <ids> Comma-separated source variants for upload lineage
|
|
6632
|
+
--source-variants <ids> Alias for --source-variant
|
|
6633
|
+
--relation-type <type> Lineage type: derived, refined, or forked (default: derived)
|
|
6634
|
+
--active-variant-behavior <b> if-missing, set-active, or keep
|
|
6635
|
+
--json Print machine-readable upload output with Space IDs
|
|
6636
|
+
--env <env> Environment (production|stage|local)
|
|
6637
|
+
--local Shortcut for --env local
|
|
6638
|
+
|
|
6639
|
+
Examples:
|
|
6640
|
+
makefx upload hero.png --space abc123 --name "Hero Character"
|
|
6641
|
+
makefx upload hero.png --space abc123 --name "Hero" --prompt "external render" --provider blender
|
|
6642
|
+
makefx upload paintover.png --space abc123 --asset def456 --source-variant var123 --relation-type refined
|
|
6643
|
+
makefx upload scene.png --space abc123 --name "Cocina" --type scene --source-variants anna,roman,bg
|
|
6644
|
+
makefx upload theme.mp3 --space abc123 --name "Theme Music" --type audio
|
|
6645
|
+
makefx upload cutscene.mp4 --space abc123 --name "Opening Cutscene" --type video
|
|
6646
|
+
makefx upload variant.jpg --space abc123 --asset def456
|
|
6647
|
+
makefx upload hero.png --space abc123 --name "Hero" --json
|
|
6648
|
+
`);
|
|
6649
|
+
}
|
|
6650
|
+
//#endregion
|
|
6651
|
+
//#region src/cli/lib/run-manifest.ts
|
|
6652
|
+
function createRunId(date = /* @__PURE__ */ new Date()) {
|
|
6653
|
+
return `${date.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z")}-${crypto.randomUUID().slice(0, 8)}`;
|
|
6654
|
+
}
|
|
6655
|
+
async function saveRunManifest(manifest, cwd = process.cwd()) {
|
|
6656
|
+
const manifestPath = path.join(cwd, ".inventory", "runs", `${manifest.runId}.json`);
|
|
6657
|
+
await mkdir(path.dirname(manifestPath), { recursive: true });
|
|
6658
|
+
await writeFile(manifestPath, JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
6659
|
+
return manifestPath;
|
|
6660
|
+
}
|
|
6661
|
+
function getRunManifestDir(projectRoot = process.cwd()) {
|
|
6662
|
+
return path.join(projectRoot, ".inventory", "runs");
|
|
6663
|
+
}
|
|
6664
|
+
async function listRunManifests(projectRoot = process.cwd()) {
|
|
6665
|
+
const runsDir = getRunManifestDir(projectRoot);
|
|
6666
|
+
let entries;
|
|
6667
|
+
try {
|
|
6668
|
+
entries = await readdir(runsDir);
|
|
6669
|
+
} catch (error) {
|
|
6670
|
+
if (error.code === "ENOENT") return [];
|
|
6671
|
+
throw error;
|
|
6789
6672
|
}
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6673
|
+
return (await Promise.all(entries.filter((entry) => entry.endsWith(".json")).map((entry) => readRunManifest(path.join(runsDir, entry))))).sort((a, b) => {
|
|
6674
|
+
const byCreatedAt = Date.parse(b.manifest.createdAt) - Date.parse(a.manifest.createdAt);
|
|
6675
|
+
if (Number.isFinite(byCreatedAt) && byCreatedAt !== 0) return byCreatedAt;
|
|
6676
|
+
return b.manifestPath.localeCompare(a.manifestPath);
|
|
6677
|
+
});
|
|
6678
|
+
}
|
|
6679
|
+
async function readRunManifest(manifestPath) {
|
|
6680
|
+
const raw = await readFile(manifestPath, "utf8");
|
|
6681
|
+
return {
|
|
6682
|
+
manifest: normalizeRunManifest(JSON.parse(raw), manifestPath),
|
|
6683
|
+
manifestPath
|
|
6684
|
+
};
|
|
6685
|
+
}
|
|
6686
|
+
async function resolveRunManifest(input) {
|
|
6687
|
+
if (input.latest) {
|
|
6688
|
+
const manifests = await listRunManifests(input.projectRoot);
|
|
6689
|
+
if (manifests.length === 0) throw new Error(`No run manifests found in ${getRunManifestDir(input.projectRoot)}`);
|
|
6690
|
+
return manifests[0];
|
|
6691
|
+
}
|
|
6692
|
+
const selector = input.runIdOrPath;
|
|
6693
|
+
if (!selector) throw new Error("Run ID, manifest path, or --latest is required");
|
|
6694
|
+
return readRunManifest(looksLikeManifestPath(selector) ? path.resolve(selector) : path.join(getRunManifestDir(input.projectRoot), `${selector}.json`));
|
|
6695
|
+
}
|
|
6696
|
+
function createMediaRunExport(record, projectRoot) {
|
|
6697
|
+
const pathBase = record.manifest.workingDir || projectRoot;
|
|
6698
|
+
return {
|
|
6699
|
+
version: 1,
|
|
6700
|
+
format: "media-handoff",
|
|
6701
|
+
runId: record.manifest.runId,
|
|
6702
|
+
manifestPath: record.manifestPath,
|
|
6703
|
+
projectRoot,
|
|
6704
|
+
success: record.manifest.success,
|
|
6705
|
+
prompt: record.manifest.prompt,
|
|
6706
|
+
name: record.manifest.name,
|
|
6707
|
+
assetType: record.manifest.assetType,
|
|
6708
|
+
spaceId: record.manifest.spaceId,
|
|
6709
|
+
baseUrl: record.manifest.baseUrl,
|
|
6710
|
+
refs: record.manifest.refs,
|
|
6711
|
+
referenceVariantIds: record.manifest.referenceVariantIds,
|
|
6712
|
+
createdAt: record.manifest.createdAt,
|
|
6713
|
+
completedAt: record.manifest.completedAt,
|
|
6714
|
+
media: sortedMedia(record.manifest).map((media) => ({
|
|
6715
|
+
...media,
|
|
6716
|
+
absolutePath: path.resolve(pathBase, media.localPath)
|
|
6717
|
+
})),
|
|
6718
|
+
images: [...record.manifest.images].sort((a, b) => a.index - b.index).map((image) => ({
|
|
6719
|
+
...image,
|
|
6720
|
+
absolutePath: path.resolve(pathBase, image.localPath)
|
|
6721
|
+
})),
|
|
6722
|
+
failed: record.manifest.failed
|
|
6723
|
+
};
|
|
6724
|
+
}
|
|
6725
|
+
function createRemotionRunExport(record, projectRoot) {
|
|
6726
|
+
return {
|
|
6727
|
+
...createMediaRunExport(record, projectRoot),
|
|
6728
|
+
format: "remotion-keyframes"
|
|
6729
|
+
};
|
|
6730
|
+
}
|
|
6731
|
+
function manifestMediaFromVariant(input) {
|
|
6732
|
+
const mediaKind = input.variant.media_kind || "image";
|
|
6733
|
+
const mediaKey = input.variant.media_key || input.variant.image_key;
|
|
6734
|
+
if (!mediaKey) throw new Error(`Variant has no media key: ${input.variant.id}`);
|
|
6735
|
+
return {
|
|
6736
|
+
index: input.index,
|
|
6737
|
+
mediaKind,
|
|
6738
|
+
assetId: input.variant.asset_id,
|
|
6739
|
+
variantId: input.variant.id,
|
|
6740
|
+
mediaKey,
|
|
6741
|
+
imageKey: input.variant.image_key,
|
|
6742
|
+
thumbKey: input.variant.thumb_key,
|
|
6743
|
+
mimeType: input.variant.media_mime_type || null,
|
|
6744
|
+
sizeBytes: input.variant.media_size_bytes ?? null,
|
|
6745
|
+
width: input.variant.media_width ?? null,
|
|
6746
|
+
height: input.variant.media_height ?? null,
|
|
6747
|
+
durationMs: input.variant.media_duration_ms ?? null,
|
|
6748
|
+
localPath: input.localPath,
|
|
6749
|
+
webUrl: `${input.baseUrl}/spaces/${input.spaceId}/assets/${input.variant.asset_id}`
|
|
6750
|
+
};
|
|
6751
|
+
}
|
|
6752
|
+
function looksLikeManifestPath(value) {
|
|
6753
|
+
return path.isAbsolute(value) || value.endsWith(".json") || value.includes("/") || value.includes("\\");
|
|
6754
|
+
}
|
|
6755
|
+
function normalizeRunManifest(manifest, manifestPath) {
|
|
6756
|
+
if (manifest.version !== 1) throw new Error(`Unsupported run manifest version in ${manifestPath}`);
|
|
6757
|
+
if (!isSupportedCommand(manifest.command)) throw new Error(`Unsupported run manifest command in ${manifestPath}`);
|
|
6758
|
+
if (!manifest.runId || typeof manifest.runId !== "string") throw new Error(`Run manifest is missing runId: ${manifestPath}`);
|
|
6759
|
+
const media = Array.isArray(manifest.media) ? manifest.media : manifest.images;
|
|
6760
|
+
if (!Array.isArray(media)) throw new Error(`Run manifest is missing media: ${manifestPath}`);
|
|
6761
|
+
if (!Array.isArray(manifest.failed)) throw new Error(`Run manifest is missing failed entries: ${manifestPath}`);
|
|
6762
|
+
const normalizedMedia = media.map((entry) => normalizeManifestMedia(entry));
|
|
6763
|
+
return {
|
|
6764
|
+
...manifest,
|
|
6765
|
+
mediaKind: manifest.mediaKind || inferManifestMediaKind(normalizedMedia),
|
|
6766
|
+
media: normalizedMedia,
|
|
6767
|
+
images: normalizedMedia.filter(isRunManifestImage)
|
|
6768
|
+
};
|
|
6769
|
+
}
|
|
6770
|
+
function sortedMedia(manifest) {
|
|
6771
|
+
return [...manifest.media].sort((a, b) => a.index - b.index);
|
|
6772
|
+
}
|
|
6773
|
+
function isSupportedCommand(command) {
|
|
6774
|
+
return command === "generate" || command === "refine" || command === "derive" || command === "batch";
|
|
6775
|
+
}
|
|
6776
|
+
function normalizeManifestMedia(entry) {
|
|
6777
|
+
const legacyImageKey = "imageKey" in entry ? entry.imageKey : null;
|
|
6778
|
+
const mediaKey = "mediaKey" in entry ? entry.mediaKey : legacyImageKey;
|
|
6779
|
+
return {
|
|
6780
|
+
index: entry.index,
|
|
6781
|
+
mediaKind: entry.mediaKind || "image",
|
|
6782
|
+
assetId: entry.assetId,
|
|
6783
|
+
variantId: entry.variantId,
|
|
6784
|
+
mediaKey: mediaKey || "",
|
|
6785
|
+
imageKey: legacyImageKey,
|
|
6786
|
+
thumbKey: entry.thumbKey,
|
|
6787
|
+
mimeType: "mimeType" in entry ? entry.mimeType : null,
|
|
6788
|
+
sizeBytes: "sizeBytes" in entry ? entry.sizeBytes : null,
|
|
6789
|
+
width: "width" in entry ? entry.width : null,
|
|
6790
|
+
height: "height" in entry ? entry.height : null,
|
|
6791
|
+
durationMs: "durationMs" in entry ? entry.durationMs : null,
|
|
6792
|
+
localPath: entry.localPath,
|
|
6793
|
+
webUrl: entry.webUrl
|
|
6794
|
+
};
|
|
6795
|
+
}
|
|
6796
|
+
function isRunManifestImage(entry) {
|
|
6797
|
+
return entry.mediaKind === "image" && Boolean(entry.imageKey);
|
|
6798
|
+
}
|
|
6799
|
+
function inferManifestMediaKind(media) {
|
|
6800
|
+
return media[0]?.mediaKind || "image";
|
|
6801
|
+
}
|
|
6802
|
+
//#endregion
|
|
6803
|
+
//#region src/cli/lib/image-transfer.ts
|
|
6804
|
+
var MAX_FILE_SIZE_MB = 10;
|
|
6805
|
+
var MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024;
|
|
6806
|
+
var ALLOWED_EXTENSIONS = [
|
|
6807
|
+
".jpg",
|
|
6808
|
+
".jpeg",
|
|
6809
|
+
".png",
|
|
6810
|
+
".gif",
|
|
6811
|
+
".webp"
|
|
6812
|
+
];
|
|
6813
|
+
var EXT_TO_MIME = {
|
|
6814
|
+
".jpg": "image/jpeg",
|
|
6815
|
+
".jpeg": "image/jpeg",
|
|
6816
|
+
".png": "image/png",
|
|
6817
|
+
".gif": "image/gif",
|
|
6818
|
+
".webp": "image/webp"
|
|
6819
|
+
};
|
|
6820
|
+
function isSupportedImagePath(filePath) {
|
|
6821
|
+
return ALLOWED_EXTENSIONS.includes(path.extname(filePath).toLowerCase());
|
|
6822
|
+
}
|
|
6823
|
+
function looksLikeFilePath(value) {
|
|
6824
|
+
return value.startsWith(".") || value.includes("/") || value.includes("\\") || isSupportedImagePath(value);
|
|
6825
|
+
}
|
|
6826
|
+
async function uploadLocalImageAsReference(input) {
|
|
6827
|
+
const ext = path.extname(input.filePath).toLowerCase();
|
|
6828
|
+
if (!ALLOWED_EXTENSIONS.includes(ext)) throw new Error(`Invalid reference file type "${ext}". Allowed: ${ALLOWED_EXTENSIONS.join(", ")}`);
|
|
6829
|
+
const fileStat = await stat(input.filePath);
|
|
6830
|
+
if (!fileStat.isFile()) throw new Error(`Reference is not a file: ${input.filePath}`);
|
|
6831
|
+
if (fileStat.size > MAX_FILE_SIZE_BYTES) throw new Error(`Reference file too large (${(fileStat.size / 1024 / 1024).toFixed(2)}MB). Maximum size: ${MAX_FILE_SIZE_MB}MB`);
|
|
6832
|
+
const fileBuffer = await readFile(input.filePath);
|
|
6833
|
+
const filename = path.basename(input.filePath);
|
|
6834
|
+
const mimeType = EXT_TO_MIME[ext] || "image/png";
|
|
6835
|
+
const assetName = input.assetName || `Reference: ${filename.replace(/\.[^/.]+$/, "")}`;
|
|
6836
|
+
const formData = new FormData();
|
|
6837
|
+
formData.append("file", new Blob([fileBuffer], { type: mimeType }), filename);
|
|
6838
|
+
formData.append("assetName", assetName);
|
|
6839
|
+
formData.append("assetType", "reference");
|
|
6840
|
+
formData.append("mediaKind", DEFAULT_MEDIA_KIND);
|
|
6841
|
+
const response = await fetch(`${input.baseUrl}/api/spaces/${input.spaceId}/upload`, {
|
|
6842
|
+
method: "POST",
|
|
6843
|
+
headers: { "Authorization": `Bearer ${input.accessToken}` },
|
|
6844
|
+
body: formData
|
|
6845
|
+
});
|
|
6846
|
+
const data = await response.json();
|
|
6847
|
+
if (!response.ok || !data.success || !data.variant) throw new Error(`Failed to upload reference "${input.filePath}": ${data.error || response.statusText}`);
|
|
6848
|
+
return {
|
|
6849
|
+
asset: data.asset,
|
|
6850
|
+
variant: data.variant
|
|
6851
|
+
};
|
|
6852
|
+
}
|
|
6853
|
+
async function downloadFile(input) {
|
|
6854
|
+
if (!input.force) try {
|
|
6855
|
+
if ((await stat(input.outputPath)).isFile()) throw new Error(`Output file already exists: ${input.outputPath}. Pass --force to overwrite.`);
|
|
6856
|
+
} catch (error) {
|
|
6857
|
+
if (error.code !== "ENOENT") throw error;
|
|
6798
6858
|
}
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6859
|
+
const headers = {};
|
|
6860
|
+
if (input.accessToken) headers.Authorization = `Bearer ${input.accessToken}`;
|
|
6861
|
+
const requestUrl = `${input.baseUrl}${input.requestPath}`;
|
|
6862
|
+
let response;
|
|
6863
|
+
try {
|
|
6864
|
+
response = await fetch(requestUrl, { headers });
|
|
6865
|
+
} catch (error) {
|
|
6866
|
+
throw new Error(`Failed to download ${input.requestPath}: ${formatFetchError(error)}`);
|
|
6804
6867
|
}
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
getSession() {
|
|
6809
|
-
this.send({ type: "session:get" });
|
|
6868
|
+
if (!response.ok) {
|
|
6869
|
+
const errorText = await readErrorText(response);
|
|
6870
|
+
throw new Error(`Failed to download ${input.requestPath}: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ""}`);
|
|
6810
6871
|
}
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
...data
|
|
6818
|
-
});
|
|
6872
|
+
await mkdir(path.dirname(input.outputPath), { recursive: true });
|
|
6873
|
+
if (!response.body) throw new Error(`Failed to download ${input.requestPath}: response body was empty`);
|
|
6874
|
+
try {
|
|
6875
|
+
await pipeline(Readable.fromWeb(response.body), createWriteStream(input.outputPath));
|
|
6876
|
+
} catch (error) {
|
|
6877
|
+
throw new Error(`Failed to write download ${input.requestPath} to ${input.outputPath}: ${formatFetchError(error)}`);
|
|
6819
6878
|
}
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6879
|
+
return {
|
|
6880
|
+
headers: response.headers,
|
|
6881
|
+
requestUrl
|
|
6882
|
+
};
|
|
6883
|
+
}
|
|
6884
|
+
async function readErrorText(response) {
|
|
6885
|
+
try {
|
|
6886
|
+
return (await response.text()).slice(0, 500).trim();
|
|
6887
|
+
} catch {
|
|
6888
|
+
return "";
|
|
6825
6889
|
}
|
|
6826
|
-
}
|
|
6890
|
+
}
|
|
6891
|
+
function formatFetchError(error) {
|
|
6892
|
+
if (!(error instanceof Error)) return String(error);
|
|
6893
|
+
const cause = error.cause instanceof Error ? ` (${error.cause.message})` : "";
|
|
6894
|
+
return `${error.message}${cause}`;
|
|
6895
|
+
}
|
|
6896
|
+
async function downloadImage(input) {
|
|
6897
|
+
await downloadFile({
|
|
6898
|
+
baseUrl: input.baseUrl,
|
|
6899
|
+
accessToken: input.accessToken,
|
|
6900
|
+
requestPath: `/api/images/${input.imageKey}`,
|
|
6901
|
+
outputPath: input.outputPath,
|
|
6902
|
+
force: input.force
|
|
6903
|
+
});
|
|
6904
|
+
}
|
|
6827
6905
|
//#endregion
|
|
6828
6906
|
//#region src/shared/videoGenerationOptions.ts
|
|
6829
6907
|
var VIDEO_GENERATION_ASPECT_RATIOS = ["16:9", "9:16"];
|
|
@@ -6832,12 +6910,27 @@ var VIDEO_GENERATION_RESOLUTIONS = [
|
|
|
6832
6910
|
"1080p",
|
|
6833
6911
|
"4k"
|
|
6834
6912
|
];
|
|
6913
|
+
var ALL_VIDEO_GENERATION_RESOLUTIONS = ["480p", ...VIDEO_GENERATION_RESOLUTIONS];
|
|
6835
6914
|
var KLING_VIDEO_GENERATION_RESOLUTIONS = ["720p", "1080p"];
|
|
6836
6915
|
var VIDEO_GENERATION_DURATION_SECONDS = [
|
|
6837
6916
|
4,
|
|
6838
6917
|
6,
|
|
6839
6918
|
8
|
|
6840
6919
|
];
|
|
6920
|
+
var SEEDANCE_2_DURATION_SECONDS = [
|
|
6921
|
+
4,
|
|
6922
|
+
5,
|
|
6923
|
+
6,
|
|
6924
|
+
7,
|
|
6925
|
+
8,
|
|
6926
|
+
9,
|
|
6927
|
+
10,
|
|
6928
|
+
11,
|
|
6929
|
+
12,
|
|
6930
|
+
13,
|
|
6931
|
+
14,
|
|
6932
|
+
15
|
|
6933
|
+
];
|
|
6841
6934
|
var VIDEO_GENERATION_TIERS = [
|
|
6842
6935
|
"generate",
|
|
6843
6936
|
"fast",
|
|
@@ -6847,7 +6940,9 @@ var VIDEO_MODEL_SELECTIONS = [
|
|
|
6847
6940
|
"veo-3.1",
|
|
6848
6941
|
"omni-flash",
|
|
6849
6942
|
"kling",
|
|
6850
|
-
"fal-seedance"
|
|
6943
|
+
"fal-seedance",
|
|
6944
|
+
"seedance-2",
|
|
6945
|
+
"seedance-2-fast"
|
|
6851
6946
|
];
|
|
6852
6947
|
var VIDEO_MODEL_SUPPORTED_OPERATIONS = {
|
|
6853
6948
|
"veo-3.1": [
|
|
@@ -6865,10 +6960,14 @@ var VIDEO_MODEL_SUPPORTED_OPERATIONS = {
|
|
|
6865
6960
|
"refine",
|
|
6866
6961
|
"derive"
|
|
6867
6962
|
],
|
|
6868
|
-
"fal-seedance": ["generate"]
|
|
6963
|
+
"fal-seedance": ["generate"],
|
|
6964
|
+
"seedance-2": ["generate", "derive"],
|
|
6965
|
+
"seedance-2-fast": ["generate", "derive"]
|
|
6869
6966
|
};
|
|
6870
6967
|
var KLING_VIDEO_MODEL = "kling-v3";
|
|
6871
6968
|
var FAL_VIDEO_MODEL = "fal-ai/bytedance/seedance/v1/pro/text-to-video";
|
|
6969
|
+
var FAL_SEEDANCE_2_MODEL = "bytedance/seedance-2.0/image-to-video";
|
|
6970
|
+
var FAL_SEEDANCE_2_FAST_MODEL = "bytedance/seedance-2.0/fast/image-to-video";
|
|
6872
6971
|
var GEMINI_OMNI_FLASH_VIDEO_MODEL = "gemini-omni-flash-preview";
|
|
6873
6972
|
var VIDEO_GENERATION_AUDIO_TOGGLE_MODELS = [];
|
|
6874
6973
|
var VIDEO_GENERATION_RESOLUTIONS_BY_TIER = {
|
|
@@ -6887,11 +6986,11 @@ var VIDEO_GENERATION_TIER_MODELS = {
|
|
|
6887
6986
|
lite: "veo-3.1-lite-generate-preview"
|
|
6888
6987
|
};
|
|
6889
6988
|
function normalizeVideoGenerationResolution(value) {
|
|
6890
|
-
return
|
|
6989
|
+
return ALL_VIDEO_GENERATION_RESOLUTIONS.includes(value) ? value : void 0;
|
|
6891
6990
|
}
|
|
6892
6991
|
function normalizeVideoGenerationDurationSeconds(value) {
|
|
6893
6992
|
const numeric = typeof value === "string" ? Number(value) : value;
|
|
6894
|
-
return
|
|
6993
|
+
return SEEDANCE_2_DURATION_SECONDS.includes(numeric) ? numeric : void 0;
|
|
6895
6994
|
}
|
|
6896
6995
|
function normalizeVideoGenerationTier(value) {
|
|
6897
6996
|
return VIDEO_GENERATION_TIERS.includes(value) ? value : void 0;
|
|
@@ -6906,6 +7005,8 @@ function getVideoGenerationModelForSelection(selection = DEFAULT_VIDEO_MODEL_SEL
|
|
|
6906
7005
|
if (selection === "omni-flash") return GEMINI_OMNI_FLASH_VIDEO_MODEL;
|
|
6907
7006
|
if (selection === "kling") return KLING_VIDEO_MODEL;
|
|
6908
7007
|
if (selection === "fal-seedance") return FAL_VIDEO_MODEL;
|
|
7008
|
+
if (selection === "seedance-2") return FAL_SEEDANCE_2_MODEL;
|
|
7009
|
+
if (selection === "seedance-2-fast") return FAL_SEEDANCE_2_FAST_MODEL;
|
|
6909
7010
|
return getVideoGenerationModelForTier(tier);
|
|
6910
7011
|
}
|
|
6911
7012
|
function getVideoGenerationResolutionsForTier(tier = DEFAULT_VIDEO_GENERATION_TIER) {
|
|
@@ -6915,7 +7016,14 @@ function isVideoGenerationResolutionSupportedForTier(resolution, tier = DEFAULT_
|
|
|
6915
7016
|
return VIDEO_GENERATION_RESOLUTIONS_BY_TIER[tier].includes(resolution);
|
|
6916
7017
|
}
|
|
6917
7018
|
function getVideoGenerationResolutionsForModel(model) {
|
|
6918
|
-
|
|
7019
|
+
if (isKlingVideoGenerationModel(model) || isFalSeedanceV1VideoGenerationModel(model)) return KLING_VIDEO_GENERATION_RESOLUTIONS;
|
|
7020
|
+
if (model === "bytedance/seedance-2.0/fast/image-to-video") return ["480p", "720p"];
|
|
7021
|
+
if (isFalSeedance2VideoGenerationModel(model)) return [
|
|
7022
|
+
"480p",
|
|
7023
|
+
"720p",
|
|
7024
|
+
"1080p"
|
|
7025
|
+
];
|
|
7026
|
+
return getVideoGenerationResolutionsForTier(getVideoGenerationTierForModel(model));
|
|
6919
7027
|
}
|
|
6920
7028
|
function isVideoGenerationResolutionSupportedForModel(model, resolution) {
|
|
6921
7029
|
return getVideoGenerationResolutionsForModel(model).includes(resolution);
|
|
@@ -6928,6 +7036,8 @@ function getVideoModelSelectionForModel(model) {
|
|
|
6928
7036
|
if (model === "gemini-omni-flash-preview") return "omni-flash";
|
|
6929
7037
|
if (model === "kling-v3") return "kling";
|
|
6930
7038
|
if (model === "fal-ai/bytedance/seedance/v1/pro/text-to-video") return "fal-seedance";
|
|
7039
|
+
if (model === "bytedance/seedance-2.0/image-to-video") return "seedance-2";
|
|
7040
|
+
if (model === "bytedance/seedance-2.0/fast/image-to-video") return "seedance-2-fast";
|
|
6931
7041
|
return getVideoGenerationTierForModel(model) ? "veo-3.1" : void 0;
|
|
6932
7042
|
}
|
|
6933
7043
|
function isVeoVideoGenerationModel(model) {
|
|
@@ -6940,8 +7050,14 @@ function isKlingVideoGenerationModel(model) {
|
|
|
6940
7050
|
return model === KLING_VIDEO_MODEL;
|
|
6941
7051
|
}
|
|
6942
7052
|
function isFalVideoGenerationModel(model) {
|
|
7053
|
+
return isFalSeedanceV1VideoGenerationModel(model) || isFalSeedance2VideoGenerationModel(model);
|
|
7054
|
+
}
|
|
7055
|
+
function isFalSeedanceV1VideoGenerationModel(model) {
|
|
6943
7056
|
return model === FAL_VIDEO_MODEL;
|
|
6944
7057
|
}
|
|
7058
|
+
function isFalSeedance2VideoGenerationModel(model) {
|
|
7059
|
+
return model === "bytedance/seedance-2.0/image-to-video" || model === "bytedance/seedance-2.0/fast/image-to-video";
|
|
7060
|
+
}
|
|
6945
7061
|
function isVideoGenerationModel(model) {
|
|
6946
7062
|
return isVeoVideoGenerationModel(model) || isGeminiOmniVideoGenerationModel(model) || isKlingVideoGenerationModel(model) || isFalVideoGenerationModel(model);
|
|
6947
7063
|
}
|
|
@@ -7022,7 +7138,7 @@ var IMAGE_MODEL_CAPABILITIES = {
|
|
|
7022
7138
|
flux: {
|
|
7023
7139
|
selection: "flux",
|
|
7024
7140
|
modelId: IMAGE_MODEL_IDS.flux,
|
|
7025
|
-
label: "FLUX.1 Dev",
|
|
7141
|
+
label: "fal.ai FLUX.1 Dev",
|
|
7026
7142
|
provider: "fal",
|
|
7027
7143
|
supportedOperations: ["generate"],
|
|
7028
7144
|
maxReferenceImages: 0,
|
|
@@ -7248,43 +7364,6 @@ var defaultDeps$9 = {
|
|
|
7248
7364
|
}
|
|
7249
7365
|
}
|
|
7250
7366
|
};
|
|
7251
|
-
var ESTIMATE_METER_LABELS = {
|
|
7252
|
-
gemini_images: "Gemini image",
|
|
7253
|
-
gemini_videos: "Veo video unit",
|
|
7254
|
-
gemini_audio: "Lyria generation",
|
|
7255
|
-
elevenlabs_audio: "ElevenLabs unit"
|
|
7256
|
-
};
|
|
7257
|
-
function formatEstimatedUsd(microUsd) {
|
|
7258
|
-
if (!Number.isFinite(microUsd) || microUsd <= 0) return "$0.00";
|
|
7259
|
-
if (microUsd < 1e4) return "<$0.01";
|
|
7260
|
-
return `$${(microUsd / 1e6).toFixed(2)}`;
|
|
7261
|
-
}
|
|
7262
|
-
function formatEstimateQuantity(quantity, singular) {
|
|
7263
|
-
const normalized = Number.isFinite(quantity) ? quantity : 0;
|
|
7264
|
-
const suffix = normalized === 1 ? singular : `${singular}s`;
|
|
7265
|
-
return `${normalized.toLocaleString()} ${suffix}`;
|
|
7266
|
-
}
|
|
7267
|
-
async function printPreflightEstimate(client, params) {
|
|
7268
|
-
let result;
|
|
7269
|
-
try {
|
|
7270
|
-
result = await client.sendGenerationEstimateRequest(params);
|
|
7271
|
-
} catch (error) {
|
|
7272
|
-
console.warn(`Preflight estimate unavailable: ${error instanceof Error ? error.message : String(error)}`);
|
|
7273
|
-
return;
|
|
7274
|
-
}
|
|
7275
|
-
if (!result.success || !result.estimate) {
|
|
7276
|
-
console.warn(`Preflight estimate unavailable: ${result.error || "unknown error"}`);
|
|
7277
|
-
return;
|
|
7278
|
-
}
|
|
7279
|
-
const estimate = result.estimate;
|
|
7280
|
-
const meterLabel = ESTIMATE_METER_LABELS[estimate.meterEventName] ?? estimate.meterEventName;
|
|
7281
|
-
const quotaLine = estimate.quota?.limit === null || estimate.quota?.limit === void 0 ? void 0 : `${estimate.quota.used.toLocaleString()} used / ${estimate.quota.limit.toLocaleString()} limit`;
|
|
7282
|
-
console.log("Preflight estimate:");
|
|
7283
|
-
console.log(` Usage: ${formatEstimateQuantity(estimate.quotaQuantity, meterLabel)}, ${formatEstimateQuantity(estimate.platformWorkflowRuns, "workflow")}`);
|
|
7284
|
-
console.log(` Estimated provider cost: ${formatEstimatedUsd(estimate.providerCostMicroUsd)}${estimate.billingMode === "byok" ? " (BYOK)" : ""}`);
|
|
7285
|
-
if (quotaLine) console.log(` Quota: ${quotaLine}`);
|
|
7286
|
-
if (!estimate.allowed) throw new Error(estimate.denyMessage || "Preflight check denied this generation request");
|
|
7287
|
-
}
|
|
7288
7367
|
async function handleGenerate(parsed) {
|
|
7289
7368
|
await handleForgeCommand("generate", parsed);
|
|
7290
7369
|
}
|
|
@@ -7398,32 +7477,19 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
|
|
|
7398
7477
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7399
7478
|
const videoFrameRefs = parseVideoFrameReferenceOptions(parsed, "generate", mediaKind).refs;
|
|
7400
7479
|
const state = videoFrameRefs.length > 0 ? await requestSpaceState$1(client) : void 0;
|
|
7401
|
-
const referenceVariantIds = videoFrameRefs.length > 0 ? await resolveReferenceVariantIds(videoFrameRefs, ctx, deps, state?.variants, CLI_GENERATION_MEDIA_KIND) : [];
|
|
7480
|
+
const referenceVariantIds = videoFrameRefs.length > 0 ? await resolveReferenceVariantIds(videoFrameRefs, ctx, deps, state?.variants, CLI_GENERATION_MEDIA_KIND, state?.assets) : [];
|
|
7402
7481
|
const imageOptions = parseImageGenerationOptions(parsed, mediaKind);
|
|
7403
7482
|
const audioModelOptions = parseAudioGenerationOptions(parsed, mediaKind);
|
|
7404
7483
|
const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
|
|
7405
7484
|
const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
|
|
7406
7485
|
const effectiveVideoModel = videoOptions.model ?? getVideoGenerationModelForSelection();
|
|
7407
7486
|
if (mediaKind === "video" && isKlingVideoGenerationModel(effectiveVideoModel) && videoFrameRefs.length > 1) throw new Error("--model kling supports at most one image reference");
|
|
7408
|
-
if (mediaKind === "video" && isFalVideoGenerationModel(effectiveVideoModel) && videoFrameRefs.length > 0) throw new Error(`--model ${getVideoModelSelectionForModel(effectiveVideoModel) ?? effectiveVideoModel} does not support image references`);
|
|
7487
|
+
if (mediaKind === "video" && isFalVideoGenerationModel(effectiveVideoModel) && !isFalSeedance2VideoGenerationModel(effectiveVideoModel) && videoFrameRefs.length > 0) throw new Error(`--model ${getVideoModelSelectionForModel(effectiveVideoModel) ?? effectiveVideoModel} does not support image references`);
|
|
7409
7488
|
const collectionPlacement = parseCollectionPlacementOptions(parsed);
|
|
7410
7489
|
const followCommandOptions = {
|
|
7411
7490
|
...followOptions,
|
|
7412
7491
|
...collectionPlacement
|
|
7413
7492
|
};
|
|
7414
|
-
await printPreflightEstimate(client, {
|
|
7415
|
-
operation: "generate",
|
|
7416
|
-
assetType,
|
|
7417
|
-
mediaKind,
|
|
7418
|
-
prompt,
|
|
7419
|
-
count: 1,
|
|
7420
|
-
model: imageOptions.model ?? audioModelOptions.model ?? videoOptions.model,
|
|
7421
|
-
aspectRatio: imageOptions.aspectRatio ?? videoOptions.aspectRatio,
|
|
7422
|
-
imageSize: imageOptions.imageSize,
|
|
7423
|
-
...musicProvider ? { musicProvider } : {},
|
|
7424
|
-
...videoAudioOptions,
|
|
7425
|
-
...videoOptions
|
|
7426
|
-
});
|
|
7427
7493
|
console.log(`Generating "${name}" in space ${ctx.spaceId}...`);
|
|
7428
7494
|
const audioVoiceOptions = mediaKind === "audio" ? parseAudioVoiceOptions(parsed) : {};
|
|
7429
7495
|
let startedVariantId;
|
|
@@ -7443,7 +7509,7 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
|
|
|
7443
7509
|
...videoAudioOptions,
|
|
7444
7510
|
...videoOptions,
|
|
7445
7511
|
onStarted: (started) => {
|
|
7446
|
-
startedVariantId = started
|
|
7512
|
+
startedVariantId = compactStartedVariantRef(started);
|
|
7447
7513
|
printFollowHint(started, ctx, outputPath, "generate", mediaKind, followCommandOptions);
|
|
7448
7514
|
}
|
|
7449
7515
|
});
|
|
@@ -7498,9 +7564,11 @@ function parseMusicProviderOption(parsed, mediaKind, assetType) {
|
|
|
7498
7564
|
async function executeRefine(parsed, ctx, client, deps, mediaKind) {
|
|
7499
7565
|
const prompt = getPrompt(parsed, "refine");
|
|
7500
7566
|
const outputPath = getOutputPath$1(parsed);
|
|
7501
|
-
const
|
|
7567
|
+
const sourceVariantIdentifier = requireOption$1(parsed, "variant");
|
|
7502
7568
|
const state = await requestSpaceState$1(client);
|
|
7503
|
-
const
|
|
7569
|
+
const variants = state.variants;
|
|
7570
|
+
const sourceVariantId = resolveVariantRef(sourceVariantIdentifier, state.assets, variants);
|
|
7571
|
+
const sourceVariant = variants.find((variant) => variant.id === sourceVariantId);
|
|
7504
7572
|
if (!sourceVariant) throw new Error(`Variant not found in space sync state: ${sourceVariantId}`);
|
|
7505
7573
|
const sourceAsset = state.assets.find((asset) => asset.id === sourceVariant.asset_id);
|
|
7506
7574
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -7509,19 +7577,6 @@ async function executeRefine(parsed, ctx, client, deps, mediaKind) {
|
|
|
7509
7577
|
const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
|
|
7510
7578
|
const collectionPlacement = parseCollectionPlacementOptions(parsed);
|
|
7511
7579
|
const followCommandOptions = { ...collectionPlacement };
|
|
7512
|
-
await printPreflightEstimate(client, {
|
|
7513
|
-
operation: "refine",
|
|
7514
|
-
assetId: sourceVariant.asset_id,
|
|
7515
|
-
assetType: sourceAsset?.type || void 0,
|
|
7516
|
-
mediaKind,
|
|
7517
|
-
prompt,
|
|
7518
|
-
count: 1,
|
|
7519
|
-
model: imageOptions.model ?? videoOptions.model,
|
|
7520
|
-
aspectRatio: imageOptions.aspectRatio ?? videoOptions.aspectRatio,
|
|
7521
|
-
imageSize: imageOptions.imageSize,
|
|
7522
|
-
...videoAudioOptions,
|
|
7523
|
-
...videoOptions
|
|
7524
|
-
});
|
|
7525
7580
|
console.log(`Refining variant ${sourceVariantId}...`);
|
|
7526
7581
|
let startedVariantId;
|
|
7527
7582
|
let result;
|
|
@@ -7536,7 +7591,7 @@ async function executeRefine(parsed, ctx, client, deps, mediaKind) {
|
|
|
7536
7591
|
...videoAudioOptions,
|
|
7537
7592
|
...videoOptions,
|
|
7538
7593
|
onStarted: (started) => {
|
|
7539
|
-
startedVariantId = started
|
|
7594
|
+
startedVariantId = compactStartedVariantRef(started);
|
|
7540
7595
|
printFollowHint(started, ctx, outputPath, "refine", mediaKind, followCommandOptions);
|
|
7541
7596
|
}
|
|
7542
7597
|
});
|
|
@@ -7580,30 +7635,19 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
|
|
|
7580
7635
|
if (referenceRefs.length === 0) throw new Error("--refs is required");
|
|
7581
7636
|
const imageOptions = parseImageGenerationOptions(parsed, mediaKind);
|
|
7582
7637
|
if (mediaKind === "image") validateImageReferenceCount(imageOptions.model, referenceRefs.length);
|
|
7583
|
-
const
|
|
7638
|
+
const state = await requestSpaceState$1(client);
|
|
7639
|
+
const referenceVariantIds = await resolveReferenceVariantIds(referenceRefs, ctx, deps, state.variants, videoFrameRefs.length > 0 ? CLI_GENERATION_MEDIA_KIND : mediaKind, state.assets);
|
|
7584
7640
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7585
7641
|
const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
|
|
7586
7642
|
const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
|
|
7587
7643
|
const effectiveVideoModel = videoOptions.model ?? getVideoGenerationModelForSelection();
|
|
7588
7644
|
if (mediaKind === "video" && isKlingVideoGenerationModel(effectiveVideoModel) && referenceRefs.length > 1) throw new Error("--model kling supports at most one image reference");
|
|
7589
|
-
if (mediaKind === "video" && isFalVideoGenerationModel(effectiveVideoModel) && referenceRefs.length > 0) throw new Error(`--model ${getVideoModelSelectionForModel(effectiveVideoModel) ?? effectiveVideoModel} does not support ${referenceRefs.length} image references`);
|
|
7645
|
+
if (mediaKind === "video" && isFalVideoGenerationModel(effectiveVideoModel) && !isFalSeedance2VideoGenerationModel(effectiveVideoModel) && referenceRefs.length > 0) throw new Error(`--model ${getVideoModelSelectionForModel(effectiveVideoModel) ?? effectiveVideoModel} does not support ${referenceRefs.length} image references`);
|
|
7590
7646
|
const collectionPlacement = parseCollectionPlacementOptions(parsed);
|
|
7591
7647
|
const followCommandOptions = {
|
|
7592
7648
|
...followOptions,
|
|
7593
7649
|
...collectionPlacement
|
|
7594
7650
|
};
|
|
7595
|
-
await printPreflightEstimate(client, {
|
|
7596
|
-
operation: "derive",
|
|
7597
|
-
assetType,
|
|
7598
|
-
mediaKind,
|
|
7599
|
-
prompt,
|
|
7600
|
-
count: 1,
|
|
7601
|
-
model: imageOptions.model ?? videoOptions.model,
|
|
7602
|
-
aspectRatio: imageOptions.aspectRatio ?? videoOptions.aspectRatio,
|
|
7603
|
-
imageSize: imageOptions.imageSize,
|
|
7604
|
-
...videoAudioOptions,
|
|
7605
|
-
...videoOptions
|
|
7606
|
-
});
|
|
7607
7651
|
console.log(`Deriving "${name}" from ${referenceVariantIds.length} reference(s)...`);
|
|
7608
7652
|
let startedVariantId;
|
|
7609
7653
|
let result;
|
|
@@ -7619,7 +7663,7 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
|
|
|
7619
7663
|
...videoAudioOptions,
|
|
7620
7664
|
...videoOptions,
|
|
7621
7665
|
onStarted: (started) => {
|
|
7622
|
-
startedVariantId = started
|
|
7666
|
+
startedVariantId = compactStartedVariantRef(started);
|
|
7623
7667
|
printFollowHint(started, ctx, outputPath, "derive", mediaKind, followCommandOptions);
|
|
7624
7668
|
}
|
|
7625
7669
|
});
|
|
@@ -7653,8 +7697,8 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
|
|
|
7653
7697
|
return result;
|
|
7654
7698
|
}
|
|
7655
7699
|
async function executeFollow(parsed, ctx, client, deps, command, mediaKind, followOptions = {}) {
|
|
7656
|
-
const
|
|
7657
|
-
if (!
|
|
7700
|
+
const variantIdentifier = normalizeCliOption(parsed.options.follow);
|
|
7701
|
+
if (!variantIdentifier) throw new Error("--follow requires a variant ID");
|
|
7658
7702
|
const outputPath = getOutputPath$1(parsed);
|
|
7659
7703
|
const timeoutMs = parseFollowTimeoutMs(parsed, mediaKind);
|
|
7660
7704
|
const collectionPlacement = parseCollectionPlacementOptions(parsed);
|
|
@@ -7662,9 +7706,11 @@ async function executeFollow(parsed, ctx, client, deps, command, mediaKind, foll
|
|
|
7662
7706
|
...followOptions,
|
|
7663
7707
|
...collectionPlacement
|
|
7664
7708
|
};
|
|
7665
|
-
console.log(`Following variant ${variantId} in space ${ctx.spaceId}...`);
|
|
7666
7709
|
const state = await requestSpaceState$1(client);
|
|
7667
|
-
const
|
|
7710
|
+
const variants = state.variants;
|
|
7711
|
+
const variantId = resolveVariantRef(variantIdentifier, state.assets, variants);
|
|
7712
|
+
console.log(`Following variant ${variantId} in space ${ctx.spaceId}...`);
|
|
7713
|
+
const initialVariant = variants.find((variant) => variant.id === variantId);
|
|
7668
7714
|
if (!initialVariant) throw new Error(`Variant not found in space sync state: ${variantId}`);
|
|
7669
7715
|
const initialStatus = initialVariant.status;
|
|
7670
7716
|
const requestId = `follow:${variantId}`;
|
|
@@ -7812,21 +7858,10 @@ async function executeBatch(parsed, ctx, client, deps, mediaKind, saveBatchManif
|
|
|
7812
7858
|
const audioModelOptions = parseAudioGenerationOptions(parsed, mediaKind);
|
|
7813
7859
|
if (mediaKind === "image") validateImageReferenceCount(imageOptions.model, refs.length);
|
|
7814
7860
|
const state = await requestSpaceState$1(client);
|
|
7815
|
-
const referenceVariantIds = refs.length > 0 ? await resolveReferenceVariantIds(refs, ctx, deps, state.variants, mediaKind) : void 0;
|
|
7861
|
+
const referenceVariantIds = refs.length > 0 ? await resolveReferenceVariantIds(refs, ctx, deps, state.variants, mediaKind, state.assets) : void 0;
|
|
7816
7862
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7817
7863
|
const runId = deps.createRunId();
|
|
7818
7864
|
const collectionPlacement = parseCollectionPlacementOptions(parsed);
|
|
7819
|
-
await printPreflightEstimate(client, {
|
|
7820
|
-
operation: "batch",
|
|
7821
|
-
assetType,
|
|
7822
|
-
mediaKind,
|
|
7823
|
-
prompt,
|
|
7824
|
-
count,
|
|
7825
|
-
model: imageOptions.model ?? audioModelOptions.model,
|
|
7826
|
-
aspectRatio: imageOptions.aspectRatio,
|
|
7827
|
-
imageSize: imageOptions.imageSize,
|
|
7828
|
-
...musicProvider ? { musicProvider } : {}
|
|
7829
|
-
});
|
|
7830
7865
|
console.log(`Batch generating ${count} ${mediaKind === "image" ? "image" : mediaKind === "video" ? "video" : "audio file"}(s) for "${name}"...`);
|
|
7831
7866
|
const audioVoiceOptions = mediaKind === "audio" ? parseAudioVoiceOptions(parsed) : {};
|
|
7832
7867
|
let startedBatch;
|
|
@@ -8027,7 +8062,7 @@ function parseRefs(value) {
|
|
|
8027
8062
|
if (refs.length === 0) throw new Error("--refs must include at least one reference");
|
|
8028
8063
|
return refs;
|
|
8029
8064
|
}
|
|
8030
|
-
async function resolveReferenceVariantIds(refs, ctx, deps, variants = [], mediaKind = CLI_GENERATION_MEDIA_KIND) {
|
|
8065
|
+
async function resolveReferenceVariantIds(refs, ctx, deps, variants = [], mediaKind = CLI_GENERATION_MEDIA_KIND, assets = []) {
|
|
8031
8066
|
const variantIds = [];
|
|
8032
8067
|
for (const ref of refs) {
|
|
8033
8068
|
if (await deps.fileExists(ref)) {
|
|
@@ -8070,8 +8105,9 @@ async function resolveReferenceVariantIds(refs, ctx, deps, variants = [], mediaK
|
|
|
8070
8105
|
continue;
|
|
8071
8106
|
}
|
|
8072
8107
|
if (looksLikeFilePath(ref)) throw new Error(`Reference file not found: ${ref}`);
|
|
8073
|
-
|
|
8074
|
-
|
|
8108
|
+
const variantId = resolveVariantRef(ref, assets, variants);
|
|
8109
|
+
validateReferenceVariant(variantId, variants, mediaKind);
|
|
8110
|
+
variantIds.push(variantId);
|
|
8075
8111
|
}
|
|
8076
8112
|
return variantIds;
|
|
8077
8113
|
}
|
|
@@ -8159,8 +8195,8 @@ function printResult(result, outputPath, ctx, manifestPath) {
|
|
|
8159
8195
|
const variant = result.variant;
|
|
8160
8196
|
if (!variant) return;
|
|
8161
8197
|
console.log("\nDone.\n");
|
|
8162
|
-
console.log(` Asset: ${variant.asset_id}`);
|
|
8163
|
-
console.log(` Variant: ${variant.id}`);
|
|
8198
|
+
console.log(` Asset: ${createAssetRef("asset", variant.asset_id)}`);
|
|
8199
|
+
console.log(` Variant: ${createVariantRef("asset", variant.asset_id, variant.id)}`);
|
|
8164
8200
|
console.log(` Media: ${variant.media_key || variant.image_key || "-"}`);
|
|
8165
8201
|
if (variant.image_key && variant.media_key !== variant.image_key) console.log(` Image: ${variant.image_key}`);
|
|
8166
8202
|
console.log(` Local: ${outputPath}`);
|
|
@@ -8168,8 +8204,12 @@ function printResult(result, outputPath, ctx, manifestPath) {
|
|
|
8168
8204
|
console.log(` Web: ${ctx.baseUrl}/spaces/${ctx.spaceId}/assets/${variant.asset_id}`);
|
|
8169
8205
|
}
|
|
8170
8206
|
function printFollowHint(started, ctx, outputPath, command, mediaKind, options = {}) {
|
|
8171
|
-
|
|
8172
|
-
console.log(`
|
|
8207
|
+
const variantRef = compactStartedVariantRef(started);
|
|
8208
|
+
console.log(` Started variant: ${variantRef}`);
|
|
8209
|
+
console.log(` Follow: ${formatFollowCommand(variantRef, outputPath, ctx, command, mediaKind, options)}`);
|
|
8210
|
+
}
|
|
8211
|
+
function compactStartedVariantRef(started) {
|
|
8212
|
+
return createVariantRef(started.assetName || "asset", started.assetId || "asset", started.jobId);
|
|
8173
8213
|
}
|
|
8174
8214
|
function throwGenerationWaitErrorIfNeeded(input, params) {
|
|
8175
8215
|
if (!isGenerationWaitTimeout(input)) throw input;
|
|
@@ -8237,7 +8277,7 @@ function formatFollowCommand(variantId, outputPath, ctx, command, mediaKind, opt
|
|
|
8237
8277
|
].map(shellQuote).join(" ");
|
|
8238
8278
|
}
|
|
8239
8279
|
function shellQuote(value) {
|
|
8240
|
-
if (/^[A-Za-z0-9_
|
|
8280
|
+
if (/^[A-Za-z0-9_./:=@~-]+$/.test(value)) return value;
|
|
8241
8281
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
8242
8282
|
}
|
|
8243
8283
|
function getPrompt(parsed, command) {
|
|
@@ -8309,16 +8349,21 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
|
|
|
8309
8349
|
if (mediaKind !== "video" && resolutionValue === void 0 && durationValue === void 0 && tierValue === void 0 && aspectValue === void 0) return {};
|
|
8310
8350
|
if (mediaKind !== "video") throw new Error("--resolution, --duration, and --tier are only supported for video generation");
|
|
8311
8351
|
const videoResolution = resolutionValue === void 0 ? void 0 : normalizeVideoGenerationResolution(resolutionValue);
|
|
8312
|
-
if (resolutionValue !== void 0 && !videoResolution) throw new Error("--resolution must be 720p, 1080p, or 4k");
|
|
8352
|
+
if (resolutionValue !== void 0 && !videoResolution) throw new Error("--resolution must be 480p, 720p, 1080p, or 4k");
|
|
8313
8353
|
const videoDurationSeconds = durationValue === void 0 ? void 0 : normalizeVideoGenerationDurationSeconds(durationValue);
|
|
8314
|
-
if (durationValue !== void 0 && !videoDurationSeconds) throw new Error("--duration must be 4
|
|
8354
|
+
if (durationValue !== void 0 && !videoDurationSeconds) throw new Error("--duration must be an integer from 4 to 15");
|
|
8315
8355
|
const videoTier = tierValue === void 0 ? void 0 : normalizeVideoGenerationTier(tierValue);
|
|
8316
8356
|
if (tierValue !== void 0 && !videoTier) throw new Error("--tier must be generate, fast, or lite");
|
|
8317
8357
|
const model = parseVideoModelOption(modelValue, videoTier);
|
|
8318
8358
|
if (isGeminiOmniVideoGenerationModel(model) && (resolutionValue !== void 0 || durationValue !== void 0 || tierValue !== void 0)) throw new Error("--resolution, --duration, and --tier are only supported with --model veo-3.1");
|
|
8319
8359
|
if ((isKlingVideoGenerationModel(model) || isFalVideoGenerationModel(model)) && tierValue !== void 0) throw new Error("--tier is only supported with --model veo-3.1");
|
|
8320
8360
|
if (videoResolution && videoTier && !isVideoGenerationResolutionSupportedForTier(videoResolution, videoTier)) throw new Error("--resolution 4k is not supported with --tier lite");
|
|
8321
|
-
if (videoResolution && (isKlingVideoGenerationModel(model) || isFalVideoGenerationModel(model)) && !isVideoGenerationResolutionSupportedForModel(model, videoResolution)) throw new Error(`--model ${getVideoModelSelectionForModel(model) ?? model}
|
|
8361
|
+
if (videoResolution && (isKlingVideoGenerationModel(model) || isFalVideoGenerationModel(model)) && !isVideoGenerationResolutionSupportedForModel(model, videoResolution)) throw new Error(`--model ${getVideoModelSelectionForModel(model) ?? model} does not support --resolution ${videoResolution}`);
|
|
8362
|
+
if (!isFalSeedance2VideoGenerationModel(model) && videoDurationSeconds && ![
|
|
8363
|
+
4,
|
|
8364
|
+
6,
|
|
8365
|
+
8
|
|
8366
|
+
].includes(videoDurationSeconds)) throw new Error("--duration must be 4, 6, or 8 for this model");
|
|
8322
8367
|
const aspectRatio = aspectValue === void 0 ? void 0 : normalizeVideoGenerationAspectRatio(aspectValue);
|
|
8323
8368
|
if (aspectValue !== void 0 && !aspectRatio) throw new Error("--aspect must be 16:9 or 9:16");
|
|
8324
8369
|
return {
|
|
@@ -8346,7 +8391,8 @@ function validateVideoFrameReferenceOptions(command, parsed, mediaKind) {
|
|
|
8346
8391
|
const tierValue = readOptionalOption(parsed, "tier", "tier") ?? readOptionalOption(parsed, "video-tier", "videoTier");
|
|
8347
8392
|
const videoTier = tierValue === void 0 ? void 0 : normalizeVideoGenerationTier(tierValue);
|
|
8348
8393
|
const model = parseVideoModelOption(readOptionalOption(parsed, "model", "model"), videoTier);
|
|
8349
|
-
if (
|
|
8394
|
+
if (isFalSeedance2VideoGenerationModel(model) && !firstFrame) throw new Error("--model seedance-2 requires --first-frame");
|
|
8395
|
+
if (!isFalSeedance2VideoGenerationModel(model) && (isFalVideoGenerationModel(model) || isGeminiOmniVideoGenerationModel(model) || isKlingVideoGenerationModel(model) && Boolean(lastFrame))) throw new Error("--first-frame and --last-frame are only supported with --model veo-3.1 or seedance-2");
|
|
8350
8396
|
}
|
|
8351
8397
|
function readVideoFrameOption(parsed, kebabName, camelName) {
|
|
8352
8398
|
const value = parsed.options[kebabName] ?? parsed.options[camelName];
|
|
@@ -8669,8 +8715,8 @@ function parseVideoCommand(value) {
|
|
|
8669
8715
|
}
|
|
8670
8716
|
function printUsage$7() {
|
|
8671
8717
|
const aspectValues = VIDEO_GENERATION_ASPECT_RATIOS.join("|");
|
|
8672
|
-
const resolutionValues = Array.from(new Set(VIDEO_GENERATION_TIERS.flatMap((tier) => getVideoGenerationResolutionsForTier(tier)))).join("|");
|
|
8673
|
-
const durationValues = VIDEO_GENERATION_DURATION_SECONDS.join("|");
|
|
8718
|
+
const resolutionValues = Array.from(new Set(["480p", ...VIDEO_GENERATION_TIERS.flatMap((tier) => getVideoGenerationResolutionsForTier(tier))])).join("|");
|
|
8719
|
+
const durationValues = Array.from(new Set([...VIDEO_GENERATION_DURATION_SECONDS, ...SEEDANCE_2_DURATION_SECONDS])).join("|");
|
|
8674
8720
|
const tierValues = VIDEO_GENERATION_TIERS.join("|");
|
|
8675
8721
|
const modelValues = (operation) => VIDEO_MODEL_SELECTIONS.filter((model) => VIDEO_MODEL_SUPPORTED_OPERATIONS[model].includes(operation)).join("|");
|
|
8676
8722
|
const resolutionByTier = VIDEO_GENERATION_TIERS.map((tier) => `${tier}: ${getVideoGenerationResolutionsForTier(tier).join(", ")}`).join("; ");
|
|
@@ -8681,21 +8727,22 @@ Usage:
|
|
|
8681
8727
|
makefx video refine --variant <variant_id> "prompt" -o <file> [--model ${modelValues("refine")}] [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
|
|
8682
8728
|
makefx video refine --follow <variant_id> -o <file> [--space <id>]
|
|
8683
8729
|
makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--model ${modelValues("derive")}] [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
|
|
8684
|
-
makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--model veo-3.1] [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
|
|
8730
|
+
makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--model veo-3.1|seedance-2|seedance-2-fast] [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
|
|
8685
8731
|
makefx video derive --follow <variant_id> -o <file> [--space <id>]
|
|
8686
8732
|
|
|
8687
8733
|
Video:
|
|
8688
8734
|
--model <value> Generate: ${modelValues("generate")}; refine/derive: ${modelValues("refine")}
|
|
8689
8735
|
--aspect <ratio> Video aspect ratio: ${aspectValues}
|
|
8690
|
-
--resolution <value>
|
|
8691
|
-
--duration <seconds> Veo/Kling
|
|
8736
|
+
--resolution <value> Supported: ${resolutionValues}; Veo: 720p|1080p|4k; Kling: 720p|1080p; Seedance 2: standard 480p|720p|1080p, fast 480p|720p (${resolutionByTier})
|
|
8737
|
+
--duration <seconds> Veo/Kling: ${VIDEO_GENERATION_DURATION_SECONDS.join("|")}; Seedance 2: ${SEEDANCE_2_DURATION_SECONDS.join("|")}
|
|
8692
8738
|
--tier <tier> Veo-only model tier: ${tierValues}
|
|
8693
|
-
--first-frame <ref> Veo start frame image variant or local image path
|
|
8694
|
-
--last-frame <ref> Veo final frame image variant or local image path
|
|
8739
|
+
--first-frame <ref> Veo or Seedance 2 start frame image variant or local image path
|
|
8740
|
+
--last-frame <ref> Veo or Seedance 2 final frame image variant or local image path
|
|
8695
8741
|
|
|
8696
|
-
|
|
8742
|
+
Frame inputs:
|
|
8697
8743
|
--first-frame resolves to the first referenceVariantId and becomes the Veo top-level image input.
|
|
8698
|
-
--last-frame resolves to the second referenceVariantId and becomes Veo config.lastFrame.
|
|
8744
|
+
--last-frame resolves to the second referenceVariantId and becomes Veo config.lastFrame or Seedance 2 end_image_url.
|
|
8745
|
+
Seedance 2 requires --first-frame and supports an optional --last-frame.
|
|
8699
8746
|
Use both flags together for first/last-frame generation; --last-frame requires --first-frame.
|
|
8700
8747
|
Do not combine frame flags with --refs. Use --refs when you want generic Veo reference images instead of first/last-frame inputs.
|
|
8701
8748
|
|
|
@@ -8944,10 +8991,10 @@ async function executeAssets(parsed, deps = defaultDeps$5) {
|
|
|
8944
8991
|
};
|
|
8945
8992
|
}
|
|
8946
8993
|
if (subcommand === "show") {
|
|
8947
|
-
const
|
|
8948
|
-
if (!
|
|
8949
|
-
const details = await getAssetDetails(ctx, deps,
|
|
8950
|
-
if (parsed.options.json === "true") deps.print(JSON.stringify(details, null, 2));
|
|
8994
|
+
const identifier = parsed.positionals[1];
|
|
8995
|
+
if (!identifier) throw new Error("Asset ID is required: makefx assets show <asset-id>");
|
|
8996
|
+
const details = await getAssetDetails(ctx, deps, await resolveAssetAtBoundary(ctx, deps, identifier));
|
|
8997
|
+
if (parsed.options.json === "true") deps.print(JSON.stringify(toAssetDetailsJson(details), null, 2));
|
|
8951
8998
|
else printAssetDetails(details, ctx, deps.print);
|
|
8952
8999
|
return {
|
|
8953
9000
|
type: "show",
|
|
@@ -8955,10 +9002,10 @@ async function executeAssets(parsed, deps = defaultDeps$5) {
|
|
|
8955
9002
|
};
|
|
8956
9003
|
}
|
|
8957
9004
|
if (subcommand === "download") {
|
|
8958
|
-
const
|
|
8959
|
-
if (!
|
|
9005
|
+
const identifier = parsed.positionals[1];
|
|
9006
|
+
if (!identifier) throw new Error("Variant ID or legacy image key is required: makefx assets download <variant-id-or-legacy-image-key> -o <file>");
|
|
8960
9007
|
const outputPath = getOutputPath(parsed);
|
|
8961
|
-
const resolved = resolveDownloadRef(
|
|
9008
|
+
const resolved = resolveDownloadRef(await resolveVariantAtBoundary$1(ctx, deps, identifier), ctx);
|
|
8962
9009
|
let download;
|
|
8963
9010
|
try {
|
|
8964
9011
|
download = await deps.downloadFile({
|
|
@@ -8989,8 +9036,9 @@ async function executeAssets(parsed, deps = defaultDeps$5) {
|
|
|
8989
9036
|
};
|
|
8990
9037
|
}
|
|
8991
9038
|
if (subcommand === "delete") {
|
|
8992
|
-
const
|
|
8993
|
-
if (!
|
|
9039
|
+
const identifier = parsed.positionals[1];
|
|
9040
|
+
if (!identifier) throw new Error("Asset ID is required: makefx assets delete <asset-id>");
|
|
9041
|
+
const assetId = await resolveAssetAtBoundary(ctx, deps, identifier);
|
|
8994
9042
|
await withAssetClient(ctx, deps, (client) => client.deleteAsset(assetId));
|
|
8995
9043
|
deps.print(`Deleted asset ${assetId}`);
|
|
8996
9044
|
return {
|
|
@@ -8999,9 +9047,10 @@ async function executeAssets(parsed, deps = defaultDeps$5) {
|
|
|
8999
9047
|
};
|
|
9000
9048
|
}
|
|
9001
9049
|
if (subcommand === "rename") {
|
|
9002
|
-
const
|
|
9050
|
+
const identifier = parsed.positionals[1];
|
|
9003
9051
|
const name = parsed.positionals[2];
|
|
9004
|
-
if (!
|
|
9052
|
+
if (!identifier || !name) throw new Error("Usage: makefx assets rename <asset-id> \"<new-name>\"");
|
|
9053
|
+
const assetId = await resolveAssetAtBoundary(ctx, deps, identifier);
|
|
9005
9054
|
const asset = await withAssetClient(ctx, deps, (client) => client.renameAsset(assetId, name));
|
|
9006
9055
|
deps.print(`Renamed asset ${assetId} -> "${asset.name}"`);
|
|
9007
9056
|
return {
|
|
@@ -9010,10 +9059,11 @@ async function executeAssets(parsed, deps = defaultDeps$5) {
|
|
|
9010
9059
|
};
|
|
9011
9060
|
}
|
|
9012
9061
|
if (subcommand === "set-active") {
|
|
9013
|
-
const
|
|
9014
|
-
const
|
|
9015
|
-
if (!
|
|
9016
|
-
const
|
|
9062
|
+
const assetIdentifier = parsed.positionals[1];
|
|
9063
|
+
const variantIdentifier = parsed.positionals[2] || normalizeOption$1(parsed.options.variant);
|
|
9064
|
+
if (!assetIdentifier || !variantIdentifier) throw new Error("Usage: makefx assets set-active <asset-id> <variant-id>");
|
|
9065
|
+
const assetId = await resolveAssetAtBoundary(ctx, deps, assetIdentifier);
|
|
9066
|
+
const asset = await setActiveVariant(ctx, deps, assetId, await resolveVariantAtBoundary$1(ctx, deps, variantIdentifier));
|
|
9017
9067
|
deps.print(`Set active variant of asset ${assetId} to ${asset.active_variant_id}`);
|
|
9018
9068
|
return {
|
|
9019
9069
|
type: "set-active",
|
|
@@ -9043,6 +9093,15 @@ async function buildContext$5(parsed, deps) {
|
|
|
9043
9093
|
projectRoot: projectConfig?.projectRoot
|
|
9044
9094
|
};
|
|
9045
9095
|
}
|
|
9096
|
+
function createReferenceClient(ctx, deps) {
|
|
9097
|
+
return () => deps.createMutationClient(ctx.env, ctx.spaceId);
|
|
9098
|
+
}
|
|
9099
|
+
function resolveAssetAtBoundary(ctx, deps, identifier) {
|
|
9100
|
+
return resolveCliAssetIdentifier(identifier, createReferenceClient(ctx, deps));
|
|
9101
|
+
}
|
|
9102
|
+
function resolveVariantAtBoundary$1(ctx, deps, identifier) {
|
|
9103
|
+
return resolveCliVariantIdentifier(identifier, createReferenceClient(ctx, deps));
|
|
9104
|
+
}
|
|
9046
9105
|
async function buildAuthContext(parsed, deps) {
|
|
9047
9106
|
const env = resolveCommandEnvironment(parsed, await deps.loadProjectConfig());
|
|
9048
9107
|
const config = await deps.loadConfig(env);
|
|
@@ -9076,7 +9135,11 @@ async function searchAssets(parsed, deps) {
|
|
|
9076
9135
|
const response = await deps.fetch(`${ctx.baseUrl}/api/assets/search?${params.toString()}`, { headers: { Authorization: `Bearer ${ctx.accessToken}` } });
|
|
9077
9136
|
if (!response.ok) throw new Error(`Search failed: ${response.status} - ${await response.text()}`);
|
|
9078
9137
|
const results = (await response.json()).results ?? [];
|
|
9079
|
-
if (parsed.options.json === "true") deps.print(JSON.stringify(results
|
|
9138
|
+
if (parsed.options.json === "true") deps.print(JSON.stringify(results.map((result) => ({
|
|
9139
|
+
...result,
|
|
9140
|
+
assetRef: createAssetRef(result.assetName, result.assetId),
|
|
9141
|
+
variantRef: result.activeVariantId ? createVariantRef(result.assetName, result.assetId, result.activeVariantId) : null
|
|
9142
|
+
})), null, 2));
|
|
9080
9143
|
else printAssetSearchResults(results, deps.print);
|
|
9081
9144
|
return {
|
|
9082
9145
|
type: "search",
|
|
@@ -9085,10 +9148,11 @@ async function searchAssets(parsed, deps) {
|
|
|
9085
9148
|
}
|
|
9086
9149
|
async function cloneAsset(parsed, deps) {
|
|
9087
9150
|
const ctx = await buildAuthContext(parsed, deps);
|
|
9088
|
-
const
|
|
9089
|
-
if (!
|
|
9151
|
+
const sourceVariantIdentifier = parsed.positionals[1] ?? normalizeOption$1(parsed.options.variant);
|
|
9152
|
+
if (!sourceVariantIdentifier) throw new Error("Usage: makefx assets clone <variant-id> --from-space <source-space-id> --to-space <target-space-id>");
|
|
9090
9153
|
const sourceSpaceId = requireOption(parsed, ["from-space", "source-space"], "Usage: makefx assets clone <variant-id> --from-space <source-space-id> --to-space <target-space-id>");
|
|
9091
9154
|
const targetSpaceId = requireOption(parsed, ["to-space", "target-space"], "Usage: makefx assets clone <variant-id> --from-space <source-space-id> --to-space <target-space-id>");
|
|
9155
|
+
const sourceVariantId = await resolveCliVariantIdentifier(sourceVariantIdentifier, () => deps.createMutationClient(ctx.env, sourceSpaceId));
|
|
9092
9156
|
const body = {
|
|
9093
9157
|
sourceSpaceId,
|
|
9094
9158
|
sourceVariantId
|
|
@@ -9107,14 +9171,20 @@ async function cloneAsset(parsed, deps) {
|
|
|
9107
9171
|
});
|
|
9108
9172
|
if (!response.ok) throw new Error(`Clone failed: ${response.status} - ${await response.text()}`);
|
|
9109
9173
|
const payload = await response.json();
|
|
9110
|
-
|
|
9174
|
+
const clonedAsset = payload.asset;
|
|
9175
|
+
const clonedVariantPayload = payload.variant;
|
|
9176
|
+
const clonedVariant = clonedVariantPayload?.variant ?? clonedVariantPayload;
|
|
9177
|
+
const clonedAssetRef = clonedAsset?.id ? createAssetRef(clonedAsset.name ?? "asset", clonedAsset.id) : void 0;
|
|
9178
|
+
const clonedVariantRef = clonedAsset?.id && clonedVariant?.id ? createVariantRef(clonedAsset.name ?? "asset", clonedAsset.id, clonedVariant.id) : void 0;
|
|
9179
|
+
if (parsed.options.json === "true") deps.print(JSON.stringify({
|
|
9180
|
+
...payload,
|
|
9181
|
+
assetRef: clonedAssetRef,
|
|
9182
|
+
variantRef: clonedVariantRef
|
|
9183
|
+
}, null, 2));
|
|
9111
9184
|
else {
|
|
9112
|
-
const asset = payload.asset;
|
|
9113
|
-
const variantPayload = payload.variant;
|
|
9114
|
-
const variant = variantPayload?.variant ?? variantPayload;
|
|
9115
9185
|
deps.print(`Cloned variant ${sourceVariantId} into space ${targetSpaceId}`);
|
|
9116
|
-
if (
|
|
9117
|
-
if (
|
|
9186
|
+
if (clonedAssetRef) deps.print(` Asset: ${clonedAssetRef}`);
|
|
9187
|
+
if (clonedVariantRef) deps.print(` Variant: ${clonedVariantRef}`);
|
|
9118
9188
|
}
|
|
9119
9189
|
return {
|
|
9120
9190
|
type: "clone",
|
|
@@ -9292,9 +9362,13 @@ function printAssetList(assets, print) {
|
|
|
9292
9362
|
return;
|
|
9293
9363
|
}
|
|
9294
9364
|
print(`Found ${assets.length} asset(s):\n`);
|
|
9295
|
-
print("Updated".padEnd(21) + "Type".padEnd(14) + "Media".padEnd(9) + "Active Variant".padEnd(
|
|
9296
|
-
print("-".repeat(
|
|
9297
|
-
for (const asset of assets)
|
|
9365
|
+
print("Updated".padEnd(21) + "Type".padEnd(14) + "Media".padEnd(9) + "Active Variant Reference".padEnd(54) + "Asset Reference".padEnd(54) + "Name");
|
|
9366
|
+
print("-".repeat(167));
|
|
9367
|
+
for (const asset of assets) {
|
|
9368
|
+
const assetRef = createAssetRef(asset.name, asset.id);
|
|
9369
|
+
const activeVariantRef = asset.active_variant_id ? createVariantRef(asset.name, asset.id, asset.active_variant_id) : "-";
|
|
9370
|
+
print(formatTimestamp(asset.updated_at).padEnd(21) + truncate(asset.type || "unknown", 12).padEnd(14) + truncate(asset.media_kind || "-", 7).padEnd(9) + activeVariantRef.padEnd(54) + assetRef.padEnd(54) + truncate(asset.name, 32));
|
|
9371
|
+
}
|
|
9298
9372
|
}
|
|
9299
9373
|
function printAssetSearchResults(results, print) {
|
|
9300
9374
|
if (results.length === 0) {
|
|
@@ -9302,16 +9376,17 @@ function printAssetSearchResults(results, print) {
|
|
|
9302
9376
|
return;
|
|
9303
9377
|
}
|
|
9304
9378
|
for (const result of results) {
|
|
9305
|
-
print(`${result.assetName}
|
|
9379
|
+
print(`${createAssetRef(result.assetName, result.assetId)} — ${result.assetName}`);
|
|
9306
9380
|
print(` Space: ${result.spaceName} (${result.spaceId})`);
|
|
9307
9381
|
print(` Type: ${result.assetType ?? "-"} Media: ${result.mediaKind}`);
|
|
9308
|
-
print(` Active: ${result.activeVariantId
|
|
9382
|
+
print(` Active: ${result.activeVariantId ? createVariantRef(result.assetName, result.assetId, result.activeVariantId) : "-"}${result.activeVariantStatus ? ` (${result.activeVariantStatus})` : ""}`);
|
|
9309
9383
|
print(` Counts: variants=${result.variantCount} completed=${result.completedVariantCount} starred=${result.starredVariantCount}`);
|
|
9310
9384
|
}
|
|
9311
9385
|
}
|
|
9312
9386
|
function printAssetDetails(details, ctx, print) {
|
|
9313
9387
|
const { asset, variants, lineage } = details;
|
|
9314
|
-
print(`\nAsset ${asset.id}\n`);
|
|
9388
|
+
print(`\nAsset ${createAssetRef(asset.name, asset.id)}\n`);
|
|
9389
|
+
print(` ID: ${asset.id}`);
|
|
9315
9390
|
print(` Name: ${asset.name}`);
|
|
9316
9391
|
print(` Type: ${asset.type || "unknown"}`);
|
|
9317
9392
|
print(` Media: ${asset.media_kind || "-"}`);
|
|
@@ -9322,7 +9397,8 @@ function printAssetDetails(details, ctx, print) {
|
|
|
9322
9397
|
if (variants.length > 0) {
|
|
9323
9398
|
print("\nVariants:");
|
|
9324
9399
|
for (const variant of [...variants].sort((a, b) => (b.updated_at || 0) - (a.updated_at || 0))) {
|
|
9325
|
-
print(` ${variant.id === asset.active_variant_id ? "*" : " "} ${variant.id}`);
|
|
9400
|
+
print(` ${variant.id === asset.active_variant_id ? "*" : " "} ${createVariantRef(asset.name, asset.id, variant.id)}`);
|
|
9401
|
+
print(` ID: ${variant.id}`);
|
|
9326
9402
|
print(` Status: ${variant.status}`);
|
|
9327
9403
|
print(` Media: ${variant.media_kind || "-"}`);
|
|
9328
9404
|
print(` File: ${variant.media_key || variant.image_key || "-"}`);
|
|
@@ -9365,7 +9441,21 @@ function toAssetJson(asset) {
|
|
|
9365
9441
|
media_kind: asset.media_kind || null,
|
|
9366
9442
|
activeVariantId: asset.active_variant_id,
|
|
9367
9443
|
createdAt: asset.created_at || null,
|
|
9368
|
-
updatedAt: asset.updated_at || null
|
|
9444
|
+
updatedAt: asset.updated_at || null,
|
|
9445
|
+
assetRef: createAssetRef(asset.name, asset.id)
|
|
9446
|
+
};
|
|
9447
|
+
}
|
|
9448
|
+
function toAssetDetailsJson(details) {
|
|
9449
|
+
return {
|
|
9450
|
+
...details,
|
|
9451
|
+
asset: {
|
|
9452
|
+
...details.asset,
|
|
9453
|
+
assetRef: createAssetRef(details.asset.name, details.asset.id)
|
|
9454
|
+
},
|
|
9455
|
+
variants: details.variants.map((variant) => ({
|
|
9456
|
+
...variant,
|
|
9457
|
+
variantRef: createVariantRef(details.asset.name, details.asset.id, variant.id)
|
|
9458
|
+
}))
|
|
9369
9459
|
};
|
|
9370
9460
|
}
|
|
9371
9461
|
function formatMetadataSummary(value, preferredKeys) {
|
|
@@ -9432,7 +9522,7 @@ async function executeVariants(parsed, deps = defaultDeps$4) {
|
|
|
9432
9522
|
const ctx = await buildContext$4(parsed, deps);
|
|
9433
9523
|
const subcommand = parsed.positionals[0];
|
|
9434
9524
|
if (subcommand === "delete") {
|
|
9435
|
-
const variantId = requireVariantId(parsed, "delete");
|
|
9525
|
+
const variantId = await resolveVariantAtBoundary(ctx, deps, requireVariantId(parsed, "delete"));
|
|
9436
9526
|
await withVariantClient(ctx, deps, (client) => client.deleteVariant(variantId));
|
|
9437
9527
|
deps.print(`Deleted variant ${variantId}`);
|
|
9438
9528
|
return {
|
|
@@ -9441,9 +9531,11 @@ async function executeVariants(parsed, deps = defaultDeps$4) {
|
|
|
9441
9531
|
};
|
|
9442
9532
|
}
|
|
9443
9533
|
if (subcommand === "retry") {
|
|
9444
|
-
const variantId = requireVariantId(parsed, "retry");
|
|
9534
|
+
const variantId = await resolveVariantAtBoundary(ctx, deps, requireVariantId(parsed, "retry"));
|
|
9445
9535
|
const variant = await withVariantClient(ctx, deps, (client) => client.retryVariant(variantId));
|
|
9446
|
-
|
|
9536
|
+
const variantRef = createVariantRef("asset", variant.asset_id, variant.id);
|
|
9537
|
+
const assetRef = createAssetRef("asset", variant.asset_id);
|
|
9538
|
+
deps.print(`Re-queued variant ${variantRef} (status: ${variant.status}). Watch progress with: assets show ${assetRef}`);
|
|
9447
9539
|
return {
|
|
9448
9540
|
type: "retry",
|
|
9449
9541
|
variant
|
|
@@ -9451,7 +9543,7 @@ async function executeVariants(parsed, deps = defaultDeps$4) {
|
|
|
9451
9543
|
}
|
|
9452
9544
|
if (subcommand === "star" || subcommand === "unstar") {
|
|
9453
9545
|
const starred = subcommand === "star";
|
|
9454
|
-
const variantId = requireVariantId(parsed, subcommand);
|
|
9546
|
+
const variantId = await resolveVariantAtBoundary(ctx, deps, requireVariantId(parsed, subcommand));
|
|
9455
9547
|
const variant = await withVariantClient(ctx, deps, (client) => client.starVariant(variantId, starred));
|
|
9456
9548
|
deps.print(`${starred ? "Starred" : "Unstarred"} variant ${variantId}`);
|
|
9457
9549
|
return {
|
|
@@ -9460,9 +9552,10 @@ async function executeVariants(parsed, deps = defaultDeps$4) {
|
|
|
9460
9552
|
};
|
|
9461
9553
|
}
|
|
9462
9554
|
if (subcommand === "rate") {
|
|
9463
|
-
const
|
|
9555
|
+
const variantIdentifier = parsed.positionals[1];
|
|
9464
9556
|
const rating = parsed.positionals[2];
|
|
9465
|
-
if (!
|
|
9557
|
+
if (!variantIdentifier || rating !== "approved" && rating !== "rejected") throw new Error("Usage: makefx variants rate <variant-id> <approved|rejected>");
|
|
9558
|
+
const variantId = await resolveVariantAtBoundary(ctx, deps, variantIdentifier);
|
|
9466
9559
|
const variant = await withVariantClient(ctx, deps, (client) => client.rateVariant(variantId, rating));
|
|
9467
9560
|
deps.print(`Rated variant ${variantId} as ${rating}`);
|
|
9468
9561
|
return {
|
|
@@ -9491,6 +9584,9 @@ async function buildContext$4(parsed, deps) {
|
|
|
9491
9584
|
spaceId
|
|
9492
9585
|
};
|
|
9493
9586
|
}
|
|
9587
|
+
function resolveVariantAtBoundary(ctx, deps, identifier) {
|
|
9588
|
+
return resolveCliVariantIdentifier(identifier, () => deps.createMutationClient(ctx.env, ctx.spaceId));
|
|
9589
|
+
}
|
|
9494
9590
|
async function withVariantClient(ctx, deps, run) {
|
|
9495
9591
|
const client = await deps.createMutationClient(ctx.env, ctx.spaceId);
|
|
9496
9592
|
await client.connect();
|
|
@@ -9522,6 +9618,7 @@ var defaultDeps$3 = {
|
|
|
9522
9618
|
loadProjectConfig,
|
|
9523
9619
|
resolveBaseUrl,
|
|
9524
9620
|
fetch,
|
|
9621
|
+
createStateClient: (env, spaceId) => WebSocketClient.create(env, spaceId),
|
|
9525
9622
|
print: console.log
|
|
9526
9623
|
};
|
|
9527
9624
|
async function handleRecipes(parsed) {
|
|
@@ -9536,15 +9633,22 @@ async function handleRecipes(parsed) {
|
|
|
9536
9633
|
async function executeRecipes(parsed, deps = defaultDeps$3) {
|
|
9537
9634
|
const subcommand = parsed.positionals[0];
|
|
9538
9635
|
if (subcommand !== "run") throw new Error(`Unknown recipes command: ${subcommand ?? "(none)"}`);
|
|
9539
|
-
const
|
|
9540
|
-
if (!
|
|
9541
|
-
const
|
|
9542
|
-
|
|
9636
|
+
const sourceVariantIdentifier = parsed.positionals[1];
|
|
9637
|
+
if (!sourceVariantIdentifier) throw new Error("Variant ID is required: makefx recipes run <variant-id>");
|
|
9638
|
+
const ctx = await buildContext$3(parsed, deps);
|
|
9639
|
+
const rerun = await runRecipe(ctx, deps, await resolveCliVariantIdentifier(sourceVariantIdentifier, () => (deps.createStateClient ?? defaultDeps$3.createStateClient)(ctx.env, ctx.spaceId)));
|
|
9640
|
+
const assetRef = createAssetRef("asset", rerun.variant.asset_id);
|
|
9641
|
+
const variantRef = createVariantRef("asset", rerun.variant.asset_id, rerun.variant.id);
|
|
9642
|
+
if (parsed.options.json === "true") deps.print(JSON.stringify({
|
|
9643
|
+
...rerun,
|
|
9644
|
+
assetRef,
|
|
9645
|
+
variantRef
|
|
9646
|
+
}, null, 2));
|
|
9543
9647
|
else {
|
|
9544
9648
|
deps.print(`Re-ran recipe from variant ${rerun.sourceVariantId}`);
|
|
9545
|
-
deps.print(` Variant: ${
|
|
9649
|
+
deps.print(` Variant: ${variantRef} (status: ${rerun.variant.status})`);
|
|
9546
9650
|
deps.print(` Request: ${rerun.requestId}`);
|
|
9547
|
-
deps.print(`Watch progress with: makefx assets show ${
|
|
9651
|
+
deps.print(`Watch progress with: makefx assets show ${assetRef}`);
|
|
9548
9652
|
}
|
|
9549
9653
|
return {
|
|
9550
9654
|
type: "run",
|
|
@@ -9561,6 +9665,7 @@ async function buildContext$3(parsed, deps) {
|
|
|
9561
9665
|
if (config.token.expiresAt < Date.now()) throw new Error(`Token expired for ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
|
|
9562
9666
|
if (env === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
9563
9667
|
return {
|
|
9668
|
+
env,
|
|
9564
9669
|
spaceId,
|
|
9565
9670
|
baseUrl: deps.resolveBaseUrl(env),
|
|
9566
9671
|
accessToken: config.token.accessToken
|
|
@@ -9675,13 +9780,16 @@ async function executeCollections(parsed, deps = defaultDeps$2) {
|
|
|
9675
9780
|
const collectionId = parsed.positionals[1];
|
|
9676
9781
|
const assetId = parsed.positionals[2] || normalizeOption(parsed.options.asset);
|
|
9677
9782
|
if (!collectionId || !assetId) throw new Error("Usage: makefx collections add-asset <collection-id> <asset-id>");
|
|
9783
|
+
const resolvedAssetId = await resolveCliAssetIdentifier(assetId, () => deps.createMutationClient(ctx.env, ctx.spaceId));
|
|
9784
|
+
const pinnedIdentifier = parseNullableOption(parsed.options.variant ?? parsed.options["pinned-variant"]);
|
|
9785
|
+
const pinnedVariantId = pinnedIdentifier ? await resolveCliVariantIdentifier(pinnedIdentifier, () => deps.createMutationClient(ctx.env, ctx.spaceId)) : null;
|
|
9678
9786
|
const item = await withCollectionClient(ctx, deps, (client) => client.createCollectionItem({
|
|
9679
9787
|
collectionId,
|
|
9680
9788
|
id: normalizeOption(parsed.options.id),
|
|
9681
9789
|
subjectType: "asset",
|
|
9682
|
-
assetId,
|
|
9790
|
+
assetId: resolvedAssetId,
|
|
9683
9791
|
role: normalizeOption(parsed.options.role),
|
|
9684
|
-
pinnedVariantId
|
|
9792
|
+
pinnedVariantId,
|
|
9685
9793
|
sortIndex: parseOptionalInteger(parsed.options["sort-index"], "sort-index")
|
|
9686
9794
|
}));
|
|
9687
9795
|
printJsonOrLine(parsed, deps, item, `Added asset ${assetId} to collection ${collectionId} as item ${item.id}`);
|
|
@@ -9694,11 +9802,12 @@ async function executeCollections(parsed, deps = defaultDeps$2) {
|
|
|
9694
9802
|
const collectionId = parsed.positionals[1];
|
|
9695
9803
|
const variantId = parsed.positionals[2] || normalizeOption(parsed.options.variant);
|
|
9696
9804
|
if (!collectionId || !variantId) throw new Error("Usage: makefx collections add-variant <collection-id> <variant-id>");
|
|
9805
|
+
const resolvedVariantId = await resolveCliVariantIdentifier(variantId, () => deps.createMutationClient(ctx.env, ctx.spaceId));
|
|
9697
9806
|
const item = await withCollectionClient(ctx, deps, (client) => client.createCollectionItem({
|
|
9698
9807
|
collectionId,
|
|
9699
9808
|
id: normalizeOption(parsed.options.id),
|
|
9700
9809
|
subjectType: "variant",
|
|
9701
|
-
variantId,
|
|
9810
|
+
variantId: resolvedVariantId,
|
|
9702
9811
|
role: normalizeOption(parsed.options.role),
|
|
9703
9812
|
sortIndex: parseOptionalInteger(parsed.options["sort-index"], "sort-index")
|
|
9704
9813
|
}));
|
|
@@ -9910,6 +10019,7 @@ function printUsageSummary(summary, print) {
|
|
|
9910
10019
|
print(` Storage: ${formatBytes(summary.totals.storageBytes)}`);
|
|
9911
10020
|
print(` Workflow runs: ${summary.totals.workflowRuns}`);
|
|
9912
10021
|
print(` Delivery: ${formatBytes(summary.totals.deliveryBytes)}`);
|
|
10022
|
+
print(` Provider spend: $${summary.providerSpend.amountUsd.toFixed(6)} (${summary.providerSpend.entries} recorded entr${summary.providerSpend.entries === 1 ? "y" : "ies"}, ${summary.providerSpend.unpricedEntries} unpriced)`);
|
|
9913
10023
|
if (summary.byMediaKind.length > 0) {
|
|
9914
10024
|
print("\nBy media kind:");
|
|
9915
10025
|
print("Media".padEnd(10) + "Storage".padEnd(14) + "Workflows".padEnd(12) + "Delivery".padEnd(14) + "Events");
|
|
@@ -10139,7 +10249,7 @@ Options:
|
|
|
10139
10249
|
}
|
|
10140
10250
|
//#endregion
|
|
10141
10251
|
//#region src/cli/index.ts
|
|
10142
|
-
var CLI_VERSION = "1.
|
|
10252
|
+
var CLI_VERSION = "1.3.0+89c141a8883e";
|
|
10143
10253
|
async function main() {
|
|
10144
10254
|
const argv = process$1.argv.slice(2);
|
|
10145
10255
|
if (argv[0] === "--") argv.shift();
|
|
@@ -10193,19 +10303,19 @@ function imageCapabilityHelp(operation) {
|
|
|
10193
10303
|
--model <value> Image model: ${imageModelValues(operation)}
|
|
10194
10304
|
--size <value> Output size (${sizeLines})
|
|
10195
10305
|
--aspect <ratio> Aspect ratio: ${imageAspectValues()}
|
|
10196
|
-
--refs <refs>
|
|
10306
|
+
--refs <refs> Compact variant refs, raw IDs, or local image paths; limit (${referenceLines})
|
|
10197
10307
|
Model operations: ${operationLines}
|
|
10198
|
-
--follow <id>
|
|
10308
|
+
--follow <ref-or-id> Resume/download a variant after a long generation or disconnect
|
|
10199
10309
|
--collection <id> Place the completed asset in a Space collection`;
|
|
10200
10310
|
}
|
|
10201
10311
|
function videoResolutionValues() {
|
|
10202
|
-
return optionValues(uniqueValues(VIDEO_GENERATION_TIERS.flatMap((tier) => getVideoGenerationResolutionsForTier(tier))));
|
|
10312
|
+
return optionValues(uniqueValues(["480p", ...VIDEO_GENERATION_TIERS.flatMap((tier) => getVideoGenerationResolutionsForTier(tier))]));
|
|
10203
10313
|
}
|
|
10204
10314
|
function videoAspectValues() {
|
|
10205
10315
|
return optionValues(VIDEO_GENERATION_ASPECT_RATIOS);
|
|
10206
10316
|
}
|
|
10207
10317
|
function videoDurationValues() {
|
|
10208
|
-
return optionValues(VIDEO_GENERATION_DURATION_SECONDS);
|
|
10318
|
+
return optionValues(uniqueValues([...VIDEO_GENERATION_DURATION_SECONDS, ...SEEDANCE_2_DURATION_SECONDS]));
|
|
10209
10319
|
}
|
|
10210
10320
|
function videoTierValues() {
|
|
10211
10321
|
return optionValues(VIDEO_GENERATION_TIERS);
|
|
@@ -10219,18 +10329,19 @@ function videoCapabilityHelp(operation) {
|
|
|
10219
10329
|
return `Video:
|
|
10220
10330
|
--model <value> Video model: ${videoModelValues(operation)}
|
|
10221
10331
|
--aspect <ratio> Video aspect ratio: ${videoAspectValues()}
|
|
10222
|
-
--resolution <value>
|
|
10223
|
-
--duration <seconds> Veo/Kling
|
|
10332
|
+
--resolution <value> Supported: ${videoResolutionValues()}; Veo: 720p|1080p|4k; Kling: 720p|1080p; Seedance 2: standard 480p|720p|1080p, fast 480p|720p (${resolutionLines})
|
|
10333
|
+
--duration <seconds> Veo/Kling: ${optionValues(VIDEO_GENERATION_DURATION_SECONDS)}; Seedance 2: ${optionValues(SEEDANCE_2_DURATION_SECONDS)}
|
|
10224
10334
|
--tier <tier> Veo-only model tier: ${videoTierValues()}
|
|
10225
|
-
--first-frame <ref> Veo start frame
|
|
10226
|
-
--last-frame <ref> Veo final frame
|
|
10335
|
+
--first-frame <ref> Veo or Seedance 2 start frame compact ref, raw ID, or local image path
|
|
10336
|
+
--last-frame <ref> Veo or Seedance 2 final frame compact ref, raw ID, or local image path
|
|
10227
10337
|
Model operations: ${operationLines}
|
|
10228
|
-
--follow <id>
|
|
10338
|
+
--follow <ref-or-id> Resume/download a variant after a long generation or disconnect
|
|
10229
10339
|
--collection <id> Place the completed asset in a Space collection
|
|
10230
10340
|
|
|
10231
|
-
|
|
10341
|
+
Frame inputs:
|
|
10232
10342
|
--first-frame resolves to the first referenceVariantId and becomes the Veo top-level image input.
|
|
10233
|
-
--last-frame resolves to the second referenceVariantId and becomes Veo config.lastFrame.
|
|
10343
|
+
--last-frame resolves to the second referenceVariantId and becomes Veo config.lastFrame or Seedance 2 end_image_url.
|
|
10344
|
+
Seedance 2 requires --first-frame and supports an optional --last-frame.
|
|
10234
10345
|
Use both flags together for first/last-frame generation; --last-frame requires --first-frame.
|
|
10235
10346
|
Do not combine frame flags with --refs. Use --refs when you want generic Veo reference images instead of first/last-frame inputs.`;
|
|
10236
10347
|
}
|
|
@@ -10324,6 +10435,7 @@ Make Effects CLI
|
|
|
10324
10435
|
Generation model:
|
|
10325
10436
|
Assets are named things in a Space. Variants are generated or uploaded versions of one asset.
|
|
10326
10437
|
References are ordinary completed variants or local files. Lineage records how a variant was made.
|
|
10438
|
+
Asset and variant arguments accept compact refs (asset:name~prefix[@variant|@active]) or raw IDs.
|
|
10327
10439
|
|
|
10328
10440
|
Start:
|
|
10329
10441
|
login Authenticate
|
|
@@ -10469,7 +10581,7 @@ Usage:
|
|
|
10469
10581
|
|
|
10470
10582
|
Options:
|
|
10471
10583
|
--space <id> Target space ID; defaults from initialized project
|
|
10472
|
-
--asset <id>
|
|
10584
|
+
--asset <ref|id> Target asset compact ref or raw ID (upload as new variant)
|
|
10473
10585
|
--name <name> New asset name (creates asset + variant)
|
|
10474
10586
|
--type <type> Asset type for new assets (default: character)
|
|
10475
10587
|
--media-kind <k> Optional explicit kind: image, audio, or video
|
|
@@ -10478,8 +10590,8 @@ Options:
|
|
|
10478
10590
|
--provider <name> Provider provenance for uploaded media
|
|
10479
10591
|
--provider-metadata <json> Provider metadata JSON object
|
|
10480
10592
|
--generation-provenance <json> Extra provenance JSON object
|
|
10481
|
-
--source-variant <
|
|
10482
|
-
--source-variants <
|
|
10593
|
+
--source-variant <refs> Comma-separated compact refs or raw IDs for upload lineage
|
|
10594
|
+
--source-variants <refs> Alias for --source-variant
|
|
10483
10595
|
--relation-type <type> Lineage type: derived, refined, or forked (default: derived)
|
|
10484
10596
|
--active-variant-behavior <b> if-missing, set-active, or keep
|
|
10485
10597
|
--json Print machine-readable upload output with Space IDs
|
|
@@ -10679,7 +10791,7 @@ Long runs:
|
|
|
10679
10791
|
console.log(`
|
|
10680
10792
|
Usage:
|
|
10681
10793
|
makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--model ${videoModelValues("derive")}] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
|
|
10682
|
-
makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--model veo-3.1] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
|
|
10794
|
+
makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--model veo-3.1|seedance-2|seedance-2-fast] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
|
|
10683
10795
|
makefx video derive --follow <variant_id> -o <file> [--collection <id>] [--space <id>]
|
|
10684
10796
|
|
|
10685
10797
|
${videoCapabilityHelp("derive")}
|
|
@@ -10699,12 +10811,12 @@ Usage:
|
|
|
10699
10811
|
makefx video generate --follow <variant_id> -o <file> [--collection <id>] [--space <id>]
|
|
10700
10812
|
makefx video refine --variant <variant_id> "prompt" -o <file> [--model ${videoModelValues()}] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
|
|
10701
10813
|
makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--model ${videoModelValues()}] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
|
|
10702
|
-
makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--model veo-3.1] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
|
|
10814
|
+
makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--model veo-3.1|seedance-2|seedance-2-fast] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--collection <id>] [--space <id>]
|
|
10703
10815
|
|
|
10704
10816
|
${videoCapabilityHelp()}
|
|
10705
10817
|
|
|
10706
10818
|
Audio:
|
|
10707
|
-
Veo and Kling default to generated audio.
|
|
10819
|
+
Veo and Kling default to generated audio. Seedance v1 is silent and generate-only; Seedance 2 is silent and supports generate and derive.
|
|
10708
10820
|
Current Veo models do not support --no-audio; the CLI rejects it before creating a job.
|
|
10709
10821
|
|
|
10710
10822
|
Long runs:
|
|
@@ -10738,6 +10850,8 @@ Usage:
|
|
|
10738
10850
|
makefx variants unstar <variant-id>
|
|
10739
10851
|
makefx variants rate <variant-id> <approved|rejected>
|
|
10740
10852
|
|
|
10853
|
+
Variant arguments accept compact refs (asset:name~prefix@variant) or raw IDs.
|
|
10854
|
+
|
|
10741
10855
|
Options:
|
|
10742
10856
|
--space <id> Target space ID; defaults from the initialized project
|
|
10743
10857
|
--env <env> Environment (production|stage|local)
|
|
@@ -10752,6 +10866,8 @@ Usage:
|
|
|
10752
10866
|
|
|
10753
10867
|
Re-runs the stored generation recipe as a new sibling variant of the same asset.
|
|
10754
10868
|
|
|
10869
|
+
The variant argument accepts a compact ref (asset:name~prefix@variant) or raw ID.
|
|
10870
|
+
|
|
10755
10871
|
Options:
|
|
10756
10872
|
--space <id> Target space ID; defaults from the initialized project
|
|
10757
10873
|
--json Print machine-readable output
|
|
@@ -10772,6 +10888,8 @@ Usage:
|
|
|
10772
10888
|
makefx assets delete <asset-id>
|
|
10773
10889
|
makefx assets rename <asset-id> "<new-name>"
|
|
10774
10890
|
makefx assets set-active <asset-id> <variant-id>
|
|
10891
|
+
|
|
10892
|
+
Asset and variant arguments accept compact refs (asset:name~prefix[@variant|@active]) or raw IDs.
|
|
10775
10893
|
`);
|
|
10776
10894
|
}
|
|
10777
10895
|
function printCollectionsHelp() {
|
|
@@ -10787,6 +10905,8 @@ Usage:
|
|
|
10787
10905
|
makefx collections remove <collection-id> <item-id>
|
|
10788
10906
|
makefx collections reorder <collection-id> <item-id,item-id,...>
|
|
10789
10907
|
|
|
10908
|
+
Asset and variant arguments accept compact refs (asset:name~prefix[@variant|@active]) or raw IDs.
|
|
10909
|
+
|
|
10790
10910
|
Options:
|
|
10791
10911
|
--space <id> Target space ID; defaults from the initialized project
|
|
10792
10912
|
--env <env> Environment (production|stage|local)
|