@melius-ai/cli 0.4.0 → 0.5.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 CHANGED
@@ -255,6 +255,25 @@ mel upload ./photo.png
255
255
  mel upload ./photo.png --node-id <nodeId> --canvas-id <canvasId>
256
256
  ```
257
257
 
258
+ ### Assets (Files / DAM library)
259
+
260
+ Requires the Pro or Enterprise plan.
261
+
262
+ | Command | Description |
263
+ | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
264
+ | `mel asset search <query>` | Search the team's Files/DAM library (uploads + past generations) by meaning; exact matches rank first. Returns up to 5 matches |
265
+ | `mel asset place <canvasId> <assetIds...>` | Place existing library assets onto a canvas by id — references the **original** asset (no duplicate) |
266
+
267
+ `mel asset search` searches by meaning (semantic), with exact filename/title matches ranked first, so query with a filename or a description of the content. It returns `{ query, total, results: [{ assetId, filename, fileType, previewUrl, ... }] }`. Filter with `--file-type <image|video|audio|pdf|text>` and `--limit <1-5>`; scope to one canvas with `--canvas-id` (omit to search the whole team library).
268
+
269
+ `mel asset place` creates a file node per asset (writes to CRDT, no re-upload) and returns `{ placed: [{ assetId, nodeId, mediaType }] }`. Wire the returned `nodeId`s into generations with `mel edge create`. This is the correct way to reuse an existing library asset — do **not** re-upload it.
270
+
271
+ ```bash
272
+ # Find an asset, then bring it onto a canvas and wire it
273
+ mel asset search "black jacket shot" --file-type image
274
+ mel asset place <canvasId> <assetId1> <assetId2>
275
+ ```
276
+
258
277
  ### Shell completion
259
278
 
260
279
  `mel completion <shell>` prints a tab-completion script for `bash`, `zsh`, or `fish`. The script is generated from the live command tree, so it never drifts from the actual commands.
package/dist/bin/mel.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  printUpgradeNoticeIfNeeded,
8
8
  withDefaultHelp,
9
9
  writeError
10
- } from "../chunk-EXHDKHNG.js";
10
+ } from "../chunk-UAK5HMFU.js";
11
11
 
12
12
  // bin/mel.ts
13
13
  var program = createProgram();
@@ -7757,9 +7757,6 @@ function paginationQuery({
7757
7757
  var c = initContract();
7758
7758
  var MAX_CUSTOM_CONTEXT_NAME_LENGTH = 80;
7759
7759
  var MAX_CUSTOM_CONTEXT_INSTRUCTIONS_LENGTH = 4e3;
7760
- var MAX_CUSTOM_CONTEXT_ASSET_DESCRIPTION_LENGTH = 500;
7761
- var MAX_CUSTOM_CONTEXT_FILE_SIZE_BYTES = 10 * 1024 * 1024;
7762
- var CUSTOM_CONTEXT_UPLOAD_PART_SIZE = 16 * 1024 * 1024;
7763
7760
  var MAX_AGENT_CUSTOM_CONTEXTS_PER_MESSAGE = 1;
7764
7761
  var CustomContextAssetSchema = external_exports.object({
7765
7762
  id: external_exports.string().uuid(),
@@ -7772,9 +7769,6 @@ var CustomContextAssetSchema = external_exports.object({
7772
7769
  previewText: external_exports.string().nullable(),
7773
7770
  description: external_exports.string().nullable()
7774
7771
  });
7775
- var UpdateCustomContextAssetBodySchema = external_exports.object({
7776
- description: external_exports.string().max(MAX_CUSTOM_CONTEXT_ASSET_DESCRIPTION_LENGTH).nullable()
7777
- });
7778
7772
  var CustomContextSummarySchema = external_exports.object({
7779
7773
  id: external_exports.string().uuid(),
7780
7774
  name: external_exports.string(),
@@ -7811,26 +7805,6 @@ var UpdateCustomContextBodySchema = external_exports.object({
7811
7805
  (body) => body.name !== void 0 || body.instructions !== void 0,
7812
7806
  { message: "At least one field must be provided" }
7813
7807
  );
7814
- var CustomContextAssetInitUploadSchema = external_exports.object({
7815
- filename: external_exports.string(),
7816
- contentType: external_exports.string(),
7817
- sizeInBytes: external_exports.number().int().positive().max(MAX_CUSTOM_CONTEXT_FILE_SIZE_BYTES)
7818
- });
7819
- var CustomContextAssetInitUploadResponseSchema = external_exports.object({
7820
- uploadId: external_exports.string(),
7821
- s3Bucket: external_exports.string(),
7822
- s3Key: external_exports.string(),
7823
- partSize: external_exports.number().int().positive()
7824
- });
7825
- var CustomContextAssetSignPartSchema = external_exports.object({
7826
- uploadId: external_exports.string(),
7827
- s3Bucket: external_exports.string(),
7828
- s3Key: external_exports.string(),
7829
- partNumber: external_exports.number().int().positive()
7830
- });
7831
- var CustomContextAssetSignPartResponseSchema = external_exports.object({
7832
- url: external_exports.string()
7833
- });
7834
7808
  var ImportCustomContextToCanvasResponseSchema = external_exports.object({
7835
7809
  groupId: external_exports.string().uuid(),
7836
7810
  nodeIds: external_exports.array(external_exports.string().uuid()),
@@ -7845,17 +7819,6 @@ var ImportCustomContextToCanvasResponseSchema = external_exports.object({
7845
7819
  })
7846
7820
  ).default([])
7847
7821
  });
7848
- var CustomContextAssetCompleteUploadSchema = external_exports.object({
7849
- uploadId: external_exports.string(),
7850
- s3Bucket: external_exports.string(),
7851
- s3Key: external_exports.string(),
7852
- filename: external_exports.string(),
7853
- contentType: external_exports.string(),
7854
- sizeInBytes: external_exports.number().int().positive().max(MAX_CUSTOM_CONTEXT_FILE_SIZE_BYTES),
7855
- previewText: external_exports.string().nullable().optional(),
7856
- description: external_exports.string().max(MAX_CUSTOM_CONTEXT_ASSET_DESCRIPTION_LENGTH).nullable().optional(),
7857
- parts: external_exports.array(CompletedPartSchema)
7858
- });
7859
7822
  var customContextContract = c.router({
7860
7823
  listCustomContexts: {
7861
7824
  method: "GET",
@@ -7920,80 +7883,6 @@ var customContextContract = c.router({
7920
7883
  404: MessageResponseSchema
7921
7884
  }
7922
7885
  },
7923
- initCustomContextAssetUpload: {
7924
- method: "POST",
7925
- path: "/teams/:teamId/custom-contexts/:contextId/assets/init",
7926
- pathParams: external_exports.object({
7927
- teamId: external_exports.string().uuid(),
7928
- contextId: external_exports.string().uuid()
7929
- }),
7930
- body: CustomContextAssetInitUploadSchema,
7931
- responses: {
7932
- 200: CustomContextAssetInitUploadResponseSchema,
7933
- 400: MessageResponseSchema,
7934
- 403: MessageResponseSchema,
7935
- 404: MessageResponseSchema
7936
- }
7937
- },
7938
- signCustomContextAssetUploadPart: {
7939
- method: "POST",
7940
- path: "/teams/:teamId/custom-contexts/:contextId/assets/sign-part",
7941
- pathParams: external_exports.object({
7942
- teamId: external_exports.string().uuid(),
7943
- contextId: external_exports.string().uuid()
7944
- }),
7945
- body: CustomContextAssetSignPartSchema,
7946
- responses: {
7947
- 200: CustomContextAssetSignPartResponseSchema,
7948
- 403: MessageResponseSchema,
7949
- 404: MessageResponseSchema
7950
- }
7951
- },
7952
- completeCustomContextAssetUpload: {
7953
- method: "POST",
7954
- path: "/teams/:teamId/custom-contexts/:contextId/assets/complete",
7955
- pathParams: external_exports.object({
7956
- teamId: external_exports.string().uuid(),
7957
- contextId: external_exports.string().uuid()
7958
- }),
7959
- body: CustomContextAssetCompleteUploadSchema,
7960
- responses: {
7961
- 200: CustomContextDetailSchema,
7962
- 400: MessageResponseSchema,
7963
- 403: MessageResponseSchema,
7964
- 404: MessageResponseSchema
7965
- }
7966
- },
7967
- removeCustomContextAsset: {
7968
- method: "DELETE",
7969
- path: "/teams/:teamId/custom-contexts/:contextId/assets/:assetId",
7970
- pathParams: external_exports.object({
7971
- teamId: external_exports.string().uuid(),
7972
- contextId: external_exports.string().uuid(),
7973
- assetId: external_exports.string().uuid()
7974
- }),
7975
- responses: {
7976
- 200: CustomContextDetailSchema,
7977
- 403: MessageResponseSchema,
7978
- 404: MessageResponseSchema
7979
- }
7980
- },
7981
- updateCustomContextAsset: {
7982
- method: "PATCH",
7983
- path: "/teams/:teamId/custom-contexts/:contextId/assets/:assetId",
7984
- pathParams: external_exports.object({
7985
- teamId: external_exports.string().uuid(),
7986
- contextId: external_exports.string().uuid(),
7987
- assetId: external_exports.string().uuid()
7988
- }),
7989
- body: UpdateCustomContextAssetBodySchema,
7990
- responses: {
7991
- 200: CustomContextDetailSchema,
7992
- 400: MessageResponseSchema,
7993
- 403: MessageResponseSchema,
7994
- 404: MessageResponseSchema
7995
- }
7996
- },
7997
7886
  importCustomContextToCanvas: {
7998
7887
  method: "POST",
7999
7888
  path: "/teams/:teamId/custom-contexts/:contextId/import-to-canvas/:canvasId",
@@ -8191,7 +8080,7 @@ var ListFilesResponseSchema = external_exports.object({
8191
8080
  hasMore: external_exports.boolean().optional()
8192
8081
  });
8193
8082
  var AgentAssetSearchQuerySchema = external_exports.object({
8194
- query: external_exports.string().trim().min(1).max(500).describe("Semantic asset search query"),
8083
+ query: external_exports.string().trim().min(1).max(500).describe("Asset search query"),
8195
8084
  limit: external_exports.coerce.number().int().min(1).max(5).default(5),
8196
8085
  source: FileSourceSchema.optional(),
8197
8086
  fileType: FileTypeSchema.optional(),
@@ -8199,6 +8088,12 @@ var AgentAssetSearchQuerySchema = external_exports.object({
8199
8088
  'Optional. Omit to search the whole team library \u2014 this is the default and what nearly every request wants (e.g. "use the asset I have"). Only set this to scope to a DIFFERENT canvas the member explicitly names ("search my other canvas"), resolving the id from canvas_list. Do NOT pass the canvas the chat is currently on (its assets are already visible via canvas_content, and scoping there hides whole-library matches), and never guess an id.'
8200
8089
  )
8201
8090
  });
8091
+ var AgentAssetSearchModeSchema = external_exports.enum(["semantic", "filename"]);
8092
+ var AgentAssetSearchRequestSchema = AgentAssetSearchQuerySchema.extend(
8093
+ {
8094
+ mode: AgentAssetSearchModeSchema.optional()
8095
+ }
8096
+ );
8202
8097
  var AgentAssetSearchResponseSchema = external_exports.object({
8203
8098
  query: external_exports.string(),
8204
8099
  results: external_exports.array(FileCardSchema),
@@ -8373,7 +8268,7 @@ var filesContract = c2.router({
8373
8268
  searchAgentAssets: {
8374
8269
  method: "GET",
8375
8270
  path: "/files/agent-search",
8376
- query: AgentAssetSearchQuerySchema,
8271
+ query: AgentAssetSearchRequestSchema,
8377
8272
  responses: {
8378
8273
  200: AgentAssetSearchResponseSchema,
8379
8274
  403: ErrorBodySchema
@@ -9135,11 +9030,10 @@ var AUTO_MODEL_REGISTRY = [
9135
9030
  {
9136
9031
  nodeType: "video",
9137
9032
  inputPattern: "frames-with-audio",
9138
- // Start + end frame + audio falls back to ltx-2.3-audio because
9139
- // kling-avatar's variant does not accept end_image_url, so
9140
- // variant selection would reject the second image.
9141
- standard: { model: "ltx-2.3-audio", variant: "image-to-video" },
9142
- fast: { model: "ltx-2.3-audio", variant: "image-to-video" }
9033
+ // Kling Avatar does not accept end_image_url, so route frame+audio
9034
+ // runs through LTX's audio-capable image-to-video variant.
9035
+ standard: { model: "ltx-2.3", variant: "image-to-video" },
9036
+ fast: { model: "ltx-2.3", variant: "image-to-video" }
9143
9037
  },
9144
9038
  {
9145
9039
  nodeType: "video",
@@ -9230,7 +9124,11 @@ var AutoModelProxy = class {
9230
9124
  resolve(input) {
9231
9125
  switch (input.nodeType) {
9232
9126
  case "video":
9233
- return this.resolveVideo(input.connectedInputs, input.tier);
9127
+ return this.resolveVideo(
9128
+ input.connectedInputs,
9129
+ input.tier,
9130
+ input.canvasVideoInputRoutingEnabled === true
9131
+ );
9234
9132
  case "image":
9235
9133
  return this.resolveImage(input.connectedInputs, input.tier);
9236
9134
  case "text":
@@ -9249,7 +9147,7 @@ var AutoModelProxy = class {
9249
9147
  return this.registry;
9250
9148
  }
9251
9149
  // ── Private resolvers ───────────────────────────────────────────────
9252
- resolveVideo(ci, tier) {
9150
+ resolveVideo(ci, tier, canvasVideoInputRoutingEnabled) {
9253
9151
  const hasAnyImage = ci.hasImage || ci.hasStartingImage || ci.hasEndImage || ci.hasReferenceImage;
9254
9152
  if (ci.hasVideo && hasAnyImage) {
9255
9153
  return {
@@ -9273,7 +9171,11 @@ var AutoModelProxy = class {
9273
9171
  return this.lookupRoute("video", "video-with-audio", tier);
9274
9172
  }
9275
9173
  if (ci.hasAudio && (ci.hasStartingImage || ci.hasImage) && ci.hasEndImage) {
9276
- return this.lookupRoute("video", "frames-with-audio", tier);
9174
+ return canvasVideoInputRoutingEnabled ? this.lookupRoute("video", "frames-with-audio", tier) : {
9175
+ valid: true,
9176
+ model: "ltx-2.3-audio",
9177
+ variant: "image-to-video"
9178
+ };
9277
9179
  }
9278
9180
  if (ci.hasAudio && hasAnyImage) {
9279
9181
  return this.lookupRoute("video", "image-with-audio", tier);
@@ -9423,6 +9325,7 @@ var GENERATION_MODES = [
9423
9325
  "video-to-video",
9424
9326
  "reference-to-video",
9425
9327
  "first-last-frame-to-video",
9328
+ "audio-to-video",
9426
9329
  "text-to-speech",
9427
9330
  "audio-to-audio",
9428
9331
  "text-to-sfx",
@@ -9811,6 +9714,7 @@ var ElevenLabsVoiceSettingsSchema = external_exports.object({
9811
9714
 
9812
9715
  // ../api-contract/src/lora.ts
9813
9716
  var c6 = initContract();
9717
+ var LORA_UPLOAD_PART_SIZE_BYTES = 16 * 1024 * 1024;
9814
9718
  var MAX_LORA_NAME_LENGTH = 80;
9815
9719
  var MAX_LORA_DESCRIPTION_LENGTH = 1e3;
9816
9720
  var MAX_LORA_TRIGGER_WORDS_LENGTH = 500;
@@ -9819,10 +9723,10 @@ var MAX_LORAS_PER_GENERATION = 5;
9819
9723
  var MIN_LORA_WEIGHT = 0;
9820
9724
  var MAX_LORA_WEIGHT = 1.5;
9821
9725
  var MIN_SDXL_STEPS = 1;
9822
- var MAX_SDXL_STEPS = 60;
9726
+ var MAX_SDXL_STEPS = 50;
9823
9727
  var MIN_SDXL_GUIDANCE_SCALE = 0;
9824
9728
  var MAX_SDXL_GUIDANCE_SCALE = 20;
9825
- var LoraBaseModelSchema = external_exports.enum(["sdxl", "flux", "other"]);
9729
+ var LoraBaseModelSchema = external_exports.enum(["sdxl", "flux", "flux-2", "other"]);
9826
9730
  var LoraSelectionSchema = external_exports.object({
9827
9731
  id: external_exports.string().uuid(),
9828
9732
  weight: external_exports.number().min(MIN_LORA_WEIGHT).max(MAX_LORA_WEIGHT)
@@ -9859,10 +9763,22 @@ var InitLoraUploadBodySchema = external_exports.object({
9859
9763
  sizeInBytes: external_exports.number().int().positive().max(MAX_LORA_FILE_SIZE_BYTES)
9860
9764
  });
9861
9765
  var InitLoraUploadResponseSchema = external_exports.object({
9862
- /** Short-lived presigned PUT the client uploads the raw weights to. */
9863
- uploadUrl: external_exports.string(),
9766
+ /** S3 multipart upload id the client threads into sign-part + create. */
9767
+ uploadId: external_exports.string(),
9864
9768
  s3Bucket: external_exports.string(),
9865
- s3Key: external_exports.string()
9769
+ s3Key: external_exports.string(),
9770
+ /** Byte size of each part except the last (see LORA_UPLOAD_PART_SIZE_BYTES). */
9771
+ partSize: external_exports.number().int().positive()
9772
+ });
9773
+ var SignLoraUploadPartBodySchema = external_exports.object({
9774
+ uploadId: external_exports.string().min(1),
9775
+ s3Bucket: external_exports.string().min(1),
9776
+ s3Key: external_exports.string().min(1),
9777
+ partNumber: external_exports.number().int().positive()
9778
+ });
9779
+ var SignLoraUploadPartResponseSchema = external_exports.object({
9780
+ /** Short-lived presigned PUT for this one part. */
9781
+ url: external_exports.string()
9866
9782
  });
9867
9783
  var CreateLoraBodySchema = external_exports.object({
9868
9784
  name: external_exports.string().trim().min(1).max(MAX_LORA_NAME_LENGTH),
@@ -9872,11 +9788,23 @@ var CreateLoraBodySchema = external_exports.object({
9872
9788
  baseModel: LoraBaseModelSchema,
9873
9789
  s3Bucket: external_exports.string().min(1),
9874
9790
  s3Key: external_exports.string().min(1),
9875
- /** Client-attested SHA-256 of the uploaded file (integrity reference). */
9876
- sha256: external_exports.string().min(1),
9791
+ /** Multipart upload id + parts to finalize before validating the object. */
9792
+ uploadId: external_exports.string().min(1),
9793
+ parts: external_exports.array(CompletedPartSchema).min(1),
9794
+ /**
9795
+ * Optional client-attested SHA-256 (integrity reference, never verified).
9796
+ * Omitted for large files — hashing gigabytes in the browser OOMs the tab —
9797
+ * where S3 multipart part ETags already guarantee integrity.
9798
+ */
9799
+ sha256: external_exports.string().optional(),
9877
9800
  fileSizeBytes: external_exports.number().int().positive().max(MAX_LORA_FILE_SIZE_BYTES),
9878
9801
  defaultScale: external_exports.number().min(MIN_LORA_WEIGHT).max(MAX_LORA_WEIGHT).optional()
9879
9802
  });
9803
+ var UpdateLoraBodySchema = external_exports.object({
9804
+ name: external_exports.string().trim().min(1).max(MAX_LORA_NAME_LENGTH).optional(),
9805
+ description: external_exports.string().max(MAX_LORA_DESCRIPTION_LENGTH).optional(),
9806
+ triggerWords: external_exports.string().max(MAX_LORA_TRIGGER_WORDS_LENGTH).optional()
9807
+ });
9880
9808
  var ForbiddenSchema = MessageResponseSchema;
9881
9809
  var NotFoundSchema = MessageResponseSchema;
9882
9810
  var BadRequestSchema = MessageResponseSchema;
@@ -9892,7 +9820,7 @@ var loraContract = c6.router({
9892
9820
  404: NotFoundSchema
9893
9821
  }
9894
9822
  },
9895
- // @SkipManagedTransaction on the handler — only mints a presigned PUT.
9823
+ // @SkipManagedTransaction on the handler — only starts an S3 multipart.
9896
9824
  initLoraUpload: {
9897
9825
  method: "POST",
9898
9826
  path: "/teams/:teamId/loras/upload",
@@ -9904,6 +9832,18 @@ var loraContract = c6.router({
9904
9832
  403: ForbiddenSchema
9905
9833
  }
9906
9834
  },
9835
+ // @SkipManagedTransaction on the handler — only mints a presigned part PUT.
9836
+ signLoraUploadPart: {
9837
+ method: "POST",
9838
+ path: "/teams/:teamId/loras/upload/sign-part",
9839
+ pathParams: external_exports.object({ teamId: external_exports.string().uuid() }),
9840
+ body: SignLoraUploadPartBodySchema,
9841
+ responses: {
9842
+ 200: SignLoraUploadPartResponseSchema,
9843
+ 400: BadRequestSchema,
9844
+ 403: ForbiddenSchema
9845
+ }
9846
+ },
9907
9847
  createLora: {
9908
9848
  method: "POST",
9909
9849
  path: "/teams/:teamId/loras",
@@ -9916,6 +9856,22 @@ var loraContract = c6.router({
9916
9856
  409: ConflictSchema
9917
9857
  }
9918
9858
  },
9859
+ updateLora: {
9860
+ method: "PATCH",
9861
+ path: "/teams/:teamId/loras/:loraId",
9862
+ pathParams: external_exports.object({
9863
+ teamId: external_exports.string().uuid(),
9864
+ loraId: external_exports.string().uuid()
9865
+ }),
9866
+ body: UpdateLoraBodySchema,
9867
+ responses: {
9868
+ 200: LoraSummarySchema,
9869
+ 400: BadRequestSchema,
9870
+ 403: ForbiddenSchema,
9871
+ 404: NotFoundSchema,
9872
+ 409: ConflictSchema
9873
+ }
9874
+ },
9919
9875
  deleteLora: {
9920
9876
  method: "DELETE",
9921
9877
  path: "/teams/:teamId/loras/:loraId",
@@ -11813,6 +11769,35 @@ var canvasContract = c7.router({
11813
11769
  404: MessageResponseSchema
11814
11770
  }
11815
11771
  },
11772
+ // Server-side placement of existing library assets onto a canvas, by id.
11773
+ // Unlike `linkLibraryAsset` (which links an asset to a node the in-app
11774
+ // client already created in the CRDT), this CREATES the file node(s)
11775
+ // server-side and references the ORIGINAL asset (no duplicate) — the path
11776
+ // MCP/CLI need, since they have no browser canvas store. Positions are
11777
+ // planned server-side into open space. Gated by the same asset-search
11778
+ // entitlement (`isAgentSearchToolAvailable`) as `searchAgentAssets`.
11779
+ placeLibraryAssets: {
11780
+ method: "POST",
11781
+ path: "/canvases/:canvasId/library-assets/place",
11782
+ pathParams: external_exports.object({ canvasId: external_exports.string().uuid() }),
11783
+ body: external_exports.object({
11784
+ assetIds: external_exports.array(external_exports.string().uuid()).min(1).max(10)
11785
+ }),
11786
+ responses: {
11787
+ 200: external_exports.object({
11788
+ placed: external_exports.array(
11789
+ external_exports.object({
11790
+ assetId: external_exports.string().uuid(),
11791
+ nodeId: external_exports.string().uuid(),
11792
+ mediaType: external_exports.enum(["image", "video", "audio", "pdf"])
11793
+ })
11794
+ )
11795
+ }),
11796
+ 403: external_exports.object({ message: external_exports.string() }),
11797
+ 404: external_exports.object({ message: external_exports.string() })
11798
+ },
11799
+ summary: "Place library assets onto a canvas"
11800
+ },
11816
11801
  // ── Canvas Settings ──────────────────────────────────────────────
11817
11802
  getCanvasSettings: {
11818
11803
  method: "GET",
@@ -11911,10 +11896,16 @@ var CompleteCustomFontUploadBodySchema = external_exports.object({
11911
11896
  sizeInBytes: external_exports.number().int().positive(),
11912
11897
  parts: external_exports.array(CompletedPartSchema)
11913
11898
  });
11899
+ var ListCustomFontsQuerySchema = external_exports.object({
11900
+ // Optional name filter (matches family name or original filename). Used by
11901
+ // the Assets page fonts view; the node font pickers omit it to list all.
11902
+ search: external_exports.string().trim().optional()
11903
+ });
11914
11904
  var customFontContract = c8.router({
11915
11905
  list: {
11916
11906
  method: "GET",
11917
11907
  path: "/custom-fonts",
11908
+ query: ListCustomFontsQuerySchema,
11918
11909
  responses: { 200: ListCustomFontsResponseSchema },
11919
11910
  summary: "List custom fonts for the team"
11920
11911
  },
@@ -12166,6 +12157,14 @@ var ModelVariantResponseSchema = external_exports.object({
12166
12157
  maxReferenceImagesWithEndImage: external_exports.number().nullable().optional(),
12167
12158
  maxVideoInputs: external_exports.number().nullable().optional(),
12168
12159
  maxAudioInputs: external_exports.number().nullable().optional(),
12160
+ /**
12161
+ * For variants accepting both video and audio: whether the connected
12162
+ * durations must line up. `false` for lipsync models (e.g. Kling Lipsync)
12163
+ * whose endpoint takes audio independent of the video length, so the
12164
+ * frontend preflight must not block a mismatch. Omitted/null means the
12165
+ * default duration-match requirement applies.
12166
+ */
12167
+ requiresMatchingAudioVideoDuration: external_exports.boolean().nullable().optional(),
12169
12168
  maxNativeOutputs: external_exports.number().nullable(),
12170
12169
  maxInputArea: external_exports.number().nullable(),
12171
12170
  inputImageFileSizeConstraints: InputFileSizeConstraintsResponseSchema.nullable().optional(),
@@ -12188,7 +12187,13 @@ var ModelVariantResponseSchema = external_exports.object({
12188
12187
  estimatedLatencySeconds: external_exports.number().nullable().optional(),
12189
12188
  defaultResolution: OutputResolutionSchema.nullable().optional(),
12190
12189
  featuredDescription: external_exports.string().nullable(),
12191
- cost: ModelCostSchema.optional()
12190
+ cost: ModelCostSchema.optional(),
12191
+ /**
12192
+ * Per-second credit multiplier applied to connected input video duration,
12193
+ * using the resolution-adjusted output per-second price as the base. Lets
12194
+ * the cost preview include the input-video surcharge that the server bills.
12195
+ */
12196
+ inputVideoCreditMultiplier: external_exports.number().optional()
12192
12197
  });
12193
12198
  var ModelResponseSchema = external_exports.object({
12194
12199
  name: external_exports.string(),
@@ -12710,6 +12715,34 @@ var EnterpriseStripeBillingInputSchema = external_exports.object({
12710
12715
  path: ["contractEndAt"]
12711
12716
  }
12712
12717
  );
12718
+ var CustomPlanCreditRolloverPolicySchema = external_exports.discriminatedUnion(
12719
+ "mode",
12720
+ [
12721
+ external_exports.object({ mode: external_exports.literal("none") }),
12722
+ external_exports.object({ mode: external_exports.literal("unlimited") }),
12723
+ external_exports.object({
12724
+ mode: external_exports.literal("months"),
12725
+ months: external_exports.number().int().nonnegative()
12726
+ }),
12727
+ external_exports.object({
12728
+ mode: external_exports.literal("percentage"),
12729
+ percentage: external_exports.number().int().min(0).max(100)
12730
+ })
12731
+ ]
12732
+ );
12733
+ var EnterpriseOrderDetailsSchema = external_exports.object({
12734
+ orderType: external_exports.string().min(1),
12735
+ customPlanType: CustomPlanTypeSchema.optional(),
12736
+ creditPackageAmount: external_exports.number().int().nonnegative(),
12737
+ creditPackageUnit: external_exports.string().min(1),
12738
+ creditRolloverPolicy: CustomPlanCreditRolloverPolicySchema.optional(),
12739
+ orderDate: external_exports.string().date(),
12740
+ /** Omit for plans with no fixed contract term (e.g. monthly Stripe plans). */
12741
+ termCount: external_exports.number().int().positive().optional(),
12742
+ termUnit: external_exports.string().min(1).optional(),
12743
+ lineItems: external_exports.array(EnterpriseOrderLineItemSchema),
12744
+ totalContractValue: external_exports.string().min(1)
12745
+ });
12713
12746
  var EnterprisePendingExpansionSchema = external_exports.object({
12714
12747
  /** Stable id minted at prepare; also the credit-grant idempotency key. */
12715
12748
  id: external_exports.string(),
@@ -12723,6 +12756,13 @@ var EnterprisePendingExpansionSchema = external_exports.object({
12723
12756
  /** New contract end when the operator chose a new term; absent means keep the existing term. */
12724
12757
  contractEndAt: external_exports.string().datetime().optional(),
12725
12758
  keepContractEnd: external_exports.boolean(),
12759
+ /**
12760
+ * Operator-authored replacement order details (line items, total contract
12761
+ * value, credit package, term) applied to the stored order when the customer
12762
+ * activates. Absent keeps the existing terms. Purely presentational — the
12763
+ * actual charge/credits come from the billing figures above.
12764
+ */
12765
+ newOrderDetails: EnterpriseOrderDetailsSchema.optional(),
12726
12766
  preparedAt: external_exports.string().datetime(),
12727
12767
  preparedByEmail: external_exports.string().nullable()
12728
12768
  });
@@ -12758,33 +12798,7 @@ var EnterpriseStripeBillingAuditEntrySchema = external_exports.object({
12758
12798
  previousStripePriceId: external_exports.string().optional(),
12759
12799
  notes: external_exports.string().optional()
12760
12800
  });
12761
- var CustomPlanCreditRolloverPolicySchema = external_exports.discriminatedUnion(
12762
- "mode",
12763
- [
12764
- external_exports.object({ mode: external_exports.literal("none") }),
12765
- external_exports.object({ mode: external_exports.literal("unlimited") }),
12766
- external_exports.object({
12767
- mode: external_exports.literal("months"),
12768
- months: external_exports.number().int().nonnegative()
12769
- }),
12770
- external_exports.object({
12771
- mode: external_exports.literal("percentage"),
12772
- percentage: external_exports.number().int().min(0).max(100)
12773
- })
12774
- ]
12775
- );
12776
- var EnterpriseOrderSchema = external_exports.object({
12777
- orderType: external_exports.string().min(1),
12778
- customPlanType: CustomPlanTypeSchema.optional(),
12779
- creditPackageAmount: external_exports.number().int().nonnegative(),
12780
- creditPackageUnit: external_exports.string().min(1),
12781
- creditRolloverPolicy: CustomPlanCreditRolloverPolicySchema.optional(),
12782
- orderDate: external_exports.string().date(),
12783
- /** Omit for plans with no fixed contract term (e.g. monthly Stripe plans). */
12784
- termCount: external_exports.number().int().positive().optional(),
12785
- termUnit: external_exports.string().min(1).optional(),
12786
- lineItems: external_exports.array(EnterpriseOrderLineItemSchema),
12787
- totalContractValue: external_exports.string().min(1),
12801
+ var EnterpriseOrderSchema = EnterpriseOrderDetailsSchema.extend({
12788
12802
  stripeBilling: EnterpriseStripeBillingInputSchema.optional()
12789
12803
  });
12790
12804
  var CustomerEnterpriseOrderSchema = EnterpriseOrderSchema.extend({
@@ -13467,6 +13481,13 @@ var publicContract = c16.router(
13467
13481
  signPart: uploadContract.signPart,
13468
13482
  complete: uploadContract.complete
13469
13483
  },
13484
+ asset: {
13485
+ // Semantic/filename search of the team's Files (DAM) library, and
13486
+ // placing a found asset onto a canvas by reference (no duplicate).
13487
+ // Both are gated to Pro + Enterprise by the handlers.
13488
+ search: filesContract.searchAgentAssets,
13489
+ place: canvasContract.placeLibraryAssets
13490
+ },
13470
13491
  model: {
13471
13492
  list: generationContract.listGenerativeModels,
13472
13493
  autoDefaults: generationContract.getAutoModelDefaults
@@ -13731,7 +13752,7 @@ function isMajorUpgrade(current, latest) {
13731
13752
  return l[0] > c17[0];
13732
13753
  }
13733
13754
  function shouldShowUpgradeNotice(ctx = {}) {
13734
- const current = ctx.current ?? "0.4.0";
13755
+ const current = ctx.current ?? "0.5.0";
13735
13756
  const latest = ctx.latest ?? serverLatestVersion;
13736
13757
  const env = ctx.env ?? process.env;
13737
13758
  const isTty = ctx.isTty ?? Boolean(process.stderr.isTTY);
@@ -13752,7 +13773,7 @@ Upgrade: npm install -g @melius-ai/cli@latest (or: brew upgrade mel) Silence:
13752
13773
  function printUpgradeNoticeIfNeeded(ctx = {}) {
13753
13774
  try {
13754
13775
  if (!shouldShowUpgradeNotice(ctx)) return;
13755
- const current = ctx.current ?? "0.4.0";
13776
+ const current = ctx.current ?? "0.5.0";
13756
13777
  const latest = ctx.latest ?? serverLatestVersion;
13757
13778
  process.stderr.write(formatUpgradeNotice(current, latest));
13758
13779
  } catch {
@@ -18429,6 +18450,82 @@ Examples:
18429
18450
  );
18430
18451
  }
18431
18452
 
18453
+ // src/commands/asset.ts
18454
+ function registerAssetCommands(program2, getOutputOpts) {
18455
+ const asset = program2.command("asset").description(
18456
+ "Search and place the team's Files (DAM) library assets. Requires a Pro or Enterprise plan"
18457
+ );
18458
+ asset.command("search").description(
18459
+ "Search the team's Files/DAM library (uploads + past generations) by meaning (semantic), with exact filename/title matches ranked first. Returns up to 5 relevant matches"
18460
+ ).argument(
18461
+ "<query>",
18462
+ 'Search terms \u2014 a filename or a description of the content, e.g. "Product_Shot_05" or "black jacket shot"'
18463
+ ).option("--limit <n>", "Max results (1-5, default 5)", "5").option(
18464
+ "--file-type <type>",
18465
+ "Filter by media type: image, video, audio, pdf, or text"
18466
+ ).option(
18467
+ "--canvas-id <canvasId>",
18468
+ "Scope to one canvas's assets (a filename match within that canvas). Omit to search the whole team library by meaning, exact matches first (the default)"
18469
+ ).addHelpText(
18470
+ "after",
18471
+ `
18472
+ Returns: { query, total, results: [{ assetId, filename, displayName, fileType, contentType, previewUrl, assetUrl, durationInMs }] }.
18473
+ Use the returned assetId values with mel asset place to bring them onto a canvas.
18474
+
18475
+ Examples:
18476
+ $ mel asset search "black jacket shot"
18477
+ $ mel asset search "logo" --file-type image --limit 3`
18478
+ ).action(
18479
+ async (query, opts) => {
18480
+ const client = getClient();
18481
+ const result = await client.asset.search({
18482
+ query: {
18483
+ query,
18484
+ limit: Number(opts.limit),
18485
+ ...opts.fileType !== void 0 && {
18486
+ fileType: opts.fileType
18487
+ },
18488
+ ...opts.canvasId !== void 0 && {
18489
+ canvasId: opts.canvasId
18490
+ }
18491
+ }
18492
+ });
18493
+ if (result.status !== 200) {
18494
+ handleApiError(result.status, result.body);
18495
+ }
18496
+ writeJson(result.body, getOutputOpts());
18497
+ }
18498
+ );
18499
+ asset.command("place").description(
18500
+ "Place existing library assets onto a canvas by id, referencing the ORIGINAL asset (no duplicate, no re-upload). Creates file nodes server-side (writes to CRDT) and returns their node ids"
18501
+ ).argument(
18502
+ "<canvasId>",
18503
+ "Canvas ID to place onto (from mel canvas create or mel canvas list)"
18504
+ ).argument(
18505
+ "<assetIds...>",
18506
+ "One or more asset IDs from mel asset search (max 10)"
18507
+ ).addHelpText(
18508
+ "after",
18509
+ `
18510
+ Returns: { placed: [{ assetId, nodeId, mediaType }] }.
18511
+ Wire the returned nodeIds into generations with mel edge create.
18512
+
18513
+ Examples:
18514
+ $ mel asset place <canvasId> <assetId>
18515
+ $ mel asset place <canvasId> <assetId1> <assetId2>`
18516
+ ).action(async (canvasId, assetIds) => {
18517
+ const client = getClient();
18518
+ const result = await client.asset.place({
18519
+ params: { canvasId },
18520
+ body: { assetIds }
18521
+ });
18522
+ if (result.status !== 200) {
18523
+ handleApiError(result.status, result.body);
18524
+ }
18525
+ writeJson(result.body, getOutputOpts());
18526
+ });
18527
+ }
18528
+
18432
18529
  // src/commands/completion.ts
18433
18530
  var GLOBAL_FLAGS = [
18434
18531
  "--json",
@@ -18564,7 +18661,7 @@ function withDefaultHelp(args) {
18564
18661
  }
18565
18662
  function createProgram() {
18566
18663
  const program2 = new Command();
18567
- program2.name("mel").description("Mel \u2014 Melius agent CLI").version("0.4.0").showSuggestionAfterError(true).option("--json", "Force JSON output (default)").option("--text", "Human-readable output").option(
18664
+ program2.name("mel").description("Mel \u2014 Melius agent CLI").version("0.5.0").showSuggestionAfterError(true).option("--json", "Force JSON output (default)").option("--text", "Human-readable output").option(
18568
18665
  "--fields <fields>",
18569
18666
  "Select specific output fields (comma-separated)"
18570
18667
  ).option("--quiet", "Suppress output, exit code only").option("--verbose", "Log request/response metadata to stderr").addHelpText(
@@ -18608,6 +18705,7 @@ Learn more: https://docs.melius.com`
18608
18705
  registerSkillCommands(program2, getOutputOpts);
18609
18706
  }
18610
18707
  registerUploadCommands(program2, getOutputOpts);
18708
+ registerAssetCommands(program2, getOutputOpts);
18611
18709
  registerCompletionCommands(program2);
18612
18710
  applyStructuredErrors(program2);
18613
18711
  return program2;
package/dist/src/index.js CHANGED
@@ -2,7 +2,7 @@ import { createRequire } from 'node:module'; const require = createRequire(impor
2
2
  import {
3
3
  createProgram,
4
4
  withDefaultHelp
5
- } from "../chunk-EXHDKHNG.js";
5
+ } from "../chunk-UAK5HMFU.js";
6
6
  export {
7
7
  createProgram,
8
8
  withDefaultHelp
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@melius-ai/cli",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "The Melius command-line interface — create canvases and run AI image/video generations from your terminal",
5
5
  "keywords": [
6
6
  "ai",