@mrgoonie/multix 1.0.5 → 1.0.7
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 +1 -1
- package/dist/cli.js +66 -32
- package/package.json +1 -2
- package/skill/SKILL.md +2 -2
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.7](https://github.com/mrgoonie/multix-cli/compare/v1.0.6...v1.0.7) (2026-10-11)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
* **core:** let a later .env file fill a blank value ([#129](https://github.com/mrgoonie/multix-cli/issues/129)) ([bdfb673](https://github.com/mrgoonie/multix-cli/commit/bdfb6739770f0e7bb9d2623606cdb32d454779d4))
|
|
14
|
+
|
|
15
|
+
## [1.0.6](https://github.com/mrgoonie/multix-cli/compare/v1.0.5...v1.0.6) (2026-10-11)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
* **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))
|
|
21
|
+
|
|
8
22
|
## [1.0.5](https://github.com/mrgoonie/multix-cli/compare/v1.0.4...v1.0.5) (2026-10-11)
|
|
9
23
|
|
|
10
24
|
|
package/README.md
CHANGED
|
@@ -115,7 +115,7 @@ 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` (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.
|
|
118
|
+
Priority: `process.env` > `cwd/.env` > `~/.multix/.env`. A blank or whitespace-only value in a `.env` file does not count as set, so a project `.env` copied from `.env.example` does not hide `~/.multix/.env`; a shell variable wins even when blank. 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
|
|
package/dist/cli.js
CHANGED
|
@@ -402,6 +402,12 @@ function parseFile(file) {
|
|
|
402
402
|
return void 0;
|
|
403
403
|
}
|
|
404
404
|
}
|
|
405
|
+
function fileMaySet(name, value) {
|
|
406
|
+
const current = process.env[name];
|
|
407
|
+
if (current === void 0) return true;
|
|
408
|
+
if (current.trim() !== "" || value.trim() === "") return false;
|
|
409
|
+
return fileOrigins.get(envNameKey(name))?.value === current;
|
|
410
|
+
}
|
|
405
411
|
function loadFile(file, source, accept = () => true, onRefused) {
|
|
406
412
|
const parsed = parseFile(file);
|
|
407
413
|
if (!parsed) return void 0;
|
|
@@ -410,7 +416,7 @@ function loadFile(file, source, accept = () => true, onRefused) {
|
|
|
410
416
|
onRefused?.(name);
|
|
411
417
|
continue;
|
|
412
418
|
}
|
|
413
|
-
if (
|
|
419
|
+
if (!fileMaySet(name, value)) continue;
|
|
414
420
|
process.env[name] = value;
|
|
415
421
|
fileOrigins.set(envNameKey(name), { source, file, value });
|
|
416
422
|
}
|
|
@@ -495,10 +501,8 @@ function inspectTrustedSetting(name, credentials, harmless) {
|
|
|
495
501
|
if (origin?.source !== "project") {
|
|
496
502
|
return value ? { status: "used", value, source: origin?.source ?? "shell" } : { status: "unset" };
|
|
497
503
|
}
|
|
504
|
+
if (value === void 0) return { status: "unset" };
|
|
498
505
|
const userValue = userFileValues[envNameKey(name)]?.trim() || void 0;
|
|
499
|
-
if (value === void 0) {
|
|
500
|
-
return userValue ? { status: "fallback", value: userValue, file: origin.file, reason: "it is empty" } : { status: "unset" };
|
|
501
|
-
}
|
|
502
506
|
const project = (basis) => ({
|
|
503
507
|
status: "used",
|
|
504
508
|
value,
|
|
@@ -518,10 +522,9 @@ function applyTrustedSetting(name, state) {
|
|
|
518
522
|
if (state.status === "unset") return void 0;
|
|
519
523
|
if (state.status === "used") return state.value;
|
|
520
524
|
if (state.status === "refused") throw new ConfigError(trustedSettingRefusal(name, state));
|
|
521
|
-
const hint = state.reason === "it is empty" ? "" : ` ${OPT_IN_HINT}`;
|
|
522
525
|
warnOnce(
|
|
523
526
|
`ignored:${name}`,
|
|
524
|
-
`Ignoring ${name} from project env file ${state.file} (${state.reason}); using the value from ~/.multix/.env
|
|
527
|
+
`Ignoring ${name} from project env file ${state.file} (${state.reason}); using the value from ~/.multix/.env. ${OPT_IN_HINT}`
|
|
525
528
|
);
|
|
526
529
|
return state.value;
|
|
527
530
|
}
|
|
@@ -3006,6 +3009,11 @@ async function poll(opts) {
|
|
|
3006
3009
|
// src/providers/byteplus/client.ts
|
|
3007
3010
|
init_errors();
|
|
3008
3011
|
|
|
3012
|
+
// src/core/env-default.ts
|
|
3013
|
+
function envDefault(name, fallback) {
|
|
3014
|
+
return process.env[name]?.trim() || fallback;
|
|
3015
|
+
}
|
|
3016
|
+
|
|
3009
3017
|
// src/providers/byteplus/models.ts
|
|
3010
3018
|
var DEFAULT_BYTEPLUS_BASE_URL = "https://ark.ap-southeast.bytepluses.com/api/v3";
|
|
3011
3019
|
var BYTEPLUS_ROUTING = {
|
|
@@ -3021,9 +3029,15 @@ var BYTEPLUS_3D_MODELS = [
|
|
|
3021
3029
|
{ id: "hitem3d-2-0-251223", name: "Hitem3d 2.0", family: "hitem3d" }
|
|
3022
3030
|
];
|
|
3023
3031
|
var BYTEPLUS_DEFAULTS = {
|
|
3024
|
-
imageModel
|
|
3025
|
-
|
|
3026
|
-
|
|
3032
|
+
get imageModel() {
|
|
3033
|
+
return envDefault("BYTEPLUS_IMAGE_MODEL", DEFAULT_BYTEPLUS_IMAGE_MODEL);
|
|
3034
|
+
},
|
|
3035
|
+
get videoModel() {
|
|
3036
|
+
return envDefault("BYTEPLUS_VIDEO_MODEL", DEFAULT_BYTEPLUS_VIDEO_MODEL);
|
|
3037
|
+
},
|
|
3038
|
+
get threeDModel() {
|
|
3039
|
+
return envDefault("BYTEPLUS_3D_MODEL", DEFAULT_BYTEPLUS_3D_MODEL);
|
|
3040
|
+
},
|
|
3027
3041
|
videoResolution: "1080p",
|
|
3028
3042
|
videoDuration: 8,
|
|
3029
3043
|
videoAspectRatio: "16:9",
|
|
@@ -3838,7 +3852,7 @@ var CLOUDFLARE_VIDEO_CREDENTIALS = [
|
|
|
3838
3852
|
function getCloudflareModel(kind, requested) {
|
|
3839
3853
|
const expected = kind === "image" ? CLOUDFLARE_IMAGE_MODEL : CLOUDFLARE_TTS_MODEL;
|
|
3840
3854
|
const overrideName = kind === "image" ? "CLOUDFLARE_AI_IMAGE_MODEL" : "CLOUDFLARE_AI_TTS_MODEL";
|
|
3841
|
-
const model = requested ??
|
|
3855
|
+
const model = requested ?? envDefault(overrideName, expected);
|
|
3842
3856
|
if (model !== expected) {
|
|
3843
3857
|
throw new ValidationError(`Unsupported Cloudflare ${kind} model: ${model}`);
|
|
3844
3858
|
}
|
|
@@ -5024,11 +5038,17 @@ var FAL_ROUTING = {
|
|
|
5024
5038
|
};
|
|
5025
5039
|
var FAL_DEFAULTS = {
|
|
5026
5040
|
// FLUX.1 [schnell] — fast, low-cost default text-to-image model.
|
|
5027
|
-
imageModel
|
|
5041
|
+
get imageModel() {
|
|
5042
|
+
return envDefault("FAL_IMAGE_MODEL", "fal-ai/flux/schnell");
|
|
5043
|
+
},
|
|
5028
5044
|
// Stable, widely available default text-to-video model.
|
|
5029
|
-
videoModel
|
|
5045
|
+
get videoModel() {
|
|
5046
|
+
return envDefault("FAL_VIDEO_MODEL", "fal-ai/kling-video/v1.6/standard/text-to-video");
|
|
5047
|
+
},
|
|
5030
5048
|
// Matching image-to-video model — used when --image-url is passed without -m.
|
|
5031
|
-
videoImageModel
|
|
5049
|
+
get videoImageModel() {
|
|
5050
|
+
return envDefault("FAL_VIDEO_IMAGE_MODEL", "fal-ai/kling-video/v1.6/standard/image-to-video");
|
|
5051
|
+
}
|
|
5032
5052
|
};
|
|
5033
5053
|
|
|
5034
5054
|
// src/providers/fal/run-helpers.ts
|
|
@@ -6098,15 +6118,15 @@ var ASPECT_RATIOS = [
|
|
|
6098
6118
|
var IMAGE_SIZES = ["1K", "2K", "4K"];
|
|
6099
6119
|
function getDefaultModel(task) {
|
|
6100
6120
|
if (task === "generate") {
|
|
6101
|
-
return
|
|
6121
|
+
return envDefault("IMAGE_GEN_MODEL", envDefault("GEMINI_IMAGE_GEN_MODEL", IMAGE_MODEL_DEFAULT));
|
|
6102
6122
|
}
|
|
6103
6123
|
if (task === "generate-video") {
|
|
6104
|
-
return
|
|
6124
|
+
return envDefault("VIDEO_GEN_MODEL", VIDEO_MODEL_DEFAULT);
|
|
6105
6125
|
}
|
|
6106
6126
|
if (task === "generate-speech") {
|
|
6107
|
-
return
|
|
6127
|
+
return envDefault("GEMINI_TTS_MODEL", envDefault("TTS_MODEL", TTS_MODEL_DEFAULT));
|
|
6108
6128
|
}
|
|
6109
|
-
return
|
|
6129
|
+
return envDefault("MULTIMODAL_MODEL", envDefault("GEMINI_MODEL", ANALYSIS_MODEL_DEFAULT));
|
|
6110
6130
|
}
|
|
6111
6131
|
|
|
6112
6132
|
// src/providers/gemini/result-formatter.ts
|
|
@@ -8969,8 +8989,12 @@ var LEONARDO_ROUTING = {
|
|
|
8969
8989
|
};
|
|
8970
8990
|
var DEFAULT_LEONARDO_MODEL_ID = "7b592283-e8a7-4c5a-9ba6-d18c31f258b9";
|
|
8971
8991
|
var LEONARDO_DEFAULTS = {
|
|
8972
|
-
modelId
|
|
8973
|
-
|
|
8992
|
+
get modelId() {
|
|
8993
|
+
return envDefault("LEONARDO_DEFAULT_MODEL", DEFAULT_LEONARDO_MODEL_ID);
|
|
8994
|
+
},
|
|
8995
|
+
get videoModel() {
|
|
8996
|
+
return envDefault("LEONARDO_VIDEO_MODEL", "MOTION2");
|
|
8997
|
+
},
|
|
8974
8998
|
width: 1024,
|
|
8975
8999
|
height: 1024,
|
|
8976
9000
|
numImages: 1
|
|
@@ -9819,10 +9843,18 @@ var ALL_MINIMAX_MODELS = /* @__PURE__ */ new Set([
|
|
|
9819
9843
|
...MINIMAX_MUSIC_MODELS
|
|
9820
9844
|
]);
|
|
9821
9845
|
var TASK_DEFAULTS2 = {
|
|
9822
|
-
image
|
|
9823
|
-
|
|
9824
|
-
|
|
9825
|
-
|
|
9846
|
+
get image() {
|
|
9847
|
+
return envDefault("MINIMAX_IMAGE_MODEL", "image-01");
|
|
9848
|
+
},
|
|
9849
|
+
get video() {
|
|
9850
|
+
return envDefault("MINIMAX_VIDEO_MODEL", "MiniMax-Hailuo-2.3");
|
|
9851
|
+
},
|
|
9852
|
+
get speech() {
|
|
9853
|
+
return envDefault("MINIMAX_SPEECH_MODEL", "speech-2.8-hd");
|
|
9854
|
+
},
|
|
9855
|
+
get music() {
|
|
9856
|
+
return envDefault("MINIMAX_MUSIC_MODEL", "music-2.5");
|
|
9857
|
+
}
|
|
9826
9858
|
};
|
|
9827
9859
|
var VIDEO_DURATIONS = [6, 10];
|
|
9828
9860
|
var VIDEO_RESOLUTIONS = ["720P", "1080P"];
|
|
@@ -10548,7 +10580,7 @@ async function transcribeOpenAIAudio(opts) {
|
|
|
10548
10580
|
|
|
10549
10581
|
// src/providers/openai/commands/generate-speech.ts
|
|
10550
10582
|
function registerOpenAIGenerateSpeechCommand(parent) {
|
|
10551
|
-
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",
|
|
10583
|
+
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) => {
|
|
10552
10584
|
const text = opts.text ?? opts.prompt;
|
|
10553
10585
|
if (!text) throw new ValidationError("Either --text or --prompt is required");
|
|
10554
10586
|
validateTtsVoice(opts.voice);
|
|
@@ -10777,7 +10809,7 @@ function registerOpenAIGenerateCommand(parent) {
|
|
|
10777
10809
|
parent.command("generate").description("Generate images with OpenAI Image API or experimental Codex driver").requiredOption("--prompt <text>", "Text prompt").option("--driver <driver>", "api|codex|auto", "auto").option(
|
|
10778
10810
|
"-m, --model <id>",
|
|
10779
10811
|
"Image model",
|
|
10780
|
-
|
|
10812
|
+
envDefault("OPENAI_IMAGE_MODEL", DEFAULT_OPENAI_IMAGE_MODEL)
|
|
10781
10813
|
).option("--size <size>", "1024x1024|1024x1536|1536x1024|auto", "1024x1024").option("--quality <q>", "low|medium|high", "medium").option(
|
|
10782
10814
|
"--format <fmt>",
|
|
10783
10815
|
"Provider output format png|jpeg|webp (explicit value keeps it; default png then WebP)"
|
|
@@ -10823,7 +10855,7 @@ function registerOpenAIImageToImageCommand(parent) {
|
|
|
10823
10855
|
).option("--driver <driver>", "api|codex|auto", "auto").option(
|
|
10824
10856
|
"-m, --model <id>",
|
|
10825
10857
|
"Image model",
|
|
10826
|
-
|
|
10858
|
+
envDefault("OPENAI_IMAGE_MODEL", DEFAULT_OPENAI_IMAGE_MODEL)
|
|
10827
10859
|
).option("--size <size>", "1024x1024|1024x1536|1536x1024|auto", "1024x1024").option("--quality <q>", "low|medium|high", "medium").option(
|
|
10828
10860
|
"--format <fmt>",
|
|
10829
10861
|
"Provider output format png|jpeg|webp (explicit value keeps it; default png then WebP)"
|
|
@@ -10867,7 +10899,7 @@ function collect6(value, prev) {
|
|
|
10867
10899
|
|
|
10868
10900
|
// src/providers/openai/commands/transcribe.ts
|
|
10869
10901
|
function registerOpenAITranscribeCommand(parent) {
|
|
10870
|
-
parent.command("transcribe").description("Transcribe audio/video with OpenAI STT").requiredOption("--input <path>", "Audio or video file").option("--model <id>", "STT model",
|
|
10902
|
+
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(
|
|
10871
10903
|
"--known-speaker-name <name>",
|
|
10872
10904
|
"Known speaker name; repeatable",
|
|
10873
10905
|
collect7,
|
|
@@ -11100,7 +11132,7 @@ function registerOpenRouterGenerateCommand(parent) {
|
|
|
11100
11132
|
).requiredOption("--prompt <text>", "Image generation prompt").option("--model <id>", "OpenRouter model id (e.g. google/gemini-3.1-flash-image-preview)").option("--aspect-ratio <ratio>", "Aspect ratio (e.g. 1:1, 16:9)", "1:1").option("--image-size <size>", "Image size hint (e.g. 1K, 2K)").option("--num-images <n>", "Number of images to generate", "1").option("--output <path>", "Copy first image to this path").addOption(imageFormatOption()).addOption(noWebpOption()).option("-v, --verbose", "Verbose logging").action(
|
|
11101
11133
|
async (opts) => {
|
|
11102
11134
|
const logger = createLogger({ verbose: opts.verbose ?? false });
|
|
11103
|
-
const model = opts.model ??
|
|
11135
|
+
const model = opts.model ?? envDefault("OPENROUTER_IMAGE_MODEL", DEFAULT_OPENROUTER_MODEL);
|
|
11104
11136
|
const numImages = Math.max(1, Number.parseInt(opts.numImages, 10) || 1);
|
|
11105
11137
|
logger.debug(`Generating ${numImages} image(s) via OpenRouter: ${model}`);
|
|
11106
11138
|
const result = await generateOpenRouterImage({
|
|
@@ -11149,7 +11181,7 @@ function registerOpenRouterImageToImageCommand(parent) {
|
|
|
11149
11181
|
throw new ValidationError("At least one --ref is required for image-to-image.");
|
|
11150
11182
|
}
|
|
11151
11183
|
const logger = createLogger({ verbose: opts.verbose ?? false });
|
|
11152
|
-
const model = opts.model ??
|
|
11184
|
+
const model = opts.model ?? envDefault("OPENROUTER_IMAGE_MODEL", DEFAULT_MODEL);
|
|
11153
11185
|
const strength = parseStrength(opts.strength);
|
|
11154
11186
|
const fallbackModels = (resolveKey("OPENROUTER_FALLBACK_MODELS") ?? "").split(",").map((m) => m.trim()).filter(Boolean);
|
|
11155
11187
|
const resolvedRefs = [];
|
|
@@ -11365,7 +11397,7 @@ function registerOpenRouterImageToVideoCommand(parent) {
|
|
|
11365
11397
|
).requiredOption("--prompt <text>", "Motion/scene prompt").requiredOption("--image-url <url>", "First-frame image URL (https)").option("--last-frame-url <url>", "Optional last-frame image URL").option("--model <id>", "OpenRouter video model id (e.g. google/veo-3.1)").option("--resolution <r>", "Resolution hint (e.g. 720p, 1080p)").option("--aspect-ratio <r>", "Aspect ratio hint (e.g. 16:9, 9:16)").option("--duration <n>", "Duration seconds").option("--seed <n>", "Fixed seed").option("--wait", "Poll until status is 'completed' or 'failed'").option("--wait-timeout <ms>", "Poll timeout in ms (with --wait)", "600000").option("--download", "Download the generated video on success (implies --wait)").option("--output <path>", "Copy downloaded video to this path").option("--no-thumb", "Skip downloading the thumbnail if the API returns one").option("-v, --verbose", "Verbose logging").action(
|
|
11366
11398
|
async (opts) => {
|
|
11367
11399
|
const logger = createLogger({ verbose: opts.verbose ?? false });
|
|
11368
|
-
const model = opts.model ??
|
|
11400
|
+
const model = opts.model ?? envDefault("OPENROUTER_VIDEO_MODEL", "google/veo-3.1");
|
|
11369
11401
|
const frame_images = [
|
|
11370
11402
|
{
|
|
11371
11403
|
type: "image_url",
|
|
@@ -12602,8 +12634,10 @@ function settingLine(label, state, commands = "commands that use it") {
|
|
|
12602
12634
|
if (state.status === "used") {
|
|
12603
12635
|
return { level: "info", message: `${label} in effect (from ${usedFrom(state)})` };
|
|
12604
12636
|
}
|
|
12605
|
-
|
|
12606
|
-
|
|
12637
|
+
return {
|
|
12638
|
+
level: "warn",
|
|
12639
|
+
message: `${label} ignored: set in project .env while ${state.reason}; using ~/.multix/.env`
|
|
12640
|
+
};
|
|
12607
12641
|
}
|
|
12608
12642
|
var sameState = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
12609
12643
|
function routingSettingReport() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrgoonie/multix",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
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": {
|
|
@@ -81,7 +81,6 @@
|
|
|
81
81
|
"commander": "^12.1.0",
|
|
82
82
|
"dotenv": "^16.4.5",
|
|
83
83
|
"execa": "^9.4.0",
|
|
84
|
-
"undici": "^7.2.0",
|
|
85
84
|
"zod": "^3.23.8"
|
|
86
85
|
},
|
|
87
86
|
"devDependencies": {
|
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.7 # 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. 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.
|
|
57
|
+
Priority: `process.env` > `cwd/.env` > `~/.multix/.env`; a blank value in a `.env` file does not count as set, so a later file can fill it (a shell value wins even when blank). 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
|
|