@melius-ai/cli 0.2.1 → 0.4.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
@@ -8,7 +8,7 @@ The programmatic interface to the Melius platform. Built for AI agents running i
8
8
  npm install -g @melius-ai/cli
9
9
  # or with Homebrew (macOS/Linux): brew install melius-ai/tap/mel
10
10
 
11
- # Authenticate
11
+ # Authenticate (see "Get an API key" below to obtain a key)
12
12
  mel auth login --api-key mel_<your-key>
13
13
 
14
14
  # Build a canvas
@@ -19,6 +19,26 @@ mel run start <nodeId> --canvas-id <canvasId>
19
19
  mel run wait <runId>
20
20
  ```
21
21
 
22
+ ## Get an API key
23
+
24
+ 1. Sign up at [app.melius.com/signup](https://app.melius.com/signup) if you don't have a Melius account yet.
25
+ 2. In the Melius app, go to **Team settings → Integrations** and create an API key (it starts with `mel_` and is shown once — copy it immediately).
26
+ 3. Authenticate the CLI with it: `mel auth login --api-key mel_<your-key>`.
27
+
28
+ ## Upgrading
29
+
30
+ Check your installed version with `mel --version`. Upgrade with the same tool you installed with:
31
+
32
+ ```bash
33
+ # npm
34
+ npm install -g @melius-ai/cli@latest
35
+
36
+ # Homebrew (macOS/Linux)
37
+ brew update && brew upgrade mel
38
+ ```
39
+
40
+ To see the latest published version, run `npm view @melius-ai/cli version` (or visit the [package page on npm](https://www.npmjs.com/package/@melius-ai/cli)). Releases follow [semantic versioning](https://semver.org) — a major version bump (for example `1.x` → `2.x`) can include breaking changes, so review what changed before upgrading across one.
41
+
22
42
  ## Sandbox setup
23
43
 
24
44
  In the Claude Code sandbox, only two environment variables are needed:
@@ -323,7 +343,7 @@ All commands follow the same contract:
323
343
  "code": "UNAUTHORIZED",
324
344
  "message": "Invalid or expired API key",
325
345
  "status": 401,
326
- "suggestion": "Run: mel auth login --api-key <key>"
346
+ "suggestion": "Sign up at https://app.melius.com/signup, then create an API key in the Melius app under Team settings → Integrations. Then run: mel auth login --api-key mel_..."
327
347
  }
328
348
  }
329
349
  ```
package/dist/bin/mel.js CHANGED
@@ -4,13 +4,17 @@ import {
4
4
  EXIT_API_ERROR,
5
5
  createProgram,
6
6
  formatError,
7
+ printUpgradeNoticeIfNeeded,
8
+ withDefaultHelp,
7
9
  writeError
8
- } from "../chunk-6IN2VKUC.js";
10
+ } from "../chunk-EXHDKHNG.js";
9
11
 
10
12
  // bin/mel.ts
11
13
  var program = createProgram();
