@melius-ai/cli 0.7.0 → 0.8.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
@@ -269,6 +269,8 @@ Requires the Pro or Enterprise plan.
269
269
 
270
270
  Scope to a **folder** with `--folder-id` (from `mel asset folders`): with a query it filters within that folder and its subfolders; **omit the query** to bring in the _whole_ folder (every asset in it). `mel asset folders` returns each folder's root-relative `path` (e.g. `Brand / Logos`) to disambiguate same-named folders.
271
271
 
272
+ Filter by **tag** with `--tags <names>` (comma-separated, case-insensitive): assets carrying **all** the named tags (AND). Combine with a query, or use `--tags` alone (or with `--folder-id`) to bring in every asset carrying them. An unknown tag name matches nothing.
273
+
272
274
  `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.
273
275
 
274
276
  ```bash
@@ -280,6 +282,10 @@ mel asset place <canvasId> <assetId1> <assetId2>
280
282
  mel asset folders # → [{ id, name, path, fileCount }]
281
283
  mel asset search --folder-id <folderId> # every asset in the folder
282
284
  mel asset search "shark" --folder-id <folderId> # or filter within it
285
+
286
+ # Filter by tag (AND across tags)
287
+ mel asset search "logo" --tags brand # tagged 'brand'
288
+ mel asset search --tags brand,hero # every asset with BOTH tags
283
289
  ```
284
290
 
285
291
  ### Shell completion
package/dist/bin/mel.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  printUpgradeNoticeIfNeeded,
8
8
  withDefaultHelp,
9
9
  writeError
10
- } from "../chunk-5QT6WMID.js";
10
+ } from "../chunk-3PBGQVUH.js";
11
11
 
12
12
  // bin/mel.ts
13
13
  var program = createProgram();
@@ -7911,6 +7911,24 @@ var FileTypeSchema = external_exports.enum([
7911
7911
  "pdf",
7912
7912
  "text"
7913
7913
  ]);
7914
+ var AssetShareModeSchema = external_exports.enum(["team", "anyone"]);
7915
+ var TAG_COLOR_PALETTE = [
7916
+ "hsl(189deg, 72%, 46%)",
7917
+ "hsl(280deg, 60%, 50%)",
7918
+ "hsl(24deg, 76%, 46%)",
7919
+ "hsl(142deg, 58%, 40%)",
7920
+ "hsl(330deg, 64%, 46%)",
7921
+ "hsl(45deg, 68%, 42%)",
7922
+ "hsl(210deg, 66%, 44%)",
7923
+ "hsl(168deg, 55%, 38%)"
7924
+ ];
7925
+ var TagColorSchema = external_exports.enum(TAG_COLOR_PALETTE);
7926
+ var MAX_ASSET_TAG_NAME_LENGTH = 100;
7927
+ var FileTagSchema = external_exports.object({
7928
+ id: external_exports.string().uuid(),
7929
+ name: external_exports.string(),
7930
+ color: external_exports.string()
7931
+ });
7914
7932
  var FileCanvasBacklinkSchema = external_exports.object({
7915
7933
  canvasId: external_exports.string().uuid(),
7916
7934
  projectId: external_exports.string().uuid(),
@@ -7939,6 +7957,9 @@ var FileCardSchema = external_exports.object({
7939
7957
  * The "Open canvas" CTA opens the first directly, or — when there is more
7940
7958
  * than one — prompts the user to pick which to open. */
7941
7959
  canvases: external_exports.array(FileCanvasBacklinkSchema),
7960
+ // The tags assigned to this file (unordered). Always present — empty when
7961
+ // untagged — so the grid can render chips without a per-card fetch.
7962
+ tags: external_exports.array(FileTagSchema),
7942
7963
  // The canvas node whose currently-active version produced this generated
7943
7964
  // asset. The Files grid shows only active-version outputs, so each
7944
7965
  // generated card maps to exactly one such node; this lets the viewer load
@@ -8049,6 +8070,13 @@ var ListFilesQuerySchema = external_exports.object({
8049
8070
  createdByUserId: external_exports.string().uuid().optional(),
8050
8071
  sort: FileSortSchema.default("created_desc"),
8051
8072
  folderId: external_exports.union([external_exports.string().uuid(), external_exports.literal("root")]).optional(),
8073
+ // Filter to files carrying ALL of these tag ids (AND — narrows the set).
8074
+ // Comma-separated in the query string (e.g. `?tagIds=<id1>,<id2>`) because
8075
+ // this GET has no array-query support; absent means no tag filter. Each id
8076
+ // is validated as a uuid after splitting.
8077
+ tagIds: external_exports.string().optional().transform(
8078
+ (value) => value ? value.split(",").map((id) => id.trim()).filter(Boolean) : void 0
8079
+ ).pipe(external_exports.array(external_exports.string().uuid()).optional()),
8052
8080
  // The "Hidden" view: lists files hidden from Files (across all folders)
8053
8081
  // instead of the normal visible listing. Coerced from the query string so
8054
8082
  // `?hidden=true` works; absent / "false" both resolve to `false`.
@@ -8083,6 +8111,17 @@ var ListFilesResponseSchema = external_exports.object({
8083
8111
  cursor: external_exports.string().nullable().optional(),
8084
8112
  hasMore: external_exports.boolean().optional()
8085
8113
  });
8114
+ var FileTabCountsQuerySchema = external_exports.object({
8115
+ q: external_exports.string().optional(),
8116
+ folderId: external_exports.union([external_exports.string().uuid(), external_exports.literal("root")]).optional()
8117
+ });
8118
+ var FileTabCountsResponseSchema = external_exports.object({
8119
+ // "All assets" — always uploads + generations (a file is one or the other).
8120
+ all: external_exports.number().int(),
8121
+ uploads: external_exports.number().int(),
8122
+ generations: external_exports.number().int(),
8123
+ favorites: external_exports.number().int()
8124
+ });
8086
8125
  var AGENT_ASSET_SEARCH_PAGE_SIZE = 20;
8087
8126
  var AgentAssetSearchQuerySchema = external_exports.object({
8088
8127
  query: external_exports.string().trim().min(1).max(500).optional().describe(
@@ -8097,6 +8136,9 @@ var AgentAssetSearchQuerySchema = external_exports.object({
8097
8136
  folderId: external_exports.string().uuid().optional().describe(
8098
8137
  'Optional. Scope to one Files folder AND its subfolders. Omit to search the whole team library \u2014 the default, and what nearly every request wants. Set it when the member names a specific folder \u2014 either to FILTER within it (pass `folderId` + `query`, e.g. "find the shark shot in my ocean folder") or to bring in EVERYTHING in it (pass `folderId` and OMIT `query`, e.g. "add all my assets from the ocean folder"). Resolve the id with list_asset_folders (match by name; if several plausibly match, ask which one); never guess a folder id.'
8099
8138
  ),
8139
+ tags: external_exports.string().trim().optional().describe(
8140
+ 'Optional. Filter to assets carrying ALL of these tags (AND). Pass a tag name ONLY when the member explicitly asks to filter by a tag (e.g. "find my assets tagged brand", "my hero tag") \u2014 never infer one from ordinary words in their request. Comma-separated (e.g. "brand" or "brand,hero"), case-insensitive. Combine with `query` to search within tagged assets, or omit `query` (with tags and/or a folderId) to bring in every asset carrying them. An unknown or misspelled tag name matches nothing, so pass only tags the member actually named.'
8141
+ ),
8100
8142
  showInThread: external_exports.boolean().optional().describe(
8101
8143
  'Slack only. Set true when the member only wants to SEE the matched asset(s) \u2014 "find X and show it to me", "do I have Y?" \u2014 and is NOT asking to place, edit, or build on them. Skips the selection card and posts every match straight into the Slack thread as image files. Leave unset (the default) whenever the member wants to USE an asset on the canvas, so the selection card renders and a canvas gets bound.'
8102
8144
  )
@@ -8125,7 +8167,10 @@ var AgentAssetSearchResponseSchema = external_exports.object({
8125
8167
  folderId: external_exports.string().uuid().optional(),
8126
8168
  canvasId: external_exports.string().uuid().optional(),
8127
8169
  source: FileSourceSchema.optional(),
8128
- fileType: FileTypeSchema.optional()
8170
+ fileType: FileTypeSchema.optional(),
8171
+ // Echoed comma-separated tag filter, so the picker's "More results" re-pages
8172
+ // with the same tags.
8173
+ tags: external_exports.string().optional()
8129
8174
  });
8130
8175
  var AgentListAssetFoldersQuerySchema = external_exports.object({});
8131
8176
  var AgentAssetFolderSchema = external_exports.object({
@@ -8169,6 +8214,46 @@ var EmbeddingStorageUsageResponseSchema = external_exports.object({
8169
8214
  usedBytes: external_exports.number(),
8170
8215
  limitBytes: external_exports.number()
8171
8216
  });
8217
+ var AssetTagResponseSchema = external_exports.object({
8218
+ id: external_exports.string().uuid(),
8219
+ teamId: external_exports.string().uuid(),
8220
+ name: external_exports.string(),
8221
+ color: external_exports.string(),
8222
+ createdByUserId: external_exports.string().uuid().nullable(),
8223
+ createdByName: external_exports.string().nullable(),
8224
+ createdAt: external_exports.string().datetime(),
8225
+ updatedAt: external_exports.string().datetime(),
8226
+ // How many of the team's assets carry this tag. Present in listAssetTags;
8227
+ // omitted on single-tag create/update responses (which don't recount).
8228
+ assetCount: external_exports.number().int().nonnegative().optional()
8229
+ });
8230
+ var AssetTagListResponseSchema = external_exports.object({
8231
+ data: external_exports.array(AssetTagResponseSchema)
8232
+ });
8233
+ var AssetTagIdParamsSchema = external_exports.object({
8234
+ tagId: external_exports.string().uuid()
8235
+ });
8236
+ var FileAssetTagParamsSchema = external_exports.object({
8237
+ assetId: external_exports.string().uuid(),
8238
+ tagId: external_exports.string().uuid()
8239
+ });
8240
+ var CreateAssetTagBodySchema = external_exports.object({
8241
+ name: external_exports.string().trim().min(1).max(MAX_ASSET_TAG_NAME_LENGTH),
8242
+ color: TagColorSchema
8243
+ });
8244
+ var UpdateAssetTagBodySchema = external_exports.object({
8245
+ name: external_exports.string().trim().min(1).max(MAX_ASSET_TAG_NAME_LENGTH).optional(),
8246
+ color: TagColorSchema.optional()
8247
+ }).refine((body) => body.name !== void 0 || body.color !== void 0, {
8248
+ message: "Provide a name or color to update"
8249
+ });
8250
+ var AssetTagAssignmentBodySchema = external_exports.object({
8251
+ tagId: external_exports.string().uuid()
8252
+ });
8253
+ var BulkAssetTagBodySchema = external_exports.object({
8254
+ assetIds: BulkFileAssetIdsSchema,
8255
+ tagId: external_exports.string().uuid()
8256
+ });
8172
8257
  var ErrorBodySchema = MessageResponseSchema;
8173
8258
  var filesContract = c2.router({
8174
8259
  createFileFolder: {
@@ -8215,6 +8300,97 @@ var filesContract = c2.router({
8215
8300
  },
8216
8301
  summary: "Delete a Files folder"
8217
8302
  },
8303
+ listAssetTags: {
8304
+ method: "GET",
8305
+ path: "/files/tags",
8306
+ responses: {
8307
+ 200: AssetTagListResponseSchema,
8308
+ 403: ErrorBodySchema
8309
+ },
8310
+ summary: "List team asset tags"
8311
+ },
8312
+ createAssetTag: {
8313
+ method: "POST",
8314
+ path: "/files/tags",
8315
+ body: CreateAssetTagBodySchema,
8316
+ responses: {
8317
+ 201: AssetTagResponseSchema,
8318
+ 403: ErrorBodySchema,
8319
+ 409: ErrorBodySchema
8320
+ },
8321
+ summary: "Create an asset tag"
8322
+ },
8323
+ updateAssetTag: {
8324
+ method: "PATCH",
8325
+ path: "/files/tags/:tagId",
8326
+ pathParams: AssetTagIdParamsSchema,
8327
+ body: UpdateAssetTagBodySchema,
8328
+ responses: {
8329
+ 200: AssetTagResponseSchema,
8330
+ 403: ErrorBodySchema,
8331
+ 404: ErrorBodySchema,
8332
+ 409: ErrorBodySchema
8333
+ },
8334
+ summary: "Rename or recolor an asset tag"
8335
+ },
8336
+ deleteAssetTag: {
8337
+ method: "DELETE",
8338
+ path: "/files/tags/:tagId",
8339
+ pathParams: AssetTagIdParamsSchema,
8340
+ body: null,
8341
+ responses: {
8342
+ 204: c2.noBody(),
8343
+ 403: ErrorBodySchema,
8344
+ 404: ErrorBodySchema
8345
+ },
8346
+ summary: "Delete an asset tag"
8347
+ },
8348
+ addAssetTag: {
8349
+ method: "POST",
8350
+ path: "/files/:assetId/tags",
8351
+ pathParams: FileAssetIdParamsSchema,
8352
+ body: AssetTagAssignmentBodySchema,
8353
+ responses: {
8354
+ 200: FileCardSchema,
8355
+ 403: ErrorBodySchema,
8356
+ 404: ErrorBodySchema
8357
+ },
8358
+ summary: "Add a tag to a file"
8359
+ },
8360
+ removeAssetTag: {
8361
+ method: "DELETE",
8362
+ path: "/files/:assetId/tags/:tagId",
8363
+ pathParams: FileAssetTagParamsSchema,
8364
+ body: null,
8365
+ responses: {
8366
+ 200: FileCardSchema,
8367
+ 403: ErrorBodySchema,
8368
+ 404: ErrorBodySchema
8369
+ },
8370
+ summary: "Remove a tag from a file"
8371
+ },
8372
+ bulkAddAssetTag: {
8373
+ method: "POST",
8374
+ path: "/files/bulk/tag",
8375
+ body: BulkAssetTagBodySchema,
8376
+ responses: {
8377
+ 200: BulkFileActionResponseSchema,
8378
+ 403: ErrorBodySchema,
8379
+ 404: ErrorBodySchema
8380
+ },
8381
+ summary: "Add a tag to files"
8382
+ },
8383
+ bulkRemoveAssetTag: {
8384
+ method: "POST",
8385
+ path: "/files/bulk/untag",
8386
+ body: BulkAssetTagBodySchema,
8387
+ responses: {
8388
+ 200: BulkFileActionResponseSchema,
8389
+ 403: ErrorBodySchema,
8390
+ 404: ErrorBodySchema
8391
+ },
8392
+ summary: "Remove a tag from files"
8393
+ },
8218
8394
  bulkMoveFiles: {
8219
8395
  method: "POST",
8220
8396
  path: "/files/bulk/move",
@@ -8305,6 +8481,16 @@ var filesContract = c2.router({
8305
8481
  },
8306
8482
  summary: "List team files"
8307
8483
  },
8484
+ getFileTabCounts: {
8485
+ method: "GET",
8486
+ path: "/files/tab-counts",
8487
+ query: FileTabCountsQuerySchema,
8488
+ responses: {
8489
+ 200: FileTabCountsResponseSchema,
8490
+ 403: ErrorBodySchema
8491
+ },
8492
+ summary: "Per-tab asset counts for the Assets page, scoped to the search"
8493
+ },
8308
8494
  searchAgentAssets: {
8309
8495
  method: "GET",
8310
8496
  path: "/files/agent-search",
@@ -8344,6 +8530,29 @@ var filesContract = c2.router({
8344
8530
  },
8345
8531
  summary: "Get a file's details with generation metadata"
8346
8532
  },
8533
+ getAssetShareMode: {
8534
+ method: "GET",
8535
+ path: "/files/:assetId/share-mode",
8536
+ pathParams: FileAssetIdParamsSchema,
8537
+ responses: {
8538
+ 200: external_exports.object({ shareMode: AssetShareModeSchema }),
8539
+ 403: ErrorBodySchema,
8540
+ 404: ErrorBodySchema
8541
+ },
8542
+ summary: "Get an asset's share mode"
8543
+ },
8544
+ updateAssetShareMode: {
8545
+ method: "PATCH",
8546
+ path: "/files/:assetId/share-mode",
8547
+ pathParams: FileAssetIdParamsSchema,
8548
+ body: external_exports.object({ shareMode: AssetShareModeSchema }),
8549
+ responses: {
8550
+ 200: external_exports.object({ shareMode: AssetShareModeSchema }),
8551
+ 403: ErrorBodySchema,
8552
+ 404: ErrorBodySchema
8553
+ },
8554
+ summary: "Set who can view an asset"
8555
+ },
8347
8556
  initFileUpload: {
8348
8557
  method: "POST",
8349
8558
  path: "/files/upload/init",
@@ -9040,38 +9249,44 @@ var AUTO_MODEL_REGISTRY = [
9040
9249
  {
9041
9250
  nodeType: "video",
9042
9251
  inputPattern: "text-only",
9043
- standard: { model: "kling-o3", variant: "text-to-video" },
9044
- fast: { model: "grok-imagine-video", variant: "text-to-video" }
9252
+ model: "kling-o3",
9253
+ variant: "text-to-video"
9045
9254
  },
9046
9255
  {
9047
9256
  nodeType: "video",
9048
9257
  inputPattern: "image-to-video",
9049
- standard: { model: "kling-o3", variant: "image-to-video" },
9050
- fast: { model: "wan-2.2", variant: "image-to-video" }
9258
+ model: "kling-o3",
9259
+ variant: "image-to-video"
9051
9260
  },
9052
9261
  {
9053
9262
  nodeType: "video",
9054
9263
  inputPattern: "first-last-frame-to-video",
9055
- standard: { model: "kling-o3", variant: "image-to-video" },
9056
- fast: { model: "kling-o3", variant: "image-to-video" }
9264
+ model: "kling-o3",
9265
+ variant: "image-to-video"
9057
9266
  },
9058
9267
  {
9059
9268
  nodeType: "video",
9060
9269
  inputPattern: "reference-to-video",
9061
- standard: { model: "kling-o3", variant: "reference-to-video" },
9062
- fast: { model: "kling-o3", variant: "reference-to-video" }
9270
+ model: "kling-o3",
9271
+ variant: "reference-to-video"
9063
9272
  },
9064
9273
  {
9065
9274
  nodeType: "video",
9066
9275
  inputPattern: "reference-with-frames-to-video",
9067
- standard: { model: "kling-o3", variant: "reference-to-video" },
9068
- fast: { model: "kling-o3", variant: "reference-to-video" }
9276
+ model: "kling-o3",
9277
+ variant: "reference-to-video"
9069
9278
  },
9070
9279
  {
9071
9280
  nodeType: "video",
9072
9281
  inputPattern: "video-with-audio",
9073
- standard: { model: "infinitalk", variant: "video-to-video" },
9074
- fast: { model: "infinitalk", variant: "video-to-video" }
9282
+ model: "infinitalk",
9283
+ variant: "video-to-video"
9284
+ },
9285
+ {
9286
+ nodeType: "video",
9287
+ inputPattern: "video-with-image-references",
9288
+ model: "kling-o3",
9289
+ variant: "video-to-video"
9075
9290
  },
9076
9291
  {
9077
9292
  nodeType: "video",
@@ -9081,85 +9296,79 @@ var AUTO_MODEL_REGISTRY = [
9081
9296
  // backend remaps reference → image_url at request build time
9082
9297
  // (see node-run-execution.ts → "primary image port" remap) since
9083
9298
  // kling-avatar's variant only accepts image_url.
9084
- standard: { model: "kling-avatar", variant: "image-to-video" },
9085
- fast: { model: "kling-avatar", variant: "image-to-video" }
9299
+ model: "kling-avatar",
9300
+ variant: "image-to-video"
9086
9301
  },
9087
9302
  {
9088
9303
  nodeType: "video",
9089
9304
  inputPattern: "frames-with-audio",
9090
9305
  // Kling Avatar does not accept end_image_url, so route frame+audio
9091
9306
  // runs through LTX's audio-capable image-to-video variant.
9092
- standard: { model: "ltx-2.3", variant: "image-to-video" },
9093
- fast: { model: "ltx-2.3", variant: "image-to-video" }
9307
+ model: "ltx-2.3",
9308
+ variant: "image-to-video"
9094
9309
  },
9095
9310
  {
9096
9311
  nodeType: "video",
9097
9312
  inputPattern: "video-to-video",
9098
- standard: { model: "grok-imagine-video", variant: "video-to-video" },
9099
- fast: { model: "grok-imagine-video", variant: "video-to-video" }
9313
+ model: "kling-o3",
9314
+ variant: "video-to-video"
9100
9315
  },
9101
9316
  // ── Image ───────────────────────────────────────────────────────────
9102
9317
  {
9103
9318
  nodeType: "image",
9104
9319
  inputPattern: "text-to-image",
9105
- standard: { model: "nano-banana-pro", variant: "text-to-image" },
9106
- fast: { model: "flux-schnell", variant: "text-to-image" }
9320
+ model: "nano-banana-pro",
9321
+ variant: "text-to-image"
9107
9322
  },
9108
9323
  {
9109
9324
  nodeType: "image",
9110
9325
  inputPattern: "image-to-image",
9111
- standard: { model: "nano-banana-pro", variant: "image-to-image" },
9112
- fast: { model: "grok-imagine", variant: "image-to-image" }
9326
+ model: "nano-banana-pro",
9327
+ variant: "image-to-image"
9113
9328
  },
9114
9329
  // ── Text ────────────────────────────────────────────────────────────
9115
9330
  {
9116
9331
  nodeType: "text",
9117
9332
  inputPattern: "default",
9118
- standard: { model: "gemini-3.1-pro", variant: "text" },
9119
- fast: { model: "gemini-3.1-pro", variant: "text" }
9333
+ model: "gemini-3.1-pro",
9334
+ variant: "text"
9120
9335
  },
9121
9336
  {
9122
9337
  nodeType: "text",
9123
9338
  inputPattern: "with-video",
9124
- standard: { model: "gemini-3.1-pro", variant: "text" },
9125
- fast: { model: "gemini-3.1-pro", variant: "text" }
9339
+ model: "gemini-3.1-pro",
9340
+ variant: "text"
9126
9341
  },
9127
9342
  // ── Audio ───────────────────────────────────────────────────────────
9128
9343
  {
9129
9344
  nodeType: "audio",
9130
9345
  inputPattern: "text-to-speech",
9131
- standard: { model: "eleven_v3", variant: "text-to-speech" },
9132
- fast: { model: "eleven_turbo_v2_5", variant: "text-to-speech" }
9346
+ model: "eleven_v3",
9347
+ variant: "text-to-speech"
9133
9348
  },
9134
9349
  {
9135
9350
  nodeType: "audio",
9136
9351
  inputPattern: "audio-to-audio",
9137
- standard: {
9138
- model: "elevenlabs-voice-changer",
9139
- variant: "audio-to-audio"
9140
- },
9141
- fast: {
9142
- model: "elevenlabs-voice-changer",
9143
- variant: "audio-to-audio"
9144
- }
9352
+ model: "elevenlabs-voice-changer",
9353
+ variant: "audio-to-audio"
9145
9354
  },
9146
9355
  {
9147
9356
  nodeType: "audio",
9148
9357
  inputPattern: "text-to-sfx",
9149
- standard: { model: "elevenlabs-sfx", variant: "text-to-sfx" },
9150
- fast: { model: "elevenlabs-sfx", variant: "text-to-sfx" }
9358
+ model: "elevenlabs-sfx",
9359
+ variant: "text-to-sfx"
9151
9360
  },
9152
9361
  {
9153
9362
  nodeType: "audio",
9154
9363
  inputPattern: "text-to-music",
9155
- standard: { model: "elevenlabs-music", variant: "text-to-music" },
9156
- fast: { model: "elevenlabs-music", variant: "text-to-music" }
9364
+ model: "elevenlabs-music",
9365
+ variant: "text-to-music"
9157
9366
  },
9158
9367
  {
9159
9368
  nodeType: "audio",
9160
9369
  inputPattern: "speech-to-text",
9161
- standard: { model: "scribe_v2", variant: "speech-to-text" },
9162
- fast: { model: "scribe_v2", variant: "speech-to-text" }
9370
+ model: "scribe_v2",
9371
+ variant: "speech-to-text"
9163
9372
  }
9164
9373
  ];
9165
9374
  var AutoModelProxy = class {
@@ -9183,15 +9392,14 @@ var AutoModelProxy = class {
9183
9392
  case "video":
9184
9393
  return this.resolveVideo(
9185
9394
  input.connectedInputs,
9186
- input.tier,
9187
9395
  input.canvasVideoInputRoutingEnabled === true
9188
9396
  );
9189
9397
  case "image":
9190
- return this.resolveImage(input.connectedInputs, input.tier);
9398
+ return this.resolveImage(input.connectedInputs);
9191
9399
  case "text":
9192
- return this.resolveText(input.connectedInputs, input.tier);
9400
+ return this.resolveText(input.connectedInputs);
9193
9401
  case "audio":
9194
- return this.resolveAudio(input.variant, input.tier);
9402
+ return this.resolveAudio(input.variant);
9195
9403
  default:
9196
9404
  return {
9197
9405
  valid: false,
@@ -9204,13 +9412,22 @@ var AutoModelProxy = class {
9204
9412
  return this.registry;
9205
9413
  }
9206
9414
  // ── Private resolvers ───────────────────────────────────────────────
9207
- resolveVideo(ci, tier, canvasVideoInputRoutingEnabled) {
9415
+ resolveVideo(ci, canvasVideoInputRoutingEnabled) {
9208
9416
  const hasAnyImage = ci.hasImage || ci.hasStartingImage || ci.hasEndImage || ci.hasReferenceImage;
9209
9417
  if (ci.hasVideo && hasAnyImage) {
9210
- return {
9211
- valid: false,
9212
- errorMessage: "You cannot have an image and a video as input at the same time"
9213
- };
9418
+ if (ci.hasEndImage) {
9419
+ return {
9420
+ valid: false,
9421
+ errorMessage: "A last frame cannot be used with a video input"
9422
+ };
9423
+ }
9424
+ if (ci.hasAudio) {
9425
+ return {
9426
+ valid: false,
9427
+ errorMessage: "Audio input is not supported with image and video inputs together"
9428
+ };
9429
+ }
9430
+ return this.lookupRoute("video", "video-with-image-references");
9214
9431
  }
9215
9432
  if (ci.hasEndImage && !ci.hasStartingImage && !ci.hasReferenceImage && !ci.hasImage && !ci.hasVideo) {
9216
9433
  return {
@@ -9225,17 +9442,17 @@ var AutoModelProxy = class {
9225
9442
  };
9226
9443
  }
9227
9444
  if (ci.hasAudio && ci.hasVideo) {
9228
- return this.lookupRoute("video", "video-with-audio", tier);
9445
+ return this.lookupRoute("video", "video-with-audio");
9229
9446
  }
9230
9447
  if (ci.hasAudio && (ci.hasStartingImage || ci.hasImage) && ci.hasEndImage) {
9231
- return canvasVideoInputRoutingEnabled ? this.lookupRoute("video", "frames-with-audio", tier) : {
9448
+ return canvasVideoInputRoutingEnabled ? this.lookupRoute("video", "frames-with-audio") : {
9232
9449
  valid: true,
9233
9450
  model: "ltx-2.3-audio",
9234
9451
  variant: "image-to-video"
9235
9452
  };
9236
9453
  }
9237
9454
  if (ci.hasAudio && hasAnyImage) {
9238
- return this.lookupRoute("video", "image-with-audio", tier);
9455
+ return this.lookupRoute("video", "image-with-audio");
9239
9456
  }
9240
9457
  if (ci.hasAudio) {
9241
9458
  return {
@@ -9244,48 +9461,40 @@ var AutoModelProxy = class {
9244
9461
  };
9245
9462
  }
9246
9463
  if (ci.hasVideo) {
9247
- return this.lookupRoute("video", "video-to-video", tier);
9464
+ return this.lookupRoute("video", "video-to-video");
9248
9465
  }
9249
9466
  const hasFrameInput = ci.hasStartingImage || ci.hasEndImage || ci.hasImage;
9250
9467
  if (ci.hasReferenceImage && hasFrameInput) {
9251
- return this.lookupRoute(
9252
- "video",
9253
- "reference-with-frames-to-video",
9254
- tier
9255
- );
9468
+ return this.lookupRoute("video", "reference-with-frames-to-video");
9256
9469
  }
9257
9470
  if (ci.hasReferenceImage) {
9258
- return this.lookupRoute("video", "reference-to-video", tier);
9471
+ return this.lookupRoute("video", "reference-to-video");
9259
9472
  }
9260
9473
  if (ci.hasStartingImage || ci.hasImage) {
9261
9474
  if (ci.hasEndImage) {
9262
- return this.lookupRoute(
9263
- "video",
9264
- "first-last-frame-to-video",
9265
- tier
9266
- );
9475
+ return this.lookupRoute("video", "first-last-frame-to-video");
9267
9476
  }
9268
- return this.lookupRoute("video", "image-to-video", tier);
9477
+ return this.lookupRoute("video", "image-to-video");
9269
9478
  }
9270
- return this.lookupRoute("video", "text-only", tier);
9479
+ return this.lookupRoute("video", "text-only");
9271
9480
  }
9272
- resolveImage(ci, tier) {
9481
+ resolveImage(ci) {
9273
9482
  if (ci.hasImage || ci.hasReferenceImage) {
9274
- return this.lookupRoute("image", "image-to-image", tier);
9483
+ return this.lookupRoute("image", "image-to-image");
9275
9484
  }
9276
- return this.lookupRoute("image", "text-to-image", tier);
9485
+ return this.lookupRoute("image", "text-to-image");
9277
9486
  }
9278
- resolveAudio(variant, tier) {
9487
+ resolveAudio(variant) {
9279
9488
  const pattern = variant ?? "text-to-speech";
9280
- return this.lookupRoute("audio", pattern, tier);
9489
+ return this.lookupRoute("audio", pattern);
9281
9490
  }
9282
- resolveText(ci, tier) {
9491
+ resolveText(ci) {
9283
9492
  if (ci.hasVideo) {
9284
- return this.lookupRoute("text", "with-video", tier);
9493
+ return this.lookupRoute("text", "with-video");
9285
9494
  }
9286
- return this.lookupRoute("text", "default", tier);
9495
+ return this.lookupRoute("text", "default");
9287
9496
  }
9288
- lookupRoute(nodeType, inputPattern, tier) {
9497
+ lookupRoute(nodeType, inputPattern) {
9289
9498
  const route = this.lookup.get(`${nodeType}:${inputPattern}`);
9290
9499
  if (!route) {
9291
9500
  return {
@@ -9293,8 +9502,7 @@ var AutoModelProxy = class {
9293
9502
  errorMessage: `No auto model route for ${nodeType}:${inputPattern}`
9294
9503
  };
9295
9504
  }
9296
- const entry = tier === "fast" ? route.fast : route.standard;
9297
- return { valid: true, model: entry.model, variant: entry.variant };
9505
+ return { valid: true, model: route.model, variant: route.variant };
9298
9506
  }
9299
9507
  };
9300
9508
 
@@ -9329,6 +9537,19 @@ var AUDIO_NODE_WIDTH = 380;
9329
9537
  var AUDIO_NODE_ESTIMATED_HEIGHT = 420;
9330
9538
  var PDF_NODE_DEFAULT_WIDTH = 440;
9331
9539
  var NODE_CARD_OVERHEAD = 252;
9540
+ var ASPECT_RATIOS = [
9541
+ "21:9",
9542
+ "16:9",
9543
+ "3:2",
9544
+ "4:3",
9545
+ "5:4",
9546
+ "1:1",
9547
+ "4:5",
9548
+ "3:4",
9549
+ "2:3",
9550
+ "9:16",
9551
+ "9:21"
9552
+ ];
9332
9553
  var MODALITIES = {
9333
9554
  text: { modelCategory: "text" },
9334
9555
  image: { modelCategory: "image" },
@@ -10072,7 +10293,8 @@ var TemplatePortSummarySchema = external_exports.object({
10072
10293
  label: external_exports.string(),
10073
10294
  handleType: external_exports.string(),
10074
10295
  required: external_exports.boolean().optional(),
10075
- maxConnections: external_exports.number().int().positive().optional()
10296
+ maxConnections: external_exports.number().int().positive().optional(),
10297
+ outputAspectRatio: external_exports.enum(ASPECT_RATIOS).nullable().optional()
10076
10298
  });
10077
10299
 
10078
10300
  // ../api-contract/src/canvas.ts
@@ -10122,6 +10344,8 @@ var ModelConfigSchema = external_exports.object({
10122
10344
  model: external_exports.string(),
10123
10345
  variant: external_exports.string(),
10124
10346
  tier: external_exports.string().nullable().optional(),
10347
+ /** HeyGen Avatar V only: the Runware avatar id for this node. */
10348
+ heygenAvatar: external_exports.string().optional(),
10125
10349
  // Magic-resize stores its per-run config here so each version carries the
10126
10350
  // ratios + resolution that produced it.
10127
10351
  ratios: external_exports.array(external_exports.string()).optional(),
@@ -10146,25 +10370,15 @@ var ModelConfigInputSchema = external_exports.object({
10146
10370
  model: external_exports.string(),
10147
10371
  variant: external_exports.string().refine(isValidGenerationMode, "Invalid generation mode"),
10148
10372
  tier: external_exports.string().nullable().optional(),
10373
+ /** HeyGen Avatar V only: the Runware avatar id for this node. */
10374
+ heygenAvatar: external_exports.string().trim().min(1).optional(),
10149
10375
  /** better-font-32b only: the font the model renders the requested text in (supplied to the model as a rendered reference image). */
10150
10376
  font: external_exports.object({
10151
10377
  source: external_exports.enum(["custom", "google"]),
10152
10378
  familyName: external_exports.string()
10153
10379
  }).optional()
10154
10380
  });
10155
- var OutputAspectRatioSchema = external_exports.enum([
10156
- "21:9",
10157
- "16:9",
10158
- "4:3",
10159
- "5:4",
10160
- "3:2",
10161
- "1:1",
10162
- "2:3",
10163
- "3:4",
10164
- "4:5",
10165
- "9:16",
10166
- "9:21"
10167
- ]);
10381
+ var OutputAspectRatioSchema = external_exports.enum(ASPECT_RATIOS);
10168
10382
  var OutputResolutionPresetSchema = external_exports.enum([
10169
10383
  "360p",
10170
10384
  "480p",
@@ -12073,6 +12287,8 @@ var GenerationRunBodySchema = external_exports.object({
12073
12287
  model: external_exports.string().trim().min(1),
12074
12288
  tier: external_exports.string().optional(),
12075
12289
  prompt: external_exports.string().trim().min(1).optional(),
12290
+ /** Selected avatar id from Runware's HeyGen Avatar V catalog. */
12291
+ heygenAvatar: external_exports.string().trim().min(1).optional(),
12076
12292
  imageUrls: external_exports.array(external_exports.string().url()).optional(),
12077
12293
  endImageUrls: external_exports.array(external_exports.string().url()).optional(),
12078
12294
  referenceImageUrls: external_exports.array(external_exports.string().url()).optional(),
@@ -12415,6 +12631,13 @@ var generationContract = c9.router({
12415
12631
  200: ListGenerativeModelsResponseSchema
12416
12632
  }
12417
12633
  },
12634
+ listHeygenAvatarVAvatars: {
12635
+ method: "GET",
12636
+ path: "/generation/heygen-avatar-v-avatars",
12637
+ responses: {
12638
+ 200: external_exports.object({ avatars: external_exports.array(external_exports.string()) })
12639
+ }
12640
+ },
12418
12641
  getAutoModelDefaults: {
12419
12642
  method: "GET",
12420
12643
  path: "/generation/auto-model-defaults",
@@ -12700,6 +12923,17 @@ var profileContract = c11.router({
12700
12923
  // ../api-contract/src/share.ts
12701
12924
  var c12 = initContract();
12702
12925
  var ShareModeSchema = external_exports.enum(["restricted", "view"]);
12926
+ var SharedAssetResponseSchema = external_exports.object({
12927
+ id: external_exports.string().uuid(),
12928
+ filename: external_exports.string(),
12929
+ fileType: FileTypeSchema,
12930
+ contentType: external_exports.string().nullable(),
12931
+ // Presigned media URL; null only when the underlying storage is missing.
12932
+ mediaUrl: external_exports.string().nullable(),
12933
+ width: external_exports.number().int().nullable(),
12934
+ height: external_exports.number().int().nullable(),
12935
+ durationInMs: external_exports.number().int().nullable()
12936
+ });
12703
12937
  var ShareCanvasResponseSchema = external_exports.object({
12704
12938
  id: external_exports.string().uuid(),
12705
12939
  projectId: external_exports.string().uuid(),
@@ -12759,6 +12993,16 @@ var shareContract = c12.router({
12759
12993
  }
12760
12994
  },
12761
12995
  // Public endpoint — no auth required
12996
+ getSharedAsset: {
12997
+ method: "GET",
12998
+ path: "/share/assets/:assetId",
12999
+ pathParams: external_exports.object({ assetId: external_exports.string().uuid() }),
13000
+ responses: {
13001
+ 200: SharedAssetResponseSchema,
13002
+ 404: MessageResponseSchema
13003
+ }
13004
+ },
13005
+ // Public endpoint — no auth required
12762
13006
  getSharedCanvas: {
12763
13007
  method: "GET",
12764
13008
  path: "/share/projects/:projectId/canvases/:canvasId",
@@ -13894,7 +14138,7 @@ function isMajorUpgrade(current, latest) {
13894
14138
  return l[0] > c17[0];
13895
14139
  }
13896
14140
  function shouldShowUpgradeNotice(ctx = {}) {
13897
- const current = ctx.current ?? "0.7.0";
14141
+ const current = ctx.current ?? "0.8.0";
13898
14142
  const latest = ctx.latest ?? serverLatestVersion;
13899
14143
  const env = ctx.env ?? process.env;
13900
14144
  const isTty = ctx.isTty ?? Boolean(process.stderr.isTTY);
@@ -13915,7 +14159,7 @@ Upgrade: npm install -g @melius-ai/cli@latest (or: brew update && brew upgrade
13915
14159
  function printUpgradeNoticeIfNeeded(ctx = {}) {
13916
14160
  try {
13917
14161
  if (!shouldShowUpgradeNotice(ctx)) return;
13918
- const current = ctx.current ?? "0.7.0";
14162
+ const current = ctx.current ?? "0.8.0";
13919
14163
  const latest = ctx.latest ?? serverLatestVersion;
13920
14164
  process.stderr.write(formatUpgradeNotice(current, latest));
13921
14165
  } catch {
@@ -18599,7 +18843,7 @@ function registerAssetCommands(program2, getOutputOpts) {
18599
18843
  "Search and place the team's Files (DAM) library assets. Requires a Pro or Enterprise plan"
18600
18844
  );
18601
18845
  asset.command("search").description(
18602
- "Search the team's Files/DAM library (uploads + past generations) by meaning (semantic), with exact filename/title matches ranked first. Returns up to 20 relevant matches per page. Scope to a folder with --folder-id; omit the query and pass --folder-id to bring in the WHOLE folder"
18846
+ "Search the team's Files/DAM library (uploads + past generations) by meaning (semantic), with exact filename/title matches ranked first. Returns up to 20 relevant matches per page. Scope to a folder with --folder-id; filter by tag with --tags; omit the query and pass --folder-id or --tags to bring in the whole folder / all tagged assets"
18603
18847
  ).argument(
18604
18848
  "[query]",
18605
18849
  'Search terms \u2014 a filename or a description of the content, e.g. "Product_Shot_05" or "black jacket shot". Optional: OMIT it and pass --folder-id to list EVERY asset in that folder'
@@ -18616,6 +18860,9 @@ function registerAssetCommands(program2, getOutputOpts) {
18616
18860
  ).option(
18617
18861
  "--folder-id <folderId>",
18618
18862
  "Scope to one Files folder AND its subfolders. WITH a query, filters within the folder; WITHOUT a query, returns every asset in the folder. Get folder ids from mel asset folders"
18863
+ ).option(
18864
+ "--tags <names>",
18865
+ "Filter to assets carrying ALL of these tags (AND), comma-separated names (case-insensitive), e.g. --tags brand or --tags brand,hero. An unknown or misspelled name matches nothing. Combine with a query, or use alone (or with --folder-id) to bring in every asset carrying them"
18619
18866
  ).addHelpText(
18620
18867
  "after",
18621
18868
  `
