@melius-ai/cli 0.6.0 → 0.7.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
@@ -261,17 +261,25 @@ Requires the Pro or Enterprise plan.
261
261
 
262
262
  | Command | Description |
263
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 20 matches per page |
264
+ | `mel asset search [query]` | Search the team's Files/DAM library (uploads + past generations) by meaning; exact matches rank first. Returns up to 20 matches per page |
265
+ | `mel asset folders` | List the library's folders (`id`, `name`, `path`, `fileCount`) so you can resolve a folder name to an id for `--folder-id` |
265
266
  | `mel asset place <canvasId> <assetIds...>` | Place existing library assets onto a canvas by id — references the **original** asset (no duplicate) |
266
267
 
267
268
  `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-20>`; page deeper with `--offset <n>` (skip the first N matches — page until the running count reaches `total`); scope to one canvas with `--canvas-id` (omit to search the whole team library).
268
269
 
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
+
269
272
  `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
273
 
271
274
  ```bash
272
275
  # Find an asset, then bring it onto a canvas and wire it
273
276
  mel asset search "black jacket shot" --file-type image
274
277
  mel asset place <canvasId> <assetId1> <assetId2>
278
+
279
+ # Bring in a whole folder: resolve the folder, then search it with no query
280
+ mel asset folders # → [{ id, name, path, fileCount }]
281
+ mel asset search --folder-id <folderId> # every asset in the folder
282
+ mel asset search "shark" --folder-id <folderId> # or filter within it
275
283
  ```
276
284
 
277
285
  ### 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-EN744KKV.js";
10
+ } from "../chunk-5QT6WMID.js";
11
11
 
12
12
  // bin/mel.ts
13
13
  var program = createProgram();
@@ -8085,13 +8085,18 @@ var ListFilesResponseSchema = external_exports.object({
8085
8085
  });
8086
8086
  var AGENT_ASSET_SEARCH_PAGE_SIZE = 20;
8087
8087
  var AgentAssetSearchQuerySchema = external_exports.object({
8088
- query: external_exports.string().trim().min(1).max(500).describe("Asset search query"),
8088
+ query: external_exports.string().trim().min(1).max(500).optional().describe(
8089
+ 'The semantic search query \u2014 a filename or a description of the asset (e.g. "red logo", "the shark photo"). Provide it to FIND specific assets. OMIT it entirely to bring in EVERY asset from a folder: when the member says "bring in all my assets from the X folder" / "add everything in X to the canvas", resolve the folder with list_asset_folders and call asset_search with just that `folderId` and NO query. Never invent a query when the member asked for everything in a folder \u2014 a query filters and will drop assets they wanted. Omitting the query requires a `folderId`.'
8090
+ ),
8089
8091
  limit: external_exports.coerce.number().int().min(1).max(AGENT_ASSET_SEARCH_PAGE_SIZE).default(AGENT_ASSET_SEARCH_PAGE_SIZE),
8090
8092
  source: FileSourceSchema.optional(),
8091
8093
  fileType: FileTypeSchema.optional(),
8092
8094
  canvasId: external_exports.string().uuid().optional().describe(
8093
8095
  '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.'
8094
8096
  ),
8097
+ folderId: external_exports.string().uuid().optional().describe(
8098
+ '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
+ ),
8095
8100
  showInThread: external_exports.boolean().optional().describe(
8096
8101
  '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.'
8097
8102
  )
@@ -8112,7 +8117,27 @@ var AgentAssetSearchRequestSchema = AgentAssetSearchQuerySchema.extend(
8112
8117
  var AgentAssetSearchResponseSchema = external_exports.object({
8113
8118
  query: external_exports.string(),
8114
8119
  results: external_exports.array(FileCardSchema),
8115
- total: external_exports.number().int().nonnegative()
8120
+ total: external_exports.number().int().nonnegative(),
8121
+ // Echo the search scope so the picker's "More results" button can re-page
8122
+ // with the SAME scope. Without this, page 2 drops the folder/canvas filter
8123
+ // and pages the whole library (and a query-less folder browse can't page at
8124
+ // all). Absent when the corresponding filter wasn't set.
8125
+ folderId: external_exports.string().uuid().optional(),
8126
+ canvasId: external_exports.string().uuid().optional(),
8127
+ source: FileSourceSchema.optional(),
8128
+ fileType: FileTypeSchema.optional()
8129
+ });
8130
+ var AgentListAssetFoldersQuerySchema = external_exports.object({});
8131
+ var AgentAssetFolderSchema = external_exports.object({
8132
+ id: external_exports.string().uuid(),
8133
+ name: external_exports.string(),
8134
+ // Full path from the team root (e.g. "Brand / Logos") so the agent can
8135
+ // disambiguate when several folders share a name.
8136
+ path: external_exports.string(),
8137
+ fileCount: external_exports.number().int().nonnegative()
8138
+ });
8139
+ var AgentListAssetFoldersResponseSchema = external_exports.object({
8140
+ folders: external_exports.array(AgentAssetFolderSchema)
8116
8141
  });
8117
8142
  var InitFilesUploadBodySchema = external_exports.object({
8118
8143
  filename: external_exports.string(),
@@ -8290,6 +8315,15 @@ var filesContract = c2.router({
8290
8315
  },
8291
8316
  summary: "Search team assets for the agent"
8292
8317
  },
8318
+ listAgentAssetFolders: {
8319
+ method: "GET",
8320
+ path: "/files/agent-folders",
8321
+ responses: {
8322
+ 200: AgentListAssetFoldersResponseSchema,
8323
+ 403: ErrorBodySchema
8324
+ },
8325
+ summary: "List team asset folders for the agent"
8326
+ },
8293
8327
  getEmbeddingStorageUsage: {
8294
8328
  method: "GET",
8295
8329
  path: "/files/embedding-storage-usage",
@@ -10165,9 +10199,10 @@ var CropRectSchema = external_exports.object({
10165
10199
  });
10166
10200
  var StitchClipOrderSchema = external_exports.array(external_exports.string());
10167
10201
  var StitchScaleFitSchema = external_exports.enum(["fit", "stretch"]);
10202
+ var roundMs = (value) => typeof value === "number" ? Math.round(value) : value;
10168
10203
  var StitchTrimWindowFields = {
10169
- trimStartMs: external_exports.number().int().nonnegative().optional(),
10170
- trimEndMs: external_exports.number().int().positive().optional()
10204
+ trimStartMs: external_exports.preprocess(roundMs, external_exports.number().int().nonnegative()).optional(),
10205
+ trimEndMs: external_exports.preprocess(roundMs, external_exports.number().int().positive()).optional()
10171
10206
  };
10172
10207
  var StitchAudioOverlaySchema = external_exports.object({
10173
10208
  nodeId: external_exports.string(),
@@ -12202,6 +12237,10 @@ var ModelCostSchema = external_exports.discriminatedUnion("type", [
12202
12237
  maxCreditCost: external_exports.number()
12203
12238
  })
12204
12239
  ]);
12240
+ var TextTokenPricingSchema = external_exports.object({
12241
+ inputCreditsPerMillionTokens: external_exports.number(),
12242
+ outputCreditsPerMillionTokens: external_exports.number()
12243
+ });
12205
12244
  var InputFileSizeConstraintsResponseSchema = external_exports.object({
12206
12245
  maximumFileBytes: external_exports.number().int().nonnegative().optional(),
12207
12246
  maximumTotalBytes: external_exports.number().int().nonnegative().optional()
@@ -12307,7 +12346,9 @@ var ModelResponseSchema = external_exports.object({
12307
12346
  hiddenFromAgent: external_exports.boolean().optional(),
12308
12347
  promoRateLimit: PromoRateLimitSchema.optional(),
12309
12348
  /** Maximum prompt length in characters. Used by text models that lack variants. */
12310
- maxPromptLength: external_exports.number().nullable().optional()
12349
+ maxPromptLength: external_exports.number().nullable().optional(),
12350
+ /** Per-1M-token credit rates for text models; drives the live cost-range estimate. */
12351
+ textTokenPricing: TextTokenPricingSchema.optional()
12311
12352
  });
12312
12353
  var ListGenerativeModelsResponseSchema = external_exports.object({
12313
12354
  models: external_exports.array(ModelResponseSchema)
@@ -12800,7 +12841,8 @@ var EnterpriseOrderLineItemSchema = external_exports.object({
12800
12841
  var EnterpriseBillingIntervalSchema = external_exports.enum(["monthly", "annual"]);
12801
12842
  var EnterpriseStripeBillingInputSchema = external_exports.object({
12802
12843
  unitAmount: external_exports.number().int().positive(),
12803
- currency: external_exports.string().length(3).transform((value) => value.toLowerCase()),
12844
+ // Expose the transform output to OpenAPI generation.
12845
+ currency: external_exports.string().length(3).transform((value) => value.toLowerCase()).pipe(external_exports.string()),
12804
12846
  billingInterval: EnterpriseBillingIntervalSchema,
12805
12847
  creditsPerPeriod: external_exports.number().int().positive(),
12806
12848
  contractEndAt: external_exports.string().datetime().optional()
@@ -12864,7 +12906,8 @@ var EnterprisePendingExpansionSchema = external_exports.object({
12864
12906
  });
12865
12907
  var EnterpriseStripeBillingSchema = external_exports.object({
12866
12908
  unitAmount: external_exports.number().int().positive(),
12867
- currency: external_exports.string().length(3).transform((value) => value.toLowerCase()),
12909
+ // Expose the transform output to OpenAPI generation.
12910
+ currency: external_exports.string().length(3).transform((value) => value.toLowerCase()).pipe(external_exports.string()),
12868
12911
  billingInterval: EnterpriseBillingIntervalSchema,
12869
12912
  creditsPerPeriod: external_exports.number().int().positive(),
12870
12913
  contractEndAt: external_exports.string().datetime().optional(),
@@ -13578,10 +13621,13 @@ var publicContract = c16.router(
13578
13621
  complete: uploadContract.complete
13579
13622
  },
13580
13623
  asset: {
13581
- // Semantic/filename search of the team's Files (DAM) library, and
13582
- // placing a found asset onto a canvas by reference (no duplicate).
13583
- // Both are gated to Pro + Enterprise by the handlers.
13624
+ // Semantic/filename search of the team's Files (DAM) library,
13625
+ // listing the library's folders (to resolve a folder name id for a
13626
+ // folder-scoped search), and placing a found asset onto a canvas by
13627
+ // reference (no duplicate). All gated to Pro + Enterprise by the
13628
+ // handlers.
13584
13629
  search: filesContract.searchAgentAssets,
13630
+ folders: filesContract.listAgentAssetFolders,
13585
13631
  place: canvasContract.placeLibraryAssets
13586
13632
  },
13587
13633
  model: {
@@ -13848,7 +13894,7 @@ function isMajorUpgrade(current, latest) {
13848
13894
  return l[0] > c17[0];
13849
13895
  }
13850
13896
  function shouldShowUpgradeNotice(ctx = {}) {
13851
- const current = ctx.current ?? "0.6.0";
13897
+ const current = ctx.current ?? "0.7.0";
13852
13898
  const latest = ctx.latest ?? serverLatestVersion;
13853
13899
  const env = ctx.env ?? process.env;
13854
13900
  const isTty = ctx.isTty ?? Boolean(process.stderr.isTTY);
@@ -13869,7 +13915,7 @@ Upgrade: npm install -g @melius-ai/cli@latest (or: brew update && brew upgrade
13869
13915
  function printUpgradeNoticeIfNeeded(ctx = {}) {
13870
13916
  try {
13871
13917
  if (!shouldShowUpgradeNotice(ctx)) return;
13872
- const current = ctx.current ?? "0.6.0";
13918
+ const current = ctx.current ?? "0.7.0";
13873
13919
  const latest = ctx.latest ?? serverLatestVersion;
13874
13920
  process.stderr.write(formatUpgradeNotice(current, latest));
13875
13921
  } catch {
@@ -18553,10 +18599,10 @@ function registerAssetCommands(program2, getOutputOpts) {
18553
18599
  "Search and place the team's Files (DAM) library assets. Requires a Pro or Enterprise plan"
18554
18600
  );
18555
18601
  asset.command("search").description(
18556
- "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"
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"
18557
18603
  ).argument(
18558
- "<query>",
18559
- 'Search terms \u2014 a filename or a description of the content, e.g. "Product_Shot_05" or "black jacket shot"'
18604
+ "[query]",
18605
+ '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'
18560
18606
  ).option("--limit <n>", "Max results per page (1-20, default 20)", "20").option(
18561
18607
  "--offset <n>",
18562
18608
  "Skip the first N matches to page deeper (default 0). Page with --limit until the running count reaches the response's total",
@@ -18567,23 +18613,41 @@ function registerAssetCommands(program2, getOutputOpts) {
18567
18613
  ).option(
18568
18614
  "--canvas-id <canvasId>",
18569
18615
  "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)"
18616
+ ).option(
18617
+ "--folder-id <folderId>",
18618
+ "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"
18570
18619
  ).addHelpText(
18571
18620
  "after",
18572
18621
  `