12
14
  try {
13
- await program.parseAsync(process.argv);
15
+ await program.parseAsync(withDefaultHelp(process.argv.slice(2)), {
16
+ from: "user"
17
+ });
14
18
  } catch (err) {
15
19
  writeError(
16
20
  formatError(
@@ -20,3 +24,6 @@ try {
20
24
  EXIT_API_ERROR
21
25
  );
22
26
  }
27
+ printUpgradeNoticeIfNeeded({
28
+ quiet: Boolean(program.opts().quiet)
29
+ });
@@ -8112,6 +8112,18 @@ var BulkMoveFilesBodySchema = external_exports.object({
8112
8112
  assetIds: BulkFileAssetIdsSchema,
8113
8113
  folderId: external_exports.string().uuid().nullable()
8114
8114
  });
8115
+ var BulkDownloadableIdsSchema = external_exports.array(external_exports.string().uuid()).max(MAX_BULK_FILE_ACTION_ASSET_IDS).default([]);
8116
+ var BulkDownloadFilesBodySchema = external_exports.object({
8117
+ assetIds: BulkDownloadableIdsSchema,
8118
+ folderIds: BulkDownloadableIdsSchema
8119
+ }).refine((body) => body.assetIds.length + body.folderIds.length > 0, {
8120
+ message: "Select at least one file or folder to download"
8121
+ });
8122
+ var BulkDownloadFilesResponseSchema = external_exports.object({
8123
+ // Presigned URL of a freshly built zip archive of the requested assets.
8124
+ url: external_exports.string().url(),
8125
+ filename: external_exports.string()
8126
+ });
8115
8127
  var BulkHideFilesBodySchema = external_exports.object({
8116
8128
  assetIds: BulkFileAssetIdsSchema
8117
8129
  });
@@ -8218,6 +8230,10 @@ var CompleteFilesUploadBodySchema = external_exports.object({
8218
8230
  var CompleteFilesUploadResponseSchema = external_exports.object({
8219
8231
  file: FileCardSchema
8220
8232
  });
8233
+ var EmbeddingStorageUsageResponseSchema = external_exports.object({
8234
+ usedBytes: external_exports.number(),
8235
+ limitBytes: external_exports.number()
8236
+ });
8221
8237
  var ErrorBodySchema = MessageResponseSchema;
8222
8238
  var filesContract = c2.router({
8223
8239
  createFileFolder: {
@@ -8287,6 +8303,17 @@ var filesContract = c2.router({
8287
8303
  },
8288
8304
  summary: "Move a file to a folder"
8289
8305
  },
8306
+ bulkDownloadFiles: {
8307
+ method: "POST",
8308
+ path: "/files/bulk/download",
8309
+ body: BulkDownloadFilesBodySchema,
8310
+ responses: {
8311
+ 200: BulkDownloadFilesResponseSchema,
8312
+ 403: ErrorBodySchema,
8313
+ 404: ErrorBodySchema
8314
+ },
8315
+ summary: "Download files and folders as a zip archive"
8316
+ },
8290
8317
  bulkHideFiles: {
8291
8318
  method: "POST",
8292
8319
  path: "/files/bulk/hide",
@@ -8353,6 +8380,15 @@ var filesContract = c2.router({
8353
8380
  },
8354
8381
  summary: "Search team assets for the agent"
8355
8382
  },
8383
+ getEmbeddingStorageUsage: {
8384
+ method: "GET",
8385
+ path: "/files/embedding-storage-usage",
8386
+ responses: {
8387
+ 200: EmbeddingStorageUsageResponseSchema,
8388
+ 403: ErrorBodySchema
8389
+ },
8390
+ summary: "Get the team's DAM embedding-storage usage and cap"
8391
+ },
8356
8392
  getFileDetail: {
8357
8393
  method: "GET",
8358
8394
  path: "/files/:assetId/detail",
@@ -9052,7 +9088,7 @@ var AUTO_MODEL_REGISTRY = [
9052
9088
  {
9053
9089
  nodeType: "video",
9054
9090
  inputPattern: "text-only",
9055
- standard: { model: "ltx-2.3", variant: "text-to-video" },
9091
+ standard: { model: "kling-o3", variant: "text-to-video" },
9056
9092
  fast: { model: "grok-imagine-video", variant: "text-to-video" }
9057
9093
  },
9058
9094
  {
@@ -9070,7 +9106,7 @@ var AUTO_MODEL_REGISTRY = [
9070
9106
  {
9071
9107
  nodeType: "video",
9072
9108
  inputPattern: "reference-to-video",
9073
- standard: { model: "veo-3.1", variant: "reference-to-video" },
9109
+ standard: { model: "kling-o3", variant: "reference-to-video" },
9074
9110
  fast: { model: "kling-o3", variant: "reference-to-video" }
9075
9111
  },
9076
9112
  {
@@ -9115,13 +9151,13 @@ var AUTO_MODEL_REGISTRY = [
9115
9151
  {
9116
9152
  nodeType: "image",
9117
9153
  inputPattern: "text-to-image",
9118
- standard: { model: "gpt-image-2-medium", variant: "text-to-image" },
9154
+ standard: { model: "nano-banana-pro", variant: "text-to-image" },
9119
9155
  fast: { model: "flux-schnell", variant: "text-to-image" }
9120
9156
  },
9121
9157
  {
9122
9158
  nodeType: "image",
9123
9159
  inputPattern: "image-to-image",
9124
- standard: { model: "gpt-image-2-medium", variant: "image-to-image" },
9160
+ standard: { model: "nano-banana-pro", variant: "image-to-image" },
9125
9161
  fast: { model: "grok-imagine", variant: "image-to-image" }
9126
9162
  },
9127
9163
  // ── Text ────────────────────────────────────────────────────────────
@@ -9773,6 +9809,128 @@ var ElevenLabsVoiceSettingsSchema = external_exports.object({
9773
9809
  outputFormat: ElevenLabsOutputFormatSchema.optional()
9774
9810
  });
9775
9811
 
9812
+ // ../api-contract/src/lora.ts
9813
+ var c6 = initContract();
9814
+ var MAX_LORA_NAME_LENGTH = 80;
9815
+ var MAX_LORA_DESCRIPTION_LENGTH = 1e3;
9816
+ var MAX_LORA_TRIGGER_WORDS_LENGTH = 500;
9817
+ var MAX_LORA_FILE_SIZE_BYTES = 2 * 1024 * 1024 * 1024;
9818
+ var MAX_LORAS_PER_GENERATION = 5;
9819
+ var MIN_LORA_WEIGHT = 0;
9820
+ var MAX_LORA_WEIGHT = 1.5;
9821
+ var MIN_SDXL_STEPS = 1;
9822
+ var MAX_SDXL_STEPS = 60;
9823
+ var MIN_SDXL_GUIDANCE_SCALE = 0;
9824
+ var MAX_SDXL_GUIDANCE_SCALE = 20;
9825
+ var LoraBaseModelSchema = external_exports.enum(["sdxl", "flux", "other"]);
9826
+ var LoraSelectionSchema = external_exports.object({
9827
+ id: external_exports.string().uuid(),
9828
+ weight: external_exports.number().min(MIN_LORA_WEIGHT).max(MAX_LORA_WEIGHT)
9829
+ });
9830
+ var LoraStackSchema = external_exports.array(LoraSelectionSchema).max(MAX_LORAS_PER_GENERATION);
9831
+ var AppliedLoraSchema = external_exports.object({
9832
+ id: external_exports.string(),
9833
+ name: external_exports.string(),
9834
+ weight: external_exports.number()
9835
+ });
9836
+ var SdxlStepsSchema = external_exports.number().int().min(MIN_SDXL_STEPS).max(MAX_SDXL_STEPS);
9837
+ var SdxlGuidanceScaleSchema = external_exports.number().min(MIN_SDXL_GUIDANCE_SCALE).max(MAX_SDXL_GUIDANCE_SCALE);
9838
+ var LoraSummarySchema = external_exports.object({
9839
+ id: external_exports.string().uuid(),
9840
+ name: external_exports.string(),
9841
+ description: external_exports.string(),
9842
+ /** Activation tokens parsed from the file (best-effort); null if none. */
9843
+ triggerWords: external_exports.string().nullable(),
9844
+ baseModel: LoraBaseModelSchema,
9845
+ /** Recommended blend weight the picker pre-fills. */
9846
+ defaultScale: external_exports.number(),
9847
+ previewUrl: external_exports.string().nullable(),
9848
+ /** teamId is null ⇒ a global/curated LoRA owned by Melius (added by us). */
9849
+ isGlobal: external_exports.boolean(),
9850
+ fileSizeBytes: external_exports.number(),
9851
+ createdAt: external_exports.string(),
9852
+ updatedAt: external_exports.string()
9853
+ });
9854
+ var ListLorasResponseSchema = external_exports.object({
9855
+ loras: external_exports.array(LoraSummarySchema)
9856
+ });
9857
+ var InitLoraUploadBodySchema = external_exports.object({
9858
+ filename: external_exports.string().min(1),
9859
+ sizeInBytes: external_exports.number().int().positive().max(MAX_LORA_FILE_SIZE_BYTES)
9860
+ });
9861
+ var InitLoraUploadResponseSchema = external_exports.object({
9862
+ /** Short-lived presigned PUT the client uploads the raw weights to. */
9863
+ uploadUrl: external_exports.string(),
9864
+ s3Bucket: external_exports.string(),
9865
+ s3Key: external_exports.string()
9866
+ });
9867
+ var CreateLoraBodySchema = external_exports.object({
9868
+ name: external_exports.string().trim().min(1).max(MAX_LORA_NAME_LENGTH),
9869
+ description: external_exports.string().max(MAX_LORA_DESCRIPTION_LENGTH).optional(),
9870
+ /** Uploader override; server falls back to the parsed metadata when omitted. */
9871
+ triggerWords: external_exports.string().max(MAX_LORA_TRIGGER_WORDS_LENGTH).optional(),
9872
+ baseModel: LoraBaseModelSchema,
9873
+ s3Bucket: external_exports.string().min(1),
9874
+ s3Key: external_exports.string().min(1),
9875
+ /** Client-attested SHA-256 of the uploaded file (integrity reference). */
9876
+ sha256: external_exports.string().min(1),
9877
+ fileSizeBytes: external_exports.number().int().positive().max(MAX_LORA_FILE_SIZE_BYTES),
9878
+ defaultScale: external_exports.number().min(MIN_LORA_WEIGHT).max(MAX_LORA_WEIGHT).optional()
9879
+ });
9880
+ var ForbiddenSchema = MessageResponseSchema;
9881
+ var NotFoundSchema = MessageResponseSchema;
9882
+ var BadRequestSchema = MessageResponseSchema;
9883
+ var ConflictSchema = MessageResponseSchema;
9884
+ var loraContract = c6.router({
9885
+ listLoras: {
9886
+ method: "GET",
9887
+ path: "/teams/:teamId/loras",
9888
+ pathParams: external_exports.object({ teamId: external_exports.string().uuid() }),
9889
+ responses: {
9890
+ 200: ListLorasResponseSchema,
9891
+ 403: ForbiddenSchema,
9892
+ 404: NotFoundSchema
9893
+ }
9894
+ },
9895
+ // @SkipManagedTransaction on the handler — only mints a presigned PUT.
9896
+ initLoraUpload: {
9897
+ method: "POST",
9898
+ path: "/teams/:teamId/loras/upload",
9899
+ pathParams: external_exports.object({ teamId: external_exports.string().uuid() }),
9900
+ body: InitLoraUploadBodySchema,
9901
+ responses: {
9902
+ 200: InitLoraUploadResponseSchema,
9903
+ 400: BadRequestSchema,
9904
+ 403: ForbiddenSchema
9905
+ }
9906
+ },
9907
+ createLora: {
9908
+ method: "POST",
9909
+ path: "/teams/:teamId/loras",
9910
+ pathParams: external_exports.object({ teamId: external_exports.string().uuid() }),
9911
+ body: CreateLoraBodySchema,
9912
+ responses: {
9913
+ 201: LoraSummarySchema,
9914
+ 400: BadRequestSchema,
9915
+ 403: ForbiddenSchema,
9916
+ 409: ConflictSchema
9917
+ }
9918
+ },
9919
+ deleteLora: {
9920
+ method: "DELETE",
9921
+ path: "/teams/:teamId/loras/:loraId",
9922
+ pathParams: external_exports.object({
9923
+ teamId: external_exports.string().uuid(),
9924
+ loraId: external_exports.string().uuid()
9925
+ }),
9926
+ responses: {
9927
+ 200: external_exports.object({ id: external_exports.string().uuid() }),
9928
+ 403: ForbiddenSchema,
9929
+ 404: NotFoundSchema
9930
+ }
9931
+ }
9932
+ });
9933
+
9776
9934
  // ../api-contract/src/preview-asset.ts
9777
9935
  var PreviewAssetSchema = external_exports.object({
9778
9936
  url: external_exports.string(),
@@ -9881,7 +10039,7 @@ var TemplatePortSummarySchema = external_exports.object({
9881
10039
  });
9882
10040
 
9883
10041
  // ../api-contract/src/canvas.ts
9884
- var c6 = initContract();
10042
+ var c7 = initContract();
9885
10043
  var CanvasResponseSchema = external_exports.object({
9886
10044
  id: external_exports.string().uuid(),
9887
10045
  teamId: external_exports.string().uuid(),
@@ -9939,7 +10097,13 @@ var ModelConfigSchema = external_exports.object({
9939
10097
  font: external_exports.object({
9940
10098
  source: external_exports.enum(["custom", "google"]),
9941
10099
  familyName: external_exports.string()
9942
- }).optional()
10100
+ }).optional(),
10101
+ /** SDXL only: the LoRA stack applied to this version (name denormalized so history survives deletion). */
10102
+ loras: external_exports.array(AppliedLoraSchema).optional(),
10103
+ /** SDXL only: sampler steps used for this version. */
10104
+ steps: external_exports.number().optional(),
10105
+ /** SDXL only: classifier-free guidance scale used for this version. */
10106
+ guidanceScale: external_exports.number().optional()
9943
10107
  });
9944
10108
  var ModelConfigInputSchema = external_exports.object({
9945
10109
  model: external_exports.string(),
@@ -10222,6 +10386,9 @@ var CanvasContentResponseSchema = external_exports.object({
10222
10386
  edges: external_exports.array(EdgeResponseSchema),
10223
10387
  modelPresets: CanvasMediaPresetSchema.optional().describe(
10224
10388
  "Canvas-wide default model + variant the user configured in canvas settings, per category (image/video/text/audio). When a node is created with no modelConfig, the server pins these defaults exactly. Use this to know what model+mode will apply, so you can pick correct edge handles and avoid hallucinating the default"
10389
+ ),
10390
+ videoDurationOptions: external_exports.array(external_exports.number().int().positive()).optional().describe(
10391
+ "The exact clip durations (seconds) the canvas default video model supports, e.g. [3,4,5,\u2026,15]. Pick each video node's duration from this list \u2014 it is the real range, so you never need model_list just to find valid durations, and you can use short values (like 3s) and odd values, not only round 5s/10s. A value below a specific variant's floor is clamped up automatically."
10225
10392
  )
10226
10393
  });
10227
10394
  var QueryBooleanSchema = external_exports.preprocess((value) => {
@@ -10330,7 +10497,17 @@ var RunNodeBodySchema = external_exports.object({
10330
10497
  * ElevenLabs voice tuning for TTS / voice-changer runs. Applied when
10331
10498
  * provided; the `voice-granular-controls` flag only gates the toolbar UI.
10332
10499
  */
10333
- elevenLabsVoiceSettings: ElevenLabsVoiceSettingsSchema.optional()
10500
+ elevenLabsVoiceSettings: ElevenLabsVoiceSettingsSchema.optional(),
10501
+ /**
10502
+ * LoRA adapters to stack on a self-hosted SDXL generation (`{ id, weight }`).
10503
+ * The server resolves each id to a presigned weights URL and validates team
10504
+ * access. Only honored on the SDXL model.
10505
+ */
10506
+ loras: LoraStackSchema.optional(),
10507
+ /** SDXL sampler steps. Only honored on the SDXL model. */
10508
+ steps: SdxlStepsSchema.optional(),
10509
+ /** SDXL guidance scale. Only honored on the SDXL model. */
10510
+ guidanceScale: SdxlGuidanceScaleSchema.optional()
10334
10511
  });
10335
10512
  var RunImageToolBodySchema = external_exports.object({
10336
10513
  canvasId: external_exports.string().uuid().optional(),
@@ -10759,7 +10936,7 @@ var CanvasSettingsResponseSchema = external_exports.object({
10759
10936
  createdAt: external_exports.string().datetime(),
10760
10937
  updatedAt: external_exports.string().datetime()
10761
10938
  });
10762
- var canvasContract = c6.router({
10939
+ var canvasContract = c7.router({
10763
10940
  createCanvas: {
10764
10941
  method: "POST",
10765
10942
  path: "/projects/:projectId/canvases",
@@ -10813,7 +10990,7 @@ var canvasContract = c6.router({
10813
10990
  canvasId: external_exports.string().uuid()
10814
10991
  }),
10815
10992
  body: null,
10816
- responses: { 204: c6.noBody() }
10993
+ responses: { 204: c7.noBody() }
10817
10994
  },
10818
10995
  duplicateCanvas: {
10819
10996
  method: "POST",
@@ -11228,7 +11405,7 @@ var canvasContract = c6.router({
11228
11405
  pathParams: external_exports.object({ nodeRunId: external_exports.string().uuid() }),
11229
11406
  body: external_exports.object({}),
11230
11407
  responses: {
11231
- 204: c6.noBody(),
11408
+ 204: c7.noBody(),
11232
11409
  404: NodeRunErrorResponseSchema,
11233
11410
  409: NodeRunErrorResponseSchema
11234
11411
  },
@@ -11319,6 +11496,35 @@ var canvasContract = c6.router({
11319
11496
  400: MessageResponseSchema
11320
11497
  }
11321
11498
  },
11499
+ validateBulkRun: {
11500
+ method: "POST",
11501
+ path: "/canvases/:canvasId/bulk-run/validate",
11502
+ pathParams: external_exports.object({ canvasId: external_exports.string().uuid() }),
11503
+ body: external_exports.object({
11504
+ nodeIds: external_exports.array(external_exports.string().uuid()).min(1).max(500),
11505
+ // Input nodes the author marked OPTIONAL (may be absent when the
11506
+ // template is applied). Preflight validates the worst case by
11507
+ // dropping edges from these sources, so a downstream node left
11508
+ // without its only required input (e.g. every prompt-feeder made
11509
+ // optional) fails here instead of only at apply time.
11510
+ optionalSourceNodeIds: external_exports.array(external_exports.string().uuid()).optional()
11511
+ }),
11512
+ responses: {
11513
+ // Read-only preflight: collect every reason a node (or the graph)
11514
+ // can't run instead of failing on the first. `nodeId: null` is a
11515
+ // graph-level issue (e.g. a cycle). Empty `issues` = runnable.
11516
+ 200: external_exports.object({
11517
+ issues: external_exports.array(
11518
+ external_exports.object({
11519
+ nodeId: external_exports.string().uuid().nullable(),
11520
+ message: external_exports.string()
11521
+ })
11522
+ )
11523
+ }),
11524
+ 400: MessageResponseSchema
11525
+ },
11526
+ summary: "Validate that a set of nodes can run as a bulk run, collecting all blockers"
11527
+ },
11322
11528
  getBulkNodeRun: {
11323
11529
  method: "GET",
11324
11530
  path: "/bulk-node-runs/:bulkNodeRunId",
@@ -11377,7 +11583,7 @@ var canvasContract = c6.router({
11377
11583
  path: "/comment-threads/:threadId",
11378
11584
  pathParams: external_exports.object({ threadId: external_exports.string().uuid() }),
11379
11585
  body: null,
11380
- responses: { 204: c6.noBody() }
11586
+ responses: { 204: c7.noBody() }
11381
11587
  },
11382
11588
  // ── Comments ────────────────────────────────────────────────────────
11383
11589
  addComment: {
@@ -11392,7 +11598,7 @@ var canvasContract = c6.router({
11392
11598
  path: "/comments/:commentId",
11393
11599
  pathParams: external_exports.object({ commentId: external_exports.string().uuid() }),
11394
11600
  body: null,
11395
- responses: { 204: c6.noBody() }
11601
+ responses: { 204: c7.noBody() }
11396
11602
  },
11397
11603
  // ── Direct CRDT Mutations (CLI/Agent) ───────────────────────────────
11398
11604
  // These endpoints write directly to the Y.Doc (CRDT) for the canvas.
@@ -11432,7 +11638,7 @@ var canvasContract = c6.router({
11432
11638
  }),
11433
11639
  body: null,
11434
11640
  responses: {
11435
- 204: c6.noBody(),
11641
+ 204: c7.noBody(),
11436
11642
  404: MessageResponseSchema,
11437
11643
  409: MessageResponseSchema
11438
11644
  }
@@ -11468,7 +11674,7 @@ var canvasContract = c6.router({
11468
11674
  }),
11469
11675
  body: null,
11470
11676
  responses: {
11471
- 204: c6.noBody(),
11677
+ 204: c7.noBody(),
11472
11678
  404: MessageResponseSchema,
11473
11679
  409: MessageResponseSchema
11474
11680
  }
@@ -11561,7 +11767,7 @@ var canvasContract = c6.router({
11561
11767
  }),
11562
11768
  body: null,
11563
11769
  responses: {
11564
- 204: c6.noBody(),
11770
+ 204: c7.noBody(),
11565
11771
  403: MessageResponseSchema,
11566
11772
  404: MessageResponseSchema,
11567
11773
  409: MessageResponseSchema
@@ -11645,7 +11851,7 @@ var canvasContract = c6.router({
11645
11851
  path: "/canvases/:canvasId/settings",
11646
11852
  pathParams: external_exports.object({ canvasId: external_exports.string().uuid() }),
11647
11853
  body: null,
11648
- responses: { 204: c6.noBody() }
11854
+ responses: { 204: c7.noBody() }
11649
11855
  },
11650
11856
  // ── Agent presence ──────────────────────────────────────────────────
11651
11857
  // Broadcast an agent's "claim region" to all connected canvas
@@ -11672,16 +11878,16 @@ var canvasContract = c6.router({
11672
11878
  }).nullable().optional(),
11673
11879
  status: external_exports.string().min(1).max(80)
11674
11880
  }).refine(
11675
- (c16) => c16.nodeIds.length > 0 || c16.bounds != null,
11881
+ (c17) => c17.nodeIds.length > 0 || c17.bounds != null,
11676
11882
  "claim must include nodeIds or bounds"
11677
11883
  ).nullable()
11678
11884
  }),
11679
- responses: { 204: c6.noBody() }
11885
+ responses: { 204: c7.noBody() }
11680
11886
  }
11681
11887
  });
11682
11888
 
11683
11889
  // ../api-contract/src/custom-font.ts
11684
- var c7 = initContract();
11890
+ var c8 = initContract();
11685
11891
  var CustomFontResponseSchema = external_exports.object({
11686
11892
  id: external_exports.string().uuid(),
11687
11893
  familyName: external_exports.string(),
@@ -11705,7 +11911,7 @@ var CompleteCustomFontUploadBodySchema = external_exports.object({
11705
11911
  sizeInBytes: external_exports.number().int().positive(),
11706
11912
  parts: external_exports.array(CompletedPartSchema)
11707
11913
  });
11708
- var customFontContract = c7.router({
11914
+ var customFontContract = c8.router({
11709
11915
  list: {
11710
11916
  method: "GET",
11711
11917
  path: "/custom-fonts",
@@ -11733,7 +11939,7 @@ var customFontContract = c7.router({
11733
11939
  });
11734
11940
 
11735
11941
  // ../api-contract/src/generation.ts
11736
- var c8 = initContract();
11942
+ var c9 = initContract();
11737
11943
  var GenerationJobStatusSchema = external_exports.enum([
11738
11944
  "in_progress",
11739
11945
  "finished",
@@ -11791,7 +11997,21 @@ var GenerationRunBodySchema = external_exports.object({
11791
11997
  * by every other model. When absent, the server falls back to a
11792
11998
  * default Google font (Inter).
11793
11999
  */
11794
- font: BetterFontSelectionSchema.optional()
12000
+ font: BetterFontSelectionSchema.optional(),
12001
+ /**
12002
+ * LoRA adapters to stack on a LoRA-capable image generation (`{ id, weight }`;
12003
+ * the server resolves each id to a presigned weights URL). Only honored on
12004
+ * LoRA-capable models (SDXL on Modal, Flux on fal); ignored by every other
12005
+ * model.
12006
+ */
12007
+ loras: LoraStackSchema.optional(),
12008
+ /** Sampler steps. Only honored on LoRA-capable models (SDXL, Flux). */
12009
+ steps: SdxlStepsSchema.optional(),
12010
+ /**
12011
+ * Classifier-free guidance scale. Only honored on LoRA-capable models
12012
+ * (SDXL, Flux).
12013
+ */
12014
+ guidanceScale: SdxlGuidanceScaleSchema.optional()
11795
12015
  });
11796
12016
  var ModelCategorySchema = external_exports.enum([
11797
12017
  "image",
@@ -12044,7 +12264,7 @@ var SeedancePrecheckResponseSchema = external_exports.object({
12044
12264
  reason: external_exports.string(),
12045
12265
  cacheKey: external_exports.string()
12046
12266
  });
12047
- var generationContract = c8.router({
12267
+ var generationContract = c9.router({
12048
12268
  listGenerativeModels: {
12049
12269
  method: "GET",
12050
12270
  path: "/generation/models",
@@ -12090,6 +12310,25 @@ var generationContract = c8.router({
12090
12310
  200: ListGenerationHistoryResponseSchema
12091
12311
  }
12092
12312
  },
12313
+ downloadGenerationHistory: {
12314
+ method: "GET",
12315
+ path: "/generation/history/download",
12316
+ // Same filters as the paginated list, minus pagination: an export
12317
+ // returns every matching row, not a page.
12318
+ query: external_exports.object({
12319
+ search: external_exports.string().optional(),
12320
+ userId: external_exports.string().optional(),
12321
+ projectId: external_exports.string().optional(),
12322
+ since: external_exports.string().datetime().optional(),
12323
+ until: external_exports.string().datetime().optional()
12324
+ }),
12325
+ responses: {
12326
+ 200: c9.otherResponse({
12327
+ contentType: "text/csv",
12328
+ body: external_exports.string()
12329
+ })
12330
+ }
12331
+ },
12093
12332
  getGenerationsByWeek: {
12094
12333
  method: "GET",
12095
12334
  path: "/generation/generations-by-week",
@@ -12111,7 +12350,7 @@ var generationContract = c8.router({
12111
12350
  });
12112
12351
 
12113
12352
  // ../api-contract/src/presets.ts
12114
- var c9 = initContract();
12353
+ var c10 = initContract();
12115
12354
  var TextNodeDataSchema = external_exports.object({
12116
12355
  title: external_exports.string(),
12117
12356
  mode: external_exports.string(),
@@ -12213,7 +12452,7 @@ var PresetResponseSchema = external_exports.object({
12213
12452
  nodes: external_exports.array(PresetNodeSchema),
12214
12453
  edges: external_exports.array(PresetEdgeSchema)
12215
12454
  });
12216
- var presetsContract = c9.router({
12455
+ var presetsContract = c10.router({
12217
12456
  listPresets: {
12218
12457
  method: "GET",
12219
12458
  path: "/presets",
@@ -12227,7 +12466,7 @@ var presetsContract = c9.router({
12227
12466
  });
12228
12467
 
12229
12468
  // ../api-contract/src/profile.ts
12230
- var c10 = initContract();
12469
+ var c11 = initContract();
12231
12470
  var MagicResizeCustomResolutionSchema = external_exports.object({
12232
12471
  width: external_exports.number().int().min(64).max(4096),
12233
12472
  height: external_exports.number().int().min(64).max(4096)
@@ -12258,7 +12497,7 @@ var ReferralRewardNotificationSchema = external_exports.object({
12258
12497
  counterpartName: external_exports.string(),
12259
12498
  redeemedAt: external_exports.string().datetime()
12260
12499
  });
12261
- var profileContract = c10.router({
12500
+ var profileContract = c11.router({
12262
12501
  getMyProfile: {
12263
12502
  method: "GET",
12264
12503
  path: "/profile/me",
@@ -12317,7 +12556,7 @@ var profileContract = c10.router({
12317
12556
  });
12318
12557
 
12319
12558
  // ../api-contract/src/share.ts
12320
- var c11 = initContract();
12559
+ var c12 = initContract();
12321
12560
  var ShareModeSchema = external_exports.enum(["restricted", "view"]);
12322
12561
  var ShareCanvasResponseSchema = external_exports.object({
12323
12562
  id: external_exports.string().uuid(),
@@ -12353,7 +12592,7 @@ var ShareProjectInfoResponseSchema = external_exports.object({
12353
12592
  avatarUrl: external_exports.string().nullable()
12354
12593
  }).nullable()
12355
12594
  });
12356
- var shareContract = c11.router({
12595
+ var shareContract = c12.router({
12357
12596
  // Public endpoint — no auth required
12358
12597
  getSharedProjectInfo: {
12359
12598
  method: "GET",
@@ -12440,7 +12679,7 @@ var shareContract = c11.router({
12440
12679
  });
12441
12680
 
12442
12681
  // ../api-contract/src/team.ts
12443
- var c12 = initContract();
12682
+ var c13 = initContract();
12444
12683
  var TeamRoleSchema = external_exports.enum(["owner", "admin", "editor", "viewer"]);
12445
12684
  var TeamPlanSchema = external_exports.enum([
12446
12685
  "TIER_0",
@@ -12586,7 +12825,25 @@ var InternalEnterpriseOrderSchema = EnterpriseOrderSchema.extend({
12586
12825
  });
12587
12826
  var TeamAdvancedSettingsSchema = external_exports.object({
12588
12827
  negativePromptEnabled: external_exports.boolean().optional(),
12589
- customSeedEnabled: external_exports.boolean().optional()
12828
+ customSeedEnabled: external_exports.boolean().optional(),
12829
+ // Auto-approve join requests from signups whose email domain matches this
12830
+ // enterprise team's owner domain. Admin-governed via the dedicated
12831
+ // domain-join-settings endpoint, not the editor-facing advanced-settings write.
12832
+ domainJoinAutoApprove: external_exports.boolean().optional()
12833
+ });
12834
+ var DomainJoinTargetSchema = external_exports.object({
12835
+ teamId: external_exports.string().uuid(),
12836
+ teamName: external_exports.string(),
12837
+ teamPhotoUrl: external_exports.string().nullable(),
12838
+ alreadyRequested: external_exports.boolean()
12839
+ });
12840
+ var JoinRequestSchema = external_exports.object({
12841
+ id: external_exports.string().uuid(),
12842
+ userId: external_exports.string().uuid(),
12843
+ userName: external_exports.string(),
12844
+ userEmail: external_exports.string(),
12845
+ avatarUrl: external_exports.string().nullable(),
12846
+ createdAt: external_exports.string().datetime()
12590
12847
  });
12591
12848
  var ActiveProductFeatureOverrideSchema = external_exports.object({
12592
12849
  feature: external_exports.string().min(1),
@@ -12636,7 +12893,7 @@ var EmailInviteSchema = external_exports.object({
12636
12893
  senderName: external_exports.string(),
12637
12894
  createdAt: external_exports.string().datetime()
12638
12895
  });
12639
- var teamContract = c12.router({
12896
+ var teamContract = c13.router({
12640
12897
  createTeam: {
12641
12898
  method: "POST",
12642
12899
  path: "/teams",
@@ -12661,6 +12918,23 @@ var teamContract = c12.router({
12661
12918
  body: external_exports.object({ token: external_exports.string().min(1) }),
12662
12919
  responses: { 200: TeamMembershipSchema }
12663
12920
  },
12921
+ getDomainJoinTarget: {
12922
+ method: "GET",
12923
+ path: "/teams/domain-join-target",
12924
+ responses: {
12925
+ 200: external_exports.object({ target: DomainJoinTargetSchema.nullable() })
12926
+ }
12927
+ },
12928
+ requestDomainJoin: {
12929
+ method: "POST",
12930
+ path: "/teams/domain-join-requests",
12931
+ body: external_exports.object({ teamId: external_exports.string().uuid() }),
12932
+ responses: {
12933
+ // "joined" when the team auto-approves; "requested" when it awaits
12934
+ // admin approval.
12935
+ 200: external_exports.object({ outcome: external_exports.enum(["joined", "requested"]) })
12936
+ }
12937
+ },
12664
12938
  // --- Team-scoped (requires X-Team-Id header) ---
12665
12939
  updateTeam: {
12666
12940
  method: "PATCH",
@@ -12684,7 +12958,7 @@ var teamContract = c12.router({
12684
12958
  method: "DELETE",
12685
12959
  path: "/teams/current",
12686
12960
  body: null,
12687
- responses: { 204: c12.noBody() }
12961
+ responses: { 204: c13.noBody() }
12688
12962
  },
12689
12963
  listMembers: {
12690
12964
  method: "GET",
@@ -12705,7 +12979,7 @@ var teamContract = c12.router({
12705
12979
  path: "/teams/current/members/:userId",
12706
12980
  pathParams: external_exports.object({ userId: external_exports.string().uuid() }),
12707
12981
  body: null,
12708
- responses: { 204: c12.noBody() }
12982
+ responses: { 204: c13.noBody() }
12709
12983
  },
12710
12984
  getShareableLink: {
12711
12985
  method: "GET",
@@ -12746,12 +13020,48 @@ var teamContract = c12.router({
12746
13020
  path: "/teams/current/invite-email/:inviteId",
12747
13021
  pathParams: external_exports.object({ inviteId: external_exports.string().uuid() }),
12748
13022
  body: null,
12749
- responses: { 204: c12.noBody() }
13023
+ responses: { 204: c13.noBody() }
13024
+ },
13025
+ listJoinRequests: {
13026
+ method: "GET",
13027
+ path: "/teams/current/join-requests",
13028
+ responses: { 200: external_exports.array(JoinRequestSchema) }
13029
+ },
13030
+ approveJoinRequest: {
13031
+ method: "POST",
13032
+ path: "/teams/current/join-requests/:requestId/approve",
13033
+ pathParams: external_exports.object({ requestId: external_exports.string().uuid() }),
13034
+ body: external_exports.object({ role: InviteLinkRoleSchema }),
13035
+ responses: { 200: MemberSchema }
13036
+ },
13037
+ denyJoinRequest: {
13038
+ method: "DELETE",
13039
+ path: "/teams/current/join-requests/:requestId",
13040
+ pathParams: external_exports.object({ requestId: external_exports.string().uuid() }),
13041
+ body: null,
13042
+ responses: { 204: c13.noBody() }
13043
+ },
13044
+ updateDomainJoinSettings: {
13045
+ method: "PATCH",
13046
+ path: "/teams/current/domain-join-settings",
13047
+ body: external_exports.object({ autoApprove: external_exports.boolean() }),
13048
+ responses: {
13049
+ 200: external_exports.object({ advancedSettings: TeamAdvancedSettingsSchema })
13050
+ }
13051
+ },
13052
+ // Admin directly adds a signup on the team's email domain — no invite for
13053
+ // the user to accept. Only users whose email domain routes to this team can
13054
+ // be added this way.
13055
+ addDomainMember: {
13056
+ method: "POST",
13057
+ path: "/teams/current/domain-members",
13058
+ body: external_exports.object({ email: external_exports.string().email() }),
13059
+ responses: { 200: MemberSchema }
12750
13060
  }
12751
13061
  });
12752
13062
 
12753
13063
  // ../api-contract/src/project.ts
12754
- var c13 = initContract();
13064
+ var c14 = initContract();
12755
13065
  var CanvasSummarySchema = external_exports.object({
12756
13066
  id: external_exports.string().uuid(),
12757
13067
  title: external_exports.string(),
@@ -12850,7 +13160,7 @@ var ProjectSettingsResponseSchema = external_exports.object({
12850
13160
  createdAt: external_exports.string().datetime(),
12851
13161
  updatedAt: external_exports.string().datetime()
12852
13162
  });
12853
- var projectContract = c13.router({
13163
+ var projectContract = c14.router({
12854
13164
  createProject: {
12855
13165
  method: "POST",
12856
13166
  path: "/projects",
@@ -12887,14 +13197,14 @@ var projectContract = c13.router({
12887
13197
  path: "/projects/:projectId",
12888
13198
  pathParams: ProjectIdParamsSchema,
12889
13199
  body: null,
12890
- responses: { 204: c13.noBody() }
13200
+ responses: { 204: c14.noBody() }
12891
13201
  },
12892
13202
  recordProjectView: {
12893
13203
  method: "POST",
12894
13204
  path: "/projects/:projectId/view",
12895
13205
  pathParams: ProjectIdParamsSchema,
12896
13206
  body: null,
12897
- responses: { 204: c13.noBody() }
13207
+ responses: { 204: c14.noBody() }
12898
13208
  },
12899
13209
  listRecentProjects: {
12900
13210
  method: "GET",
@@ -12994,12 +13304,12 @@ var projectContract = c13.router({
12994
13304
  path: "/projects/:projectId/settings",
12995
13305
  pathParams: ProjectIdParamsSchema,
12996
13306
  body: null,
12997
- responses: { 204: c13.noBody() }
13307
+ responses: { 204: c14.noBody() }
12998
13308
  }
12999
13309
  });
13000
13310
 
13001
13311
  // ../api-contract/src/upload.ts
13002
- var c14 = initContract();
13312
+ var c15 = initContract();
13003
13313
  var InitUploadBodySchema = external_exports.object({
13004
13314
  nodeId: external_exports.string().uuid().optional(),
13005
13315
  filename: external_exports.string(),
@@ -13071,7 +13381,7 @@ var CompleteUploadResponseSchema = external_exports.object({
13071
13381
  // clients tolerate deploy skew with older core versions.
13072
13382
  nodeVersionId: external_exports.string().uuid().nullable().optional()
13073
13383
  });
13074
- var uploadContract = c14.router({
13384
+ var uploadContract = c15.router({
13075
13385
  init: {
13076
13386
  method: "POST",
13077
13387
  path: "/upload/init",
@@ -13096,8 +13406,8 @@ var uploadContract = c14.router({
13096
13406
  });
13097
13407
 
13098
13408
  // ../api-contract/src/public/index.ts
13099
- var c15 = initContract();
13100
- var publicContract = c15.router(
13409
+ var c16 = initContract();
13410
+ var publicContract = c16.router(
13101
13411
  {
13102
13412
  project: {
13103
13413
  create: projectContract.createProject,
@@ -13191,6 +13501,10 @@ var publicContract = c15.router(
13191
13501
  }
13192
13502
  );
13193
13503
 
13504
+ // src/lib/onboarding.ts
13505
+ var SIGNUP_URL = "https://app.melius.com/signup";
13506
+ var GET_API_KEY_STEPS = `Sign up at ${SIGNUP_URL}, then create an API key in the Melius app under Team settings \u2192 Integrations`;
13507
+
13194
13508
  // src/lib/errors.ts
13195
13509
  var EXIT_API_ERROR = 1;
13196
13510
  var EXIT_USAGE_ERROR = 2;
@@ -13216,7 +13530,7 @@ function handleApiError(status, body, suggestion) {
13216
13530
  writeError(
13217
13531
  formatError("UNAUTHORIZED", "Invalid or expired API key", {
13218
13532
  status,
13219
- suggestion: suggestion ?? "Run: mel auth login --api-key <key>"
13533
+ suggestion: suggestion ?? `${GET_API_KEY_STEPS}. Then run: mel auth login --api-key mel_...`
13220
13534
  }),
13221
13535
  EXIT_AUTH_ERROR
13222
13536
  );
@@ -13386,6 +13700,65 @@ function setConfigValue(key, value) {
13386
13700
  writeConfigFile({ [key]: value });
13387
13701
  }
13388
13702
 
13703
+ // src/lib/update-notice.ts
13704
+ var MEL_CLI_LATEST_VERSION_HEADER = "x-mel-cli-latest-version";
13705
+ var serverLatestVersion = null;
13706
+ function recordServerLatestVersion(value) {
13707
+ if (value) serverLatestVersion = value;
13708
+ }
13709
+ var SEMVER_PATTERN = /^v?\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/;
13710
+ function parseVersion(version) {
13711
+ const trimmed = version.trim();
13712
+ if (!SEMVER_PATTERN.test(trimmed)) return null;
13713
+ const core = trimmed.replace(/^v/, "").split(/[-+]/)[0];
13714
+ const [major, minor, patch] = core.split(".").map((p) => Number.parseInt(p, 10));
13715
+ return [major, minor, patch];
13716
+ }
13717
+ function isNewerVersion(current, latest) {
13718
+ const c17 = parseVersion(current);
13719
+ const l = parseVersion(latest);
13720
+ if (!c17 || !l) return false;
13721
+ for (let i = 0; i < 3; i++) {
13722
+ if (l[i] > c17[i]) return true;
13723
+ if (l[i] < c17[i]) return false;
13724
+ }
13725
+ return false;
13726
+ }
13727
+ function isMajorUpgrade(current, latest) {
13728
+ const c17 = parseVersion(current);
13729
+ const l = parseVersion(latest);
13730
+ if (!c17 || !l) return false;
13731
+ return l[0] > c17[0];
13732
+ }
13733
+ function shouldShowUpgradeNotice(ctx = {}) {
13734
+ const current = ctx.current ?? "0.4.0";
13735
+ const latest = ctx.latest ?? serverLatestVersion;
13736
+ const env = ctx.env ?? process.env;
13737
+ const isTty = ctx.isTty ?? Boolean(process.stderr.isTTY);
13738
+ if (!latest) return false;
13739
+ if (ctx.quiet) return false;
13740
+ if (!isTty) return false;
13741
+ if (env["MEL_NO_UPDATE_NOTIFIER"]) return false;
13742
+ if (env["CI"]) return false;
13743
+ return isNewerVersion(current, latest);
13744
+ }
13745
+ function formatUpgradeNotice(current, latest) {
13746
+ const breaking = isMajorUpgrade(current, latest) ? " This is a new major version that may include breaking changes." : "";
13747
+ return `
13748
+ mel ${latest} is available (you have ${current}).${breaking}
13749
+ Upgrade: npm install -g @melius-ai/cli@latest (or: brew upgrade mel) Silence: MEL_NO_UPDATE_NOTIFIER=1
13750
+ `;
13751
+ }
13752
+ function printUpgradeNoticeIfNeeded(ctx = {}) {
13753
+ try {
13754
+ if (!shouldShowUpgradeNotice(ctx)) return;
13755
+ const current = ctx.current ?? "0.4.0";
13756
+ const latest = ctx.latest ?? serverLatestVersion;
13757
+ process.stderr.write(formatUpgradeNotice(current, latest));
13758
+ } catch {
13759
+ }
13760
+ }
13761
+
13389
13762
  // src/lib/client.ts
13390
13763
  var _client = null;
13391
13764
  var _verbose = false;
@@ -13444,7 +13817,7 @@ function getClient() {
13444
13817
  if (!config.apiKey) {
13445
13818
  writeError(
13446
13819
  formatError("AUTH_REQUIRED", "No API key configured", {
13447
- suggestion: "Run: mel auth login --api-key <key>"
13820
+ suggestion: `${GET_API_KEY_STEPS}. Then run: mel auth login --api-key mel_...`
13448
13821
  }),
13449
13822
  EXIT_AUTH_ERROR
13450
13823
  );
@@ -13516,6 +13889,9 @@ function createClient(config) {
13516
13889
  }
13517
13890
  const t0 = _verbose ? Date.now() : 0;
13518
13891
  const response = await fetchWithRateLimitRetry(path4, fetchOpts);
13892
+ recordServerLatestVersion(
13893
+ response.headers.get(MEL_CLI_LATEST_VERSION_HEADER)
13894
+ );
13519
13895
  const contentType = response.headers.get("content-type");
13520
13896
  let responseBody;
13521
13897
  if (contentType?.includes("application/json")) {
@@ -13635,6 +14011,8 @@ function registerAuthCommands(program2, getOutputOpts) {
13635
14011
  auth.command("login").description("Store an API key and validate it").requiredOption("--api-key <key>", "API key (mel_...)").addHelpText(
13636
14012
  "after",
13637
14013
  `
14014
+ Get an API key: ${GET_API_KEY_STEPS}.
14015
+
13638
14016
  Returns: { message, user: { id, email, name } }
13639
14017
 
13640
14018
  Examples:
@@ -14064,8 +14442,8 @@ function computeAutoformat(allNodes, allEdges, nodeIds) {
14064
14442
  topologyEdges.push({ ...edge, srcNodeId: src, dstNodeId: dst });
14065
14443
  }
14066
14444
  const rawComponents = findConnectedComponents(targetIds, topologyEdges);
14067
- const connectedComponents = rawComponents.filter((c16) => c16.length > 1);
14068
- const isolatedIds = rawComponents.filter((c16) => c16.length === 1).flat().sort();
14445
+ const connectedComponents = rawComponents.filter((c17) => c17.length > 1);
14446
+ const isolatedIds = rawComponents.filter((c17) => c17.length === 1).flat().sort();
14069
14447
  if (isolatedIds.length > 0) connectedComponents.push(isolatedIds);
14070
14448
  const components = connectedComponents.sort((a, b) => {
14071
14449
  const aHasText = a.some((id) => {
@@ -14255,7 +14633,7 @@ function computeAutoformat(allNodes, allEdges, nodeIds) {
14255
14633
  const col = i % cols;
14256
14634
  const row = Math.floor(i / cols);
14257
14635
  let cx = originX;
14258
- for (let c16 = 0; c16 < col; c16++) cx += colWidths[c16] + COL_GAP2;
14636
+ for (let c17 = 0; c17 < col; c17++) cx += colWidths[c17] + COL_GAP2;
14259
14637
  let cy = originY;
14260
14638
  for (let r = 0; r < row; r++) cy += rowHeights[r] + ROW_GAP2;
14261
14639
  posMap.set(targets[i].id, { x: cx, y: cy });
@@ -14330,16 +14708,16 @@ function findNearestClearPosition(idealX, idealY, blockW, blockH, obstacles) {
14330
14708
  let bestPos = null;
14331
14709
  let bestMaxDim = Infinity;
14332
14710
  let bestDist = Infinity;
14333
- for (const c16 of candidates) {
14334
- if (!overlapsAny(c16.x, c16.y, blockW, blockH, obstacles)) {
14335
- const totalW = Math.max(allMaxX, c16.x + blockW) - Math.min(allMinX, c16.x);
14336
- const totalH = Math.max(allMaxY, c16.y + blockH) - Math.min(allMinY, c16.y);
14711
+ for (const c17 of candidates) {
14712
+ if (!overlapsAny(c17.x, c17.y, blockW, blockH, obstacles)) {
14713
+ const totalW = Math.max(allMaxX, c17.x + blockW) - Math.min(allMinX, c17.x);
14714
+ const totalH = Math.max(allMaxY, c17.y + blockH) - Math.min(allMinY, c17.y);
14337
14715
  const maxDim = Math.max(totalW, totalH);
14338
- const dist = Math.abs(c16.x - idealX) + Math.abs(c16.y - idealY);
14716
+ const dist = Math.abs(c17.x - idealX) + Math.abs(c17.y - idealY);
14339
14717
  if (maxDim < bestMaxDim || maxDim === bestMaxDim && dist < bestDist) {
14340
14718
  bestMaxDim = maxDim;
14341
14719
  bestDist = dist;
14342
- bestPos = c16;
14720
+ bestPos = c17;
14343
14721
  }
14344
14722
  }
14345
14723
  }
@@ -16386,7 +16764,7 @@ Destination handles for image/video edges to text nodes:
16386
16764
  --dst-handle image when supportedInputs includes "image"
16387
16765
  --dst-handle video when supportedInputs includes "video"
16388
16766
  Models with video+image: Gemini (3.1 Pro, 3 Flash, 2.5 Pro), Qwen 3.5 397B
16389
- Models with image-only: GPT-5.x, Claude Opus/Sonnet, Qwen3 VL 235B
16767
+ Models with image-only: GPT-5.x, Claude Opus/Sonnet, Qwen 3 VL 235B
16390
16768
 
16391
16769
  Destination handles for image edges to video nodes (always set explicitly):
16392
16770
  Derive from the model's variant inputs (mel model list --category video):
@@ -18181,12 +18559,24 @@ Examples:
18181
18559
  }
18182
18560
 
18183
18561
  // src/index.ts
18562
+ function withDefaultHelp(args) {
18563
+ return args.length === 0 ? ["--help"] : args;
18564
+ }
18184
18565
  function createProgram() {
18185
18566
  const program2 = new Command();
18186
- program2.name("mel").description("Mel \u2014 Melius agent CLI").version("0.2.1").showSuggestionAfterError(true).option("--json", "Force JSON output (default)").option("--text", "Human-readable output").option(
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(
18187
18568
  "--fields <fields>",
18188
18569
  "Select specific output fields (comma-separated)"
18189
- ).option("--quiet", "Suppress output, exit code only").option("--verbose", "Log request/response metadata to stderr").addHelpText("after", "\nLearn more: https://docs.melius.com");
18570
+ ).option("--quiet", "Suppress output, exit code only").option("--verbose", "Log request/response metadata to stderr").addHelpText(
18571
+ "after",
18572
+ `
18573
+ Getting started:
18574
+ 1. ${GET_API_KEY_STEPS}
18575
+ 2. mel auth login --api-key mel_...
18576
+ 3. mel project list
18577
+
18578
+ Learn more: https://docs.melius.com`
18579
+ );
18190
18580
  program2.hook("preAction", () => {
18191
18581
  const opts = program2.opts();
18192
18582
  if (opts.verbose) setVerbose(true);
@@ -18248,5 +18638,7 @@ export {
18248
18638
  EXIT_API_ERROR,
18249
18639
  formatError,
18250
18640
  writeError,
18641
+ printUpgradeNoticeIfNeeded,
18642
+ withDefaultHelp,
18251
18643
  createProgram
18252
18644
  };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Command } from 'commander';
2
2
 
3
+ declare function withDefaultHelp(args: string[]): string[];
3
4
  declare function createProgram(): Command;
4
5
 
5
- export { createProgram };
6
+ export { createProgram, withDefaultHelp };
package/dist/src/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
2
  import {
3
- createProgram
4
- } from "../chunk-6IN2VKUC.js";
3
+ createProgram,
4
+ withDefaultHelp
5
+ } from "../chunk-EXHDKHNG.js";
5
6
  export {
6
- createProgram
7
+ createProgram,
8
+ withDefaultHelp
7
9
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@melius-ai/cli",
3
- "version": "0.2.1",
3
+ "version": "0.4.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",