@melius-ai/cli 0.3.0 → 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
@@ -25,6 +25,20 @@ mel run wait <runId>
25
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
26
  3. Authenticate the CLI with it: `mel auth login --api-key mel_<your-key>`.
27
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
+
28
42
  ## Sandbox setup
29
43
 
30
44
  In the Claude Code sandbox, only two environment variables are needed:
package/dist/bin/mel.js CHANGED
@@ -4,9 +4,10 @@ import {
4
4
  EXIT_API_ERROR,
5
5
  createProgram,
6
6
  formatError,
7
+ printUpgradeNoticeIfNeeded,
7
8
  withDefaultHelp,
8
9
  writeError
9
- } from "../chunk-JVD4O5T3.js";
10
+ } from "../chunk-EXHDKHNG.js";
10
11
 
11
12
  // bin/mel.ts
12
13
  var program = createProgram();
@@ -23,3 +24,6 @@ try {
23
24
  EXIT_API_ERROR
24
25
  );
25
26
  }
27
+ printUpgradeNoticeIfNeeded({
28
+ quiet: Boolean(program.opts().quiet)
29
+ });
@@ -9809,6 +9809,128 @@ var ElevenLabsVoiceSettingsSchema = external_exports.object({
9809
9809
  outputFormat: ElevenLabsOutputFormatSchema.optional()
9810
9810
  });
9811
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
+
9812
9934
  // ../api-contract/src/preview-asset.ts
