makefx 0.2.6 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/makefx.mjs +260 -20
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -176,4 +176,4 @@ Run `makefx --help` or `makefx help <command>` for command-specific options.
176
176
  - Media generation guide: https://makefx.app/docs/media-playbooks
177
177
  - Source: https://github.com/krasnoperov/inventory
178
178
 
179
- Version: 0.2.6
179
+ Version: 0.2.8
package/makefx.mjs CHANGED
@@ -19831,6 +19831,19 @@ var SpaceRoleSchema = _enum([
19831
19831
  "editor",
19832
19832
  "viewer"
19833
19833
  ]);
19834
+ var SpaceAccessRoleSchema = _enum(["editor", "viewer"]);
19835
+ var SpaceAccessRequestStatusSchema = _enum([
19836
+ "pending",
19837
+ "approved",
19838
+ "rejected",
19839
+ "canceled"
19840
+ ]);
19841
+ var SpaceInvitationStatusSchema = _enum([
19842
+ "pending",
19843
+ "accepted",
19844
+ "revoked",
19845
+ "expired"
19846
+ ]);
19834
19847
  var SpaceSchema = object({
19835
19848
  id: string$1(),
19836
19849
  name: string$1(),
@@ -19861,6 +19874,98 @@ var SpaceIdParamsSchema = object({ id: string$1().openapi({ param: {
19861
19874
  name: "id",
19862
19875
  in: "path"
19863
19876
  } }) });
19877
+ var SpaceAccessRequestParamsSchema = SpaceIdParamsSchema.extend({ requestId: string$1().openapi({ param: {
19878
+ name: "requestId",
19879
+ in: "path"
19880
+ } }) });
19881
+ var SpaceInvitationParamsSchema = SpaceIdParamsSchema.extend({ invitationId: string$1().openapi({ param: {
19882
+ name: "invitationId",
19883
+ in: "path"
19884
+ } }) });
19885
+ var SpaceSharingUserSchema = object({
19886
+ id: string$1(),
19887
+ email: string$1(),
19888
+ name: string$1().nullable()
19889
+ }).openapi("SpaceSharingUser");
19890
+ var SpaceSharingMemberSchema = object({
19891
+ user_id: string$1(),
19892
+ role: SpaceRoleSchema,
19893
+ joined_at: number$1(),
19894
+ user: SpaceSharingUserSchema
19895
+ }).openapi("SpaceSharingMember");
19896
+ var SpaceAccessRequestSchema = object({
19897
+ id: string$1(),
19898
+ space_id: string$1(),
19899
+ requester_user_id: string$1(),
19900
+ requested_role: SpaceAccessRoleSchema,
19901
+ status: SpaceAccessRequestStatusSchema,
19902
+ message: string$1().nullable(),
19903
+ created_at: string$1(),
19904
+ updated_at: string$1(),
19905
+ resolved_at: string$1().nullable(),
19906
+ resolved_by_user_id: string$1().nullable()
19907
+ }).openapi("SpaceAccessRequest");
19908
+ var SpaceAccessRequestWithRequesterSchema = SpaceAccessRequestSchema.extend({ requester: SpaceSharingUserSchema }).openapi("SpaceAccessRequestWithRequester");
19909
+ var SpaceInvitationSchema = object({
19910
+ id: string$1(),
19911
+ space_id: string$1(),
19912
+ email: string$1(),
19913
+ normalized_email: string$1(),
19914
+ role: SpaceAccessRoleSchema,
19915
+ status: SpaceInvitationStatusSchema,
19916
+ invited_by_user_id: string$1(),
19917
+ accepted_by_user_id: string$1().nullable(),
19918
+ created_at: string$1(),
19919
+ updated_at: string$1(),
19920
+ expires_at: string$1().nullable(),
19921
+ resolved_at: string$1().nullable()
19922
+ }).openapi("SpaceInvitation");
19923
+ var SpaceInvitationWithUsersSchema = SpaceInvitationSchema.extend({
19924
+ invitedBy: SpaceSharingUserSchema.nullable(),
19925
+ acceptedBy: SpaceSharingUserSchema.nullable()
19926
+ }).openapi("SpaceInvitationWithUsers");
19927
+ var SpaceAccessStateSchema = object({
19928
+ status: _enum([
19929
+ "member",
19930
+ "pending_request",
19931
+ "pending_invitation",
19932
+ "none"
19933
+ ]),
19934
+ member: SpaceSharingMemberSchema.nullable(),
19935
+ pendingRequest: SpaceAccessRequestSchema.nullable(),
19936
+ pendingInvitation: SpaceInvitationSchema.nullable()
19937
+ }).openapi("SpaceAccessState");
19938
+ var GetSpaceAccessResponseSchema = object({
19939
+ success: literal(true),
19940
+ access: SpaceAccessStateSchema
19941
+ }).openapi("GetSpaceAccessResponse");
19942
+ var CreateSpaceAccessRequestRequestSchema = object({
19943
+ requestedRole: SpaceAccessRoleSchema.default("viewer").optional(),
19944
+ message: string$1().nullable().optional()
19945
+ }).openapi("CreateSpaceAccessRequestRequest");
19946
+ var SpaceAccessRequestResponseSchema = object({
19947
+ success: literal(true),
19948
+ request: SpaceAccessRequestSchema
19949
+ }).openapi("SpaceAccessRequestResponse");
19950
+ var ApproveSpaceAccessRequestRequestSchema = object({ role: SpaceAccessRoleSchema.optional() }).openapi("ApproveSpaceAccessRequestRequest");
19951
+ var CancelSpaceAccessRequestResponseSchema = object({
19952
+ success: literal(true),
19953
+ request: SpaceAccessRequestSchema.nullable()
19954
+ }).openapi("CancelSpaceAccessRequestResponse");
19955
+ var SpaceSharingResponseSchema = object({
19956
+ success: literal(true),
19957
+ members: array(SpaceSharingMemberSchema),
19958
+ pendingAccessRequests: array(SpaceAccessRequestWithRequesterSchema),
19959
+ pendingInvitations: array(SpaceInvitationWithUsersSchema)
19960
+ }).openapi("SpaceSharingResponse");
19961
+ var CreateSpaceInvitationRequestSchema = object({
19962
+ email: string$1().trim().email(),
19963
+ role: SpaceAccessRoleSchema
19964
+ }).openapi("CreateSpaceInvitationRequest");
19965
+ var SpaceInvitationResponseSchema = object({
19966
+ success: literal(true),
19967
+ invitation: SpaceInvitationSchema
19968
+ }).openapi("SpaceInvitationResponse");
19864
19969
  var ProductionIdParamsSchema = SpaceIdParamsSchema.extend({ productionId: string$1().openapi({ param: {
19865
19970
  name: "productionId",
19866
19971
  in: "path"
@@ -20692,6 +20797,63 @@ var apiEndpoints = {
20692
20797
  paramsSchema: SpaceIdParamsSchema,
20693
20798
  responseSchema: GetSpaceResponseSchema
20694
20799
  },
20800
+ "GET /api/spaces/:id/access": {
20801
+ method: "GET",
20802
+ path: "/api/spaces/:id/access",
20803
+ paramsSchema: SpaceIdParamsSchema,
20804
+ responseSchema: GetSpaceAccessResponseSchema
20805
+ },
20806
+ "POST /api/spaces/:id/access-requests": {
20807
+ method: "POST",
20808
+ path: "/api/spaces/:id/access-requests",
20809
+ paramsSchema: SpaceIdParamsSchema,
20810
+ jsonSchema: CreateSpaceAccessRequestRequestSchema,
20811
+ responseSchema: SpaceAccessRequestResponseSchema
20812
+ },
20813
+ "DELETE /api/spaces/:id/access-requests/me": {
20814
+ method: "DELETE",
20815
+ path: "/api/spaces/:id/access-requests/me",
20816
+ paramsSchema: SpaceIdParamsSchema,
20817
+ responseSchema: CancelSpaceAccessRequestResponseSchema
20818
+ },
20819
+ "GET /api/spaces/:id/sharing": {
20820
+ method: "GET",
20821
+ path: "/api/spaces/:id/sharing",
20822
+ paramsSchema: SpaceIdParamsSchema,
20823
+ responseSchema: SpaceSharingResponseSchema
20824
+ },
20825
+ "POST /api/spaces/:id/invitations": {
20826
+ method: "POST",
20827
+ path: "/api/spaces/:id/invitations",
20828
+ paramsSchema: SpaceIdParamsSchema,
20829
+ jsonSchema: CreateSpaceInvitationRequestSchema,
20830
+ responseSchema: SpaceInvitationResponseSchema
20831
+ },
20832
+ "POST /api/spaces/:id/access-requests/:requestId/approve": {
20833
+ method: "POST",
20834
+ path: "/api/spaces/:id/access-requests/:requestId/approve",
20835
+ paramsSchema: SpaceAccessRequestParamsSchema,
20836
+ jsonSchema: ApproveSpaceAccessRequestRequestSchema.optional(),
20837
+ responseSchema: SpaceAccessRequestResponseSchema
20838
+ },
20839
+ "POST /api/spaces/:id/access-requests/:requestId/reject": {
20840
+ method: "POST",
20841
+ path: "/api/spaces/:id/access-requests/:requestId/reject",
20842
+ paramsSchema: SpaceAccessRequestParamsSchema,
20843
+ responseSchema: SpaceAccessRequestResponseSchema
20844
+ },
20845
+ "POST /api/spaces/:id/invitations/:invitationId/revoke": {
20846
+ method: "POST",
20847
+ path: "/api/spaces/:id/invitations/:invitationId/revoke",
20848
+ paramsSchema: SpaceInvitationParamsSchema,
20849
+ responseSchema: SpaceInvitationResponseSchema
20850
+ },
20851
+ "POST /api/spaces/:id/invitations/:invitationId/accept": {
20852
+ method: "POST",
20853
+ path: "/api/spaces/:id/invitations/:invitationId/accept",
20854
+ paramsSchema: SpaceInvitationParamsSchema,
20855
+ responseSchema: SpaceInvitationResponseSchema
20856
+ },
20695
20857
  "GET /api/support/spaces/:id": {
20696
20858
  method: "GET",
20697
20859
  path: "/api/support/spaces/:id",
@@ -23181,6 +23343,7 @@ async function executeForgeCommand(command, parsed, deps = defaultDeps$10, optio
23181
23343
  validateImageCommandReferenceCount(command, parsed, mediaKind, parseImageGenerationOptions(parsed, mediaKind).model);
23182
23344
  validateVideoAudioOptions(parsed, mediaKind);
23183
23345
  parseVideoGenerationOptions(parsed, mediaKind);
23346
+ validateVideoFrameReferenceOptions(command, parsed, mediaKind);
23184
23347
  if (command !== "batch") validateProductionMetadataOptions(parsed);
23185
23348
  const ctx = await buildContext$7(parsed, deps);
23186
23349
  const client = await deps.createClient(ctx.env, ctx.spaceId);
@@ -23222,6 +23385,7 @@ async function prepareAudioParsedArgs(parsed, mode) {
23222
23385
  const positionals = [...parsed.positionals];
23223
23386
  const effectiveMode = mode ?? getAudioModeFromType(options.type);
23224
23387
  validateAudioProviderOption(options.provider, effectiveMode);
23388
+ validateAudioModelOption(options.model, effectiveMode);
23225
23389
  if (mode) options.type = getMediaOperationEntry(mode).assetType;
23226
23390
  validateAudioVoiceOptions(options);
23227
23391
  if (options.input) {
@@ -23246,23 +23410,28 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
23246
23410
  const assetType = requireOption(parsed, "type");
23247
23411
  const musicProvider = parseMusicProviderOption(parsed, mediaKind, assetType);
23248
23412
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
23413
+ const videoFrameRefs = parseVideoFrameReferenceOptions(parsed, "generate", mediaKind).refs;
23414
+ const state = videoFrameRefs.length > 0 ? await requestSpaceState(client) : void 0;
23415
+ const referenceVariantIds = videoFrameRefs.length > 0 ? await resolveReferenceVariantIds(videoFrameRefs, ctx, deps, state?.variants, CLI_GENERATION_MEDIA_KIND) : [];
23249
23416
  const scene = parseSceneMetadata(parsed, {
23250
23417
  prompt,
23251
- refs: [],
23252
- referenceVariantIds: [],
23418
+ refs: videoFrameRefs,
23419
+ referenceVariantIds,
23253
23420
  mediaKind
23254
23421
  });
23255
23422
  const imageOptions = parseImageGenerationOptions(parsed, mediaKind);
23423
+ const audioModelOptions = parseAudioGenerationOptions(parsed, mediaKind);
23256
23424
  const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
23257
23425
  const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
23258
23426
  const styleSelection = await resolveStyleSelection(parsed, ctx, deps);
23427
+ const disableStyle = parsed.options["no-style"] === "true" || videoFrameRefs.length > 0;
23259
23428
  await printPreflightEstimate(client, {
23260
23429
  operation: "generate",
23261
23430
  assetType,
23262
23431
  mediaKind,
23263
23432
  prompt,
23264
23433
  count: 1,
23265
- model: imageOptions.model,
23434
+ model: imageOptions.model ?? audioModelOptions.model,
23266
23435
  imageSize: imageOptions.imageSize,
23267
23436
  ...musicProvider ? { musicProvider } : {},
23268
23437
  ...videoAudioOptions,
@@ -23275,9 +23444,11 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
23275
23444
  name,
23276
23445
  assetType,
23277
23446
  prompt,
23447
+ ...referenceVariantIds.length > 0 ? { referenceVariantIds } : {},
23278
23448
  ...imageOptions,
23449
+ ...audioModelOptions,
23279
23450
  aspectRatio: imageOptions.aspectRatio ?? videoOptions.aspectRatio,
23280
- disableStyle: parsed.options["no-style"] === "true",
23451
+ disableStyle,
23281
23452
  ...styleSelection.stylePresetId ? { stylePresetId: styleSelection.stylePresetId } : {},
23282
23453
  mediaKind,
23283
23454
  ...audioVoiceOptions,
@@ -23305,8 +23476,8 @@ async function executeGenerate(parsed, ctx, client, deps, mediaKind, followOptio
23305
23476
  name,
23306
23477
  assetType,
23307
23478
  startedAt,
23308
- refs: [],
23309
- referenceVariantIds: [],
23479
+ refs: videoFrameRefs,
23480
+ referenceVariantIds,
23310
23481
  scene
23311
23482
  });
23312
23483
  await downloadResult(result, outputPath, ctx, deps);
@@ -23321,6 +23492,10 @@ function validateAudioProviderOption(value, mode) {
23321
23492
  if (mode !== "music") throw new Error("--provider is only supported for audio music");
23322
23493
  if (value !== "elevenlabs" && value !== "lyria") throw new Error("--provider must be elevenlabs or lyria");
23323
23494
  }
23495
+ function validateAudioModelOption(value, mode) {
23496
+ if (!value) return;
23497
+ if (mode !== "speech" && mode !== "dialogue") throw new Error("--model is only supported for speech and dialogue audio");
23498
+ }
23324
23499
  function parseMusicProviderOption(parsed, mediaKind, assetType) {
23325
23500
  const value = parsed.options.provider;
23326
23501
  if (!value) return void 0;
@@ -23406,20 +23581,24 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
23406
23581
  const outputPath = getOutputPath$1(parsed);
23407
23582
  const name = requireOption(parsed, "name");
23408
23583
  const assetType = requireOption(parsed, "type");
23409
- const refs = parseRefs(requireOption(parsed, "refs"));
23584
+ const videoFrameRefs = parseVideoFrameReferenceOptions(parsed, "derive", mediaKind).refs;
23585
+ const refs = parsed.options.refs ? parseRefs(requireOption(parsed, "refs")) : [];
23586
+ const referenceRefs = videoFrameRefs.length > 0 ? videoFrameRefs : refs;
23587
+ if (referenceRefs.length === 0) throw new Error("--refs is required");
23410
23588
  const imageOptions = parseImageGenerationOptions(parsed, mediaKind);
23411
- if (mediaKind === "image") validateImageReferenceCount(imageOptions.model, refs.length);
23412
- const referenceVariantIds = await resolveReferenceVariantIds(refs, ctx, deps, (await requestSpaceState(client)).variants, mediaKind);
23589
+ if (mediaKind === "image") validateImageReferenceCount(imageOptions.model, referenceRefs.length);
23590
+ const referenceVariantIds = await resolveReferenceVariantIds(referenceRefs, ctx, deps, (await requestSpaceState(client)).variants, videoFrameRefs.length > 0 ? CLI_GENERATION_MEDIA_KIND : mediaKind);
23413
23591
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
23414
23592
  const scene = parseSceneMetadata(parsed, {
23415
23593
  prompt,
23416
- refs,
23594
+ refs: referenceRefs,
23417
23595
  referenceVariantIds,
23418
23596
  mediaKind
23419
23597
  });
23420
23598
  const videoAudioOptions = parseVideoAudioOptions(parsed, mediaKind);
23421
23599
  const videoOptions = parseVideoGenerationOptions(parsed, mediaKind);
23422
23600
  const styleSelection = await resolveStyleSelection(parsed, ctx, deps);
23601
+ const disableStyle = parsed.options["no-style"] === "true" || videoFrameRefs.length > 0;
23423
23602
  await printPreflightEstimate(client, {
23424
23603
  operation: "derive",
23425
23604
  assetType,
@@ -23440,7 +23619,7 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
23440
23619
  referenceVariantIds,
23441
23620
  ...imageOptions,
23442
23621
  aspectRatio: imageOptions.aspectRatio ?? videoOptions.aspectRatio,
23443
- disableStyle: parsed.options["no-style"] === "true",
23622
+ disableStyle,
23444
23623
  ...styleSelection.stylePresetId ? { stylePresetId: styleSelection.stylePresetId } : {},
23445
23624
  mediaKind,
23446
23625
  ...videoAudioOptions,
@@ -23466,7 +23645,7 @@ async function executeDerive(parsed, ctx, client, deps, mediaKind, followOptions
23466
23645
  name,
23467
23646
  assetType,
23468
23647
  startedAt,
23469
- refs,
23648
+ refs: referenceRefs,
23470
23649
  referenceVariantIds,
23471
23650
  scene
23472
23651
  });
@@ -23631,6 +23810,7 @@ async function executeBatch(parsed, ctx, client, deps, mediaKind, saveBatchManif
23631
23810
  const mode = parseBatchMode(parsed.options.mode || "explore");
23632
23811
  const refs = parsed.options.refs ? parseRefs(parsed.options.refs) : [];
23633
23812
  const imageOptions = parseImageGenerationOptions(parsed, mediaKind);
23813
+ const audioModelOptions = parseAudioGenerationOptions(parsed, mediaKind);
23634
23814
  if (mediaKind === "image") validateImageReferenceCount(imageOptions.model, refs.length);
23635
23815
  const state = await requestSpaceState(client);
23636
23816
  const referenceVariantIds = refs.length > 0 ? await resolveReferenceVariantIds(refs, ctx, deps, state.variants, mediaKind) : void 0;
@@ -23643,7 +23823,7 @@ async function executeBatch(parsed, ctx, client, deps, mediaKind, saveBatchManif
23643
23823
  mediaKind,
23644
23824
  prompt,
23645
23825
  count,
23646
- model: imageOptions.model,
23826
+ model: imageOptions.model ?? audioModelOptions.model,
23647
23827
  imageSize: imageOptions.imageSize,
23648
23828
  ...musicProvider ? { musicProvider } : {}
23649
23829
  });
@@ -23659,6 +23839,7 @@ async function executeBatch(parsed, ctx, client, deps, mediaKind, saveBatchManif
23659
23839
  mode,
23660
23840
  referenceVariantIds,
23661
23841
  ...imageOptions,
23842
+ ...audioModelOptions,
23662
23843
  aspectRatio: imageOptions.aspectRatio,
23663
23844
  disableStyle: parsed.options["no-style"] === "true",
23664
23845
  ...styleSelection.stylePresetId ? { stylePresetId: styleSelection.stylePresetId } : {},
@@ -24101,6 +24282,31 @@ function parseVideoGenerationOptions(parsed, mediaKind) {
24101
24282
  ...videoTier ? { videoTier } : {}
24102
24283
  };
24103
24284
  }
24285
+ function parseVideoFrameReferenceOptions(parsed, command, mediaKind) {
24286
+ validateVideoFrameReferenceOptions(command, parsed, mediaKind);
24287
+ const firstFrame = readVideoFrameOption(parsed, "first-frame", "firstFrame");
24288
+ const lastFrame = readVideoFrameOption(parsed, "last-frame", "lastFrame");
24289
+ return { refs: [...firstFrame ? [firstFrame] : [], ...lastFrame ? [lastFrame] : []] };
24290
+ }
24291
+ function validateVideoFrameReferenceOptions(command, parsed, mediaKind) {
24292
+ const firstFrame = readVideoFrameOption(parsed, "first-frame", "firstFrame");
24293
+ const lastFrame = readVideoFrameOption(parsed, "last-frame", "lastFrame");
24294
+ if (!firstFrame && !lastFrame) return;
24295
+ if (mediaKind !== "video") throw new Error("--first-frame and --last-frame are only supported for video generation");
24296
+ if (command !== "generate" && command !== "derive") throw new Error("--first-frame and --last-frame are only supported for video generate and video derive");
24297
+ if (lastFrame && !firstFrame) throw new Error("--last-frame requires --first-frame");
24298
+ if (parsed.options.refs) throw new Error("--first-frame and --last-frame cannot be combined with --refs");
24299
+ if (readStylePresetOption(parsed)) throw new Error("--first-frame and --last-frame cannot be combined with --style-preset");
24300
+ }
24301
+ function readVideoFrameOption(parsed, kebabName, camelName) {
24302
+ const value = parsed.options[kebabName] ?? parsed.options[camelName];
24303
+ if (value === void 0) return void 0;
24304
+ const flag = `--${kebabName}`;
24305
+ if (value === "true") throw new Error(`${flag} requires a variant ID or local image path`);
24306
+ const trimmed = value.trim();
24307
+ if (!trimmed) throw new Error(`${flag} requires a variant ID or local image path`);
24308
+ return trimmed;
24309
+ }
24104
24310
  function parseDialogueVoiceIds(value) {
24105
24311
  const normalized = normalizeCliOption(value);
24106
24312
  if (!normalized) return void 0;
@@ -24112,6 +24318,11 @@ function normalizeCliOption(value) {
24112
24318
  if (value === void 0 || value === "true") return void 0;
24113
24319
  return value.trim() || void 0;
24114
24320
  }
24321
+ function parseAudioGenerationOptions(parsed, mediaKind) {
24322
+ if (mediaKind !== "audio") return {};
24323
+ const model = normalizeCliOption(readOptionalOption(parsed, "model", "model"));
24324
+ return model ? { model } : {};
24325
+ }
24115
24326
  function parseImageGenerationOptions(parsed, mediaKind) {
24116
24327
  if (mediaKind !== "image") return {};
24117
24328
  const model = parseImageModelOption(readOptionalOption(parsed, "model", "model"));
@@ -24427,11 +24638,12 @@ function printUsage$8() {
24427
24638
  const resolutionByTier = VIDEO_GENERATION_TIERS.map((tier) => `${tier}: ${getVideoGenerationResolutionsForTier(tier).join(", ")}`).join("; ");
24428
24639
  console.log(`
24429
24640
  Usage:
24430
- makefx video generate "prompt" --name <name> --type <type> -o <file> [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
24641
+ makefx video generate "prompt" --name <name> --type <type> -o <file> [--first-frame <variant_or_file>] [--last-frame <variant_or_file>] [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
24431
24642
  makefx video generate --follow <variant_id> -o <file> [--space <id>]
24432
24643
  makefx video refine --variant <variant_id> "prompt" -o <file> [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
24433
24644
  makefx video refine --follow <variant_id> -o <file> [--space <id>]
24434
24645
  makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
24646
+ makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--aspect ${aspectValues}] [--resolution ${resolutionValues}] [--duration ${durationValues}] [--tier ${tierValues}] [--audio] [--space <id>]
24435
24647
  makefx video derive --follow <variant_id> -o <file> [--space <id>]
24436
24648
 
24437
24649
  Video:
@@ -24439,6 +24651,15 @@ Video:
24439
24651
  --resolution <value> Veo output resolution (${resolutionByTier})
24440
24652
  --duration <seconds> Veo output duration: ${durationValues}
24441
24653
  --tier <tier> Veo model tier: ${tierValues}
24654
+ --first-frame <ref> Veo start frame image variant or local image path
24655
+ --last-frame <ref> Veo final frame image variant or local image path
24656
+
24657
+ Veo 3.1 frames:
24658
+ --first-frame resolves to the first referenceVariantId and becomes the Veo top-level image input.
24659
+ --last-frame resolves to the second referenceVariantId and becomes Veo config.lastFrame.
24660
+ Use both flags together for first/last-frame generation; --last-frame requires --first-frame.
24661
+ Frame flags disable style injection so style refs cannot be prepended ahead of the start/end frames.
24662
+ Do not combine frame flags with --refs or --style-preset. Use --refs when you want generic Veo reference images instead of first/last-frame inputs.
24442
24663
 
24443
24664
  Audio:
24444
24665
  --audio Request native synchronized Veo audio (default)
@@ -26552,7 +26773,7 @@ Options:
26552
26773
  }
26553
26774
  //#endregion
26554
26775
  //#region src/cli/index.ts
26555
- var CLI_VERSION = "0.2.6+be63b9dd565a";
26776
+ var CLI_VERSION = "0.2.8+62a28e206c2a";
26556
26777
  async function main() {
26557
26778
  const argv = process$1.argv.slice(2);
26558
26779
  if (argv[0] === "--") argv.shift();
@@ -26622,7 +26843,16 @@ function videoCapabilityHelp() {
26622
26843
  --aspect <ratio> Veo aspect ratio: ${videoAspectValues()}
26623
26844
  --resolution <value> Veo output resolution (${resolutionLines})
26624
26845
  --duration <seconds> Veo output duration: ${videoDurationValues()}
26625
- --tier <tier> Veo model tier: ${videoTierValues()}`;
26846
+ --tier <tier> Veo model tier: ${videoTierValues()}
26847
+ --first-frame <ref> Veo start frame image variant or local image path
26848
+ --last-frame <ref> Veo final frame image variant or local image path
26849
+
26850
+ Veo 3.1 frames:
26851
+ --first-frame resolves to the first referenceVariantId and becomes the Veo top-level image input.
26852
+ --last-frame resolves to the second referenceVariantId and becomes Veo config.lastFrame.
26853
+ Use both flags together for first/last-frame generation; --last-frame requires --first-frame.
26854
+ Frame flags disable style injection so style refs cannot be prepended ahead of the start/end frames.
26855
+ Do not combine frame flags with --refs or --style-preset. Use --refs when you want generic Veo reference images instead of first/last-frame inputs.`;
26626
26856
  }
26627
26857
  function configureLocalTls(args) {
26628
26858
  if (args.includes("--local") || args.includes("--env") && args[args.indexOf("--env") + 1] === "local") process$1.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
@@ -26806,10 +27036,10 @@ Audio:
26806
27036
  audio sfx generate "prompt" --name <name> -o <file>
26807
27037
 
26808
27038
  Video:
26809
- video generate "prompt" --name <name> --type <type> -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio]
27039
+ video generate "prompt" --name <name> --type <type> -o <file> [--first-frame <variant_or_file>] [--last-frame <variant_or_file>] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio]
26810
27040
  video generate --follow <variant_id> -o <file>
26811
27041
  video refine --variant <variant_id> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio]
26812
- video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio]
27042
+ video derive (--refs <variant_or_file,variant_or_file> | --first-frame <variant_or_file> [--last-frame <variant_or_file>]) --name <name> --type <type> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio]
26813
27043
 
26814
27044
  Options:
26815
27045
  --env <environment> Target environment (production|stage|local), default: production
@@ -26830,6 +27060,7 @@ Examples:
26830
27060
  makefx batch "Three Russafa market keyframes" --name "Market Keyframe" --type scene --count 3 --output-dir keyframes
26831
27061
  makefx audio sfx generate "A short brass victory sting" --name "Victory Sting" -o victory.wav
26832
27062
  makefx video generate "A looping idle animation" --name "Idle Animation" --type animation --duration 6 --resolution 1080p --tier fast -o idle.mp4
27063
+ makefx video derive --first-frame keyframes/start.png --last-frame keyframes/end.png --name "Camera Move" --type animation "slow dolly from start to end" -o move.mp4
26833
27064
  makefx productions export --production-id s01e01-a2
26834
27065
  makefx upload hero.png --name "Hero" --collection collection_cast
26835
27066
  makefx upload hero.png --name "Hero" --collection-name "Cast" --json
@@ -27037,6 +27268,7 @@ Usage:
27037
27268
  makefx audio ${first} generate --follow <variant_id> -o <file> [--space <id>]
27038
27269
  ${first === "music" ? " makefx audio music generate \"prompt\" --provider lyria --name <name> -o <file> [--space <id>]\n" : ""}
27039
27270
  ${first === "music" ? "Provider selection:\n --provider <elevenlabs|lyria> Music provider (default: server default)\n" : ""}
27271
+ ${first === "speech" || first === "dialogue" ? "Model selection:\n --model <model_id> ElevenLabs model (default: eleven_v3)\n" : ""}
27040
27272
  ${first === "speech" || first === "dialogue" ? "Voice selection:\n --voice <voice_id> Speech voice, or dialogue fallback voice\n --dialogue-voices <id,id,...> Dialogue voices ordered by first speaker appearance\n" : ""}
27041
27273
  `);
27042
27274
  return;
@@ -27047,6 +27279,8 @@ Usage:
27047
27279
  makefx audio ${first} batch "prompt" --name <name> --count <2-8> --output-dir <dir> [--space <id>]
27048
27280
  ${first === "music" ? " makefx audio music batch \"prompt\" --provider lyria --name <name> --count <2-8> --output-dir <dir> [--space <id>]\n" : ""}
27049
27281
  ${first === "music" ? "Provider selection:\n --provider <elevenlabs|lyria> Music provider (default: server default)\n" : ""}
27282
+ ${first === "speech" || first === "dialogue" ? "Model selection:\n --model <model_id> ElevenLabs model (default: eleven_v3)\n" : ""}
27283
+ ${first === "speech" || first === "dialogue" ? "Voice selection:\n --voice <voice_id> Speech voice, or dialogue fallback voice\n --dialogue-voices <id,id,...> Dialogue voices ordered by first speaker appearance\n" : ""}
27050
27284
  `);
27051
27285
  return;
27052
27286
  }
@@ -27055,6 +27289,7 @@ Usage:
27055
27289
  makefx audio ${first} generate "prompt" --name <name> -o <file> [--space <id>]
27056
27290
  makefx audio ${first} batch "prompt" --name <name> --count <2-8> --output-dir <dir> [--space <id>]
27057
27291
  ${first === "music" ? "\nProvider selection:\n --provider <elevenlabs|lyria> Music provider (default: server default)\n" : ""}
27292
+ ${first === "speech" || first === "dialogue" ? "\nModel selection:\n --model <model_id> ElevenLabs model (default: eleven_v3)\n" : ""}
27058
27293
  ${first === "speech" || first === "dialogue" ? "\nVoice selection:\n --voice <voice_id> Speech voice, or dialogue fallback voice\n --dialogue-voices <id,id,...> Dialogue voices ordered by first speaker appearance\n" : ""}
27059
27294
  `);
27060
27295
  return;
@@ -27098,6 +27333,9 @@ Voice selection:
27098
27333
  --voice <voice_id> Speech voice, or dialogue fallback voice
27099
27334
  --dialogue-voices <id,id,...> Dialogue voices ordered by first speaker appearance
27100
27335
 
27336
+ Model selection:
27337
+ --model <model_id> ElevenLabs speech/dialogue model (default: eleven_v3)
27338
+
27101
27339
  Low-level compatibility:
27102
27340
  makefx audio generate "prompt" --name <name> --type <type> -o <file> [--space <id>]
27103
27341
  makefx audio batch "prompt" --name <name> --type <type> --count <2-8> --output-dir <dir> [--space <id>]
@@ -27108,7 +27346,7 @@ function printVideoHelp(positionals) {
27108
27346
  if (subcommand === "generate") {
27109
27347
  console.log(`
27110
27348
  Usage:
27111
- makefx video generate "prompt" --name <name> --type <type> -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
27349
+ makefx video generate "prompt" --name <name> --type <type> -o <file> [--first-frame <variant_or_file>] [--last-frame <variant_or_file>] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
27112
27350
  makefx video generate --follow <variant_id> -o <file> [--space <id>]
27113
27351
 
27114
27352
  ${videoCapabilityHelp()}
@@ -27143,6 +27381,7 @@ Production metadata:
27143
27381
  console.log(`
27144
27382
  Usage:
27145
27383
  makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
27384
+ makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
27146
27385
  makefx video derive --follow <variant_id> -o <file> [--space <id>]
27147
27386
 
27148
27387
  ${videoCapabilityHelp()}
@@ -27158,10 +27397,11 @@ Production metadata:
27158
27397
  }
27159
27398
  console.log(`
27160
27399
  Usage:
27161
- makefx video generate "prompt" --name <name> --type <type> -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
27400
+ makefx video generate "prompt" --name <name> --type <type> -o <file> [--first-frame <variant_or_file>] [--last-frame <variant_or_file>] [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
27162
27401
  makefx video generate --follow <variant_id> -o <file> [--space <id>]
27163
27402
  makefx video refine --variant <variant_id> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
27164
27403
  makefx video derive --refs <variant_or_file,variant_or_file> --name <name> --type <type> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
27404
+ makefx video derive --first-frame <variant_or_file> [--last-frame <variant_or_file>] --name <name> --type <type> "prompt" -o <file> [--aspect ${videoAspectValues()}] [--resolution ${videoResolutionValues()}] [--duration ${videoDurationValues()}] [--tier ${videoTierValues()}] [--audio] [--space <id>]
27165
27405
 
27166
27406
  ${videoCapabilityHelp()}
27167
27407
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "makefx",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "Command-line interface for AI-assisted game asset production with Make Effects.",
5
5
  "license": "MIT",
6
6
  "type": "module",