18573
18622
  Returns: { query, total, results: [{ assetId, filename, displayName, fileType, contentType, previewUrl, assetUrl, durationInMs }] }.
18574
18623
  total is the full match count; page through it with --limit + --offset.
18575
18624
  Use the returned assetId values with mel asset place to bring them onto a canvas.
18625
+ Resolve a folder name to an id with mel asset folders first.
18576
18626
 
18577
18627
  Examples:
18578
18628
  $ mel asset search "black jacket shot"
18579
18629
  $ mel asset search "logo" --file-type image --limit 10
18580
- $ mel asset search "logo" --limit 20 --offset 20`
18630
+ $ mel asset search "logo" --limit 20 --offset 20
18631
+ $ mel asset search "shark" --folder-id <folderId> # find within a folder
18632
+ $ mel asset search --folder-id <folderId> # bring in the WHOLE folder`
18581
18633
  ).action(
18582
18634
  async (query, opts) => {
18635
+ if (query === void 0 && opts.folderId === void 0) {
18636
+ writeError(
18637
+ formatError(
18638
+ "USAGE_ERROR",
18639
+ "Provide a search query, or --folder-id to bring in a whole folder",
18640
+ {
18641
+ suggestion: "Run mel asset folders to list folder ids, then: mel asset search --folder-id <folderId>"
18642
+ }
18643
+ ),
18644
+ EXIT_USAGE_ERROR
18645
+ );
18646
+ }
18583
18647
  const client = getClient();
18584
18648
  const result = await client.asset.search({
18585
18649
  query: {
18586
- query,
18650
+ ...query !== void 0 && { query },
18587
18651
  limit: Number(opts.limit),
18588
18652
  offset: Number(opts.offset),
18589
18653
  ...opts.fileType !== void 0 && {
@@ -18591,6 +18655,9 @@ Examples:
18591
18655
  },
18592
18656
  ...opts.canvasId !== void 0 && {
18593
18657
  canvasId: opts.canvasId
18658
+ },
18659
+ ...opts.folderId !== void 0 && {
18660
+ folderId: opts.folderId
18594
18661
  }
18595
18662
  }
18596
18663
  });
@@ -18604,6 +18671,31 @@ Examples:
18604
18671
  writeJson(result.body, getOutputOpts());
18605
18672
  }
18606
18673
  );
