makefx 1.2.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 +976 -765
- 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,556 +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");
|
|
5483
|
+
};
|
|
5484
|
+
function booleanFromSqlite(value) {
|
|
5485
|
+
return value === true || value === 1;
|
|
5585
5486
|
}
|
|
5586
|
-
function
|
|
5587
|
-
if (
|
|
5588
|
-
if (
|
|
5589
|
-
if (
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
if (usedOptions.length === 0) return;
|
|
5595
|
-
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.`);
|
|
5596
|
-
}
|
|
5597
|
-
function parseCsvOption(value, optionName) {
|
|
5598
|
-
if (!value) return [];
|
|
5599
|
-
if (value === "true") throw new UploadUsageError(`${optionName} requires a value`);
|
|
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 booleanFromSqlite(value) {
|
|
5920
|
-
return value === true || value === 1;
|
|
5921
|
-
}
|
|
5922
|
-
function collectionItemMatchesInput(item, input) {
|
|
5923
|
-
if (item.subject_type !== input.subjectType) return false;
|
|
5924
|
-
if (input.subjectType === "asset" && item.asset_id !== input.assetId) return false;
|
|
5925
|
-
if (input.subjectType === "variant" && item.variant_id !== input.variantId) return false;
|
|
5926
|
-
if (input.role !== void 0 && item.role !== input.role) return false;
|
|
5927
|
-
if (input.pinnedVariantId !== void 0 && item.pinned_variant_id !== input.pinnedVariantId) return false;
|
|
5928
|
-
if (input.sortIndex !== void 0 && item.sort_index !== input.sortIndex) return false;
|
|
5929
|
-
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;
|
|
5930
5495
|
}
|
|
5931
5496
|
var WebSocketClient = class WebSocketClient {
|
|
5932
5497
|
ws = null;
|
|
@@ -6602,176 +6167,741 @@ var WebSocketClient = class WebSocketClient {
|
|
|
6602
6167
|
try {
|
|
6603
6168
|
this.send(message);
|
|
6604
6169
|
} catch (err) {
|
|
6605
|
-
this.generateHandlers.delete(requestId);
|
|
6606
|
-
clearTimeout(timeout);
|
|
6170
|
+
this.generateHandlers.delete(requestId);
|
|
6171
|
+
clearTimeout(timeout);
|
|
6172
|
+
reject(err);
|
|
6173
|
+
}
|
|
6174
|
+
});
|
|
6175
|
+
}
|
|
6176
|
+
/**
|
|
6177
|
+
* Send a batch generation request and wait for all variants to finish.
|
|
6178
|
+
*/
|
|
6179
|
+
async sendBatchRequest(params) {
|
|
6180
|
+
const requestId = crypto.randomUUID();
|
|
6181
|
+
return new Promise((resolve, reject) => {
|
|
6182
|
+
const timeout = setTimeout(() => {
|
|
6183
|
+
const handler = this.batchHandlers.get(requestId);
|
|
6184
|
+
if (handler) {
|
|
6185
|
+
this.batchHandlers.delete(requestId);
|
|
6186
|
+
for (const variantId of handler.pending) this.batchVariantToRequestId.delete(variantId);
|
|
6187
|
+
reject(/* @__PURE__ */ new Error("Batch request timed out"));
|
|
6188
|
+
}
|
|
6189
|
+
}, 3e5);
|
|
6190
|
+
this.batchHandlers.set(requestId, {
|
|
6191
|
+
onStarted: params.onStarted,
|
|
6192
|
+
onResult: resolve,
|
|
6193
|
+
reject,
|
|
6194
|
+
timeout,
|
|
6195
|
+
pending: /* @__PURE__ */ new Set(),
|
|
6196
|
+
completed: [],
|
|
6197
|
+
failed: []
|
|
6198
|
+
});
|
|
6199
|
+
const message = {
|
|
6200
|
+
type: "batch:request",
|
|
6201
|
+
requestId,
|
|
6202
|
+
name: params.name,
|
|
6203
|
+
assetType: params.assetType,
|
|
6204
|
+
prompt: params.prompt,
|
|
6205
|
+
count: params.count,
|
|
6206
|
+
mode: params.mode,
|
|
6207
|
+
referenceVariantIds: params.referenceVariantIds,
|
|
6208
|
+
model: params.model,
|
|
6209
|
+
aspectRatio: params.aspectRatio,
|
|
6210
|
+
imageSize: params.imageSize,
|
|
6211
|
+
mediaKind: params.mediaKind,
|
|
6212
|
+
voiceId: params.voiceId,
|
|
6213
|
+
dialogueVoiceIds: params.dialogueVoiceIds,
|
|
6214
|
+
musicProvider: params.musicProvider
|
|
6215
|
+
};
|
|
6216
|
+
try {
|
|
6217
|
+
this.send(message);
|
|
6218
|
+
} catch (err) {
|
|
6219
|
+
this.batchHandlers.delete(requestId);
|
|
6220
|
+
clearTimeout(timeout);
|
|
6221
|
+
reject(err);
|
|
6222
|
+
}
|
|
6223
|
+
});
|
|
6224
|
+
}
|
|
6225
|
+
/**
|
|
6226
|
+
* Send a describe image request and wait for response
|
|
6227
|
+
*/
|
|
6228
|
+
async sendDescribeRequest(params) {
|
|
6229
|
+
const requestId = crypto.randomUUID();
|
|
6230
|
+
return new Promise((resolve, reject) => {
|
|
6231
|
+
this.describeHandlers.set(requestId, {
|
|
6232
|
+
resolve,
|
|
6233
|
+
reject
|
|
6234
|
+
});
|
|
6235
|
+
const message = {
|
|
6236
|
+
type: "describe:request",
|
|
6237
|
+
requestId,
|
|
6238
|
+
assetId: params.assetId,
|
|
6239
|
+
variantId: params.variantId,
|
|
6240
|
+
assetName: params.assetName,
|
|
6241
|
+
focus: params.focus,
|
|
6242
|
+
question: params.question
|
|
6243
|
+
};
|
|
6244
|
+
try {
|
|
6245
|
+
this.send(message);
|
|
6246
|
+
} catch (err) {
|
|
6247
|
+
this.describeHandlers.delete(requestId);
|
|
6607
6248
|
reject(err);
|
|
6608
6249
|
}
|
|
6250
|
+
setTimeout(() => {
|
|
6251
|
+
if (this.describeHandlers.has(requestId)) {
|
|
6252
|
+
this.describeHandlers.delete(requestId);
|
|
6253
|
+
reject(/* @__PURE__ */ new Error("Describe request timed out"));
|
|
6254
|
+
}
|
|
6255
|
+
}, 6e4);
|
|
6609
6256
|
});
|
|
6610
6257
|
}
|
|
6611
6258
|
/**
|
|
6612
|
-
* Send a
|
|
6259
|
+
* Send a compare images request and wait for response
|
|
6613
6260
|
*/
|
|
6614
|
-
async
|
|
6261
|
+
async sendCompareRequest(params) {
|
|
6615
6262
|
const requestId = crypto.randomUUID();
|
|
6616
6263
|
return new Promise((resolve, reject) => {
|
|
6617
|
-
|
|
6618
|
-
|
|
6619
|
-
|
|
6620
|
-
this.batchHandlers.delete(requestId);
|
|
6621
|
-
for (const variantId of handler.pending) this.batchVariantToRequestId.delete(variantId);
|
|
6622
|
-
reject(/* @__PURE__ */ new Error("Batch request timed out"));
|
|
6623
|
-
}
|
|
6624
|
-
}, 3e5);
|
|
6625
|
-
this.batchHandlers.set(requestId, {
|
|
6626
|
-
onStarted: params.onStarted,
|
|
6627
|
-
onResult: resolve,
|
|
6628
|
-
reject,
|
|
6629
|
-
timeout,
|
|
6630
|
-
pending: /* @__PURE__ */ new Set(),
|
|
6631
|
-
completed: [],
|
|
6632
|
-
failed: []
|
|
6264
|
+
this.compareHandlers.set(requestId, {
|
|
6265
|
+
resolve,
|
|
6266
|
+
reject
|
|
6633
6267
|
});
|
|
6634
6268
|
const message = {
|
|
6635
|
-
type: "
|
|
6269
|
+
type: "compare:request",
|
|
6636
6270
|
requestId,
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
prompt: params.prompt,
|
|
6640
|
-
count: params.count,
|
|
6641
|
-
mode: params.mode,
|
|
6642
|
-
referenceVariantIds: params.referenceVariantIds,
|
|
6643
|
-
model: params.model,
|
|
6644
|
-
aspectRatio: params.aspectRatio,
|
|
6645
|
-
imageSize: params.imageSize,
|
|
6646
|
-
mediaKind: params.mediaKind,
|
|
6647
|
-
voiceId: params.voiceId,
|
|
6648
|
-
dialogueVoiceIds: params.dialogueVoiceIds,
|
|
6649
|
-
musicProvider: params.musicProvider
|
|
6271
|
+
variantIds: params.variantIds,
|
|
6272
|
+
aspects: params.aspects
|
|
6650
6273
|
};
|
|
6651
6274
|
try {
|
|
6652
6275
|
this.send(message);
|
|
6653
6276
|
} catch (err) {
|
|
6654
|
-
this.
|
|
6655
|
-
clearTimeout(timeout);
|
|
6277
|
+
this.compareHandlers.delete(requestId);
|
|
6656
6278
|
reject(err);
|
|
6657
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
|
|
6658
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;
|
|
6659
6562
|
}
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
variantId: params.variantId,
|
|
6675
|
-
assetName: params.assetName,
|
|
6676
|
-
focus: params.focus,
|
|
6677
|
-
question: params.question
|
|
6678
|
-
};
|
|
6679
|
-
try {
|
|
6680
|
-
this.send(message);
|
|
6681
|
-
} catch (err) {
|
|
6682
|
-
this.describeHandlers.delete(requestId);
|
|
6683
|
-
reject(err);
|
|
6684
|
-
}
|
|
6685
|
-
setTimeout(() => {
|
|
6686
|
-
if (this.describeHandlers.has(requestId)) {
|
|
6687
|
-
this.describeHandlers.delete(requestId);
|
|
6688
|
-
reject(/* @__PURE__ */ new Error("Describe request timed out"));
|
|
6689
|
-
}
|
|
6690
|
-
}, 6e4);
|
|
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
|
|
6691
6577
|
});
|
|
6578
|
+
} catch (error) {
|
|
6579
|
+
console.warn(`Warning: upload succeeded but mirror registry was not updated: ${error instanceof Error ? error.message : String(error)}`);
|
|
6692
6580
|
}
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
reject
|
|
6702
|
-
});
|
|
6703
|
-
const message = {
|
|
6704
|
-
type: "compare:request",
|
|
6705
|
-
requestId,
|
|
6706
|
-
variantIds: params.variantIds,
|
|
6707
|
-
aspects: params.aspects
|
|
6708
|
-
};
|
|
6709
|
-
try {
|
|
6710
|
-
this.send(message);
|
|
6711
|
-
} catch (err) {
|
|
6712
|
-
this.compareHandlers.delete(requestId);
|
|
6713
|
-
reject(err);
|
|
6714
|
-
}
|
|
6715
|
-
setTimeout(() => {
|
|
6716
|
-
if (this.compareHandlers.has(requestId)) {
|
|
6717
|
-
this.compareHandlers.delete(requestId);
|
|
6718
|
-
reject(/* @__PURE__ */ new Error("Compare request timed out"));
|
|
6719
|
-
}
|
|
6720
|
-
}, 6e4);
|
|
6721
|
-
});
|
|
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`);
|
|
6722
6589
|
}
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
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;
|
|
6728
6672
|
}
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
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];
|
|
6737
6691
|
}
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
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;
|
|
6746
6858
|
}
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
|
|
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)}`);
|
|
6752
6867
|
}
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
getSession() {
|
|
6757
|
-
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}` : ""}`);
|
|
6758
6871
|
}
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
...data
|
|
6766
|
-
});
|
|
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)}`);
|
|
6767
6878
|
}
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
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 "";
|
|
6773
6889
|
}
|
|
6774
|
-
}
|
|
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
|
+
}
|
|
6775
6905
|
//#endregion
|
|
6776
6906
|
//#region src/shared/videoGenerationOptions.ts
|
|
6777
6907
|
var VIDEO_GENERATION_ASPECT_RATIOS = ["16:9", "9:16"];
|
|
@@ -7347,7 +7477,7 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
|
|
|
7347
7477
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7348
7478
|
const videoFrameRefs = parseVideoFrameReferenceOptions(parsed, "generate", mediaKind).refs;
|
|
7349
7479
|
const state = videoFrameRefs.length > 0 ? await requestSpaceState$1(client) : void 0;
|
|
7350
|
-
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) : [];
|
|
7351
7481
|
const imageOptions = parseImageGenerationOptions(parsed, mediaKind);
|
|
7352
7482
|
const audioModelOptions = parseAudioGenerationOptions(parsed, mediaKind);
|
|
7353
7483
|
const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
|
|
@@ -7379,7 +7509,7 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
|
|
|
7379
7509
|
...videoAudioOptions,
|
|
7380
7510
|
...videoOptions,
|
|
7381
7511
|
onStarted: (started) => {
|
|
7382
|
-
startedVariantId = started
|
|
7512
|
+
startedVariantId = compactStartedVariantRef(started);
|
|
7383
7513
|
printFollowHint(started, ctx, outputPath, "generate", mediaKind, followCommandOptions);
|
|
7384
7514
|
}
|
|
7385
7515
|
});
|
|
@@ -7434,9 +7564,11 @@ function parseMusicProviderOption(parsed, mediaKind, assetType) {
|
|
|
7434
7564
|
async function executeRefine(parsed, ctx, client, deps, mediaKind) {
|
|
7435
7565
|
const prompt = getPrompt(parsed, "refine");
|
|
7436
7566
|
const outputPath = getOutputPath$1(parsed);
|
|
7437
|
-
const
|
|
7567
|
+
const sourceVariantIdentifier = requireOption$1(parsed, "variant");
|
|
7438
7568
|
const state = await requestSpaceState$1(client);
|
|
7439
|
-
const
|
|
7569
|
+
const variants = state.variants;
|
|
7570
|
+
const sourceVariantId = resolveVariantRef(sourceVariantIdentifier, state.assets, variants);
|
|
7571
|
+
const sourceVariant = variants.find((variant) => variant.id === sourceVariantId);
|
|
7440
7572
|
if (!sourceVariant) throw new Error(`Variant not found in space sync state: ${sourceVariantId}`);
|
|
7441
7573
|
const sourceAsset = state.assets.find((asset) => asset.id === sourceVariant.asset_id);
|
|
7442
7574
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -7459,7 +7591,7 @@ async function executeRefine(parsed, ctx, client, deps, mediaKind) {
|
|
|
7459
7591
|
...videoAudioOptions,
|
|
7460
7592
|
...videoOptions,
|
|
7461
7593
|
onStarted: (started) => {
|
|
7462
|
-
startedVariantId = started
|
|
7594
|
+
startedVariantId = compactStartedVariantRef(started);
|
|
7463
7595
|
printFollowHint(started, ctx, outputPath, "refine", mediaKind, followCommandOptions);
|
|
7464
7596
|
}
|
|
7465
7597
|
});
|
|
@@ -7503,7 +7635,8 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
|
|
|
7503
7635
|
if (referenceRefs.length === 0) throw new Error("--refs is required");
|
|
7504
7636
|
const imageOptions = parseImageGenerationOptions(parsed, mediaKind);
|
|
7505
7637
|
if (mediaKind === "image") validateImageReferenceCount(imageOptions.model, referenceRefs.length);
|
|
7506
|
-
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);
|
|
7507
7640
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7508
7641
|
const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
|
|
7509
7642
|
const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
|
|
@@ -7530,7 +7663,7 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
|
|
|
7530
7663
|
...videoAudioOptions,
|
|
7531
7664
|
...videoOptions,
|
|
7532
7665
|
onStarted: (started) => {
|
|
7533
|
-
startedVariantId = started
|
|
7666
|
+
startedVariantId = compactStartedVariantRef(started);
|
|
7534
7667
|
printFollowHint(started, ctx, outputPath, "derive", mediaKind, followCommandOptions);
|
|
7535
7668
|
}
|
|
7536
7669
|
});
|
|
@@ -7564,8 +7697,8 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
|
|
|
7564
7697
|
return result;
|
|
7565
7698
|
}
|
|
7566
7699
|
async function executeFollow(parsed, ctx, client, deps, command, mediaKind, followOptions = {}) {
|
|
7567
|
-
const
|
|
7568
|
-
if (!
|
|
7700
|
+
const variantIdentifier = normalizeCliOption(parsed.options.follow);
|
|
7701
|
+
if (!variantIdentifier) throw new Error("--follow requires a variant ID");
|
|
7569
7702
|
const outputPath = getOutputPath$1(parsed);
|
|
7570
7703
|
const timeoutMs = parseFollowTimeoutMs(parsed, mediaKind);
|
|
7571
7704
|
const collectionPlacement = parseCollectionPlacementOptions(parsed);
|
|
@@ -7573,9 +7706,11 @@ async function executeFollow(parsed, ctx, client, deps, command, mediaKind, foll
|
|
|
7573
7706
|
...followOptions,
|
|
7574
7707
|
...collectionPlacement
|
|
7575
7708
|
};
|
|
7576
|
-
console.log(`Following variant ${variantId} in space ${ctx.spaceId}...`);
|
|
7577
7709
|
const state = await requestSpaceState$1(client);
|
|
7578
|
-
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);
|
|
7579
7714
|
if (!initialVariant) throw new Error(`Variant not found in space sync state: ${variantId}`);
|
|
7580
7715
|
const initialStatus = initialVariant.status;
|
|
7581
7716
|
const requestId = `follow:${variantId}`;
|
|
@@ -7723,7 +7858,7 @@ async function executeBatch(parsed, ctx, client, deps, mediaKind, saveBatchManif
|
|
|
7723
7858
|
const audioModelOptions = parseAudioGenerationOptions(parsed, mediaKind);
|
|
7724
7859
|
if (mediaKind === "image") validateImageReferenceCount(imageOptions.model, refs.length);
|
|
7725
7860
|
const state = await requestSpaceState$1(client);
|
|
7726
|
-
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;
|
|
7727
7862
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7728
7863
|
const runId = deps.createRunId();
|
|
7729
7864
|
const collectionPlacement = parseCollectionPlacementOptions(parsed);
|
|
@@ -7927,7 +8062,7 @@ function parseRefs(value) {
|
|
|
7927
8062
|
if (refs.length === 0) throw new Error("--refs must include at least one reference");
|
|
7928
8063
|
return refs;
|
|
7929
8064
|
}
|
|
7930
|
-
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 = []) {
|
|
7931
8066
|
const variantIds = [];
|
|
7932
8067
|
for (const ref of refs) {
|
|
7933
8068
|
if (await deps.fileExists(ref)) {
|
|
@@ -7970,8 +8105,9 @@ async function resolveReferenceVariantIds(refs, ctx, deps, variants = [], mediaK
|
|
|
7970
8105
|
continue;
|
|
7971
8106
|
}
|
|
7972
8107
|
if (looksLikeFilePath(ref)) throw new Error(`Reference file not found: ${ref}`);
|
|
7973
|
-
|
|
7974
|
-
|
|
8108
|
+
const variantId = resolveVariantRef(ref, assets, variants);
|
|
8109
|
+
validateReferenceVariant(variantId, variants, mediaKind);
|
|
8110
|
+
variantIds.push(variantId);
|
|
7975
8111
|
}
|
|
7976
8112
|
return variantIds;
|
|
7977
8113
|
}
|
|
@@ -8059,8 +8195,8 @@ function printResult(result, outputPath, ctx, manifestPath) {
|
|
|
8059
8195
|
const variant = result.variant;
|
|
8060
8196
|
if (!variant) return;
|
|
8061
8197
|
console.log("\nDone.\n");
|
|
8062
|
-
console.log(` Asset: ${variant.asset_id}`);
|
|
8063
|
-
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)}`);
|
|
8064
8200
|
console.log(` Media: ${variant.media_key || variant.image_key || "-"}`);
|
|
8065
8201
|
if (variant.image_key && variant.media_key !== variant.image_key) console.log(` Image: ${variant.image_key}`);
|
|
8066
8202
|
console.log(` Local: ${outputPath}`);
|
|
@@ -8068,8 +8204,12 @@ function printResult(result, outputPath, ctx, manifestPath) {
|
|
|
8068
8204
|
console.log(` Web: ${ctx.baseUrl}/spaces/${ctx.spaceId}/assets/${variant.asset_id}`);
|
|
8069
8205
|
}
|
|
8070
8206
|
function printFollowHint(started, ctx, outputPath, command, mediaKind, options = {}) {
|
|
8071
|
-
|
|
8072
|
-
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);
|
|
8073
8213
|
}
|
|
8074
8214
|
function throwGenerationWaitErrorIfNeeded(input, params) {
|
|
8075
8215
|
if (!isGenerationWaitTimeout(input)) throw input;
|
|
@@ -8137,7 +8277,7 @@ function formatFollowCommand(variantId, outputPath, ctx, command, mediaKind, opt
|
|
|
8137
8277
|
].map(shellQuote).join(" ");
|
|
8138
8278
|
}
|
|
8139
8279
|
function shellQuote(value) {
|
|
8140
|
-
if (/^[A-Za-z0-9_
|
|
8280
|
+
if (/^[A-Za-z0-9_./:=@~-]+$/.test(value)) return value;
|
|
8141
8281
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
8142
8282
|
}
|
|
8143
8283
|
function getPrompt(parsed, command) {
|
|
@@ -8851,10 +8991,10 @@ async function executeAssets(parsed, deps = defaultDeps$5) {
|
|
|
8851
8991
|
};
|
|
8852
8992
|
}
|
|
8853
8993
|
if (subcommand === "show") {
|
|
8854
|
-
const
|
|
8855
|
-
if (!
|
|
8856
|
-
const details = await getAssetDetails(ctx, deps,
|
|
8857
|
-
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));
|
|
8858
8998
|
else printAssetDetails(details, ctx, deps.print);
|
|
8859
8999
|
return {
|
|
8860
9000
|
type: "show",
|
|
@@ -8862,10 +9002,10 @@ async function executeAssets(parsed, deps = defaultDeps$5) {
|
|
|
8862
9002
|
};
|
|
8863
9003
|
}
|
|
8864
9004
|
if (subcommand === "download") {
|
|
8865
|
-
const
|
|
8866
|
-
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>");
|
|
8867
9007
|
const outputPath = getOutputPath(parsed);
|
|
8868
|
-
const resolved = resolveDownloadRef(
|
|
9008
|
+
const resolved = resolveDownloadRef(await resolveVariantAtBoundary$1(ctx, deps, identifier), ctx);
|
|
8869
9009
|
let download;
|
|
8870
9010
|
try {
|
|
8871
9011
|
download = await deps.downloadFile({
|
|
@@ -8896,8 +9036,9 @@ async function executeAssets(parsed, deps = defaultDeps$5) {
|
|
|
8896
9036
|
};
|
|
8897
9037
|
}
|
|
8898
9038
|
if (subcommand === "delete") {
|
|
8899
|
-
const
|
|
8900
|
-
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);
|
|
8901
9042
|
await withAssetClient(ctx, deps, (client) => client.deleteAsset(assetId));
|
|
8902
9043
|
deps.print(`Deleted asset ${assetId}`);
|
|
8903
9044
|
return {
|
|
@@ -8906,9 +9047,10 @@ async function executeAssets(parsed, deps = defaultDeps$5) {
|
|
|
8906
9047
|
};
|
|
8907
9048
|
}
|
|
8908
9049
|
if (subcommand === "rename") {
|
|
8909
|
-
const
|
|
9050
|
+
const identifier = parsed.positionals[1];
|
|
8910
9051
|
const name = parsed.positionals[2];
|
|
8911
|
-
if (!
|
|
9052
|
+
if (!identifier || !name) throw new Error("Usage: makefx assets rename <asset-id> \"<new-name>\"");
|
|
9053
|
+
const assetId = await resolveAssetAtBoundary(ctx, deps, identifier);
|
|
8912
9054
|
const asset = await withAssetClient(ctx, deps, (client) => client.renameAsset(assetId, name));
|
|
8913
9055
|
deps.print(`Renamed asset ${assetId} -> "${asset.name}"`);
|
|
8914
9056
|
return {
|
|
@@ -8917,10 +9059,11 @@ async function executeAssets(parsed, deps = defaultDeps$5) {
|
|
|
8917
9059
|
};
|
|
8918
9060
|
}
|
|
8919
9061
|
if (subcommand === "set-active") {
|
|
8920
|
-
const
|
|
8921
|
-
const
|
|
8922
|
-
if (!
|
|
8923
|
-
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));
|
|
8924
9067
|
deps.print(`Set active variant of asset ${assetId} to ${asset.active_variant_id}`);
|
|
8925
9068
|
return {
|
|
8926
9069
|
type: "set-active",
|
|
@@ -8950,6 +9093,15 @@ async function buildContext$5(parsed, deps) {
|
|
|
8950
9093
|
projectRoot: projectConfig?.projectRoot
|
|
8951
9094
|
};
|
|
8952
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
|
+
}
|
|
8953
9105
|
async function buildAuthContext(parsed, deps) {
|
|
8954
9106
|
const env = resolveCommandEnvironment(parsed, await deps.loadProjectConfig());
|
|
8955
9107
|
const config = await deps.loadConfig(env);
|
|
@@ -8983,7 +9135,11 @@ async function searchAssets(parsed, deps) {
|
|
|
8983
9135
|
const response = await deps.fetch(`${ctx.baseUrl}/api/assets/search?${params.toString()}`, { headers: { Authorization: `Bearer ${ctx.accessToken}` } });
|
|
8984
9136
|
if (!response.ok) throw new Error(`Search failed: ${response.status} - ${await response.text()}`);
|
|
8985
9137
|
const results = (await response.json()).results ?? [];
|
|
8986
|
-
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));
|
|
8987
9143
|
else printAssetSearchResults(results, deps.print);
|
|
8988
9144
|
return {
|
|
8989
9145
|
type: "search",
|
|
@@ -8992,10 +9148,11 @@ async function searchAssets(parsed, deps) {
|
|
|
8992
9148
|
}
|
|
8993
9149
|
async function cloneAsset(parsed, deps) {
|
|
8994
9150
|
const ctx = await buildAuthContext(parsed, deps);
|
|
8995
|
-
const
|
|
8996
|
-
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>");
|
|
8997
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>");
|
|
8998
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));
|
|
8999
9156
|
const body = {
|
|
9000
9157
|
sourceSpaceId,
|
|
9001
9158
|
sourceVariantId
|
|
@@ -9014,14 +9171,20 @@ async function cloneAsset(parsed, deps) {
|
|
|
9014
9171
|
});
|
|
9015
9172
|
if (!response.ok) throw new Error(`Clone failed: ${response.status} - ${await response.text()}`);
|
|
9016
9173
|
const payload = await response.json();
|
|
9017
|
-
|
|
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));
|
|
9018
9184
|
else {
|
|
9019
|
-
const asset = payload.asset;
|
|
9020
|
-
const variantPayload = payload.variant;
|
|
9021
|
-
const variant = variantPayload?.variant ?? variantPayload;
|
|
9022
9185
|
deps.print(`Cloned variant ${sourceVariantId} into space ${targetSpaceId}`);
|
|
9023
|
-
if (
|
|
9024
|
-
if (
|
|
9186
|
+
if (clonedAssetRef) deps.print(` Asset: ${clonedAssetRef}`);
|
|
9187
|
+
if (clonedVariantRef) deps.print(` Variant: ${clonedVariantRef}`);
|
|
9025
9188
|
}
|
|
9026
9189
|
return {
|
|
9027
9190
|
type: "clone",
|
|
@@ -9199,9 +9362,13 @@ function printAssetList(assets, print) {
|
|
|
9199
9362
|
return;
|
|
9200
9363
|
}
|
|
9201
9364
|
print(`Found ${assets.length} asset(s):\n`);
|
|
9202
|
-
print("Updated".padEnd(21) + "Type".padEnd(14) + "Media".padEnd(9) + "Active Variant".padEnd(
|
|
9203
|
-
print("-".repeat(
|
|
9204
|
-
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
|
+
}
|
|
9205
9372
|
}
|
|
9206
9373
|
function printAssetSearchResults(results, print) {
|
|
9207
9374
|
if (results.length === 0) {
|
|
@@ -9209,16 +9376,17 @@ function printAssetSearchResults(results, print) {
|
|
|
9209
9376
|
return;
|
|
9210
9377
|
}
|
|
9211
9378
|
for (const result of results) {
|
|
9212
|
-
print(`${result.assetName}
|
|
9379
|
+
print(`${createAssetRef(result.assetName, result.assetId)} — ${result.assetName}`);
|
|
9213
9380
|
print(` Space: ${result.spaceName} (${result.spaceId})`);
|
|
9214
9381
|
print(` Type: ${result.assetType ?? "-"} Media: ${result.mediaKind}`);
|
|
9215
|
-
print(` Active: ${result.activeVariantId
|
|
9382
|
+
print(` Active: ${result.activeVariantId ? createVariantRef(result.assetName, result.assetId, result.activeVariantId) : "-"}${result.activeVariantStatus ? ` (${result.activeVariantStatus})` : ""}`);
|
|
9216
9383
|
print(` Counts: variants=${result.variantCount} completed=${result.completedVariantCount} starred=${result.starredVariantCount}`);
|
|
9217
9384
|
}
|
|
9218
9385
|
}
|
|
9219
9386
|
function printAssetDetails(details, ctx, print) {
|
|
9220
9387
|
const { asset, variants, lineage } = details;
|
|
9221
|
-
print(`\nAsset ${asset.id}\n`);
|
|
9388
|
+
print(`\nAsset ${createAssetRef(asset.name, asset.id)}\n`);
|
|
9389
|
+
print(` ID: ${asset.id}`);
|
|
9222
9390
|
print(` Name: ${asset.name}`);
|
|
9223
9391
|
print(` Type: ${asset.type || "unknown"}`);
|
|
9224
9392
|
print(` Media: ${asset.media_kind || "-"}`);
|
|
@@ -9229,7 +9397,8 @@ function printAssetDetails(details, ctx, print) {
|
|
|
9229
9397
|
if (variants.length > 0) {
|
|
9230
9398
|
print("\nVariants:");
|
|
9231
9399
|
for (const variant of [...variants].sort((a, b) => (b.updated_at || 0) - (a.updated_at || 0))) {
|
|
9232
|
-
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}`);
|
|
9233
9402
|
print(` Status: ${variant.status}`);
|
|
9234
9403
|
print(` Media: ${variant.media_kind || "-"}`);
|
|
9235
9404
|
print(` File: ${variant.media_key || variant.image_key || "-"}`);
|
|
@@ -9272,7 +9441,21 @@ function toAssetJson(asset) {
|
|
|
9272
9441
|
media_kind: asset.media_kind || null,
|
|
9273
9442
|
activeVariantId: asset.active_variant_id,
|
|
9274
9443
|
createdAt: asset.created_at || null,
|
|
9275
|
-
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
|
+
}))
|
|
9276
9459
|
};
|
|
9277
9460
|
}
|
|
9278
9461
|
function formatMetadataSummary(value, preferredKeys) {
|
|
@@ -9339,7 +9522,7 @@ async function executeVariants(parsed, deps = defaultDeps$4) {
|
|
|
9339
9522
|
const ctx = await buildContext$4(parsed, deps);
|
|
9340
9523
|
const subcommand = parsed.positionals[0];
|
|
9341
9524
|
if (subcommand === "delete") {
|
|
9342
|
-
const variantId = requireVariantId(parsed, "delete");
|
|
9525
|
+
const variantId = await resolveVariantAtBoundary(ctx, deps, requireVariantId(parsed, "delete"));
|
|
9343
9526
|
await withVariantClient(ctx, deps, (client) => client.deleteVariant(variantId));
|
|
9344
9527
|
deps.print(`Deleted variant ${variantId}`);
|
|
9345
9528
|
return {
|
|
@@ -9348,9 +9531,11 @@ async function executeVariants(parsed, deps = defaultDeps$4) {
|
|
|
9348
9531
|
};
|
|
9349
9532
|
}
|
|
9350
9533
|
if (subcommand === "retry") {
|
|
9351
|
-
const variantId = requireVariantId(parsed, "retry");
|
|
9534
|
+
const variantId = await resolveVariantAtBoundary(ctx, deps, requireVariantId(parsed, "retry"));
|
|
9352
9535
|
const variant = await withVariantClient(ctx, deps, (client) => client.retryVariant(variantId));
|
|
9353
|
-
|
|
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}`);
|
|
9354
9539
|
return {
|
|
9355
9540
|
type: "retry",
|
|
9356
9541
|
variant
|
|
@@ -9358,7 +9543,7 @@ async function executeVariants(parsed, deps = defaultDeps$4) {
|
|
|
9358
9543
|
}
|
|
9359
9544
|
if (subcommand === "star" || subcommand === "unstar") {
|
|
9360
9545
|
const starred = subcommand === "star";
|
|
9361
|
-
const variantId = requireVariantId(parsed, subcommand);
|
|
9546
|
+
const variantId = await resolveVariantAtBoundary(ctx, deps, requireVariantId(parsed, subcommand));
|
|
9362
9547
|
const variant = await withVariantClient(ctx, deps, (client) => client.starVariant(variantId, starred));
|
|
9363
9548
|
deps.print(`${starred ? "Starred" : "Unstarred"} variant ${variantId}`);
|
|
9364
9549
|
return {
|
|
@@ -9367,9 +9552,10 @@ async function executeVariants(parsed, deps = defaultDeps$4) {
|
|
|
9367
9552
|
};
|
|
9368
9553
|
}
|
|
9369
9554
|
if (subcommand === "rate") {
|
|
9370
|
-
const
|
|
9555
|
+
const variantIdentifier = parsed.positionals[1];
|
|
9371
9556
|
const rating = parsed.positionals[2];
|
|
9372
|
-
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);
|
|
9373
9559
|
const variant = await withVariantClient(ctx, deps, (client) => client.rateVariant(variantId, rating));
|
|
9374
9560
|
deps.print(`Rated variant ${variantId} as ${rating}`);
|
|
9375
9561
|
return {
|
|
@@ -9398,6 +9584,9 @@ async function buildContext$4(parsed, deps) {
|
|
|
9398
9584
|
spaceId
|
|
9399
9585
|
};
|
|
9400
9586
|
}
|
|
9587
|
+
function resolveVariantAtBoundary(ctx, deps, identifier) {
|
|
9588
|
+
return resolveCliVariantIdentifier(identifier, () => deps.createMutationClient(ctx.env, ctx.spaceId));
|
|
9589
|
+
}
|
|
9401
9590
|
async function withVariantClient(ctx, deps, run) {
|
|
9402
9591
|
const client = await deps.createMutationClient(ctx.env, ctx.spaceId);
|
|
9403
9592
|
await client.connect();
|
|
@@ -9429,6 +9618,7 @@ var defaultDeps$3 = {
|
|
|
9429
9618
|
loadProjectConfig,
|
|
9430
9619
|
resolveBaseUrl,
|
|
9431
9620
|
fetch,
|
|
9621
|
+
createStateClient: (env, spaceId) => WebSocketClient.create(env, spaceId),
|
|
9432
9622
|
print: console.log
|
|
9433
9623
|
};
|
|
9434
9624
|
async function handleRecipes(parsed) {
|
|
@@ -9443,15 +9633,22 @@ async function handleRecipes(parsed) {
|
|
|
9443
9633
|
async function executeRecipes(parsed, deps = defaultDeps$3) {
|
|
9444
9634
|
const subcommand = parsed.positionals[0];
|
|
9445
9635
|
if (subcommand !== "run") throw new Error(`Unknown recipes command: ${subcommand ?? "(none)"}`);
|
|
9446
|
-
const
|
|
9447
|
-
if (!
|
|
9448
|
-
const
|
|
9449
|
-
|
|
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));
|
|
9450
9647
|
else {
|
|
9451
9648
|
deps.print(`Re-ran recipe from variant ${rerun.sourceVariantId}`);
|
|
9452
|
-
deps.print(` Variant: ${
|
|
9649
|
+
deps.print(` Variant: ${variantRef} (status: ${rerun.variant.status})`);
|
|
9453
9650
|
deps.print(` Request: ${rerun.requestId}`);
|
|
9454
|
-
deps.print(`Watch progress with: makefx assets show ${
|
|
9651
|
+
deps.print(`Watch progress with: makefx assets show ${assetRef}`);
|
|
9455
9652
|
}
|
|
9456
9653
|
return {
|
|
9457
9654
|
type: "run",
|
|
@@ -9468,6 +9665,7 @@ async function buildContext$3(parsed, deps) {
|
|
|
9468
9665
|
if (config.token.expiresAt < Date.now()) throw new Error(`Token expired for ${env} environment. Run: ${loginCommandForEnvironment(env)}`);
|
|
9469
9666
|
if (env === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
9470
9667
|
return {
|
|
9668
|
+
env,
|
|
9471
9669
|
spaceId,
|
|
9472
9670
|
baseUrl: deps.resolveBaseUrl(env),
|
|
9473
9671
|
accessToken: config.token.accessToken
|
|
@@ -9582,13 +9780,16 @@ async function executeCollections(parsed, deps = defaultDeps$2) {
|
|
|
9582
9780
|
const collectionId = parsed.positionals[1];
|
|
9583
9781
|
const assetId = parsed.positionals[2] || normalizeOption(parsed.options.asset);
|
|
9584
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;
|
|
9585
9786
|
const item = await withCollectionClient(ctx, deps, (client) => client.createCollectionItem({
|
|
9586
9787
|
collectionId,
|
|
9587
9788
|
id: normalizeOption(parsed.options.id),
|
|
9588
9789
|
subjectType: "asset",
|
|
9589
|
-
assetId,
|
|
9790
|
+
assetId: resolvedAssetId,
|
|
9590
9791
|
role: normalizeOption(parsed.options.role),
|
|
9591
|
-
pinnedVariantId
|
|
9792
|
+
pinnedVariantId,
|
|
9592
9793
|
sortIndex: parseOptionalInteger(parsed.options["sort-index"], "sort-index")
|
|
9593
9794
|
}));
|
|
9594
9795
|
printJsonOrLine(parsed, deps, item, `Added asset ${assetId} to collection ${collectionId} as item ${item.id}`);
|
|
@@ -9601,11 +9802,12 @@ async function executeCollections(parsed, deps = defaultDeps$2) {
|
|
|
9601
9802
|
const collectionId = parsed.positionals[1];
|
|
9602
9803
|
const variantId = parsed.positionals[2] || normalizeOption(parsed.options.variant);
|
|
9603
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));
|
|
9604
9806
|
const item = await withCollectionClient(ctx, deps, (client) => client.createCollectionItem({
|
|
9605
9807
|
collectionId,
|
|
9606
9808
|
id: normalizeOption(parsed.options.id),
|
|
9607
9809
|
subjectType: "variant",
|
|
9608
|
-
variantId,
|
|
9810
|
+
variantId: resolvedVariantId,
|
|
9609
9811
|
role: normalizeOption(parsed.options.role),
|
|
9610
9812
|
sortIndex: parseOptionalInteger(parsed.options["sort-index"], "sort-index")
|
|
9611
9813
|
}));
|
|
@@ -10047,7 +10249,7 @@ Options:
|
|
|
10047
10249
|
}
|
|
10048
10250
|
//#endregion
|
|
10049
10251
|
//#region src/cli/index.ts
|
|
10050
|
-
var CLI_VERSION = "1.
|
|
10252
|
+
var CLI_VERSION = "1.3.0+89c141a8883e";
|
|
10051
10253
|
async function main() {
|
|
10052
10254
|
const argv = process$1.argv.slice(2);
|
|
10053
10255
|
if (argv[0] === "--") argv.shift();
|
|
@@ -10101,9 +10303,9 @@ function imageCapabilityHelp(operation) {
|
|
|
10101
10303
|
--model <value> Image model: ${imageModelValues(operation)}
|
|
10102
10304
|
--size <value> Output size (${sizeLines})
|
|
10103
10305
|
--aspect <ratio> Aspect ratio: ${imageAspectValues()}
|
|
10104
|
-
--refs <refs>
|
|
10306
|
+
--refs <refs> Compact variant refs, raw IDs, or local image paths; limit (${referenceLines})
|
|
10105
10307
|
Model operations: ${operationLines}
|
|
10106
|
-
--follow <id>
|
|
10308
|
+
--follow <ref-or-id> Resume/download a variant after a long generation or disconnect
|
|
10107
10309
|
--collection <id> Place the completed asset in a Space collection`;
|
|
10108
10310
|
}
|
|
10109
10311
|
function videoResolutionValues() {
|
|
@@ -10130,10 +10332,10 @@ function videoCapabilityHelp(operation) {
|
|
|
10130
10332
|
--resolution <value> Supported: ${videoResolutionValues()}; Veo: 720p|1080p|4k; Kling: 720p|1080p; Seedance 2: standard 480p|720p|1080p, fast 480p|720p (${resolutionLines})
|
|
10131
10333
|
--duration <seconds> Veo/Kling: ${optionValues(VIDEO_GENERATION_DURATION_SECONDS)}; Seedance 2: ${optionValues(SEEDANCE_2_DURATION_SECONDS)}
|
|
10132
10334
|
--tier <tier> Veo-only model tier: ${videoTierValues()}
|
|
10133
|
-
--first-frame <ref> Veo or Seedance 2 start frame
|
|
10134
|
-
--last-frame <ref> Veo or Seedance 2 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
|
|
10135
10337
|
Model operations: ${operationLines}
|
|
10136
|
-
--follow <id>
|
|
10338
|
+
--follow <ref-or-id> Resume/download a variant after a long generation or disconnect
|
|
10137
10339
|
--collection <id> Place the completed asset in a Space collection
|
|
10138
10340
|
|
|
10139
10341
|
Frame inputs:
|
|
@@ -10233,6 +10435,7 @@ Make Effects CLI
|
|
|
10233
10435
|
Generation model:
|
|
10234
10436
|
Assets are named things in a Space. Variants are generated or uploaded versions of one asset.
|
|
10235
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.
|
|
10236
10439
|
|
|
10237
10440
|
Start:
|
|
10238
10441
|
login Authenticate
|
|
@@ -10378,7 +10581,7 @@ Usage:
|
|
|
10378
10581
|
|
|
10379
10582
|
Options:
|
|
10380
10583
|
--space <id> Target space ID; defaults from initialized project
|
|
10381
|
-
--asset <id>
|
|
10584
|
+
--asset <ref|id> Target asset compact ref or raw ID (upload as new variant)
|
|
10382
10585
|
--name <name> New asset name (creates asset + variant)
|
|
10383
10586
|
--type <type> Asset type for new assets (default: character)
|
|
10384
10587
|
--media-kind <k> Optional explicit kind: image, audio, or video
|
|
@@ -10387,8 +10590,8 @@ Options:
|
|
|
10387
10590
|
--provider <name> Provider provenance for uploaded media
|
|
10388
10591
|
--provider-metadata <json> Provider metadata JSON object
|
|
10389
10592
|
--generation-provenance <json> Extra provenance JSON object
|
|
10390
|
-
--source-variant <
|
|
10391
|
-
--source-variants <
|
|
10593
|
+
--source-variant <refs> Comma-separated compact refs or raw IDs for upload lineage
|
|
10594
|
+
--source-variants <refs> Alias for --source-variant
|
|
10392
10595
|
--relation-type <type> Lineage type: derived, refined, or forked (default: derived)
|
|
10393
10596
|
--active-variant-behavior <b> if-missing, set-active, or keep
|
|
10394
10597
|
--json Print machine-readable upload output with Space IDs
|
|
@@ -10647,6 +10850,8 @@ Usage:
|
|
|
10647
10850
|
makefx variants unstar <variant-id>
|
|
10648
10851
|
makefx variants rate <variant-id> <approved|rejected>
|
|
10649
10852
|
|
|
10853
|
+
Variant arguments accept compact refs (asset:name~prefix@variant) or raw IDs.
|
|
10854
|
+
|
|
10650
10855
|
Options:
|
|
10651
10856
|
--space <id> Target space ID; defaults from the initialized project
|
|
10652
10857
|
--env <env> Environment (production|stage|local)
|
|
@@ -10661,6 +10866,8 @@ Usage:
|
|
|
10661
10866
|
|
|
10662
10867
|
Re-runs the stored generation recipe as a new sibling variant of the same asset.
|
|
10663
10868
|
|
|
10869
|
+
The variant argument accepts a compact ref (asset:name~prefix@variant) or raw ID.
|
|
10870
|
+
|
|
10664
10871
|
Options:
|
|
10665
10872
|
--space <id> Target space ID; defaults from the initialized project
|
|
10666
10873
|
--json Print machine-readable output
|
|
@@ -10681,6 +10888,8 @@ Usage:
|
|
|
10681
10888
|
makefx assets delete <asset-id>
|
|
10682
10889
|
makefx assets rename <asset-id> "<new-name>"
|
|
10683
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.
|
|
10684
10893
|
`);
|
|
10685
10894
|
}
|
|
10686
10895
|
function printCollectionsHelp() {
|
|
@@ -10696,6 +10905,8 @@ Usage:
|
|
|
10696
10905
|
makefx collections remove <collection-id> <item-id>
|
|
10697
10906
|
makefx collections reorder <collection-id> <item-id,item-id,...>
|
|
10698
10907
|
|
|
10908
|
+
Asset and variant arguments accept compact refs (asset:name~prefix[@variant|@active]) or raw IDs.
|
|
10909
|
+
|
|
10699
10910
|
Options:
|
|
10700
10911
|
--space <id> Target space ID; defaults from the initialized project
|
|
10701
10912
|
--env <env> Environment (production|stage|local)
|