comfyui-mcp 0.51.17 → 0.51.19
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/dist/i18n/catalogs.test.js +209 -0
- package/dist/i18n/catalogs.test.js.map +1 -0
- package/dist/i18n/i18n.test.js +8 -0
- package/dist/i18n/i18n.test.js.map +1 -1
- package/dist/services/download-cache.js +39 -0
- package/dist/services/download-cache.js.map +1 -1
- package/dist/services/download-root-correspondence.js +64 -0
- package/dist/services/download-root-correspondence.js.map +1 -0
- package/dist/services/download-volume.js +190 -0
- package/dist/services/download-volume.js.map +1 -0
- package/dist/services/model-resolver.js +39 -1
- package/dist/services/model-resolver.js.map +1 -1
- package/locales/ar/main.json +187 -0
- package/locales/en/main.json +187 -0
- package/locales/es/main.json +187 -0
- package/locales/fa/main.json +187 -0
- package/locales/fr/main.json +187 -0
- package/locales/ja/main.json +187 -0
- package/locales/ko/main.json +187 -0
- package/locales/pt-BR/main.json +187 -0
- package/locales/ru/main.json +187 -0
- package/locales/tr/main.json +187 -0
- package/locales/zh/main.json +187 -0
- package/locales/zh-TW/main.json +187 -0
- package/package.json +3 -2
- package/scripts/i18n-build-en.mjs +816 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SHIPPED catalogs, rendered through the real runtime.
|
|
3
|
+
*
|
|
4
|
+
* i18n-check.mjs already compares the files to each other: same keys, same placeholders, right
|
|
5
|
+
* plural categories. What it cannot see is whether the running process can find and use them —
|
|
6
|
+
* a catalog can be perfect JSON in a directory `catalogFor` never looks in, under a code
|
|
7
|
+
* `resolveLocale` maps somewhere else, and the only symptom is that every language quietly
|
|
8
|
+
* renders English. That failure looks identical to "translation not started yet" and is exactly
|
|
9
|
+
* what this repo shipped before these files existed.
|
|
10
|
+
*
|
|
11
|
+
* So every assertion here goes through `trFor` rather than through the JSON, and the load-
|
|
12
|
+
* bearing one is the sentinel: a fallback string no catalog contains, which comes back
|
|
13
|
+
* unchanged if and only if the lookup missed.
|
|
14
|
+
*/
|
|
15
|
+
import { describe, it, expect, afterEach } from "vitest";
|
|
16
|
+
import { execFileSync } from "node:child_process";
|
|
17
|
+
import { readFileSync } from "node:fs";
|
|
18
|
+
import { join } from "node:path";
|
|
19
|
+
import { trFor, LOCALES, __resetI18nForTest } from "./index.js";
|
|
20
|
+
import { displayWidth, RULE_MAX } from "./terminal-layout.js";
|
|
21
|
+
afterEach(() => __resetI18nForTest());
|
|
22
|
+
const ROOT = join(import.meta.dirname, "..", "..");
|
|
23
|
+
const TRANSLATED = LOCALES.filter((l) => l !== "en");
|
|
24
|
+
function flatten(node, prefix = "", out = {}) {
|
|
25
|
+
for (const [k, v] of Object.entries((node ?? {}))) {
|
|
26
|
+
const key = prefix ? `${prefix}.${k}` : k;
|
|
27
|
+
if (v && typeof v === "object")
|
|
28
|
+
flatten(v, key, out);
|
|
29
|
+
else if (typeof v === "string")
|
|
30
|
+
out[key] = v;
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
const english = flatten(JSON.parse(readFileSync(join(ROOT, "locales", "en", "main.json"), "utf8")));
|
|
35
|
+
const KEYS = Object.keys(english).sort();
|
|
36
|
+
/** Placeholder names a value declares, e.g. `{url}` -> "url". */
|
|
37
|
+
const holes = (s) => (s.match(/\{(\w+)\}/g) ?? []).map((h) => h.slice(1, -1));
|
|
38
|
+
/**
|
|
39
|
+
* Substitution values chosen to be findable in the output. `count` stays a NUMBER because
|
|
40
|
+
* `trFor` only takes the plural path when it is one — passing a string everywhere would leave
|
|
41
|
+
* the counted strings' branch untested.
|
|
42
|
+
*/
|
|
43
|
+
function varsFor(text) {
|
|
44
|
+
const vars = {};
|
|
45
|
+
for (const name of holes(text))
|
|
46
|
+
vars[name] = name === "count" ? 7 : `«${name}»`;
|
|
47
|
+
return vars;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Status markers are NOT decoration: they are what a reader scans before reading a word, and
|
|
51
|
+
* `ready-banner.ts` states outright that every translation must reproduce them. A catalog that
|
|
52
|
+
* drops the 🟢 changes what the line asserts; one that keeps a ⚠️ the frame re-adds prints two.
|
|
53
|
+
*/
|
|
54
|
+
const MARKERS = ["🟢", "⚠️", "✓", "✅", "🔒", "⏸", "🕶️", "👁️", "ℹ️"];
|
|
55
|
+
describe("English is generated, not written", () => {
|
|
56
|
+
it("locales/en/main.json still matches what the call sites declare", () => {
|
|
57
|
+
// Same contract as the docs:gen gate — a committed generated file that no longer matches
|
|
58
|
+
// its source is a silent lie, and here the lie is "these keys are the ones we render".
|
|
59
|
+
const fresh = execFileSync(process.execPath, [join(ROOT, "scripts", "i18n-build-en.mjs"), "--print"], {
|
|
60
|
+
cwd: ROOT,
|
|
61
|
+
encoding: "utf8",
|
|
62
|
+
maxBuffer: 1 << 26,
|
|
63
|
+
});
|
|
64
|
+
expect(fresh).toBe(readFileSync(join(ROOT, "locales", "en", "main.json"), "utf8"));
|
|
65
|
+
});
|
|
66
|
+
it("declares a catalog worth translating", () => {
|
|
67
|
+
expect(KEYS.length).toBeGreaterThan(100);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe.each(TRANSLATED)("%s renders through the real runtime", (locale) => {
|
|
71
|
+
it("answers EVERY key — a sentinel fallback never survives", () => {
|
|
72
|
+
// The whole point. `«no catalog»` appears in no file, so getting it back means the lookup
|
|
73
|
+
// missed: wrong directory, wrong locale code, a nesting level `flatten` did not descend.
|
|
74
|
+
const missed = KEYS.filter((key) => trFor(locale, key, "«no catalog»") === "«no catalog»");
|
|
75
|
+
expect(missed).toEqual([]);
|
|
76
|
+
});
|
|
77
|
+
it("never renders a key as its own name", () => {
|
|
78
|
+
const leaked = KEYS.filter((key) => {
|
|
79
|
+
const out = trFor(locale, key, english[key], varsFor(english[key]));
|
|
80
|
+
return out === key || out.includes(key);
|
|
81
|
+
});
|
|
82
|
+
expect(leaked).toEqual([]);
|
|
83
|
+
});
|
|
84
|
+
it("substitutes every placeholder and leaves none behind", () => {
|
|
85
|
+
const broken = [];
|
|
86
|
+
for (const key of KEYS) {
|
|
87
|
+
const vars = varsFor(english[key]);
|
|
88
|
+
const out = trFor(locale, key, english[key], vars);
|
|
89
|
+
for (const [name, value] of Object.entries(vars)) {
|
|
90
|
+
if (!out.includes(String(value)))
|
|
91
|
+
broken.push(`${key}: {${name}} did not substitute`);
|
|
92
|
+
}
|
|
93
|
+
// A `{leftover}` means the translation renamed or invented a placeholder: the runtime
|
|
94
|
+
// leaves an unknown hole verbatim, so the reader sees braces instead of the answer.
|
|
95
|
+
const leftover = out.match(/\{\w+\}/g);
|
|
96
|
+
if (leftover)
|
|
97
|
+
broken.push(`${key}: unresolved ${leftover.join(", ")}`);
|
|
98
|
+
}
|
|
99
|
+
expect(broken).toEqual([]);
|
|
100
|
+
});
|
|
101
|
+
it("renders no empty value", () => {
|
|
102
|
+
const empty = KEYS.filter((key) => !trFor(locale, key, english[key], varsFor(english[key])).trim());
|
|
103
|
+
expect(empty).toEqual([]);
|
|
104
|
+
});
|
|
105
|
+
it("keeps the status marker the English line opens with", () => {
|
|
106
|
+
const dropped = [];
|
|
107
|
+
for (const key of KEYS) {
|
|
108
|
+
const marker = MARKERS.find((m) => english[key].startsWith(m));
|
|
109
|
+
if (!marker)
|
|
110
|
+
continue;
|
|
111
|
+
const out = trFor(locale, key, english[key], varsFor(english[key]));
|
|
112
|
+
if (!out.startsWith(marker))
|
|
113
|
+
dropped.push(`${key}: expected to start with ${marker}`);
|
|
114
|
+
}
|
|
115
|
+
expect(dropped).toEqual([]);
|
|
116
|
+
});
|
|
117
|
+
it("keeps every backticked command and every ENV_VAR verbatim", () => {
|
|
118
|
+
// These are things the reader TYPES. A translated `codex login` or a localised
|
|
119
|
+
// OPENROUTER_API_KEY is an instruction that cannot work, and no shape check sees it.
|
|
120
|
+
const lost = [];
|
|
121
|
+
for (const key of KEYS) {
|
|
122
|
+
const out = trFor(locale, key, english[key], varsFor(english[key]));
|
|
123
|
+
for (const cmd of english[key].match(/`[^`]+`/g) ?? []) {
|
|
124
|
+
if (!out.includes(cmd))
|
|
125
|
+
lost.push(`${key}: lost ${cmd}`);
|
|
126
|
+
}
|
|
127
|
+
for (const env of english[key].match(/\b[A-Z][A-Z0-9]*(?:_[A-Z0-9]+){2,}\b/g) ?? []) {
|
|
128
|
+
if (!out.includes(env))
|
|
129
|
+
lost.push(`${key}: lost ${env}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
expect(lost).toEqual([]);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
/**
|
|
136
|
+
* Strings that land INSIDE one of the two `════` boxes the CLI draws.
|
|
137
|
+
*
|
|
138
|
+
* Enumerated rather than matched on a `cli.connect_`/`cli.tunnel_` prefix: `connect_url_invalid`
|
|
139
|
+
* and `cannot_start` share those prefixes and are free-flowing fatal lines with no box around
|
|
140
|
+
* them, so a keyword rule would hold them to a width they have no reason to respect — and the
|
|
141
|
+
* repo has been bitten before by a guard whose over-broad direction is invisible in its own
|
|
142
|
+
* output. A key added to a banner has to be added here too; the render in the PR is the
|
|
143
|
+
* backstop that notices if it is not.
|
|
144
|
+
*/
|
|
145
|
+
const BOXED_KEYS = [
|
|
146
|
+
"connect_title",
|
|
147
|
+
"connect_bridge_secure",
|
|
148
|
+
"connect_label_bridge",
|
|
149
|
+
"connect_label_driving",
|
|
150
|
+
"connect_label_secure",
|
|
151
|
+
"connect_secure_note",
|
|
152
|
+
"connect_next_steps",
|
|
153
|
+
"connect_step_open_comfyui",
|
|
154
|
+
"connect_step_enable_external_orchestrator",
|
|
155
|
+
"connect_step_click_connect",
|
|
156
|
+
"connect_quiet_note",
|
|
157
|
+
"tunnel_title",
|
|
158
|
+
"tunnel_label_public_url",
|
|
159
|
+
"tunnel_label_token",
|
|
160
|
+
"tunnel_desktop_connector_path",
|
|
161
|
+
"tunnel_field_header",
|
|
162
|
+
"tunnel_field_name",
|
|
163
|
+
"tunnel_field_url",
|
|
164
|
+
"tunnel_header_alt",
|
|
165
|
+
"tunnel_headless_snippet",
|
|
166
|
+
"tunnel_keep_open",
|
|
167
|
+
];
|
|
168
|
+
describe("box-drawn banners survive translation", () => {
|
|
169
|
+
it.each(LOCALES)("%s keeps every boxed line inside the rule", (locale) => {
|
|
170
|
+
// CJK is TWO cells per character and the box caps its rule at RULE_MAX, so a sentence that
|
|
171
|
+
// is a comfortable 70 characters in English can be a 140-cell line that walks straight out
|
|
172
|
+
// of the frame. This is a NECESSARY condition, not a sufficient one — every boxed line also
|
|
173
|
+
// carries a prefix (a label column, a step number) that this cannot know — which is why the
|
|
174
|
+
// PR pastes real renders. What it does catch, cheaply and forever, is the gross case.
|
|
175
|
+
const budget = RULE_MAX - 1; // every free-standing banner line is written as ` ${text}`
|
|
176
|
+
const tooWide = [];
|
|
177
|
+
for (const key of BOXED_KEYS) {
|
|
178
|
+
const full = `cli.${key}`;
|
|
179
|
+
expect(english[full], `${full} is not in the English catalog — was a banner key renamed?`).toBeTypeOf("string");
|
|
180
|
+
const rendered = trFor(locale, full, english[full], varsFor(english[full]));
|
|
181
|
+
for (const line of rendered.split("\n")) {
|
|
182
|
+
const w = displayWidth(line);
|
|
183
|
+
if (w > budget)
|
|
184
|
+
tooWide.push(`${full}: ${w} cells > ${budget} — ${line}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
expect(tooWide).toEqual([]);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
describe("the catalogs are actually being read", () => {
|
|
191
|
+
it("translates every key that is prose rather than an acronym", () => {
|
|
192
|
+
// Guards the case a sentinel cannot: a file that loads but is a copy of English. The
|
|
193
|
+
// exemption is i18n-check's own rule — a value with no run of four lowercase letters is
|
|
194
|
+
// "API", "URL", "PANEL / COMFYUI", which are the same word in every language and would
|
|
195
|
+
// be WRONG to change. Using the same rule here keeps the two gates from disagreeing.
|
|
196
|
+
const isProse = (s) => /[a-z]{4}/.test(s);
|
|
197
|
+
for (const locale of TRANSLATED) {
|
|
198
|
+
const same = KEYS.filter((key) => isProse(english[key]) && trFor(locale, key, english[key]) === english[key]);
|
|
199
|
+
expect(`${locale}: ${same.join(", ") || "none"}`).toBe(`${locale}: none`);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
it("resolves the regional codes the way the files are named", () => {
|
|
203
|
+
// `pt-BR` and `zh-TW` are the two codes where a directory name and a resolved locale could
|
|
204
|
+
// disagree; if they did, those two languages would silently render English forever.
|
|
205
|
+
expect(trFor("pt_BR.UTF-8", "console.credentials.save", "Save")).not.toBe("Save");
|
|
206
|
+
expect(trFor("zh-HK", "console.credentials.save", "Save")).not.toBe("Save");
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
//# sourceMappingURL=catalogs.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalogs.test.js","sourceRoot":"","sources":["../../src/i18n/catalogs.test.ts"],"names":[],"mappings":"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"}
|
package/dist/i18n/i18n.test.js
CHANGED
|
@@ -43,6 +43,14 @@ describe("locale resolution", () => {
|
|
|
43
43
|
it("--lang beats the environment, and explicit env beats the POSIX chain", () => {
|
|
44
44
|
const prev = { ...process.env };
|
|
45
45
|
try {
|
|
46
|
+
// Own the WHOLE chain, not just the link under test. The suite now pins
|
|
47
|
+
// COMFYUI_MCP_LANG=en (see helpers/isolated-test-home.ts), and this case asserts that
|
|
48
|
+
// LANG is consulted — which is only observable when the higher-precedence variables are
|
|
49
|
+
// absent. Leaving them to the ambient environment made the test assert "en beats fr" on
|
|
50
|
+
// a pinned machine and "ja beats fr" for anyone with LANG=ja_JP, i.e. it measured the
|
|
51
|
+
// developer rather than the code.
|
|
52
|
+
for (const k of ["COMFYUI_MCP_LANG", "LC_ALL", "LC_MESSAGES"])
|
|
53
|
+
delete process.env[k];
|
|
46
54
|
process.env.LANG = "fr_FR.UTF-8";
|
|
47
55
|
expect(processLocale(["node", "cli", "--lang", "ko"])).toBe("ko");
|
|
48
56
|
expect(processLocale(["node", "cli", "--lang=ja"])).toBe("ja");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.test.js","sourceRoot":"","sources":["../../src/i18n/i18n.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"i18n.test.js","sourceRoot":"","sources":["../../src/i18n/i18n.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAElG,SAAS,CAAC,GAAG,EAAE,CAAC,kBAAkB,EAAE,CAAC,CAAC;AAEtC,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,EAAE,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACjF,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,qBAAqB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAChG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6EAA6E,EAAE,GAAG,EAAE;QACrF,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAC7D,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,wFAAwF;QACxF,uEAAuE;QACvE,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAClD,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sFAAsF,EAAE,GAAG,EAAE;QAC9F,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7C,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QACvC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QACrC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,IAAI,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAChC,IAAI,CAAC;YACH,wEAAwE;YACxE,sFAAsF;YACtF,wFAAwF;YACxF,wFAAwF;YACxF,sFAAsF;YACtF,kCAAkC;YAClC,KAAK,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,QAAQ,EAAE,aAAa,CAAC;gBAAE,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACrF,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,aAAa,CAAC;YACjC,MAAM,CAAC,aAAa,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClE,MAAM,CAAC,aAAa,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/D,MAAM,CAAC,aAAa,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClD,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,IAAI,CAAC;YACpC,MAAM,CAAC,aAAa,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpD,CAAC;gBAAS,CAAC;YACT,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,IAAI,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAChC,IAAI,CAAC;YACH,KAAK,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,CAAC;gBAAE,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC7F,MAAM,CAAC,aAAa,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpD,CAAC;gBAAS,CAAC;YACT,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;IACvB,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,KAAK,GAAG,EAAE,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;QAChE,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClE,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACnE,8EAA8E;QAC9E,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,kDAAkD,EAAE,GAAG,EAAE;IAChE,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;QACjF,qFAAqF;QACrF,sFAAsF;QACtF,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;QAC1C,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,IAAI,CAAC;YACpC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC3C,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,4BAA4B;YACjF,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAC5D,CAAC;gBAAS,CAAC;YACT,IAAI,IAAI,KAAK,SAAS;gBAAE,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;;gBACvD,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC3C,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,0FAA0F;QAC1F,qFAAqF;QACrF,wEAAwE;QACxE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACpG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+EAA+E,EAAE,GAAG,EAAE;QACvF,MAAM,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CACjC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CACtF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -11,6 +11,7 @@ import { downloadFailureHint, readErrorBody } from "./download-failure-hint.js";
|
|
|
11
11
|
import { logger } from "../utils/logger.js";
|
|
12
12
|
import { redactUrlForLogs } from "./download-auth.js";
|
|
13
13
|
import { reportDownloadProgress } from "./download-progress.js";
|
|
14
|
+
import { checkCacheVolumeSpace } from "./download-volume.js";
|
|
14
15
|
import { abortableDelay, backoffDelayMs, classifyDownloadFailure, downloadRetryPolicy, } from "./download-retry.js";
|
|
15
16
|
import { cloudPrincipalKey, downloadCloudUrlToFile, supportsCloudDownload, } from "./storage/index.js";
|
|
16
17
|
const DEFAULT_CACHE_DIR = join(homedir(), ".comfyui-mcp", "cache");
|
|
@@ -1760,6 +1761,44 @@ stagedFileIsShared = false) {
|
|
|
1760
1761
|
// download_model action:"status" can report the partial was reused, not discarded (#467).
|
|
1761
1762
|
onResume?.({ outcome: "resumed", discardedBytes: 0, discarded: false });
|
|
1762
1763
|
}
|
|
1764
|
+
// #1477 — REFUSE before the first byte when the staging volume cannot hold this.
|
|
1765
|
+
//
|
|
1766
|
+
// The whole file is staged in the download cache before it lands at its
|
|
1767
|
+
// destination, and that cache lives under homedir() — on Windows, essentially
|
|
1768
|
+
// always the system drive, while models are almost always on a big secondary
|
|
1769
|
+
// volume. A 32 GB download to a volume with 1 TB free was written to one with
|
|
1770
|
+
// 0.7 GB free, and took it to the edge of zero. Driving a system drive to zero
|
|
1771
|
+
// risks the page file and general OS stability, so this failure does not stay
|
|
1772
|
+
// confined to the download that caused it.
|
|
1773
|
+
//
|
|
1774
|
+
// Content-Length is already parsed here, so the check costs nothing. It fails
|
|
1775
|
+
// SOFT: an unmeasurable volume must not become an unusable one.
|
|
1776
|
+
{
|
|
1777
|
+
const lengthHeaderPre = Number(res.headers.get("content-length") || 0);
|
|
1778
|
+
const fresh200TotalPre = Math.max(lengthHeaderPre > 0 ? lengthHeaderPre : 0, redirectSize ?? 0);
|
|
1779
|
+
// On a resume only the REMAINING bytes are written; the rest is already on disk.
|
|
1780
|
+
//
|
|
1781
|
+
// When the 206 carries no Content-Range total, `rangeTotal` is null and the old
|
|
1782
|
+
// arithmetic produced 0 — silently SKIPPING the guard on exactly the resume path
|
|
1783
|
+
// it was written to protect (review found this). Content-Length on a 206 is the
|
|
1784
|
+
// remaining slice, which is precisely the quantity still to be written, so fall
|
|
1785
|
+
// back to it rather than to nothing.
|
|
1786
|
+
const remainingFromRange = rangeTotal != null ? Math.max(rangeTotal - (resumeFromBytes || 0), 0) : undefined;
|
|
1787
|
+
const needBytes = appendMode
|
|
1788
|
+
? (remainingFromRange ?? (lengthHeaderPre > 0 ? lengthHeaderPre : 0))
|
|
1789
|
+
: fresh200TotalPre;
|
|
1790
|
+
const refusal = await checkCacheVolumeSpace({
|
|
1791
|
+
needBytes,
|
|
1792
|
+
cacheDir: dirname(targetPath),
|
|
1793
|
+
// `resuming` is "we are APPENDING"; `partialExists` is "there are bytes on disk
|
|
1794
|
+
// either way". Review found these conflated, so a restart after a server ignored
|
|
1795
|
+
// our Range told the user nothing had been downloaded while a partial sat there.
|
|
1796
|
+
resuming: appendMode,
|
|
1797
|
+
partialExists: (resumeFromBytes || 0) > 0,
|
|
1798
|
+
});
|
|
1799
|
+
if (refusal)
|
|
1800
|
+
throw new ModelError(refusal, { path: targetPath });
|
|
1801
|
+
}
|
|
1763
1802
|
const nodeStream = Readable.fromWeb(res.body);
|
|
1764
1803
|
const fileStream = createWriteStream(targetPath, { flags });
|
|
1765
1804
|
// Truncation/verification target = the true full-file size. For a validated 206
|