9813
9935
  var PreviewAssetSchema = external_exports.object({
9814
9936
  url: external_exports.string(),
@@ -9917,7 +10039,7 @@ var TemplatePortSummarySchema = external_exports.object({
9917
10039
  });
9918
10040
 
9919
10041
  // ../api-contract/src/canvas.ts
9920
- var c6 = initContract();
10042
+ var c7 = initContract();
9921
10043
  var CanvasResponseSchema = external_exports.object({
9922
10044
  id: external_exports.string().uuid(),
9923
10045
  teamId: external_exports.string().uuid(),
@@ -9975,7 +10097,13 @@ var ModelConfigSchema = external_exports.object({
9975
10097
  font: external_exports.object({
9976
10098
  source: external_exports.enum(["custom", "google"]),
9977
10099
  familyName: external_exports.string()
9978
- }).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()
9979
10107
  });
9980
10108
  var ModelConfigInputSchema = external_exports.object({
9981
10109
  model: external_exports.string(),
@@ -10369,7 +10497,17 @@ var RunNodeBodySchema = external_exports.object({
10369
10497
  * ElevenLabs voice tuning for TTS / voice-changer runs. Applied when
10370
10498
  * provided; the `voice-granular-controls` flag only gates the toolbar UI.
10371
10499
  */
10372
- 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()
10373
10511
  });
10374
10512
  var RunImageToolBodySchema = external_exports.object({
10375
10513
  canvasId: external_exports.string().uuid().optional(),
@@ -10798,7 +10936,7 @@ var CanvasSettingsResponseSchema = external_exports.object({
10798
10936
  createdAt: external_exports.string().datetime(),
10799
10937
  updatedAt: external_exports.string().datetime()
10800
10938
  });
10801
- var canvasContract = c6.router({
10939
+ var canvasContract = c7.router({
10802
10940
  createCanvas: {
10803
10941
  method: "POST",
10804
10942
  path: "/projects/:projectId/canvases",
@@ -10852,7 +10990,7 @@ var canvasContract = c6.router({
10852
10990
  canvasId: external_exports.string().uuid()
10853
10991
  }),
10854
10992
  body: null,
10855
- responses: { 204: c6.noBody() }
10993
+ responses: { 204: c7.noBody() }
10856
10994
  },
10857
10995
  duplicateCanvas: {
10858
10996
  method: "POST",
@@ -11267,7 +11405,7 @@ var canvasContract = c6.router({
11267
11405
  pathParams: external_exports.object({ nodeRunId: external_exports.string().uuid() }),
11268
11406
  body: external_exports.object({}),
11269
11407
  responses: {
11270
- 204: c6.noBody(),
11408
+ 204: c7.noBody(),
11271
11409
  404: NodeRunErrorResponseSchema,
11272
11410
  409: NodeRunErrorResponseSchema
11273
11411
  },
@@ -11445,7 +11583,7 @@ var canvasContract = c6.router({
11445
11583
  path: "/comment-threads/:threadId",
11446
11584
  pathParams: external_exports.object({ threadId: external_exports.string().uuid() }),
11447
11585
  body: null,
11448
- responses: { 204: c6.noBody() }
11586
+ responses: { 204: c7.noBody() }
11449
11587
  },
11450
11588
  // ── Comments ────────────────────────────────────────────────────────
11451
11589
  addComment: {
@@ -11460,7 +11598,7 @@ var canvasContract = c6.router({
11460
11598
  path: "/comments/:commentId",
11461
11599
  pathParams: external_exports.object({ commentId: external_exports.string().uuid() }),
11462
11600
  body: null,
11463
- responses: { 204: c6.noBody() }
11601
+ responses: { 204: c7.noBody() }
11464
11602
  },
11465
11603
  // ── Direct CRDT Mutations (CLI/Agent) ───────────────────────────────
11466
11604
  // These endpoints write directly to the Y.Doc (CRDT) for the canvas.
@@ -11500,7 +11638,7 @@ var canvasContract = c6.router({
11500
11638
  }),
11501
11639
  body: null,
11502
11640
  responses: {
11503
- 204: c6.noBody(),
11641
+ 204: c7.noBody(),
11504
11642
  404: MessageResponseSchema,
11505
11643
  409: MessageResponseSchema
11506
11644
  }
@@ -11536,7 +11674,7 @@ var canvasContract = c6.router({
11536
11674
  }),
11537
11675
  body: null,
11538
11676
  responses: {
11539
- 204: c6.noBody(),
11677
+ 204: c7.noBody(),
11540
11678
  404: MessageResponseSchema,
11541
11679
  409: MessageResponseSchema
11542
11680
  }
@@ -11629,7 +11767,7 @@ var canvasContract = c6.router({
11629
11767
  }),
11630
11768
  body: null,
11631
11769
  responses: {
11632
- 204: c6.noBody(),
11770
+ 204: c7.noBody(),
11633
11771
  403: MessageResponseSchema,
11634
11772
  404: MessageResponseSchema,
11635
11773
  409: MessageResponseSchema
@@ -11713,7 +11851,7 @@ var canvasContract = c6.router({
11713
11851
  path: "/canvases/:canvasId/settings",
11714
11852
  pathParams: external_exports.object({ canvasId: external_exports.string().uuid() }),
11715
11853
  body: null,
11716
- responses: { 204: c6.noBody() }
11854
+ responses: { 204: c7.noBody() }
11717
11855
  },
11718
11856
  // ── Agent presence ──────────────────────────────────────────────────
11719
11857
  // Broadcast an agent's "claim region" to all connected canvas
@@ -11740,16 +11878,16 @@ var canvasContract = c6.router({
11740
11878
  }).nullable().optional(),
11741
11879
  status: external_exports.string().min(1).max(80)
11742
11880
  }).refine(
11743
- (c16) => c16.nodeIds.length > 0 || c16.bounds != null,
11881
+ (c17) => c17.nodeIds.length > 0 || c17.bounds != null,
11744
11882
  "claim must include nodeIds or bounds"
11745
11883
  ).nullable()
11746
11884
  }),
11747
- responses: { 204: c6.noBody() }
11885
+ responses: { 204: c7.noBody() }
11748
11886
  }
11749
11887
  });
11750
11888
 
11751
11889
  // ../api-contract/src/custom-font.ts
11752
- var c7 = initContract();
11890
+ var c8 = initContract();
11753
11891
  var CustomFontResponseSchema = external_exports.object({
11754
11892
  id: external_exports.string().uuid(),
11755
11893
  familyName: external_exports.string(),
@@ -11773,7 +11911,7 @@ var CompleteCustomFontUploadBodySchema = external_exports.object({
11773
11911
  sizeInBytes: external_exports.number().int().positive(),
11774
11912
  parts: external_exports.array(CompletedPartSchema)
11775
11913
  });
11776
- var customFontContract = c7.router({
11914
+ var customFontContract = c8.router({
11777
11915
  list: {
11778
11916
  method: "GET",
11779
11917
  path: "/custom-fonts",
@@ -11801,7 +11939,7 @@ var customFontContract = c7.router({
11801
11939
  });
11802
11940
 
11803
11941
  // ../api-contract/src/generation.ts
11804
- var c8 = initContract();
11942
+ var c9 = initContract();
11805
11943
  var GenerationJobStatusSchema = external_exports.enum([
11806
11944
  "in_progress",
11807
11945
  "finished",
@@ -11859,7 +11997,21 @@ var GenerationRunBodySchema = external_exports.object({
11859
11997
  * by every other model. When absent, the server falls back to a
11860
11998
  * default Google font (Inter).
11861
11999
  */
11862
- 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()
11863
12015
  });
11864
12016
  var ModelCategorySchema = external_exports.enum([
11865
12017
  "image",
@@ -12112,7 +12264,7 @@ var SeedancePrecheckResponseSchema = external_exports.object({
12112
12264
  reason: external_exports.string(),
12113
12265
  cacheKey: external_exports.string()
12114
12266
  });
12115
- var generationContract = c8.router({
12267
+ var generationContract = c9.router({
12116
12268
  listGenerativeModels: {
12117
12269
  method: "GET",
12118
12270
  path: "/generation/models",
@@ -12171,7 +12323,7 @@ var generationContract = c8.router({
12171
12323
  until: external_exports.string().datetime().optional()
12172
12324
  }),
12173
12325
  responses: {
12174
- 200: c8.otherResponse({
12326
+ 200: c9.otherResponse({
12175
12327
  contentType: "text/csv",
12176
12328
  body: external_exports.string()
12177
12329
  })
@@ -12198,7 +12350,7 @@ var generationContract = c8.router({
12198
12350
  });
12199
12351
 
12200
12352
  // ../api-contract/src/presets.ts
12201
- var c9 = initContract();
12353
+ var c10 = initContract();
12202
12354
  var TextNodeDataSchema = external_exports.object({
12203
12355
  title: external_exports.string(),
12204
12356
  mode: external_exports.string(),
@@ -12300,7 +12452,7 @@ var PresetResponseSchema = external_exports.object({
12300
12452
  nodes: external_exports.array(PresetNodeSchema),
12301
12453
  edges: external_exports.array(PresetEdgeSchema)
12302
12454
  });
12303
- var presetsContract = c9.router({
12455
+ var presetsContract = c10.router({
12304
12456
  listPresets: {
12305
12457
  method: "GET",
12306
12458
  path: "/presets",
@@ -12314,7 +12466,7 @@ var presetsContract = c9.router({
12314
12466
  });
12315
12467
 
12316
12468
  // ../api-contract/src/profile.ts
12317
- var c10 = initContract();
12469
+ var c11 = initContract();
12318
12470
  var MagicResizeCustomResolutionSchema = external_exports.object({
12319
12471
  width: external_exports.number().int().min(64).max(4096),
12320
12472
  height: external_exports.number().int().min(64).max(4096)
@@ -12345,7 +12497,7 @@ var ReferralRewardNotificationSchema = external_exports.object({
12345
12497
  counterpartName: external_exports.string(),
12346
12498
  redeemedAt: external_exports.string().datetime()
12347
12499
  });
12348
- var profileContract = c10.router({
12500
+ var profileContract = c11.router({
12349
12501
  getMyProfile: {
12350
12502
  method: "GET",
12351
12503
  path: "/profile/me",
@@ -12404,7 +12556,7 @@ var profileContract = c10.router({
12404
12556
  });
12405
12557
 
12406
12558
  // ../api-contract/src/share.ts
12407
- var c11 = initContract();
12559
+ var c12 = initContract();
12408
12560
  var ShareModeSchema = external_exports.enum(["restricted", "view"]);
12409
12561
  var ShareCanvasResponseSchema = external_exports.object({
12410
12562
  id: external_exports.string().uuid(),
@@ -12440,7 +12592,7 @@ var ShareProjectInfoResponseSchema = external_exports.object({
12440
12592
  avatarUrl: external_exports.string().nullable()
12441
12593
  }).nullable()
12442
12594
  });
12443
- var shareContract = c11.router({
12595
+ var shareContract = c12.router({
12444
12596
  // Public endpoint — no auth required
12445
12597
  getSharedProjectInfo: {
12446
12598
  method: "GET",
@@ -12527,7 +12679,7 @@ var shareContract = c11.router({
12527
12679
  });
12528
12680
 
12529
12681
  // ../api-contract/src/team.ts
12530
- var c12 = initContract();
12682
+ var c13 = initContract();
12531
12683
  var TeamRoleSchema = external_exports.enum(["owner", "admin", "editor", "viewer"]);
12532
12684
  var TeamPlanSchema = external_exports.enum([
12533
12685
  "TIER_0",
@@ -12741,7 +12893,7 @@ var EmailInviteSchema = external_exports.object({
12741
12893
  senderName: external_exports.string(),
12742
12894
  createdAt: external_exports.string().datetime()
12743
12895
  });
12744
- var teamContract = c12.router({
12896
+ var teamContract = c13.router({
12745
12897
  createTeam: {
12746
12898
  method: "POST",
12747
12899
  path: "/teams",
@@ -12806,7 +12958,7 @@ var teamContract = c12.router({
12806
12958
  method: "DELETE",
12807
12959
  path: "/teams/current",
12808
12960
  body: null,
12809
- responses: { 204: c12.noBody() }
12961
+ responses: { 204: c13.noBody() }
12810
12962
  },
12811
12963
  listMembers: {
12812
12964
  method: "GET",
@@ -12827,7 +12979,7 @@ var teamContract = c12.router({
12827
12979
  path: "/teams/current/members/:userId",
12828
12980
  pathParams: external_exports.object({ userId: external_exports.string().uuid() }),
12829
12981
  body: null,
12830
- responses: { 204: c12.noBody() }
12982
+ responses: { 204: c13.noBody() }
12831
12983
  },
12832
12984
  getShareableLink: {
12833
12985
  method: "GET",
@@ -12868,7 +13020,7 @@ var teamContract = c12.router({
12868
13020
  path: "/teams/current/invite-email/:inviteId",
12869
13021
  pathParams: external_exports.object({ inviteId: external_exports.string().uuid() }),
12870
13022
  body: null,
12871
- responses: { 204: c12.noBody() }
13023
+ responses: { 204: c13.noBody() }
12872
13024
  },
12873
13025
  listJoinRequests: {
12874
13026
  method: "GET",
@@ -12887,7 +13039,7 @@ var teamContract = c12.router({
12887
13039
  path: "/teams/current/join-requests/:requestId",
12888
13040
  pathParams: external_exports.object({ requestId: external_exports.string().uuid() }),
12889
13041
  body: null,
12890
- responses: { 204: c12.noBody() }
13042
+ responses: { 204: c13.noBody() }
12891
13043
  },
12892
13044
  updateDomainJoinSettings: {
12893
13045
  method: "PATCH",
@@ -12909,7 +13061,7 @@ var teamContract = c12.router({
12909
13061
  });
12910
13062
 
12911
13063
  // ../api-contract/src/project.ts
12912
- var c13 = initContract();
13064
+ var c14 = initContract();
12913
13065
  var CanvasSummarySchema = external_exports.object({
12914
13066
  id: external_exports.string().uuid(),
12915
13067
  title: external_exports.string(),
@@ -13008,7 +13160,7 @@ var ProjectSettingsResponseSchema = external_exports.object({
13008
13160
  createdAt: external_exports.string().datetime(),
13009
13161
  updatedAt: external_exports.string().datetime()
13010
13162
  });
13011
- var projectContract = c13.router({
13163
+ var projectContract = c14.router({
13012
13164
  createProject: {
13013
13165
  method: "POST",
13014
13166
  path: "/projects",
@@ -13045,14 +13197,14 @@ var projectContract = c13.router({
13045
13197
  path: "/projects/:projectId",
13046
13198
  pathParams: ProjectIdParamsSchema,
13047
13199
  body: null,
13048
- responses: { 204: c13.noBody() }
13200
+ responses: { 204: c14.noBody() }
13049
13201
  },
13050
13202
  recordProjectView: {
13051
13203
  method: "POST",
13052
13204
  path: "/projects/:projectId/view",
13053
13205
  pathParams: ProjectIdParamsSchema,
13054
13206
  body: null,
13055
- responses: { 204: c13.noBody() }
13207
+ responses: { 204: c14.noBody() }
13056
13208
  },
13057
13209
  listRecentProjects: {
13058
13210
  method: "GET",
@@ -13152,12 +13304,12 @@ var projectContract = c13.router({
13152
13304
  path: "/projects/:projectId/settings",
13153
13305
  pathParams: ProjectIdParamsSchema,
13154
13306
  body: null,
13155
- responses: { 204: c13.noBody() }
13307
+ responses: { 204: c14.noBody() }
13156
13308
  }
13157
13309
  });
13158
13310
 
13159
13311
  // ../api-contract/src/upload.ts
13160
- var c14 = initContract();
13312
+ var c15 = initContract();
13161
13313
  var InitUploadBodySchema = external_exports.object({
13162
13314
  nodeId: external_exports.string().uuid().optional(),
13163
13315
  filename: external_exports.string(),
@@ -13229,7 +13381,7 @@ var CompleteUploadResponseSchema = external_exports.object({
13229
13381
  // clients tolerate deploy skew with older core versions.
13230
13382
  nodeVersionId: external_exports.string().uuid().nullable().optional()
13231
13383
  });
13232
- var uploadContract = c14.router({
13384
+ var uploadContract = c15.router({
13233
13385
  init: {
13234
13386
  method: "POST",
13235
13387
  path: "/upload/init",
@@ -13254,8 +13406,8 @@ var uploadContract = c14.router({
13254
13406
  });
13255
13407
 
13256
13408
  // ../api-contract/src/public/index.ts
13257
- var c15 = initContract();
13258
- var publicContract = c15.router(
13409
+ var c16 = initContract();
13410
+ var publicContract = c16.router(
13259
13411
  {
13260
13412
  project: {
13261
13413
  create: projectContract.createProject,
@@ -13548,6 +13700,65 @@ function setConfigValue(key, value) {
13548
13700
  writeConfigFile({ [key]: value });
13549
13701
  }
13550
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
+
13551
13762
  // src/lib/client.ts
13552
13763
  var _client = null;
13553
13764
  var _verbose = false;
@@ -13678,6 +13889,9 @@ function createClient(config) {
13678
13889
  }
13679
13890
  const t0 = _verbose ? Date.now() : 0;
13680
13891
  const response = await fetchWithRateLimitRetry(path4, fetchOpts);
13892
+ recordServerLatestVersion(
13893
+ response.headers.get(MEL_CLI_LATEST_VERSION_HEADER)
13894
+ );
13681
13895
  const contentType = response.headers.get("content-type");
13682
13896
  let responseBody;
13683
13897
  if (contentType?.includes("application/json")) {
@@ -14228,8 +14442,8 @@ function computeAutoformat(allNodes, allEdges, nodeIds) {
14228
14442
  topologyEdges.push({ ...edge, srcNodeId: src, dstNodeId: dst });
14229
14443
  }
14230
14444
  const rawComponents = findConnectedComponents(targetIds, topologyEdges);
14231
- const connectedComponents = rawComponents.filter((c16) => c16.length > 1);
14232
- 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();
14233
14447
  if (isolatedIds.length > 0) connectedComponents.push(isolatedIds);
14234
14448
  const components = connectedComponents.sort((a, b) => {
14235
14449
  const aHasText = a.some((id) => {
@@ -14419,7 +14633,7 @@ function computeAutoformat(allNodes, allEdges, nodeIds) {
14419
14633
  const col = i % cols;
14420
14634
  const row = Math.floor(i / cols);
14421
14635
  let cx = originX;
14422
- 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;
14423
14637
  let cy = originY;
14424
14638
  for (let r = 0; r < row; r++) cy += rowHeights[r] + ROW_GAP2;
14425
14639
  posMap.set(targets[i].id, { x: cx, y: cy });
@@ -14494,16 +14708,16 @@ function findNearestClearPosition(idealX, idealY, blockW, blockH, obstacles) {
14494
14708
  let bestPos = null;
14495
14709
  let bestMaxDim = Infinity;
14496
14710
  let bestDist = Infinity;
14497
- for (const c16 of candidates) {
14498
- if (!overlapsAny(c16.x, c16.y, blockW, blockH, obstacles)) {
14499
- const totalW = Math.max(allMaxX, c16.x + blockW) - Math.min(allMinX, c16.x);
14500
- 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);
14501
14715
  const maxDim = Math.max(totalW, totalH);
14502
- 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);
14503
14717
  if (maxDim < bestMaxDim || maxDim === bestMaxDim && dist < bestDist) {
14504
14718
  bestMaxDim = maxDim;
14505
14719
  bestDist = dist;
14506
- bestPos = c16;
14720
+ bestPos = c17;
14507
14721
  }
14508
14722
  }
14509
14723
  }
@@ -18350,7 +18564,7 @@ function withDefaultHelp(args) {
18350
18564
  }
18351
18565
  function createProgram() {
18352
18566
  const program2 = new Command();
18353
- program2.name("mel").description("Mel \u2014 Melius agent CLI").version("0.3.0").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(
18354
18568
  "--fields <fields>",
18355
18569
  "Select specific output fields (comma-separated)"
18356
18570
  ).option("--quiet", "Suppress output, exit code only").option("--verbose", "Log request/response metadata to stderr").addHelpText(
@@ -18424,6 +18638,7 @@ export {
18424
18638
  EXIT_API_ERROR,
18425
18639
  formatError,
18426
18640
  writeError,
18641
+ printUpgradeNoticeIfNeeded,
18427
18642
  withDefaultHelp,
18428
18643
  createProgram
18429
18644
  };
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-JVD4O5T3.js";
5
+ } from "../chunk-EXHDKHNG.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.3.0",
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",