18674
+ asset.command("folders").description(
18675
+ "List the team's Files/DAM folders (id, name, full path, file count). Use a folder's id with mel asset search --folder-id to scope a search or bring in the whole folder"
18676
+ ).addHelpText(
18677
+ "after",
18678
+ `
18679
+ Returns: an array of { id, name, path, fileCount }.
18680
+ path is the folder's location from the library root (e.g. "Brand / Logos") \u2014 use it to disambiguate same-named folders.
18681
+ Pass a folder id to mel asset search --folder-id <folderId>.
18682
+
18683
+ Examples:
18684
+ $ mel asset folders
18685
+ $ mel asset folders --text`
18686
+ ).action(async () => {
18687
+ const client = getClient();
18688
+ const result = await client.asset.folders();
18689
+ if (result.status !== 200) {
18690
+ handleApiError(
18691
+ result.status,
18692
+ result.body,
18693
+ result.status === 403 ? ASSET_PLAN_REQUIRED_SUGGESTION : void 0
18694
+ );
18695
+ }
18696
+ const body = result.body;
18697
+ writeJson(body.folders, getOutputOpts());
18698
+ });
18607
18699
  asset.command("place").description(
18608
18700
  "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"
18609
18701
  ).argument(
@@ -18773,7 +18865,7 @@ function withDefaultHelp(args) {
18773
18865
  }
18774
18866
  function createProgram() {
18775
18867
  const program2 = new Command();
18776
- program2.name("mel").description("Mel \u2014 Melius agent CLI").version("0.6.0").showSuggestionAfterError(true).option("--json", "Force JSON output (default)").option("--text", "Human-readable output").option(
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(
18777
18869
  "--fields <fields>",
18778
18870
  "Select specific output fields (comma-separated)"
18779
18871
  ).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-EN744KKV.js";
5
+ } from "../chunk-5QT6WMID.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.6.0",
3
+ "version": "0.7.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",