@mrgoonie/multix 1.0.4 → 1.0.6
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/CHANGELOG.md +14 -0
- package/README.md +3 -2
- package/dist/cli.js +151 -29
- package/package.json +1 -1
- package/skill/SKILL.md +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.0.6](https://github.com/mrgoonie/multix-cli/compare/v1.0.5...v1.0.6) (2026-10-11)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
* **providers:** read model defaults after loading .env files ([#121](https://github.com/mrgoonie/multix-cli/issues/121)) ([5f36dba](https://github.com/mrgoonie/multix-cli/commit/5f36dba0fc7a1ccbe3d904e928c4ef82b3c6ce36))
|
|
14
|
+
|
|
15
|
+
## [1.0.5](https://github.com/mrgoonie/multix-cli/compare/v1.0.4...v1.0.5) (2026-10-11)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
* **core:** only load multix settings from a project .env ([#116](https://github.com/mrgoonie/multix-cli/issues/116)) ([896c0c0](https://github.com/mrgoonie/multix-cli/commit/896c0c00caf46ac46593f67f9a75508a4ac404cd))
|
|
21
|
+
|
|
8
22
|
## [1.0.4](https://github.com/mrgoonie/multix-cli/compare/v1.0.3...v1.0.4) (2026-10-11)
|
|
9
23
|
|
|
10
24
|
|
package/README.md
CHANGED
|
@@ -115,10 +115,11 @@ Set at least one provider key. Add to `.env` in your project root or `~/.multix/
|
|
|
115
115
|
|
|
116
116
|
Set extra keys as `GEMINI_API_KEY_2`, `GEMINI_API_KEY_3`, … (any numeric suffix; numbered keys alone are enough). `multix` tries `GEMINI_API_KEY` first, then the numbered keys in ascending order, skipping duplicates. When a key returns HTTP 429 (or 400/403 with `RESOURCE_EXHAUSTED`), it cools down for the server's `Retry-After`/`retryDelay` (default 60s) and the same request is retried with the next ready key; other errors are not rotated. A Files API upload is repeated on the new key if the following generate call is rate-limited. Veo rotates on submit only, so a rate limit while polling or downloading never starts a second billed job. `doc convert` stops its own retries on a rate limit. Cooldowns last for the current process only, and logs name the env var, never the key. `multix check` lists the keys in rotation and pings each one. Quotas are per Google Cloud project: keys from the same project share one quota, so rotation only helps across projects.
|
|
117
117
|
|
|
118
|
-
Priority: `process.env` > `cwd/.env` > `~/.multix/.env`. Set `MULTIX_LEGACY_CLAUDE_ENV=1` to also read legacy AgentKit files (`.claude/skills/{ai-multimodal,ak-ai-multimodal}/.env`, `.claude/skills/.env`, `.claude/.env`, project first, then home) with the lowest priority (credential names only, never endpoint/proxy settings); `multix check -v` lists the env files that were loaded.
|
|
118
|
+
Priority: `process.env` > `cwd/.env` > `~/.multix/.env`. Set `MULTIX_LEGACY_CLAUDE_ENV=1` (shell or `~/.multix/.env`) to also read legacy AgentKit files (`.claude/skills/{ai-multimodal,ak-ai-multimodal}/.env`, `.claude/skills/.env`, `.claude/.env`, project first, then home) with the lowest priority (credential names only, never endpoint/proxy settings); `multix check -v` lists the env files that were loaded.
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
A project `.env` may only set variables `multix` reads: provider keys, the provider settings in `.env.example` (`*_BASE_URL`, model overrides, Cloudflare IDs), the documented `MULTIX_*` settings (`MULTIX_OUTPUT_DIR`, so a project can choose where outputs go, `MULTIX_IMAGE_FORMAT`, `MULTIX_MAX_DOWNLOAD_MB`, `MULTIX_UPLOAD_MIN_KBPS`) and `NO_COLOR`. The opt-ins `MULTIX_ALLOW_PROJECT_BASE_URL` and `MULTIX_LEGACY_CLAUDE_ENV` are refused there; set them in the shell or `~/.multix/.env`. Other names, such as `NODE_OPTIONS`, `npm_config_registry`, `LD_PRELOAD` or `HTTPS_PROXY`, are not loaded, so they never reach `multix` or the tools it starts (`npm` in `multix update`, ffmpeg, ImageMagick, cwebp); one warning on stderr lists the ignored names, never their values. The shell and `~/.multix/.env` are not filtered.
|
|
121
121
|
|
|
122
|
+
`*_BASE_URL`, `CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_AI_GATEWAY_ID` decide where your API key is sent. Values from the shell or `~/.multix/.env` are always used. A value from the project `.env` (or a legacy `.claude` file under it) is used only when every key the provider sends with it comes from that same project file (the repository's own key). That protects your key, not your data: a project `.env` that ships its own key and base URL routes that project's requests, including your prompts and any files you upload, to that host, and its key replaces yours from `~/.multix/.env`, so review a cloned repository's `.env` before running `multix` in it. If a key comes from anywhere else, the project value is ignored: the `~/.multix/.env` value is used with a warning (variable, file and key source named, never the value), or, if there is none, the command stops with an error instead of falling back to the vendor default. `multix check` shows whether each such setting is in effect or ignored. To use a project value for one command, run `MULTIX_ALLOW_PROJECT_BASE_URL=1 multix ...`; do not put the opt-in in `~/.multix/.env`, which disables the check for every directory. Non-default base URLs must be `https://` (plain `http://` only for `localhost`, `127.0.0.1`, `[::1]`), and `multix` warns once per variable on stderr with the provider and hostname only.
|
|
122
123
|
## Commands
|
|
123
124
|
|
|
124
125
|
### `multix check`
|
package/dist/cli.js
CHANGED
|
@@ -402,11 +402,15 @@ function parseFile(file) {
|
|
|
402
402
|
return void 0;
|
|
403
403
|
}
|
|
404
404
|
}
|
|
405
|
-
function loadFile(file, source, accept = () => true) {
|
|
405
|
+
function loadFile(file, source, accept = () => true, onRefused) {
|
|
406
406
|
const parsed = parseFile(file);
|
|
407
407
|
if (!parsed) return void 0;
|
|
408
408
|
for (const [name, value] of Object.entries(parsed)) {
|
|
409
|
-
if (!accept(name)
|
|
409
|
+
if (!accept(name)) {
|
|
410
|
+
onRefused?.(name);
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
if (process.env[name] !== void 0) continue;
|
|
410
414
|
process.env[name] = value;
|
|
411
415
|
fileOrigins.set(envNameKey(name), { source, file, value });
|
|
412
416
|
}
|
|
@@ -421,7 +425,13 @@ function byNameKey(values) {
|
|
|
421
425
|
}
|
|
422
426
|
return out;
|
|
423
427
|
}
|
|
424
|
-
|
|
428
|
+
var MAX_LISTED_NAMES = 10;
|
|
429
|
+
function listNames(names) {
|
|
430
|
+
const shown = names.slice(0, MAX_LISTED_NAMES).join(", ");
|
|
431
|
+
const rest = names.length - MAX_LISTED_NAMES;
|
|
432
|
+
return rest > 0 ? `${shown} and ${rest} more` : shown;
|
|
433
|
+
}
|
|
434
|
+
function loadEnv({ isProjectEnvName: isProjectEnvName2 }) {
|
|
425
435
|
if (loaded) return;
|
|
426
436
|
loaded = true;
|
|
427
437
|
loadedFiles = [];
|
|
@@ -429,12 +439,22 @@ function loadEnv() {
|
|
|
429
439
|
userFileValues = {};
|
|
430
440
|
const cwd = process.cwd();
|
|
431
441
|
const home = process.env.MULTIX_DISABLE_HOME_ENV ? void 0 : os.homedir();
|
|
432
|
-
|
|
442
|
+
const projectFile = path.resolve(cwd, ".env");
|
|
443
|
+
const refused = [];
|
|
444
|
+
loadFile(projectFile, "project", isProjectEnvName2, (name) => refused.push(name));
|
|
445
|
+
if (refused.length > 0) {
|
|
446
|
+
warnOnce(
|
|
447
|
+
"project-env-refused",
|
|
448
|
+
`Ignoring ${refused.length} variable(s) in project env file ${projectFile}: ${listNames(refused)}. A project .env may only set provider keys and documented multix settings; set anything else in your shell.`
|
|
449
|
+
);
|
|
450
|
+
}
|
|
433
451
|
if (home) userFileValues = byNameKey(loadFile(path.join(home, ".multix", ".env"), "user"));
|
|
434
452
|
if (legacyClaudeEnvEnabled()) {
|
|
435
453
|
const projectLegacy = new Set(legacyFilesUnder(cwd));
|
|
454
|
+
const projectLegacyName = (name) => isLegacyAllowedName(name) && isProjectEnvName2(name);
|
|
436
455
|
for (const file of legacyClaudeEnvFiles(cwd, home)) {
|
|
437
|
-
|
|
456
|
+
if (projectLegacy.has(file)) loadFile(file, "project", projectLegacyName);
|
|
457
|
+
else loadFile(file, "legacy", isLegacyAllowedName);
|
|
438
458
|
}
|
|
439
459
|
}
|
|
440
460
|
}
|
|
@@ -1548,7 +1568,7 @@ function uploadMimeTypeFor(filename) {
|
|
|
1548
1568
|
|
|
1549
1569
|
// src/providers/atlascloud/commands/env.ts
|
|
1550
1570
|
var ATLAS_KEY_URL = "https://www.atlascloud.ai/console/api-keys";
|
|
1551
|
-
var
|
|
1571
|
+
var ATLAS_MODEL_ENV = {
|
|
1552
1572
|
image: "ATLASCLOUD_IMAGE_MODEL",
|
|
1553
1573
|
imageEdit: "ATLASCLOUD_IMAGE_EDIT_MODEL",
|
|
1554
1574
|
video: "ATLASCLOUD_VIDEO_MODEL",
|
|
@@ -1559,7 +1579,7 @@ var MODEL_ENV = {
|
|
|
1559
1579
|
imageTo3d: "ATLASCLOUD_IMAGE_TO_3D_MODEL"
|
|
1560
1580
|
};
|
|
1561
1581
|
function atlasDefaultModel(key) {
|
|
1562
|
-
return resolveKey(
|
|
1582
|
+
return resolveKey(ATLAS_MODEL_ENV[key])?.trim() || ATLAS_DEFAULT_MODELS[key];
|
|
1563
1583
|
}
|
|
1564
1584
|
function requireAtlasKey() {
|
|
1565
1585
|
const apiKey = resolveRoutedKey(ATLAS_ROUTING);
|
|
@@ -2986,6 +3006,11 @@ async function poll(opts) {
|
|
|
2986
3006
|
// src/providers/byteplus/client.ts
|
|
2987
3007
|
init_errors();
|
|
2988
3008
|
|
|
3009
|
+
// src/core/env-default.ts
|
|
3010
|
+
function envDefault(name, fallback) {
|
|
3011
|
+
return process.env[name]?.trim() || fallback;
|
|
3012
|
+
}
|
|
3013
|
+
|
|
2989
3014
|
// src/providers/byteplus/models.ts
|
|
2990
3015
|
var DEFAULT_BYTEPLUS_BASE_URL = "https://ark.ap-southeast.bytepluses.com/api/v3";
|
|
2991
3016
|
var BYTEPLUS_ROUTING = {
|
|
@@ -3001,9 +3026,15 @@ var BYTEPLUS_3D_MODELS = [
|
|
|
3001
3026
|
{ id: "hitem3d-2-0-251223", name: "Hitem3d 2.0", family: "hitem3d" }
|
|
3002
3027
|
];
|
|
3003
3028
|
var BYTEPLUS_DEFAULTS = {
|
|
3004
|
-
imageModel
|
|
3005
|
-
|
|
3006
|
-
|
|
3029
|
+
get imageModel() {
|
|
3030
|
+
return envDefault("BYTEPLUS_IMAGE_MODEL", DEFAULT_BYTEPLUS_IMAGE_MODEL);
|
|
3031
|
+
},
|
|
3032
|
+
get videoModel() {
|
|
3033
|
+
return envDefault("BYTEPLUS_VIDEO_MODEL", DEFAULT_BYTEPLUS_VIDEO_MODEL);
|
|
3034
|
+
},
|
|
3035
|
+
get threeDModel() {
|
|
3036
|
+
return envDefault("BYTEPLUS_3D_MODEL", DEFAULT_BYTEPLUS_3D_MODEL);
|
|
3037
|
+
},
|
|
3007
3038
|
videoResolution: "1080p",
|
|
3008
3039
|
videoDuration: 8,
|
|
3009
3040
|
videoAspectRatio: "16:9",
|
|
@@ -5004,11 +5035,17 @@ var FAL_ROUTING = {
|
|
|
5004
5035
|
};
|
|
5005
5036
|
var FAL_DEFAULTS = {
|
|
5006
5037
|
// FLUX.1 [schnell] — fast, low-cost default text-to-image model.
|
|
5007
|
-
imageModel
|
|
5038
|
+
get imageModel() {
|
|
5039
|
+
return envDefault("FAL_IMAGE_MODEL", "fal-ai/flux/schnell");
|
|
5040
|
+
},
|
|
5008
5041
|
// Stable, widely available default text-to-video model.
|
|
5009
|
-
videoModel
|
|
5042
|
+
get videoModel() {
|
|
5043
|
+
return envDefault("FAL_VIDEO_MODEL", "fal-ai/kling-video/v1.6/standard/text-to-video");
|
|
5044
|
+
},
|
|
5010
5045
|
// Matching image-to-video model — used when --image-url is passed without -m.
|
|
5011
|
-
videoImageModel
|
|
5046
|
+
get videoImageModel() {
|
|
5047
|
+
return envDefault("FAL_VIDEO_IMAGE_MODEL", "fal-ai/kling-video/v1.6/standard/image-to-video");
|
|
5048
|
+
}
|
|
5012
5049
|
};
|
|
5013
5050
|
|
|
5014
5051
|
// src/providers/fal/run-helpers.ts
|
|
@@ -6078,15 +6115,15 @@ var ASPECT_RATIOS = [
|
|
|
6078
6115
|
var IMAGE_SIZES = ["1K", "2K", "4K"];
|
|
6079
6116
|
function getDefaultModel(task) {
|
|
6080
6117
|
if (task === "generate") {
|
|
6081
|
-
return
|
|
6118
|
+
return envDefault("IMAGE_GEN_MODEL", envDefault("GEMINI_IMAGE_GEN_MODEL", IMAGE_MODEL_DEFAULT));
|
|
6082
6119
|
}
|
|
6083
6120
|
if (task === "generate-video") {
|
|
6084
|
-
return
|
|
6121
|
+
return envDefault("VIDEO_GEN_MODEL", VIDEO_MODEL_DEFAULT);
|
|
6085
6122
|
}
|
|
6086
6123
|
if (task === "generate-speech") {
|
|
6087
|
-
return
|
|
6124
|
+
return envDefault("GEMINI_TTS_MODEL", envDefault("TTS_MODEL", TTS_MODEL_DEFAULT));
|
|
6088
6125
|
}
|
|
6089
|
-
return
|
|
6126
|
+
return envDefault("MULTIMODAL_MODEL", envDefault("GEMINI_MODEL", ANALYSIS_MODEL_DEFAULT));
|
|
6090
6127
|
}
|
|
6091
6128
|
|
|
6092
6129
|
// src/providers/gemini/result-formatter.ts
|
|
@@ -8949,8 +8986,12 @@ var LEONARDO_ROUTING = {
|
|
|
8949
8986
|
};
|
|
8950
8987
|
var DEFAULT_LEONARDO_MODEL_ID = "7b592283-e8a7-4c5a-9ba6-d18c31f258b9";
|
|
8951
8988
|
var LEONARDO_DEFAULTS = {
|
|
8952
|
-
modelId
|
|
8953
|
-
|
|
8989
|
+
get modelId() {
|
|
8990
|
+
return envDefault("LEONARDO_DEFAULT_MODEL", DEFAULT_LEONARDO_MODEL_ID);
|
|
8991
|
+
},
|
|
8992
|
+
get videoModel() {
|
|
8993
|
+
return envDefault("LEONARDO_VIDEO_MODEL", "MOTION2");
|
|
8994
|
+
},
|
|
8954
8995
|
width: 1024,
|
|
8955
8996
|
height: 1024,
|
|
8956
8997
|
numImages: 1
|
|
@@ -9799,10 +9840,18 @@ var ALL_MINIMAX_MODELS = /* @__PURE__ */ new Set([
|
|
|
9799
9840
|
...MINIMAX_MUSIC_MODELS
|
|
9800
9841
|
]);
|
|
9801
9842
|
var TASK_DEFAULTS2 = {
|
|
9802
|
-
image
|
|
9803
|
-
|
|
9804
|
-
|
|
9805
|
-
|
|
9843
|
+
get image() {
|
|
9844
|
+
return envDefault("MINIMAX_IMAGE_MODEL", "image-01");
|
|
9845
|
+
},
|
|
9846
|
+
get video() {
|
|
9847
|
+
return envDefault("MINIMAX_VIDEO_MODEL", "MiniMax-Hailuo-2.3");
|
|
9848
|
+
},
|
|
9849
|
+
get speech() {
|
|
9850
|
+
return envDefault("MINIMAX_SPEECH_MODEL", "speech-2.8-hd");
|
|
9851
|
+
},
|
|
9852
|
+
get music() {
|
|
9853
|
+
return envDefault("MINIMAX_MUSIC_MODEL", "music-2.5");
|
|
9854
|
+
}
|
|
9806
9855
|
};
|
|
9807
9856
|
var VIDEO_DURATIONS = [6, 10];
|
|
9808
9857
|
var VIDEO_RESOLUTIONS = ["720P", "1080P"];
|
|
@@ -10528,7 +10577,7 @@ async function transcribeOpenAIAudio(opts) {
|
|
|
10528
10577
|
|
|
10529
10578
|
// src/providers/openai/commands/generate-speech.ts
|
|
10530
10579
|
function registerOpenAIGenerateSpeechCommand(parent) {
|
|
10531
|
-
parent.command("generate-speech").description("Generate speech with OpenAI TTS").option("--text <str>", "Text to speak").option("--prompt <str>", "Alias for --text").option("--model <id>", "TTS model",
|
|
10580
|
+
parent.command("generate-speech").description("Generate speech with OpenAI TTS").option("--text <str>", "Text to speak").option("--prompt <str>", "Alias for --text").option("--model <id>", "TTS model", envDefault("OPENAI_TTS_MODEL", DEFAULT_OPENAI_TTS_MODEL)).option("--voice <name>", "OpenAI voice", "marin").option("--instructions <text>", "Voice/style instructions").option("--output-format <fmt>", "mp3|opus|aac|flac|wav|pcm", "mp3").option("--output <path>", "Copy generated audio to this path").option("-v, --verbose", "Verbose logging").action(async (opts) => {
|
|
10532
10581
|
const text = opts.text ?? opts.prompt;
|
|
10533
10582
|
if (!text) throw new ValidationError("Either --text or --prompt is required");
|
|
10534
10583
|
validateTtsVoice(opts.voice);
|
|
@@ -10847,7 +10896,7 @@ function collect6(value, prev) {
|
|
|
10847
10896
|
|
|
10848
10897
|
// src/providers/openai/commands/transcribe.ts
|
|
10849
10898
|
function registerOpenAITranscribeCommand(parent) {
|
|
10850
|
-
parent.command("transcribe").description("Transcribe audio/video with OpenAI STT").requiredOption("--input <path>", "Audio or video file").option("--model <id>", "STT model",
|
|
10899
|
+
parent.command("transcribe").description("Transcribe audio/video with OpenAI STT").requiredOption("--input <path>", "Audio or video file").option("--model <id>", "STT model", envDefault("OPENAI_STT_MODEL", DEFAULT_OPENAI_STT_MODEL)).option("--format <fmt>", "json|text|diarized_json", "text").option("--language <code>", "ISO language code").option("--chunking-strategy <strategy>", "e.g. auto").option(
|
|
10851
10900
|
"--known-speaker-name <name>",
|
|
10852
10901
|
"Known speaker name; repeatable",
|
|
10853
10902
|
collect7,
|
|
@@ -12462,12 +12511,12 @@ To configure multix, set at least one provider API key:
|
|
|
12462
12511
|
var FFMPEG_HINT = "ffmpeg not found \u2014 media optimize/split/batch commands unavailable.\n Linux: sudo apt-get install ffmpeg\n macOS: brew install ffmpeg\n Windows: https://ffmpeg.org/download.html";
|
|
12463
12512
|
var MAGICK_HINT = "ImageMagick (magick) not found \u2014 image optimization unavailable.\n Linux: sudo apt-get install imagemagick\n macOS: brew install imagemagick\n Windows: https://imagemagick.org/script/download.php";
|
|
12464
12513
|
|
|
12465
|
-
// src/
|
|
12514
|
+
// src/providers/provider-keys.ts
|
|
12466
12515
|
function keyNames(routing) {
|
|
12467
12516
|
const [envPrimary, envFallback] = routing.keyEnvs;
|
|
12468
12517
|
return envFallback ? { envPrimary, envFallback } : { envPrimary };
|
|
12469
12518
|
}
|
|
12470
|
-
var
|
|
12519
|
+
var PROVIDER_KEYS = [
|
|
12471
12520
|
{
|
|
12472
12521
|
name: "Gemini",
|
|
12473
12522
|
envPrimary: "GEMINI_API_KEY",
|
|
@@ -12535,6 +12584,8 @@ var PROVIDERS = [
|
|
|
12535
12584
|
link: "https://app.heygen.com/developers/api"
|
|
12536
12585
|
}
|
|
12537
12586
|
];
|
|
12587
|
+
|
|
12588
|
+
// src/commands/check.ts
|
|
12538
12589
|
function resolveProviderKey(p) {
|
|
12539
12590
|
if (p.envPrimary === "GEMINI_API_KEY") {
|
|
12540
12591
|
const first = listGeminiKeys()[0];
|
|
@@ -12643,7 +12694,7 @@ function registerCheckCommand(program2) {
|
|
|
12643
12694
|
}
|
|
12644
12695
|
let anyKey = false;
|
|
12645
12696
|
const resolved = /* @__PURE__ */ new Map();
|
|
12646
|
-
for (const p of
|
|
12697
|
+
for (const p of PROVIDER_KEYS) {
|
|
12647
12698
|
const r = resolveProviderKey(p);
|
|
12648
12699
|
resolved.set(p.name, r);
|
|
12649
12700
|
if (r.key) anyKey = true;
|
|
@@ -13485,8 +13536,79 @@ function registerCommands(program2) {
|
|
|
13485
13536
|
init_errors();
|
|
13486
13537
|
init_redact();
|
|
13487
13538
|
|
|
13539
|
+
// src/project-env-names.ts
|
|
13540
|
+
var OWN_SETTINGS = [
|
|
13541
|
+
"MULTIX_OUTPUT_DIR",
|
|
13542
|
+
"MULTIX_IMAGE_FORMAT",
|
|
13543
|
+
MAX_DOWNLOAD_ENV,
|
|
13544
|
+
UPLOAD_MIN_KBPS_ENV,
|
|
13545
|
+
// Read before the project file loads, so setting it there has no effect.
|
|
13546
|
+
"MULTIX_DISABLE_HOME_ENV"
|
|
13547
|
+
];
|
|
13548
|
+
var INLINE_SETTINGS = [
|
|
13549
|
+
"GEMINI_MODEL",
|
|
13550
|
+
"MULTIMODAL_MODEL",
|
|
13551
|
+
"IMAGE_GEN_MODEL",
|
|
13552
|
+
"GEMINI_IMAGE_GEN_MODEL",
|
|
13553
|
+
"VIDEO_GEN_MODEL",
|
|
13554
|
+
"GEMINI_TTS_MODEL",
|
|
13555
|
+
"TTS_MODEL",
|
|
13556
|
+
"OPENAI_IMAGE_MODEL",
|
|
13557
|
+
"OPENAI_TTS_MODEL",
|
|
13558
|
+
"OPENAI_STT_MODEL",
|
|
13559
|
+
"OPENROUTER_IMAGE_MODEL",
|
|
13560
|
+
"OPENROUTER_VIDEO_MODEL",
|
|
13561
|
+
"OPENROUTER_FALLBACK_MODELS",
|
|
13562
|
+
"OPENROUTER_SITE_URL",
|
|
13563
|
+
"OPENROUTER_APP_NAME",
|
|
13564
|
+
"MINIMAX_IMAGE_MODEL",
|
|
13565
|
+
"MINIMAX_VIDEO_MODEL",
|
|
13566
|
+
"MINIMAX_SPEECH_MODEL",
|
|
13567
|
+
"MINIMAX_MUSIC_MODEL",
|
|
13568
|
+
"LEONARDO_DEFAULT_MODEL",
|
|
13569
|
+
"LEONARDO_VIDEO_MODEL",
|
|
13570
|
+
"BYTEPLUS_IMAGE_MODEL",
|
|
13571
|
+
"BYTEPLUS_VIDEO_MODEL",
|
|
13572
|
+
"BYTEPLUS_3D_MODEL",
|
|
13573
|
+
"BYTEPLUS_VIDEO_PARAMS_MODE",
|
|
13574
|
+
"FAL_IMAGE_MODEL",
|
|
13575
|
+
"FAL_VIDEO_MODEL",
|
|
13576
|
+
"FAL_VIDEO_IMAGE_MODEL",
|
|
13577
|
+
"REPLICATE_IMAGE_MODEL",
|
|
13578
|
+
"REPLICATE_VIDEO_MODEL",
|
|
13579
|
+
"CLOUDFLARE_AI_IMAGE_MODEL",
|
|
13580
|
+
"CLOUDFLARE_AI_TTS_MODEL",
|
|
13581
|
+
// Read in providers/cloudflare/client.ts (collectPayloadHeader).
|
|
13582
|
+
"CLOUDFLARE_AI_GATEWAY_COLLECT_LOG_PAYLOAD",
|
|
13583
|
+
"NO_COLOR"
|
|
13584
|
+
];
|
|
13585
|
+
var ROUTING = [
|
|
13586
|
+
ATLAS_ROUTING,
|
|
13587
|
+
BYTEPLUS_ROUTING,
|
|
13588
|
+
FAL_ROUTING,
|
|
13589
|
+
HEYGEN_ROUTING,
|
|
13590
|
+
LEONARDO_ROUTING,
|
|
13591
|
+
REPLICATE_ROUTING
|
|
13592
|
+
];
|
|
13593
|
+
var PROJECT_ENV_NAMES = /* @__PURE__ */ new Set([
|
|
13594
|
+
...PROVIDER_KEYS.flatMap((p) => p.envFallback ? [p.envPrimary, p.envFallback] : [p.envPrimary]),
|
|
13595
|
+
...ROUTING.flatMap((r) => [r.name, ...r.keyEnvs]),
|
|
13596
|
+
CLOUDFLARE_ACCOUNT_ID_ENV,
|
|
13597
|
+
CLOUDFLARE_GATEWAY_ID_ENV,
|
|
13598
|
+
...CLOUDFLARE_VIDEO_CREDENTIALS,
|
|
13599
|
+
...Object.values(ATLAS_MODEL_ENV),
|
|
13600
|
+
MAX_UPLOAD_ENV,
|
|
13601
|
+
...OWN_SETTINGS,
|
|
13602
|
+
...INLINE_SETTINGS
|
|
13603
|
+
]);
|
|
13604
|
+
var GEMINI_NUMBERED_KEY = /^GEMINI_API_KEY_\d+$/;
|
|
13605
|
+
function isProjectEnvName(name, platform = process.platform) {
|
|
13606
|
+
const key = envNameKey(name, platform);
|
|
13607
|
+
return PROJECT_ENV_NAMES.has(key) || GEMINI_NUMBERED_KEY.test(key);
|
|
13608
|
+
}
|
|
13609
|
+
|
|
13488
13610
|
// src/cli.ts
|
|
13489
|
-
loadEnv();
|
|
13611
|
+
loadEnv({ isProjectEnvName });
|
|
13490
13612
|
var require3 = createRequire2(import.meta.url);
|
|
13491
13613
|
var pkg = require3("../package.json");
|
|
13492
13614
|
var program = new Command().name("multix").description(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrgoonie/multix",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "AI multimodal CLI — OpenAI, Gemini, MiniMax, OpenRouter, Leonardo, BytePlus, ElevenLabs, fal.ai, Atlas Cloud, Replicate, HeyGen, ffmpeg, ImageMagick, doc-to-md",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/skill/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: multix
|
|
3
3
|
description: AI multimodal CLI — generate and edit images (OpenAI, Codex driver, Gemini Nano Banana, Imagen, MiniMax, OpenRouter, Leonardo, BytePlus Seedream, Cloudflare Workers AI FLUX.1 Schnell, fal.ai FLUX, Replicate FLUX), generate video (Gemini Veo, MiniMax Hailuo, OpenRouter via Veo/Seedance/Kling, Leonardo via Motion/Veo/Kling/Hailuo/Seedance/LTX, BytePlus Seedance, Cloudflare AI Gateway via Replicate, fal.ai queue models, Replicate direct API models incl. P-Video, HeyGen Video Agent and scripted avatar videos), video translation and lipsync (HeyGen), TTS/STT/music (OpenAI, Gemini Flash TTS incl. Gemini 3.8 with delivery-style control, MiniMax, Cloudflare Workers AI MeloTTS, ElevenLabs), 3D models (BytePlus Hyper3D/Hitem3d), analyze/transcribe media, convert documents to Markdown, optimize media via ffmpeg/ImageMagick, and self-update the CLI. Use whenever the user wants to create, edit, or transform images/video/audio/3D/documents from a CLI, mentions any of: OpenAI, Codex image driver, image-to-image, i2i, image edit, watercolor/cyberpunk style transfer, reference image, OpenRouter, Nano Banana, Flux, Seedream, Veo, Hailuo, Seedance, Kling, Cloudflare Workers AI, AI Gateway, fal.ai, Atlas Cloud, Replicate, replicate.com models, Replicate predictions, HeyGen, avatar video, talking head, Video Agent, video translation, dubbing, lipsync, video generation, text-to-video, image-to-video, i2v, ElevenLabs voice cloning, updating/upgrading multix, or asks for batch media optimization.
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.6 # x-release-please-version
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# multix — AI Multimodal CLI
|
|
@@ -54,7 +54,7 @@ CLOUDFLARE_API_TOKEN # Cloudflare Workers AI / AI Gateway token
|
|
|
54
54
|
# Video additionally requires CLOUDFLARE_AI_GATEWAY_ID and REPLICATE_API_TOKEN.
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
Priority: `process.env` > `cwd/.env` > `~/.multix/.env`. Set `MULTIX_LEGACY_CLAUDE_ENV=1` to also read legacy AgentKit `.claude` env files (credential names only, lowest priority); `multix check -v` lists loaded env files.
|
|
57
|
+
Priority: `process.env` > `cwd/.env` > `~/.multix/.env`. Set `MULTIX_LEGACY_CLAUDE_ENV=1` to also read legacy AgentKit `.claude` env files (credential names only, lowest priority); `multix check -v` lists loaded env files. A project `.env` may only set names multix reads (provider keys and settings from `.env.example`, the documented `MULTIX_*` settings such as `MULTIX_OUTPUT_DIR`, `NO_COLOR`; never `MULTIX_ALLOW_PROJECT_BASE_URL` or `MULTIX_LEGACY_CLAUDE_ENV`); anything else there (`NODE_OPTIONS`, `npm_config_*`, `LD_PRELOAD`, proxy/TLS variables) is not loaded, with one stderr warning naming the ignored variables. Put such variables in the shell.
|
|
58
58
|
|
|
59
59
|
## Gemini text-output tasks
|
|
60
60
|
|
|
@@ -413,7 +413,7 @@ Requires `cwebp` (libwebp: `brew install webp`, `apt install webp`) on `PATH`.
|
|
|
413
413
|
| `REPLICATE_IMAGE_MODEL` / `REPLICATE_VIDEO_MODEL` | Replicate default models (default `black-forest-labs/flux-schnell`, `prunaai/p-video`) |
|
|
414
414
|
| `CLOUDFLARE_AI_IMAGE_MODEL` / `CLOUDFLARE_AI_TTS_MODEL` | Fixed-model settings: only `@cf/black-forest-labs/flux-1-schnell` and `@cf/myshell-ai/melotts` respectively are accepted |
|
|
415
415
|
| `MULTIX_DISABLE_HOME_ENV` | `1` to skip every home-directory env file (`~/.multix/.env`, `~/.claude/...`) |
|
|
416
|
-
| `MULTIX_LEGACY_CLAUDE_ENV` | `1` to also read legacy `.claude` env files (credential names only) |
|
|
416
|
+
| `MULTIX_LEGACY_CLAUDE_ENV` | `1` to also read legacy `.claude` env files (credential names only); shell or `~/.multix/.env` only, ignored in a project `.env` |
|
|
417
417
|
| `MULTIX_ALLOW_PROJECT_BASE_URL` | Set `1` for one command (`MULTIX_ALLOW_PROJECT_BASE_URL=1 multix ...`) to honour `*_BASE_URL`, `CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_AI_GATEWAY_ID` from the project `.env` even when the key comes from elsewhere. Without it, a project value is used only when every key sent with it is in the same project file (a project `.env` that ships its own key and base URL then receives that project's prompts and uploaded files, and its key replaces yours, so review a cloned repo's `.env` first); otherwise the `~/.multix/.env` value is used with a warning, or the command stops with a config error. `multix check` shows the effective state. Ignored in a project `.env`; avoid `~/.multix/.env` (it trusts every directory). Non-default base URLs must be `https://` (http only for localhost/127.0.0.1/[::1]) |
|
|
418
418
|
|
|
419
419
|
## Quick examples for agents
|