Skip to content

Commit c5576a4

Browse files
authored
Merge pull request #157 from MiniMax-AI/release/v1.0.14
release: v1.0.14
2 parents b263dd3 + 435758c commit c5576a4

11 files changed

Lines changed: 49 additions & 54 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mmx-cli",
3-
"version": "1.0.13",
3+
"version": "1.0.14",
44
"description": "CLI for the MiniMax AI Platform",
55
"type": "module",
66
"engines": {

src/auth/setup.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ interface AuthChoice {
1717
const AUTH_CHOICES: AuthChoice[] = [
1818
{ value: 'oauth-global', label: `MiniMax (OAuth login → ${stripScheme(REGIONS.global)})` },
1919
{ value: 'oauth-cn', label: `MiniMax (OAuth login → ${stripScheme(REGIONS.cn)})` },
20-
{ value: 'api-key', label: 'API key' },
20+
{ value: 'api-key', label: `API key (${stripScheme(REGIONS.global)} or ${stripScheme(REGIONS.cn)})` },
2121
];
2222

2323
function stripScheme(url: string): string {

src/commands/music/cover.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ import { musicCoverModel } from './models';
1515

1616
export default defineCommand({
1717
name: 'music cover',
18-
description: 'Generate a cover version of a song based on reference audio (music-cover / music-cover-free)',
18+
description: 'Generate a cover version of a song based on reference audio (music-cover)',
1919
apiDocs: '/docs/api-reference/music-generation',
2020
usage: 'mmx music cover --prompt <text> (--audio <url> | --audio-file <path>) [--lyrics <text>] [--out <path>] [flags]',
2121
options: [
22-
{ flag: '--model <model>', description: 'Model: music-cover (Token Plan), music-cover-free (Pay-as-you-go, default). Override only if needed.' },
22+
{ flag: '--model <model>', description: 'Model: music-cover (default).' },
2323
{ flag: '--prompt <text>', description: 'Target cover style, e.g. "Indie folk, acoustic guitar, warm male vocal"' },
2424
{ flag: '--audio <url>', description: 'URL of the reference audio (mp3, wav, flac, etc. — 6s to 6min, max 50MB)' },
2525
{ flag: '--audio-file <path>', description: 'Local reference audio file (auto base64-encoded)' },
@@ -72,7 +72,7 @@ export default defineCommand({
7272
const format = detectOutputFormat(config.output);
7373

7474
const model = (flags.model as string) || musicCoverModel(config);
75-
const VALID_MODELS = ['music-cover', 'music-cover-free'];
75+
const VALID_MODELS = ['music-cover'];
7676
if (flags.model && !VALID_MODELS.includes(model)) {
7777
throw new CLIError(
7878
`Invalid model "${model}". Valid models: ${VALID_MODELS.join(', ')}`,

src/commands/music/generate.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { musicGenerateModel } from './models';
1515

1616
export default defineCommand({
1717
name: 'music generate',
18-
description: 'Generate a song (music-2.6 / music-2.6-free / music-2.5+ / music-2.5)',
18+
description: 'Generate a song (music-2.6 / music-2.5+ / music-2.5)',
1919
apiDocs: '/docs/api-reference/music-generation',
2020
usage: 'mmx music generate --prompt <text> (--lyrics <text> | --instrumental | --lyrics-optimizer) [--out <path>] [flags]',
2121
options: [
@@ -36,7 +36,7 @@ export default defineCommand({
3636
{ flag: '--structure <text>', description: 'Song structure, e.g. "verse-chorus-verse-bridge-chorus"' },
3737
{ flag: '--references <text>', description: 'Reference tracks or artists, e.g. "similar to Ed Sheeran"' },
3838
{ flag: '--extra <text>', description: 'Additional fine-grained requirements not covered above' },
39-
{ flag: '--model <model>', description: 'Model: music-2.6 (recommended), music-2.6-free (default, unlimited), music-2.5+, or music-2.5.' },
39+
{ flag: '--model <model>', description: 'Model: music-2.6 (default), music-2.5+, or music-2.5.' },
4040
{ flag: '--output-format <fmt>', description: 'Return format: hex (default, saved to file) or url (24h expiry, download promptly). When --stream, only hex.' },
4141
{ flag: '--aigc-watermark', description: 'Embed AI-generated content watermark in audio for content provenance' },
4242
{ flag: '--format <fmt>', description: `Audio format: ${formatList(MUSIC_FORMATS)} (default: mp3)` },
@@ -127,7 +127,7 @@ export default defineCommand({
127127
const outPath = (flags.out as string | undefined) ?? `music_${ts}.${ext}`;
128128

129129
const model = (flags.model as string) || musicGenerateModel(config);
130-
const VALID_MODELS = ['music-2.6', 'music-2.6-free', 'music-2.5+', 'music-2.5'];
130+
const VALID_MODELS = ['music-2.6', 'music-2.5+', 'music-2.5'];
131131
if (flags.model && !VALID_MODELS.includes(model)) {
132132
throw new CLIError(
133133
`Invalid model "${model}". Valid models: ${VALID_MODELS.join(', ')}`,

src/commands/music/models.ts

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,14 @@
11
import type { Config } from '../../config/schema';
22

3-
/**
4-
* sk-cp-xxx = Token Plan (coding plan) → standard models (music-2.6, music-cover)
5-
* sk-api-xxx / other = Pay as you go → free-tier models (music-2.6-free, music-cover-free)
6-
*/
7-
export function isCodingPlan(config: Config): boolean {
8-
const key = config.apiKey ?? config.fileApiKey ?? '';
9-
return key.startsWith('sk-cp-');
10-
}
11-
123
export function musicGenerateModel(config: Config): string {
13-
// Config default > key-type-based default
14-
if (config.defaultMusicModel) return config.defaultMusicModel;
15-
return isCodingPlan(config) ? 'music-2.6' : 'music-2.6-free';
4+
return config.defaultMusicModel ?? 'music-2.6';
165
}
176

18-
const VALID_COVER_MODELS = new Set(['music-cover', 'music-cover-free']);
7+
const VALID_COVER_MODELS = new Set(['music-cover']);
198

209
export function musicCoverModel(config: Config): string {
21-
// Config default (only if it's a valid cover model) > key-type-based default
2210
if (config.defaultMusicModel && VALID_COVER_MODELS.has(config.defaultMusicModel)) {
2311
return config.defaultMusicModel;
2412
}
25-
return isCodingPlan(config) ? 'music-cover' : 'music-cover-free';
13+
return 'music-cover';
2614
}

src/config/paths.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { join } from 'path';
44
const CONFIG_DIR_NAME = '.mmx';
55

66
export function getConfigDir(): string {
7+
if (process.env.MMX_CONFIG_DIR) return process.env.MMX_CONFIG_DIR;
78
return join(homedir(), CONFIG_DIR_NAME);
89
}
910

src/sdk/music/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ export class MusicSDK extends Client {
180180
throw new SDKError('lyrics is required', ExitCode.USAGE);
181181
}
182182

183-
const VALID_MODELS = ['music-2.6', 'music-2.6-free', 'music-2.5+', 'music-2.5'];
183+
const VALID_MODELS = ['music-2.6', 'music-2.5+', 'music-2.5'];
184184
if (model && !VALID_MODELS.includes(model)) {
185185
throw new SDKError(
186186
`Invalid model: ${model}. Valid models are ${VALID_MODELS.join(', ')}.`,

test/auth/credentials.test.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@ import { tmpdir } from 'os';
77

88
describe('credentials', () => {
99
const testDir = join(tmpdir(), `mmx-test-${Date.now()}`);
10-
const originalHome = process.env.HOME;
10+
const originalConfigDir = process.env.MMX_CONFIG_DIR;
1111

1212
beforeEach(() => {
13-
mkdirSync(join(testDir, '.mmx'), { recursive: true });
14-
process.env.HOME = testDir;
13+
const configDir = join(testDir, '.mmx');
14+
mkdirSync(configDir, { recursive: true });
15+
process.env.MMX_CONFIG_DIR = configDir;
1516
});
1617

1718
afterEach(() => {
18-
process.env.HOME = originalHome;
19+
if (originalConfigDir) process.env.MMX_CONFIG_DIR = originalConfigDir;
20+
else delete process.env.MMX_CONFIG_DIR;
1921
if (existsSync(testDir)) {
2022
rmSync(testDir, { recursive: true, force: true });
2123
}

test/auth/resolver.test.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
import { describe, it, expect, afterEach } from 'bun:test';
1+
import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
22
import { resolveCredential } from '../../src/auth/resolver';
33
import type { Config } from '../../src/config/schema';
4+
import { mkdirSync, rmSync } from 'fs';
5+
import { join } from 'path';
6+
import { tmpdir } from 'os';
47

58
function makeConfig(overrides: Partial<Config> = {}): Config {
69
return {
@@ -20,8 +23,20 @@ function makeConfig(overrides: Partial<Config> = {}): Config {
2023
}
2124

2225
describe('resolveCredential', () => {
26+
const testDir = join(tmpdir(), `mmx-resolver-test-${Date.now()}`);
27+
const originalConfigDir = process.env.MMX_CONFIG_DIR;
28+
29+
beforeEach(() => {
30+
const configDir = join(testDir, '.mmx');
31+
mkdirSync(configDir, { recursive: true });
32+
process.env.MMX_CONFIG_DIR = configDir;
33+
});
34+
2335
afterEach(() => {
36+
if (originalConfigDir) process.env.MMX_CONFIG_DIR = originalConfigDir;
37+
else delete process.env.MMX_CONFIG_DIR;
2438
delete process.env.MINIMAX_API_KEY;
39+
rmSync(testDir, { recursive: true, force: true });
2540
});
2641

2742
it('resolves from flag (apiKey in config)', async () => {

test/commands/music/models.test.ts

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,28 @@
11
import { describe, it, expect } from 'bun:test';
2-
import { musicGenerateModel, musicCoverModel, isCodingPlan } from '../../../src/commands/music/models';
2+
import { musicGenerateModel, musicCoverModel } from '../../../src/commands/music/models';
33
import type { Config } from '../../../src/config/schema';
44

55
describe('music models', () => {
6-
it('isCodingPlan returns true for sk-cp- key', () => {
7-
expect(isCodingPlan({ apiKey: 'sk-cp-abc' } as Config)).toBe(true);
8-
});
9-
10-
it('isCodingPlan returns false for sk-api- key', () => {
11-
expect(isCodingPlan({ apiKey: 'sk-api-xyz' } as Config)).toBe(false);
12-
});
13-
146
it('musicGenerateModel uses defaultMusicModel when set', () => {
15-
const config = { apiKey: 'sk-api-xyz', defaultMusicModel: 'music-2.6' } as Config;
16-
expect(musicGenerateModel(config)).toBe('music-2.6');
7+
const config = { defaultMusicModel: 'music-2.5+' } as Config;
8+
expect(musicGenerateModel(config)).toBe('music-2.5+');
179
});
1810

19-
it('musicGenerateModel falls back to key-type default when no defaultMusicModel', () => {
20-
const cpConfig = { apiKey: 'sk-cp-abc' } as Config;
21-
expect(musicGenerateModel(cpConfig)).toBe('music-2.6');
22-
23-
const apiConfig = { apiKey: 'sk-api-xyz' } as Config;
24-
expect(musicGenerateModel(apiConfig)).toBe('music-2.6-free');
11+
it('musicGenerateModel defaults to music-2.6', () => {
12+
expect(musicGenerateModel({} as Config)).toBe('music-2.6');
2513
});
2614

2715
it('musicCoverModel ignores defaultMusicModel for non-cover models', () => {
28-
const config = { apiKey: 'sk-api-xyz', defaultMusicModel: 'music-2.6' } as Config;
29-
expect(musicCoverModel(config)).toBe('music-cover-free');
16+
const config = { defaultMusicModel: 'music-2.6' } as Config;
17+
expect(musicCoverModel(config)).toBe('music-cover');
3018
});
3119

32-
it('musicCoverModel uses key-type default when no defaultMusicModel', () => {
33-
const cpConfig = { apiKey: 'sk-cp-abc' } as Config;
34-
expect(musicCoverModel(cpConfig)).toBe('music-cover');
20+
it('musicCoverModel uses defaultMusicModel when it is a cover model', () => {
21+
const config = { defaultMusicModel: 'music-cover' } as Config;
22+
expect(musicCoverModel(config)).toBe('music-cover');
23+
});
3524

36-
const apiConfig = { apiKey: 'sk-api-xyz' } as Config;
37-
expect(musicCoverModel(apiConfig)).toBe('music-cover-free');
25+
it('musicCoverModel defaults to music-cover', () => {
26+
expect(musicCoverModel({} as Config)).toBe('music-cover');
3827
});
3928
});

0 commit comments

Comments
 (0)