@@ -18629,16 +18876,18 @@ Examples:
18629
18876
  $ mel asset search "logo" --file-type image --limit 10
18630
18877
  $ mel asset search "logo" --limit 20 --offset 20
18631
18878
  $ mel asset search "shark" --folder-id <folderId> # find within a folder
18632
- $ mel asset search --folder-id <folderId> # bring in the WHOLE folder`
18879
+ $ mel asset search --folder-id <folderId> # bring in the WHOLE folder
18880
+ $ mel asset search "logo" --tags brand # find tagged assets
18881
+ $ mel asset search --tags brand,hero # every asset with BOTH tags`
18633
18882
  ).action(
18634
18883
  async (query, opts) => {
18635
- if (query === void 0 && opts.folderId === void 0) {
18884
+ if (query === void 0 && opts.folderId === void 0 && opts.tags === void 0) {
18636
18885
  writeError(
18637
18886
  formatError(
18638
18887
  "USAGE_ERROR",
18639
- "Provide a search query, or --folder-id to bring in a whole folder",
18888
+ "Provide a search query, --folder-id to bring in a whole folder, or --tags to bring in tagged assets",
18640
18889
  {
18641
- suggestion: "Run mel asset folders to list folder ids, then: mel asset search --folder-id <folderId>"
18890
+ suggestion: "Run mel asset folders to list folder ids, then: mel asset search --folder-id <folderId> (or: mel asset search --tags <name>)"
18642
18891
  }
18643
18892
  ),
18644
18893
  EXIT_USAGE_ERROR
@@ -18658,7 +18907,8 @@ Examples:
18658
18907
  },
18659
18908
  ...opts.folderId !== void 0 && {
18660
18909
  folderId: opts.folderId
18661
- }
18910
+ },
18911
+ ...opts.tags !== void 0 && { tags: opts.tags }
18662
18912
  }
18663
18913
  });
18664
18914
  if (result.status !== 200) {
@@ -18865,7 +19115,7 @@ function withDefaultHelp(args) {
18865
19115
  }
18866
19116
  function createProgram() {
18867
19117
  const program2 = new Command();
18868
- program2.name("mel").description("Mel \u2014 Melius agent CLI").version("0.7.0").showSuggestionAfterError(true).option("--json", "Force JSON output (default)").option("--text", "Human-readable output").option(
19118
+ program2.name("mel").description("Mel \u2014 Melius agent CLI").version("0.8.0").showSuggestionAfterError(true).option("--json", "Force JSON output (default)").option("--text", "Human-readable output").option(
18869
19119
  "--fields <fields>",
18870
19120
  "Select specific output fields (comma-separated)"
18871
19121
  ).option("--quiet", "Suppress output, exit code only").option("--verbose", "Log request/response metadata to stderr").addHelpText(
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-5QT6WMID.js";
5
+ } from "../chunk-3PBGQVUH.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.7.0",
3
+ "version": "0.8.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",