@melius-ai/cli 0.5.2 → 0.6.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
@@ -259,12 +259,12 @@ mel upload ./photo.png --node-id <nodeId> --canvas-id <canvasId>
259
259
 
260
260
  Requires the Pro or Enterprise plan.
261
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) |
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 20 matches per page |
265
+ | `mel asset place <canvasId> <assetIds...>` | Place existing library assets onto a canvas by id — references the **original** asset (no duplicate) |
266
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).
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-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
268
 
269
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
270
 
package/dist/bin/mel.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  printUpgradeNoticeIfNeeded,
8
8
  withDefaultHelp,
9
9
  writeError
10
- } from "../chunk-4GUG5TD2.js";
10
+ } from "../chunk-EN744KKV.js";
11
11
 
12
12
  // bin/mel.ts
13
13
  var program = createProgram();
@@ -7914,7 +7914,11 @@ var FileTypeSchema = external_exports.enum([
7914
7914
  var FileCanvasBacklinkSchema = external_exports.object({
7915
7915
  canvasId: external_exports.string().uuid(),
7916
7916
  projectId: external_exports.string().uuid(),
7917
- canvasTitle: external_exports.string()
7917
+ canvasTitle: external_exports.string(),
7918
+ // A node on this canvas whose active version holds the asset, so opening
7919
+ // the canvas can center on it. Null when no such node survives (e.g. it was
7920
+ // deleted but the asset is still referenced elsewhere on the canvas).
7921
+ nodeId: external_exports.string().uuid().nullable().optional()
7918
7922
  });
7919
7923
  var FileCardSchema = external_exports.object({
7920
7924
  assetId: external_exports.string().uuid(),
@@ -8079,9 +8083,10 @@ var ListFilesResponseSchema = external_exports.object({
8079
8083
  cursor: external_exports.string().nullable().optional(),
8080
8084
  hasMore: external_exports.boolean().optional()
8081
8085
  });
8086
+ var AGENT_ASSET_SEARCH_PAGE_SIZE = 20;
8082
8087
  var AgentAssetSearchQuerySchema = external_exports.object({
8083
8088
  query: external_exports.string().trim().min(1).max(500).describe("Asset search query"),
8084
- limit: external_exports.coerce.number().int().min(1).max(5).default(5),
8089
+ limit: external_exports.coerce.number().int().min(1).max(AGENT_ASSET_SEARCH_PAGE_SIZE).default(AGENT_ASSET_SEARCH_PAGE_SIZE),
8085
8090
  source: FileSourceSchema.optional(),
8086
8091
  fileType: FileTypeSchema.optional(),
8087
8092
  canvasId: external_exports.string().uuid().optional().describe(
@@ -8094,7 +8099,14 @@ var AgentAssetSearchQuerySchema = external_exports.object({
8094
8099
  var AgentAssetSearchModeSchema = external_exports.enum(["semantic", "filename"]);
8095
8100
  var AgentAssetSearchRequestSchema = AgentAssetSearchQuerySchema.extend(
8096
8101
  {
8097
- mode: AgentAssetSearchModeSchema.optional()
8102
+ mode: AgentAssetSearchModeSchema.optional(),
8103
+ // Pagination offset for the picker's "More results" button. Like
8104
+ // `mode`, it lives here and NOT on `AgentAssetSearchQuerySchema` (the
8105
+ // LLM tool input) so the model can never paginate — paging is a member
8106
+ // action. Optional (not `.default(0)`): a default would make `offset`
8107
+ // required in the inferred type and break assignment from the tool
8108
+ // input, which has no offset. The service treats an absent offset as 0.
8109
+ offset: external_exports.coerce.number().int().min(0).optional()
8098
8110
  }
8099
8111
  );
8100
8112
  var AgentAssetSearchResponseSchema = external_exports.object({
@@ -8703,7 +8715,15 @@ var agentContract = c3.router({
8703
8715
  // clients that predate selection persistence.
8704
8716
  assetIds: external_exports.array(external_exports.string()).optional()
8705
8717
  }),
8706
- external_exports.object({ action: external_exports.literal("decline") })
8718
+ external_exports.object({
8719
+ action: external_exports.literal("decline"),
8720
+ // When the member declines these results and instead types a new
8721
+ // query into the card's "search for something else" input, the
8722
+ // resumed turn re-runs asset_search with exactly this query
8723
+ // instead of the agent asking a clarify. Bounds mirror
8724
+ // `AgentAssetSearchQuerySchema.query`. Omitted = plain decline.
8725
+ searchAgainQuery: external_exports.string().trim().min(1).max(500).optional()
8726
+ })
8707
8727
  ]),
8708
8728
  responses: {
8709
8729
  200: AgentToolApprovalResponseSchema,
@@ -9061,14 +9081,14 @@ var AUTO_MODEL_REGISTRY = [
9061
9081
  {
9062
9082
  nodeType: "text",
9063
9083
  inputPattern: "default",
9064
- standard: { model: "gemini-3-flash", variant: "text" },
9065
- fast: { model: "gemini-3-flash", variant: "text" }
9084
+ standard: { model: "gemini-3.1-pro", variant: "text" },
9085
+ fast: { model: "gemini-3.1-pro", variant: "text" }
9066
9086
  },
9067
9087
  {
9068
9088
  nodeType: "text",
9069
9089
  inputPattern: "with-video",
9070
- standard: { model: "gemini-3-flash", variant: "text" },
9071
- fast: { model: "gemini-3-flash", variant: "text" }
9090
+ standard: { model: "gemini-3.1-pro", variant: "text" },
9091
+ fast: { model: "gemini-3.1-pro", variant: "text" }
9072
9092
  },
9073
9093
  // ── Audio ───────────────────────────────────────────────────────────
9074
9094
  {
@@ -9928,15 +9948,22 @@ var TemplatePortSchema = external_exports.discriminatedUnion("direction", [
9928
9948
  /** Creator-set cap on connections into this input. Absent = unlimited. */
9929
9949
  maxConnections: external_exports.number().int().positive().optional(),
9930
9950
  /**
9931
- * Hidden input: not exposed as a connectable handle on the collapsed box
9951
+ * Locked input: not exposed as a connectable handle on the collapsed box
9932
9952
  * — its value comes from the source baked into the template definition
9933
9953
  * (used as-is for an upload/custom text, regenerated for a generation
9934
9954
  * node). The port is still recorded (rather than dropped) so it
9935
- * round-trips for editing in the internal tool. At apply, hidden input
9955
+ * round-trips for editing in the internal tool. At apply, locked input
9936
9956
  * ports are not materialized as instance bindings, so no handle renders
9937
9957
  * and they never gate a run.
9938
9958
  */
9939
- hidden: external_exports.boolean().optional(),
9959
+ locked: external_exports.boolean().optional(),
9960
+ /**
9961
+ * For a locked input only: the template node key of the baked source
9962
+ * whose value is frozen in. Lets apply resolve the materialized source
9963
+ * node so "Expand template" can surface it into the input column.
9964
+ * Absent for visible inputs (the user supplies their own source).
9965
+ */
9966
+ sourceNodeKey: external_exports.string().optional(),
9940
9967
  /**
9941
9968
  * Every internal handle this input fans out to. Absent/empty = the
9942
9969
  * single `nodeKey`/`internalHandle` binding (pre-fan-out templates).
@@ -9971,12 +9998,12 @@ var InstancePortBindingSchema = external_exports.discriminatedUnion("direction",
9971
9998
  required: external_exports.boolean().optional(),
9972
9999
  maxConnections: external_exports.number().int().positive().optional(),
9973
10000
  /**
9974
- * Mirror of `TemplatePort.hidden`. Hidden input ports are not
10001
+ * Mirror of `TemplatePort.locked`. Locked input ports are not
9975
10002
  * materialized as instance bindings today (the box never renders them),
9976
10003
  * so this is carried for symmetry/forward-compat rather than read at
9977
10004
  * runtime.
9978
10005
  */
9979
- hidden: external_exports.boolean().optional(),
10006
+ locked: external_exports.boolean().optional(),
9980
10007
  /**
9981
10008
  * Every internal endpoint this input fans out to (resolved form of
9982
10009
  * `TemplatePort.internalTargets`). Absent/empty = the single
@@ -10156,6 +10183,8 @@ var AssetSummaryDetailsSchema = external_exports.object({
10156
10183
  summary: external_exports.string()
10157
10184
  });
10158
10185
  var AssetResponseSchema = external_exports.object({
10186
+ /** Omitted from persisted snapshots created before this field existed. */
10187
+ assetId: external_exports.string().uuid().optional(),
10159
10188
  url: external_exports.string().nullable(),
10160
10189
  originalUrl: external_exports.string().nullable(),
10161
10190
  previewUrl: external_exports.string().nullable(),
@@ -10302,6 +10331,8 @@ var NodeResponseSchema = external_exports.object({
10302
10331
  templatePorts: external_exports.array(InstancePortBindingSchema).nullable().optional(),
10303
10332
  /** The source template id on a template-instance group (from CRDT). */
10304
10333
  templateId: external_exports.string().uuid().nullable().optional(),
10334
+ /** Whether a template-instance group may be expanded to its workflow (from CRDT). */
10335
+ isExpandable: external_exports.boolean().nullable().optional(),
10305
10336
  /** Direct child node IDs when nodeType is group (for agent wiring). */
10306
10337
  childNodeIds: external_exports.array(external_exports.string().uuid()).optional(),
10307
10338
  /** Per-ratio outputs for magic-resize nodes (from CRDT); one per variant. */
@@ -10407,8 +10438,11 @@ var NodeRunStatusSchema = external_exports.enum([
10407
10438
  var CreateNodeRunResponseSchema = external_exports.object({
10408
10439
  id: external_exports.string().uuid()
10409
10440
  });
10441
+ var RunOriginSchema = external_exports.enum(["canvas", "playground"]);
10410
10442
  var RunNodeBodySchema = external_exports.object({
10411
10443
  canvasId: external_exports.string().uuid().optional(),
10444
+ /** Product surface this run originated on. Defaults to `canvas` server-side. */
10445
+ origin: RunOriginSchema.optional(),
10412
10446
  textPrompt: external_exports.string().optional(),
10413
10447
  modelConfig: ModelConfigInputSchema.optional(),
10414
10448
  outputAspectRatio: OutputAspectRatioSchema.optional(),
@@ -10723,7 +10757,13 @@ var CreateDirectNodeBodyObjectSchema = external_exports.object({
10723
10757
  /** For template-instance groups only: resolved input/output port bindings. */
10724
10758
  templatePorts: external_exports.array(InstancePortBindingSchema).nullable().optional(),
10725
10759
  /** For template-instance groups only: the id of the source template. */
10726
- templateId: external_exports.string().uuid().nullable().optional()
10760
+ templateId: external_exports.string().uuid().nullable().optional(),
10761
+ /** For template-instance groups only: whether the box may be expanded to its
10762
+ * workflow (snapshot of the template's setting at apply time). */
10763
+ isExpandable: external_exports.boolean().nullable().optional(),
10764
+ /** For template-instance groups only: node ids of the baked locked-input
10765
+ * sources, surfaced into the input column when the box is expanded. */
10766
+ lockedInputNodeIds: external_exports.array(external_exports.string().uuid()).nullable().optional()
10727
10767
  });
10728
10768
  var CreateDirectNodeBodySchema = CreateDirectNodeBodyObjectSchema.superRefine(
10729
10769
  validateDirectFileNodeAssetFields
@@ -11060,6 +11100,31 @@ var canvasContract = c7.router({
11060
11100
  404: MessageResponseSchema
11061
11101
  }
11062
11102
  },
11103
+ // Mint per-node presigned download URLs (Content-Disposition: attachment)
11104
+ // so a client can trigger a real file download. Used by the display_canvas
11105
+ // MCP App, whose sandboxed iframe cannot download directly and must hand a
11106
+ // download-forcing URL to the host. Returns only nodes with a downloadable
11107
+ // active-version asset; nodes without one are omitted.
11108
+ getNodeDownloadUrls: {
11109
+ method: "POST",
11110
+ path: "/canvases/:canvasId/node-download-urls",
11111
+ pathParams: external_exports.object({ canvasId: external_exports.string().uuid() }),
11112
+ body: external_exports.object({
11113
+ nodeIds: external_exports.array(external_exports.string().uuid()).min(1).max(100)
11114
+ }),
11115
+ responses: {
11116
+ 200: external_exports.object({
11117
+ urls: external_exports.array(
11118
+ external_exports.object({
11119
+ nodeId: external_exports.string().uuid(),
11120
+ downloadUrl: external_exports.string().url(),
11121
+ filename: external_exports.string()
11122
+ })
11123
+ )
11124
+ }),
11125
+ 404: MessageResponseSchema
11126
+ }
11127
+ },
11063
11128
  listCanvasAssets: {
11064
11129
  method: "GET",
11065
11130
  path: "/canvases/:canvasId/assets",
@@ -11451,6 +11516,8 @@ var canvasContract = c7.router({
11451
11516
  pathParams: external_exports.object({ canvasId: external_exports.string().uuid() }),
11452
11517
  body: external_exports.object({
11453
11518
  nodeIds: external_exports.array(external_exports.string().uuid()).min(1).max(500),
11519
+ /** Product surface this run originated on. Defaults to `canvas` server-side. */
11520
+ origin: RunOriginSchema.optional(),
11454
11521
  /** Explicit image URLs applied to every node in the bulk run (merged with edge-resolved images). */
11455
11522
  imageUrls: external_exports.array(external_exports.string().url()).optional(),
11456
11523
  /**
@@ -13781,7 +13848,7 @@ function isMajorUpgrade(current, latest) {
13781
13848
  return l[0] > c17[0];
13782
13849
  }
13783
13850
  function shouldShowUpgradeNotice(ctx = {}) {
13784
- const current = ctx.current ?? "0.5.2";
13851
+ const current = ctx.current ?? "0.6.0";
13785
13852
  const latest = ctx.latest ?? serverLatestVersion;
13786
13853
  const env = ctx.env ?? process.env;
13787
13854
  const isTty = ctx.isTty ?? Boolean(process.stderr.isTTY);
@@ -13802,7 +13869,7 @@ Upgrade: npm install -g @melius-ai/cli@latest (or: brew update && brew upgrade
13802
13869
  function printUpgradeNoticeIfNeeded(ctx = {}) {
13803
13870
  try {
13804
13871
  if (!shouldShowUpgradeNotice(ctx)) return;
13805
- const current = ctx.current ?? "0.5.2";
13872
+ const current = ctx.current ?? "0.6.0";
13806
13873
  const latest = ctx.latest ?? serverLatestVersion;
13807
13874
  process.stderr.write(formatUpgradeNotice(current, latest));
13808
13875
  } catch {
@@ -18486,11 +18553,15 @@ function registerAssetCommands(program2, getOutputOpts) {
18486
18553
  "Search and place the team's Files (DAM) library assets. Requires a Pro or Enterprise plan"
18487
18554
  );
18488
18555
  asset.command("search").description(
18489
- "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"
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"
18490
18557
  ).argument(
18491
18558
  "<query>",
18492
18559
  'Search terms \u2014 a filename or a description of the content, e.g. "Product_Shot_05" or "black jacket shot"'
18493
- ).option("--limit <n>", "Max results (1-5, default 5)", "5").option(
18560
+ ).option("--limit <n>", "Max results per page (1-20, default 20)", "20").option(
18561
+ "--offset <n>",
18562
+ "Skip the first N matches to page deeper (default 0). Page with --limit until the running count reaches the response's total",
18563
+ "0"
18564
+ ).option(
18494
18565
  "--file-type <type>",
18495
18566
  "Filter by media type: image, video, audio, pdf, or text"
18496
18567
  ).option(
@@ -18500,11 +18571,13 @@ function registerAssetCommands(program2, getOutputOpts) {
18500
18571
  "after",
18501
18572
  `
18502
18573
  Returns: { query, total, results: [{ assetId, filename, displayName, fileType, contentType, previewUrl, assetUrl, durationInMs }] }.
18574
+ total is the full match count; page through it with --limit + --offset.
18503
18575
  Use the returned assetId values with mel asset place to bring them onto a canvas.
18504
18576
 
18505
18577
  Examples:
18506
18578
  $ mel asset search "black jacket shot"
18507
- $ mel asset search "logo" --file-type image --limit 3`
18579
+ $ mel asset search "logo" --file-type image --limit 10
18580
+ $ mel asset search "logo" --limit 20 --offset 20`
18508
18581
  ).action(
18509
18582
  async (query, opts) => {
18510
18583
  const client = getClient();
@@ -18512,6 +18585,7 @@ Examples:
18512
18585
  query: {
18513
18586
  query,
18514
18587
  limit: Number(opts.limit),
18588
+ offset: Number(opts.offset),
18515
18589
  ...opts.fileType !== void 0 && {
18516
18590
  fileType: opts.fileType
18517
18591
  },
@@ -18699,7 +18773,7 @@ function withDefaultHelp(args) {
18699
18773
  }
18700
18774
  function createProgram() {
18701
18775
  const program2 = new Command();
18702
- program2.name("mel").description("Mel \u2014 Melius agent CLI").version("0.5.2").showSuggestionAfterError(true).option("--json", "Force JSON output (default)").option("--text", "Human-readable output").option(
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(
18703
18777
  "--fields <fields>",
18704
18778
  "Select specific output fields (comma-separated)"
18705
18779
  ).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-4GUG5TD2.js";
5
+ } from "../chunk-EN744KKV.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.5.2",
3
+ "version": "0.6.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",