@bendyline/gezel-inference 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +13 -2
- package/dist/cache/adapter.d.ts +115 -0
- package/dist/cache/adapter.js +23 -0
- package/dist/cache/budget.d.ts +15 -0
- package/dist/cache/budget.js +31 -0
- package/dist/cache/controller.d.ts +205 -0
- package/dist/cache/controller.js +377 -0
- package/dist/catalog/LICENSE +21 -0
- package/dist/catalog/chat-models/bt/btl4-35b-q4/manifest.json +146 -0
- package/dist/catalog/chat-models/bt/btl4-35b-q4/versions/1.0.0/manifest.json +15 -0
- package/dist/catalog/chat-models/bt/btl4-35b-q4/versions/1.0.1/manifest.json +15 -0
- package/dist/catalog/chat-models/bt/btl4-compact-iq2/manifest.json +146 -0
- package/dist/catalog/chat-models/bt/btl4-compact-iq2/versions/1.0.0/manifest.json +15 -0
- package/dist/catalog/chat-models/bt/btl4-compact-iq2/versions/1.0.1/manifest.json +15 -0
- package/dist/catalog/chat-models/bt/btl4-compact-iq2/versions/1.0.2/manifest.json +15 -0
- package/dist/catalog/chat-models/de/deepseek-r1-8b-q4/manifest.json +166 -0
- package/dist/catalog/chat-models/de/deepseek-r1-8b-q4/versions/1.1.0/manifest.json +62 -0
- package/dist/catalog/chat-models/de/deepseek-r1-8b-q4/versions/1.1.1/manifest.json +61 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-mxfp4/manifest.json +125 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-mxfp4/versions/1.0.0/manifest.json +27 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q2/manifest.json +125 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q2/versions/1.0.0/manifest.json +27 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q2/versions/1.1.0/manifest.json +27 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q2q4/manifest.json +126 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q2q4/versions/1.0.0/manifest.json +27 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q4/manifest.json +318 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q4/versions/1.0.0/manifest.json +225 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q4/versions/1.1.0/manifest.json +225 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q4/manifest.json +249 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q4/versions/1.0.0/manifest.json +70 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q4/versions/1.1.0/manifest.json +72 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q4/versions/1.1.2/manifest.json +78 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q4/versions/1.1.3/manifest.json +78 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q4/versions/1.2.0/manifest.json +98 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q8/manifest.json +228 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q8/versions/1.0.0/manifest.json +72 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q8/versions/1.0.2/manifest.json +78 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q8/versions/1.0.3/manifest.json +78 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q8/versions/1.1.0/manifest.json +78 -0
- package/dist/catalog/chat-models/ge/gemma4-26b-q4/manifest.json +220 -0
- package/dist/catalog/chat-models/ge/gemma4-26b-q4/versions/1.1.0/manifest.json +75 -0
- package/dist/catalog/chat-models/ge/gemma4-26b-q4/versions/1.2.0/manifest.json +75 -0
- package/dist/catalog/chat-models/ge/gemma4-26b-q4/versions/1.2.1/manifest.json +80 -0
- package/dist/catalog/chat-models/ge/gemma4-26b-q4/versions/1.2.2/manifest.json +80 -0
- package/dist/catalog/chat-models/ge/gemma4-26b-q4/versions/1.3.0/manifest.json +81 -0
- package/dist/catalog/chat-models/ge/gemma4-31b-q4/manifest.json +226 -0
- package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.1.0/manifest.json +80 -0
- package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.1.1/manifest.json +82 -0
- package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.2.0/manifest.json +82 -0
- package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.2.1/manifest.json +95 -0
- package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.2.2/manifest.json +95 -0
- package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.3.0/manifest.json +86 -0
- package/dist/catalog/chat-models/ge/gemma4-e2b-q4/manifest.json +213 -0
- package/dist/catalog/chat-models/ge/gemma4-e2b-q4/versions/1.1.0/manifest.json +67 -0
- package/dist/catalog/chat-models/ge/gemma4-e2b-q4/versions/1.1.2/manifest.json +75 -0
- package/dist/catalog/chat-models/ge/gemma4-e2b-q4/versions/1.2.0/manifest.json +71 -0
- package/dist/catalog/chat-models/ge/gemma4-e2b-q4/versions/1.2.1/manifest.json +71 -0
- package/dist/catalog/chat-models/ge/gemma4-e2b-q4/versions/1.3.0/manifest.json +71 -0
- package/dist/catalog/chat-models/ge/gemma4-e4b-q4/manifest.json +205 -0
- package/dist/catalog/chat-models/ge/gemma4-e4b-q4/versions/1.1.0/manifest.json +72 -0
- package/dist/catalog/chat-models/ge/gemma4-e4b-q4/versions/1.1.2/manifest.json +75 -0
- package/dist/catalog/chat-models/ge/gemma4-e4b-q4/versions/1.2.0/manifest.json +76 -0
- package/dist/catalog/chat-models/ge/gemma4-e4b-q4/versions/1.2.1/manifest.json +76 -0
- package/dist/catalog/chat-models/ge/gemma4-e4b-q4/versions/1.3.0/manifest.json +76 -0
- package/dist/catalog/chat-models/gl/glm-5.2-754b-q2/manifest.json +127 -0
- package/dist/catalog/chat-models/gl/glm-5.2-754b-q2/versions/1.0.0/manifest.json +20 -0
- package/dist/catalog/chat-models/gl/glm-5.3-flash-320b-q2/manifest.json +140 -0
- package/dist/catalog/chat-models/gl/glm-5.3-flash-320b-q2/versions/1.0.0/manifest.json +23 -0
- package/dist/catalog/chat-models/gl/glm-5.3-flash-320b-q2/versions/1.0.1/manifest.json +26 -0
- package/dist/catalog/chat-models/gp/gpt-oss-120b-q4/manifest.json +247 -0
- package/dist/catalog/chat-models/gp/gpt-oss-120b-q4/versions/1.0.0/manifest.json +137 -0
- package/dist/catalog/chat-models/gp/gpt-oss-120b-q4/versions/1.1.0/manifest.json +135 -0
- package/dist/catalog/chat-models/gp/gpt-oss-20b-q4/manifest.json +195 -0
- package/dist/catalog/chat-models/gp/gpt-oss-20b-q4/versions/1.1.0/manifest.json +72 -0
- package/dist/catalog/chat-models/gp/gpt-oss-20b-q4/versions/1.1.1/manifest.json +71 -0
- package/dist/catalog/chat-models/gr/granite4.2-30b-q4/manifest.json +200 -0
- package/dist/catalog/chat-models/gr/granite4.2-30b-q4/versions/1.0.0/manifest.json +72 -0
- package/dist/catalog/chat-models/gr/granite4.2-3b-q4/manifest.json +196 -0
- package/dist/catalog/chat-models/gr/granite4.2-3b-q4/versions/1.0.0/manifest.json +57 -0
- package/dist/catalog/chat-models/gr/granite4.2-8b-q4/manifest.json +189 -0
- package/dist/catalog/chat-models/gr/granite4.2-8b-q4/versions/1.0.0/manifest.json +57 -0
- package/dist/catalog/chat-models/index.json +1 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q4/manifest.json +235 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q4/versions/1.0.0/manifest.json +124 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q4/versions/1.0.1/manifest.json +124 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q4/versions/1.0.2/manifest.json +123 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q6/manifest.json +257 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q6/versions/1.0.0/manifest.json +145 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q6/versions/1.0.1/manifest.json +145 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q8/manifest.json +285 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q8/versions/1.0.0/manifest.json +174 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q8/versions/1.0.1/manifest.json +174 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q8/versions/1.0.2/manifest.json +173 -0
- package/dist/catalog/chat-models/lf/lfm2.5-2.6b-q4/manifest.json +162 -0
- package/dist/catalog/chat-models/lf/lfm2.5-2.6b-q4/versions/1.0.0/manifest.json +59 -0
- package/dist/catalog/chat-models/lf/lfm2.5-2.6b-q4/versions/1.0.1/manifest.json +58 -0
- package/dist/catalog/chat-models/ll/llama3.2-3b-q4/manifest.json +134 -0
- package/dist/catalog/chat-models/ll/llama3.2-3b-q4/versions/1.1.0/manifest.json +57 -0
- package/dist/catalog/chat-models/ll/llama3.2-3b-q4/versions/1.1.1/manifest.json +56 -0
- package/dist/catalog/chat-models/mi/minicpm5-1b-q4/manifest.json +156 -0
- package/dist/catalog/chat-models/mi/minicpm5-1b-q4/versions/1.0.0/manifest.json +57 -0
- package/dist/catalog/chat-models/mi/minicpm5-2b-q4/manifest.json +161 -0
- package/dist/catalog/chat-models/mi/minicpm5-2b-q4/versions/1.0.0/manifest.json +57 -0
- package/dist/catalog/chat-models/mi/mistral-7b-q4/manifest.json +159 -0
- package/dist/catalog/chat-models/mi/mistral-7b-q4/versions/1.1.0/manifest.json +62 -0
- package/dist/catalog/chat-models/mi/mistral-7b-q4/versions/1.1.1/manifest.json +61 -0
- package/dist/catalog/chat-models/mi/mistral-medium-3.5-128b-q4/manifest.json +275 -0
- package/dist/catalog/chat-models/mi/mistral-medium-3.5-128b-q4/versions/1.0.0/manifest.json +154 -0
- package/dist/catalog/chat-models/mi/mistral-medium-3.5-128b-q4/versions/1.0.1/manifest.json +153 -0
- package/dist/catalog/chat-models/mu/muse-glimmer-30b-q4/manifest.json +135 -0
- package/dist/catalog/chat-models/mu/muse-glimmer-30b-q4/versions/1.0.0/manifest.json +20 -0
- package/dist/catalog/chat-models/mu/muse-glimmer-30b-q4/versions/1.0.1/manifest.json +20 -0
- package/dist/catalog/chat-models/mu/muse-glimmer-30b-q4/versions/1.0.2/manifest.json +20 -0
- package/dist/catalog/chat-models/na/nanbeige4.2-3b-q4/manifest.json +138 -0
- package/dist/catalog/chat-models/na/nanbeige4.2-3b-q4/versions/1.0.0/manifest.json +14 -0
- package/dist/catalog/chat-models/ne/nemotron3-nano-30b-q4/manifest.json +212 -0
- package/dist/catalog/chat-models/ne/nemotron3-nano-30b-q4/versions/1.0.0/manifest.json +94 -0
- package/dist/catalog/chat-models/ne/nemotron3-nano-30b-q4/versions/1.0.1/manifest.json +94 -0
- package/dist/catalog/chat-models/ne/nemotron3-nano-30b-q4/versions/1.0.2/manifest.json +93 -0
- package/dist/catalog/chat-models/ne/nemotron3-super-120b-q4/manifest.json +135 -0
- package/dist/catalog/chat-models/ne/nemotron3-super-120b-q4/versions/1.0.0/manifest.json +30 -0
- package/dist/catalog/chat-models/ne/nemotron3-super-120b-q4/versions/1.0.1/manifest.json +30 -0
- package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q4/manifest.json +192 -0
- package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q4/versions/1.0.0/manifest.json +74 -0
- package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q4/versions/1.0.1/manifest.json +73 -0
- package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q8/manifest.json +207 -0
- package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q8/versions/1.0.0/manifest.json +89 -0
- package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q8/versions/1.0.1/manifest.json +88 -0
- package/dist/catalog/chat-models/or/ornith-35b-q4/manifest.json +224 -0
- package/dist/catalog/chat-models/or/ornith-35b-q4/versions/1.0.0/manifest.json +94 -0
- package/dist/catalog/chat-models/or/ornith-35b-q4/versions/1.0.1/manifest.json +93 -0
- package/dist/catalog/chat-models/or/ornith-35b-q8/manifest.json +244 -0
- package/dist/catalog/chat-models/or/ornith-35b-q8/versions/1.0.0/manifest.json +114 -0
- package/dist/catalog/chat-models/or/ornith-35b-q8/versions/1.0.1/manifest.json +113 -0
- package/dist/catalog/chat-models/or/ornith-9b-q4/manifest.json +215 -0
- package/dist/catalog/chat-models/or/ornith-9b-q4/versions/1.0.0/manifest.json +84 -0
- package/dist/catalog/chat-models/or/ornith-9b-q4/versions/1.0.1/manifest.json +83 -0
- package/dist/catalog/chat-models/or/ornith1.5-35b-a3b-q4/manifest.json +208 -0
- package/dist/catalog/chat-models/or/ornith1.5-35b-a3b-q4/versions/1.0.0/manifest.json +74 -0
- package/dist/catalog/chat-models/or/ornith1.5-35b-a3b-q8/manifest.json +223 -0
- package/dist/catalog/chat-models/or/ornith1.5-35b-a3b-q8/versions/1.0.0/manifest.json +89 -0
- package/dist/catalog/chat-models/or/ornith1.5-9b-q4/manifest.json +187 -0
- package/dist/catalog/chat-models/or/ornith1.5-9b-q4/versions/1.0.0/manifest.json +53 -0
- package/dist/catalog/chat-models/or/ornith1.5-9b-q4/versions/1.0.1/manifest.json +77 -0
- package/dist/catalog/chat-models/or/ornith1.5-9b-q8/manifest.json +192 -0
- package/dist/catalog/chat-models/or/ornith1.5-9b-q8/versions/1.0.0/manifest.json +58 -0
- package/dist/catalog/chat-models/or/ornith1.5-9b-q8/versions/1.0.1/manifest.json +82 -0
- package/dist/catalog/chat-models/qw/qwen3.5-0.8b-q4/manifest.json +192 -0
- package/dist/catalog/chat-models/qw/qwen3.5-0.8b-q4/versions/1.0.0/manifest.json +75 -0
- package/dist/catalog/chat-models/qw/qwen3.5-122b-a10b-q4/manifest.json +315 -0
- package/dist/catalog/chat-models/qw/qwen3.5-122b-a10b-q4/versions/1.0.0/manifest.json +164 -0
- package/dist/catalog/chat-models/qw/qwen3.5-122b-a10b-q4/versions/1.0.1/manifest.json +164 -0
- package/dist/catalog/chat-models/qw/qwen3.5-122b-a10b-q4/versions/1.0.2/manifest.json +164 -0
- package/dist/catalog/chat-models/qw/qwen3.5-122b-a10b-q4/versions/1.0.3/manifest.json +163 -0
- package/dist/catalog/chat-models/qw/qwen3.5-27b-q4/manifest.json +217 -0
- package/dist/catalog/chat-models/qw/qwen3.5-27b-q4/versions/1.0.0/manifest.json +90 -0
- package/dist/catalog/chat-models/qw/qwen3.5-2b-q4/manifest.json +194 -0
- package/dist/catalog/chat-models/qw/qwen3.5-2b-q4/versions/1.1.0/manifest.json +77 -0
- package/dist/catalog/chat-models/qw/qwen3.5-2b-q4/versions/1.1.2/manifest.json +76 -0
- package/dist/catalog/chat-models/qw/qwen3.5-2b-q4/versions/1.1.3/manifest.json +76 -0
- package/dist/catalog/chat-models/qw/qwen3.5-4b-q4/manifest.json +188 -0
- package/dist/catalog/chat-models/qw/qwen3.5-4b-q4/versions/1.1.0/manifest.json +77 -0
- package/dist/catalog/chat-models/qw/qwen3.5-4b-q4/versions/1.1.2/manifest.json +76 -0
- package/dist/catalog/chat-models/qw/qwen3.5-4b-q4/versions/1.1.3/manifest.json +76 -0
- package/dist/catalog/chat-models/qw/qwen3.5-9b-q4/manifest.json +205 -0
- package/dist/catalog/chat-models/qw/qwen3.5-9b-q4/versions/1.1.0/manifest.json +82 -0
- package/dist/catalog/chat-models/qw/qwen3.5-9b-q4/versions/1.1.2/manifest.json +81 -0
- package/dist/catalog/chat-models/qw/qwen3.5-9b-q4/versions/1.1.3/manifest.json +81 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q4/manifest.json +230 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q4/versions/1.1.0/manifest.json +92 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q4/versions/1.1.4/manifest.json +91 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q4/versions/1.1.5/manifest.json +91 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q4/versions/1.1.6/manifest.json +115 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q8/manifest.json +240 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q8/versions/1.0.0/manifest.json +102 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q8/versions/1.0.2/manifest.json +103 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q8/versions/1.0.3/manifest.json +103 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q8/versions/1.0.4/manifest.json +127 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q4/manifest.json +233 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q4/versions/1.0.0/manifest.json +92 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q4/versions/1.0.1/manifest.json +93 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q4/versions/1.0.2/manifest.json +93 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q4/versions/1.0.3/manifest.json +117 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q8/manifest.json +252 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q8/versions/1.0.0/manifest.json +112 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q8/versions/1.0.1/manifest.json +113 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q8/versions/1.0.2/manifest.json +113 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q8/versions/1.0.3/manifest.json +137 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-iq1-s/manifest.json +195 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-iq1-s/versions/1.0.0/manifest.json +19 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q2/manifest.json +194 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q2/versions/1.0.0/manifest.json +19 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q3/manifest.json +194 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q3/versions/1.0.0/manifest.json +19 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q3/versions/1.0.1/manifest.json +19 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/manifest.json +291 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.0/manifest.json +20 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.1/manifest.json +93 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.2/manifest.json +92 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.3/manifest.json +116 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.4/manifest.json +116 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.5/manifest.json +116 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q6/manifest.json +278 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q6/versions/1.0.0/manifest.json +20 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q6/versions/1.0.1/manifest.json +104 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q6/versions/1.0.2/manifest.json +103 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q6/versions/1.0.3/manifest.json +127 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q8/manifest.json +278 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q8/versions/1.0.0/manifest.json +113 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q8/versions/1.0.1/manifest.json +113 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q8/versions/1.0.2/manifest.json +137 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq3/manifest.json +221 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq3/versions/1.0.0/manifest.json +36 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq4/manifest.json +429 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq4/versions/1.0.0/manifest.json +36 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq4/versions/1.1.0/manifest.json +205 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq4/versions/1.1.1/manifest.json +244 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-q2/manifest.json +203 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-q2/versions/1.0.0/manifest.json +21 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-q2/versions/1.0.1/manifest.json +31 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-q2/versions/1.0.2/manifest.json +30 -0
- package/dist/catalog/chat-models/raw-index.json +1 -0
- package/dist/catalog/chat-models/ta/talkie-1930-13b-q4/manifest.json +79 -0
- package/dist/catalog/chat-models/ta/talkie-1930-13b-q4/versions/1.0.0/manifest.json +15 -0
- package/dist/catalog/chat-models/ta/talkie-1930-13b-q4/versions/1.0.1/manifest.json +15 -0
- package/dist/catalog/chat-models/te/ternary-bonsai-27b-q2/manifest.json +204 -0
- package/dist/catalog/chat-models/te/ternary-bonsai-27b-q2/versions/1.0.0/manifest.json +70 -0
- package/dist/catalog/chat-models/te/ternary-bonsai-27b-q2/versions/1.0.1/manifest.json +70 -0
- package/dist/catalog/chat-models/un/underdog-saluki-27b-iq2-mix/manifest.json +164 -0
- package/dist/catalog/chat-models/un/underdog-saluki-27b-iq2-mix/versions/1.0.0/manifest.json +14 -0
- package/dist/catalog/knowledge-catalogs/be/bendyline-how-to-books/manifest.json +26 -0
- package/dist/catalog/knowledge-catalogs/be/bendyline-how-to-books/versions/2026.10.8/manifest.json +8950 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-alaska-part-0001/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-alaska-part-0001/versions/2026.10.1/manifest.json +658 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-nevada-part-0001/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-nevada-part-0001/versions/2026.10.1/manifest.json +666 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-us-300-399-part-0001/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-us-300-399-part-0001/versions/2026.10.2/manifest.json +182 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-us-347-349/manifest.json +25 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-us-347-349/versions/2026.10.5/manifest.json +38 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-utah-part-0001/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-utah-part-0001/versions/2026.10.1/manifest.json +558 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-utah-part-0002/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-utah-part-0002/versions/2026.10.1/manifest.json +258 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0001/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0001/versions/2026.10.1/manifest.json +318 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0002/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0002/versions/2026.10.1/manifest.json +266 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0003/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0003/versions/2026.10.1/manifest.json +186 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0004/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0004/versions/2026.10.1/manifest.json +138 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0005/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0005/versions/2026.10.1/manifest.json +138 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-wyoming-part-0001/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-wyoming-part-0001/versions/2026.10.3/manifest.json +626 -0
- package/dist/catalog/knowledge-catalogs/index.json +1 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-aspnet-core-en/manifest.json +22 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-aspnet-core-en/versions/2026.10.16/manifest.json +18270 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-ai-platform-en/manifest.json +23 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-ai-platform-en/versions/2026.10.16/manifest.json +1098 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-apps-compute-en/manifest.json +23 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-apps-compute-en/versions/2026.10.16/manifest.json +722 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-data-aiot-en/manifest.json +23 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-data-aiot-en/versions/2026.10.16/manifest.json +530 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-management-hybrid-en/manifest.json +23 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-management-hybrid-en/versions/2026.10.16/manifest.json +602 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-network-security-en/manifest.json +23 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-network-security-en/versions/2026.10.16/manifest.json +250 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-dotnet-en/manifest.json +22 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-dotnet-en/versions/2026.10.16/manifest.json +16794 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-entity-framework-en/manifest.json +22 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-entity-framework-en/versions/2026.10.16/manifest.json +1106 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-microsoft-365-en/manifest.json +22 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-microsoft-365-en/versions/2026.10.16/manifest.json +234 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-powershell-en/manifest.json +22 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-powershell-en/versions/2026.10.16/manifest.json +522 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-sql-server-en/manifest.json +22 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-sql-server-en/versions/2026.10.16/manifest.json +1850 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-windows-apps-en/manifest.json +22 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-windows-apps-en/versions/2026.10.16/manifest.json +1734 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-windows-server-en/manifest.json +22 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-windows-server-en/versions/2026.10.16/manifest.json +774 -0
- package/dist/catalog/knowledge-catalogs/raw-index.json +1 -0
- package/dist/catalog/knowledge-catalogs/re/regional-american-south/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-american-south/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-american-south/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-american-south/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-andes-amazon/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-andes-amazon/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-andes-amazon/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-andes-amazon/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-australia-nz/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-australia-nz/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-australia-nz/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-australia-nz/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-brazil/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-brazil/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-brazil/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-brazil/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-britain-ireland/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-britain-ireland/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-britain-ireland/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-britain-ireland/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-california-southwest/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-california-southwest/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-california-southwest/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-california-southwest/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-canada-alaska/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-canada-alaska/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-canada-alaska/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-canada-alaska/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-central-eastern-europe/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-central-eastern-europe/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-central-eastern-europe/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-central-eastern-europe/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-asia/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-asia/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-asia/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-asia/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-southern-africa/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-southern-africa/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-southern-africa/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-southern-africa/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mediterranean/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mediterranean/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mediterranean/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mediterranean/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mexico-central-america/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mexico-central-america/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mexico-central-america/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mexico-central-america/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-middle-east/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-middle-east/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-middle-east/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-middle-east/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-midwest/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-midwest/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-midwest/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-midwest/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-north-africa/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-north-africa/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-north-africa/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-north-africa/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northeast/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northeast/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northeast/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northeast/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-eurasia/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-eurasia/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-eurasia/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-eurasia/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-europe/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-europe/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-europe/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-europe/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-islands/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-islands/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-islands/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-islands/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-northwest/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-northwest/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-northwest/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-northwest/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-rockies-plains/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-rockies-plains/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-rockies-plains/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-rockies-plains/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-south-asia/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-south-asia/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-south-asia/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-south-asia/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southeast-asia/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southeast-asia/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southeast-asia/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southeast-asia/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southern-cone/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southern-cone/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southern-cone/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southern-cone/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-west-central-africa/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-west-central-africa/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-west-central-africa/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-west-central-africa/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-western-europe/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-western-europe/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-western-europe/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-western-europe/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/manifest.json +28 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/versions/2026.4.2/manifest.json +53 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/versions/2026.4.3/manifest.json +885 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/versions/2026.4.5/manifest.json +157 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/art.json +11 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/manifest.json +32 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/versions/2026.4.2/manifest.json +69 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/versions/2026.4.3/manifest.json +741 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/versions/2026.4.5/manifest.json +173 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/manifest.json +69 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/versions/2026.4.4/manifest.json +217 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/versions/2026.4.5/manifest.json +217 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/manifest.json +64 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/versions/2026.4.4/manifest.json +197 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/versions/2026.4.5/manifest.json +197 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/manifest.json +64 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/versions/2026.4.5/manifest.json +197 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/art.json +11 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/manifest.json +29 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/versions/2026.4.2/manifest.json +57 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/versions/2026.4.3/manifest.json +925 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/versions/2026.4.5/manifest.json +185 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/manifest.json +28 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/versions/2026.4.2/manifest.json +53 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/versions/2026.4.3/manifest.json +1665 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/versions/2026.4.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/manifest.json +29 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/versions/2026.4.2/manifest.json +57 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/versions/2026.4.3/manifest.json +1233 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/versions/2026.4.5/manifest.json +141 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/art.json +11 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/manifest.json +29 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/versions/2026.4.2/manifest.json +57 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/versions/2026.4.3/manifest.json +493 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/versions/2026.4.5/manifest.json +185 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/manifest.json +63 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/versions/2026.4.4/manifest.json +193 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/versions/2026.4.5/manifest.json +193 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/manifest.json +30 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/versions/2026.4.2/manifest.json +61 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/versions/2026.4.3/manifest.json +665 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/versions/2026.4.5/manifest.json +177 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/manifest.json +29 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/versions/2026.4.2/manifest.json +57 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/versions/2026.4.3/manifest.json +745 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/versions/2026.4.5/manifest.json +185 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/manifest.json +62 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/versions/2026.4.4/manifest.json +189 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/versions/2026.4.5/manifest.json +189 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/manifest.json +64 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/versions/2026.4.5/manifest.json +197 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/manifest.json +64 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/versions/2026.4.4/manifest.json +197 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/versions/2026.4.5/manifest.json +197 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/manifest.json +30 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/versions/2026.4.2/manifest.json +61 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/versions/2026.4.3/manifest.json +1253 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/versions/2026.4.5/manifest.json +189 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/manifest.json +29 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/versions/2026.4.2/manifest.json +57 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/versions/2026.4.3/manifest.json +1957 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/versions/2026.4.5/manifest.json +185 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/manifest.json +63 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/versions/2026.4.5/manifest.json +193 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/art.json +11 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/manifest.json +45 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/versions/2026.4.4/manifest.json +121 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/versions/2026.4.5/manifest.json +173 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/manifest.json +62 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/versions/2026.4.4/manifest.json +189 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/versions/2026.4.5/manifest.json +189 -0
- package/dist/catalog/provenance.json +8 -0
- package/dist/chat/catalog-model-lookup.d.ts +21 -0
- package/dist/chat/catalog-model-lookup.js +48 -0
- package/dist/chat/local-model-tier.d.ts +1 -0
- package/dist/chat/local-model-tier.js +2 -0
- package/dist/chat/vision-capability.d.ts +1 -0
- package/dist/chat/vision-capability.js +3 -0
- package/dist/engine-components.d.ts +30 -0
- package/dist/engine-components.js +144 -0
- package/dist/engines/electron-native-reuse.d.ts +65 -0
- package/dist/engines/electron-native-reuse.js +305 -0
- package/dist/engines/native-file-manifest.json +1320 -0
- package/dist/engines/native-manifest.d.ts +70 -0
- package/dist/engines/native-manifest.js +98 -0
- package/dist/engines/registry.d.ts +88 -0
- package/dist/engines/registry.js +217 -0
- package/dist/engines/resolver.d.ts +121 -0
- package/dist/engines/resolver.js +894 -0
- package/dist/engines/signature.d.ts +85 -0
- package/dist/engines/signature.js +231 -0
- package/dist/fs/atomic.d.ts +53 -0
- package/dist/fs/atomic.js +202 -0
- package/dist/fs/config-store.d.ts +14 -0
- package/dist/fs/config-store.js +101 -0
- package/dist/fs/home-permissions.d.ts +18 -0
- package/dist/fs/home-permissions.js +27 -0
- package/dist/fs/safe-paths.d.ts +107 -0
- package/dist/fs/safe-paths.js +264 -0
- package/dist/fs/security-json.d.ts +13 -0
- package/dist/fs/security-json.js +67 -0
- package/dist/http/auth-context.d.ts +23 -0
- package/dist/http/auth-context.js +1 -0
- package/dist/http/engine-runtime-context.d.ts +30 -0
- package/dist/http/engine-runtime-context.js +1 -0
- package/dist/http/external-conversation-contract.d.ts +49 -0
- package/dist/http/external-conversation-contract.js +1 -0
- package/dist/http/external-conversation-headers.d.ts +11 -0
- package/dist/http/external-conversation-headers.js +11 -0
- package/dist/http/inference-context.d.ts +36 -0
- package/dist/http/inference-context.js +1 -0
- package/dist/http/model-inventory-cache.d.ts +8 -0
- package/dist/http/model-inventory-cache.js +8 -0
- package/dist/http/openai-compat/action-ledger.d.ts +15 -0
- package/dist/http/openai-compat/action-ledger.js +119 -0
- package/dist/http/openai-compat/apple-model.d.ts +3 -0
- package/dist/http/openai-compat/apple-model.js +44 -0
- package/dist/http/openai-compat/caller-owned-profile.d.ts +7 -0
- package/dist/http/openai-compat/caller-owned-profile.js +18 -0
- package/dist/http/openai-compat/chat-progress.d.ts +9 -0
- package/dist/http/openai-compat/chat-progress.js +69 -0
- package/dist/http/openai-compat/chat-target.d.ts +76 -0
- package/dist/http/openai-compat/chat-target.js +97 -0
- package/dist/http/openai-compat/embeddings.d.ts +37 -0
- package/dist/http/openai-compat/embeddings.js +86 -0
- package/dist/http/openai-compat/request-tuning.d.ts +35 -0
- package/dist/http/openai-compat/request-tuning.js +87 -0
- package/dist/http/openai-compat/responses-streaming.d.ts +351 -0
- package/dist/http/openai-compat/responses-streaming.js +717 -0
- package/dist/http/openai-compat/responses-translate.d.ts +215 -0
- package/dist/http/openai-compat/responses-translate.js +377 -0
- package/dist/http/openai-compat/streaming-telemetry.d.ts +30 -0
- package/dist/http/openai-compat/streaming-telemetry.js +88 -0
- package/dist/http/openai-compat/streaming.d.ts +141 -0
- package/dist/http/openai-compat/streaming.js +687 -0
- package/dist/http/openai-compat/tool-call-stream-filter.d.ts +33 -0
- package/dist/http/openai-compat/tool-call-stream-filter.js +110 -0
- package/dist/http/openai-compat/translate.d.ts +254 -0
- package/dist/http/openai-compat/translate.js +485 -0
- package/dist/http/routes/engines.d.ts +13 -0
- package/dist/http/routes/engines.js +366 -0
- package/dist/http/routes/machine-engine-proxy.d.ts +26 -0
- package/dist/http/routes/machine-engine-proxy.js +43 -0
- package/dist/http/routes/model-bundles.d.ts +4 -0
- package/dist/http/routes/model-bundles.js +190 -0
- package/dist/http/routes/v1-chat.d.ts +72 -0
- package/dist/http/routes/v1-chat.js +645 -0
- package/dist/http/routes/v1-embeddings.d.ts +3 -0
- package/dist/http/routes/v1-embeddings.js +82 -0
- package/dist/http/routes/v1-knowledge.d.ts +4 -0
- package/dist/http/routes/v1-knowledge.js +304 -0
- package/dist/http/routes/v1-models-ensure.d.ts +32 -0
- package/dist/http/routes/v1-models-ensure.js +122 -0
- package/dist/http/routes/v1-models.d.ts +8 -0
- package/dist/http/routes/v1-models.js +189 -0
- package/dist/http/routes/v1-responses.d.ts +20 -0
- package/dist/http/routes/v1-responses.js +327 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/inference-service.d.ts +28 -0
- package/dist/inference-service.js +275 -0
- package/dist/knowledge/admission.d.ts +3 -0
- package/dist/knowledge/admission.js +22 -0
- package/dist/knowledge/bundled-catalog.d.ts +2 -0
- package/dist/knowledge/bundled-catalog.js +2 -0
- package/dist/knowledge/catalog-host.d.ts +103 -0
- package/dist/knowledge/catalog-host.js +180 -0
- package/dist/knowledge/catalog-source.d.ts +22 -0
- package/dist/knowledge/catalog-source.js +35 -0
- package/dist/knowledge/install.d.ts +55 -0
- package/dist/knowledge/install.js +274 -0
- package/dist/knowledge/manager.d.ts +287 -0
- package/dist/knowledge/manager.js +1540 -0
- package/dist/knowledge/registry.d.ts +35 -0
- package/dist/knowledge/registry.js +123 -0
- package/dist/knowledge/search-worker.d.ts +17 -0
- package/dist/knowledge/search-worker.js +36 -0
- package/dist/knowledge/shared-install-contract.d.ts +19 -0
- package/dist/knowledge/shared-install-contract.js +1 -0
- package/dist/knowledge/spatial-query.d.ts +11 -0
- package/dist/knowledge/spatial-query.js +33 -0
- package/dist/knowledge/trust-anchors.d.ts +11 -0
- package/dist/knowledge/trust-anchors.js +51 -0
- package/dist/knowledge/vector-floors.d.ts +44 -0
- package/dist/knowledge/vector-floors.js +92 -0
- package/dist/knowledge/worker-host.d.ts +9 -0
- package/dist/knowledge/worker-host.js +179 -0
- package/dist/kokoro-lexicon/LICENSE +202 -0
- package/dist/kokoro-lexicon/lexicon-gb-en.txt.gz +0 -0
- package/dist/kokoro-lexicon/lexicon-us-en.txt.gz +0 -0
- package/dist/kokoro-lexicon/manifest.json +23 -0
- package/dist/machine-engine/inspect-runtime.d.ts +3 -0
- package/dist/machine-engine/inspect-runtime.js +48 -0
- package/dist/machine-engine/knowledge-assets.d.ts +79 -0
- package/dist/machine-engine/knowledge-assets.js +505 -0
- package/dist/memory/embed-core.d.ts +131 -0
- package/dist/memory/embed-core.js +398 -0
- package/dist/memory/embed-worker.d.ts +23 -0
- package/dist/memory/embed-worker.js +49 -0
- package/dist/memory/embeddings.d.ts +105 -0
- package/dist/memory/embeddings.js +467 -0
- package/dist/model-profile/behaviors/tools-mlx-template-fix.d.ts +1 -0
- package/dist/model-profile/behaviors/tools-mlx-template-fix.js +2 -0
- package/dist/model-profile/behaviors/turn-ramble-detection.d.ts +1 -0
- package/dist/model-profile/behaviors/turn-ramble-detection.js +2 -0
- package/dist/model-profile/defaults.d.ts +1 -0
- package/dist/model-profile/defaults.js +2 -0
- package/dist/model-profile/index.d.ts +9 -0
- package/dist/model-profile/index.js +7 -0
- package/dist/model-profile/registry.d.ts +15 -0
- package/dist/model-profile/registry.js +18 -0
- package/dist/model-profile/runtime.d.ts +48 -0
- package/dist/model-profile/runtime.js +131 -0
- package/dist/model-profile/tool-grammar.d.ts +1 -0
- package/dist/model-profile/tool-grammar.js +2 -0
- package/dist/model-profile/tuning.d.ts +19 -0
- package/dist/model-profile/tuning.js +21 -0
- package/dist/model-profile/types.d.ts +1 -0
- package/dist/model-profile/types.js +2 -0
- package/dist/models/bundle-storage.d.ts +28 -0
- package/dist/models/bundle-storage.js +80 -0
- package/dist/models/catalog-drift.d.ts +48 -0
- package/dist/models/catalog-drift.js +94 -0
- package/dist/models/catalog-payload-identity.d.ts +107 -0
- package/dist/models/catalog-payload-identity.js +254 -0
- package/dist/models/ensure.d.ts +125 -0
- package/dist/models/ensure.js +205 -0
- package/dist/models/gezmodel.d.ts +47 -0
- package/dist/models/gezmodel.js +742 -0
- package/dist/models/install-registry.d.ts +101 -0
- package/dist/models/install-registry.js +216 -0
- package/dist/models/model-id.d.ts +22 -0
- package/dist/models/model-id.js +40 -0
- package/dist/models/storage-roots.d.ts +274 -0
- package/dist/models/storage-roots.js +865 -0
- package/dist/native-release-entry.d.ts +16 -0
- package/dist/native-release-entry.js +16 -0
- package/dist/perf/redact-path.d.ts +2 -0
- package/dist/perf/redact-path.js +27 -0
- package/dist/perf/responsiveness.d.ts +70 -0
- package/dist/perf/responsiveness.js +560 -0
- package/dist/providers/active-install-message.d.ts +42 -0
- package/dist/providers/active-install-message.js +49 -0
- package/dist/providers/apple-foundation-models/binary.d.ts +4 -0
- package/dist/providers/apple-foundation-models/binary.js +18 -0
- package/dist/providers/apple-foundation-models/helper.d.ts +66 -0
- package/dist/providers/apple-foundation-models/helper.js +262 -0
- package/dist/providers/apple-foundation-models/provider.d.ts +82 -0
- package/dist/providers/apple-foundation-models/provider.js +389 -0
- package/dist/providers/apple-foundation-models/status.d.ts +9 -0
- package/dist/providers/apple-foundation-models/status.js +49 -0
- package/dist/providers/audio/kokoro-frontend.d.ts +50 -0
- package/dist/providers/audio/kokoro-frontend.js +113 -0
- package/dist/providers/audio/managed-speech-model.d.ts +9 -0
- package/dist/providers/audio/managed-speech-model.js +86 -0
- package/dist/providers/audio/types.d.ts +202 -0
- package/dist/providers/audio/types.js +17 -0
- package/dist/providers/audio/whisper-cpp.d.ts +99 -0
- package/dist/providers/audio/whisper-cpp.js +420 -0
- package/dist/providers/audio-persister-contract.d.ts +13 -0
- package/dist/providers/audio-persister-contract.js +1 -0
- package/dist/providers/catalog-model-config.d.ts +63 -0
- package/dist/providers/catalog-model-config.js +95 -0
- package/dist/providers/code-block-salvage.d.ts +1 -0
- package/dist/providers/code-block-salvage.js +2 -0
- package/dist/providers/codex-cli/reasoning.d.ts +8 -0
- package/dist/providers/codex-cli/reasoning.js +17 -0
- package/dist/providers/complete-tool-call.d.ts +16 -0
- package/dist/providers/complete-tool-call.js +25 -0
- package/dist/providers/constrained-turn.d.ts +1 -0
- package/dist/providers/constrained-turn.js +2 -0
- package/dist/providers/deliverable-read-pacing.d.ts +1 -0
- package/dist/providers/deliverable-read-pacing.js +2 -0
- package/dist/providers/direct-file-work-prompt.d.ts +1 -0
- package/dist/providers/direct-file-work-prompt.js +2 -0
- package/dist/providers/ds4/build-provider.d.ts +100 -0
- package/dist/providers/ds4/build-provider.js +539 -0
- package/dist/providers/ds4/cache-adapter.d.ts +42 -0
- package/dist/providers/ds4/cache-adapter.js +110 -0
- package/dist/providers/ds4/dspark.d.ts +83 -0
- package/dist/providers/ds4/dspark.js +107 -0
- package/dist/providers/ds4/mtp.d.ts +32 -0
- package/dist/providers/ds4/mtp.js +46 -0
- package/dist/providers/ds4/provider.d.ts +67 -0
- package/dist/providers/ds4/provider.js +104 -0
- package/dist/providers/ds4/residency.d.ts +143 -0
- package/dist/providers/ds4/residency.js +139 -0
- package/dist/providers/ds4/stdout-parser.d.ts +47 -0
- package/dist/providers/ds4/stdout-parser.js +134 -0
- package/dist/providers/duplicate-tool-calls.d.ts +1 -0
- package/dist/providers/duplicate-tool-calls.js +2 -0
- package/dist/providers/file-repair-policy.d.ts +1 -0
- package/dist/providers/file-repair-policy.js +2 -0
- package/dist/providers/gpu-arbiter.d.ts +159 -0
- package/dist/providers/gpu-arbiter.js +301 -0
- package/dist/providers/image-persister-contract.d.ts +15 -0
- package/dist/providers/image-persister-contract.js +1 -0
- package/dist/providers/llama-cpp/build-metadata.d.ts +13 -0
- package/dist/providers/llama-cpp/build-metadata.js +39 -0
- package/dist/providers/llama-cpp/build-provider.d.ts +66 -0
- package/dist/providers/llama-cpp/build-provider.js +1491 -0
- package/dist/providers/llama-cpp/cache-adapter.d.ts +242 -0
- package/dist/providers/llama-cpp/cache-adapter.js +689 -0
- package/dist/providers/llama-cpp/devices.d.ts +130 -0
- package/dist/providers/llama-cpp/devices.js +256 -0
- package/dist/providers/llama-cpp/disk-cache.d.ts +8 -0
- package/dist/providers/llama-cpp/disk-cache.js +112 -0
- package/dist/providers/llama-cpp/engine-flags.d.ts +181 -0
- package/dist/providers/llama-cpp/engine-flags.js +279 -0
- package/dist/providers/llama-cpp/gguf-metadata-async.d.ts +11 -0
- package/dist/providers/llama-cpp/gguf-metadata-async.js +180 -0
- package/dist/providers/llama-cpp/gguf-metadata-worker.d.ts +7 -0
- package/dist/providers/llama-cpp/gguf-metadata-worker.js +27 -0
- package/dist/providers/llama-cpp/gguf-metadata.d.ts +198 -0
- package/dist/providers/llama-cpp/gguf-metadata.js +615 -0
- package/dist/providers/llama-cpp/gguf-quantization-backfill.d.ts +32 -0
- package/dist/providers/llama-cpp/gguf-quantization-backfill.js +75 -0
- package/dist/providers/llama-cpp/index.d.ts +10 -0
- package/dist/providers/llama-cpp/index.js +13 -0
- package/dist/providers/llama-cpp/kv-cache-type.d.ts +118 -0
- package/dist/providers/llama-cpp/kv-cache-type.js +140 -0
- package/dist/providers/llama-cpp/log.d.ts +92 -0
- package/dist/providers/llama-cpp/log.js +280 -0
- package/dist/providers/llama-cpp/models.d.ts +389 -0
- package/dist/providers/llama-cpp/models.js +1011 -0
- package/dist/providers/llama-cpp/offload-planner.d.ts +339 -0
- package/dist/providers/llama-cpp/offload-planner.js +524 -0
- package/dist/providers/llama-cpp/provider.d.ts +493 -0
- package/dist/providers/llama-cpp/provider.js +862 -0
- package/dist/providers/llama-cpp/reasoning-launch.d.ts +7 -0
- package/dist/providers/llama-cpp/reasoning-launch.js +14 -0
- package/dist/providers/llama-cpp/spec-draft.d.ts +44 -0
- package/dist/providers/llama-cpp/spec-draft.js +44 -0
- package/dist/providers/llama-cpp/stdout-parser.d.ts +70 -0
- package/dist/providers/llama-cpp/stdout-parser.js +197 -0
- package/dist/providers/local-tool-call-salvage.d.ts +1 -0
- package/dist/providers/local-tool-call-salvage.js +2 -0
- package/dist/providers/local-turn-policy.d.ts +1 -0
- package/dist/providers/local-turn-policy.js +2 -0
- package/dist/providers/mlx/async-file-handoff.d.ts +11 -0
- package/dist/providers/mlx/async-file-handoff.js +25 -0
- package/dist/providers/mlx/build-provider.d.ts +65 -0
- package/dist/providers/mlx/build-provider.js +717 -0
- package/dist/providers/mlx/cache-adapter.d.ts +161 -0
- package/dist/providers/mlx/cache-adapter.js +445 -0
- package/dist/providers/mlx/chat-protocol.d.ts +48 -0
- package/dist/providers/mlx/chat-protocol.js +8 -0
- package/dist/providers/mlx/config-parser.d.ts +29 -0
- package/dist/providers/mlx/config-parser.js +81 -0
- package/dist/providers/mlx/engine-gate.d.ts +51 -0
- package/dist/providers/mlx/engine-gate.js +207 -0
- package/dist/providers/mlx/engine-hold.d.ts +41 -0
- package/dist/providers/mlx/engine-hold.js +59 -0
- package/dist/providers/mlx/engine-log-router.d.ts +84 -0
- package/dist/providers/mlx/engine-log-router.js +137 -0
- package/dist/providers/mlx/engine-stats-sampler.d.ts +36 -0
- package/dist/providers/mlx/engine-stats-sampler.js +59 -0
- package/dist/providers/mlx/index.d.ts +10 -0
- package/dist/providers/mlx/index.js +10 -0
- package/dist/providers/mlx/log.d.ts +55 -0
- package/dist/providers/mlx/log.js +157 -0
- package/dist/providers/mlx/model-geometry.d.ts +35 -0
- package/dist/providers/mlx/model-geometry.js +118 -0
- package/dist/providers/mlx/models.d.ts +289 -0
- package/dist/providers/mlx/models.js +1079 -0
- package/dist/providers/mlx/provider.d.ts +404 -0
- package/dist/providers/mlx/provider.js +3017 -0
- package/dist/providers/mlx/python/cache_persist.py +348 -0
- package/dist/providers/mlx/python/cache_seed.py +402 -0
- package/dist/providers/mlx/python/gezel_mlx_server.py +4491 -0
- package/dist/providers/mlx/python/lfm2_compat.py +55 -0
- package/dist/providers/mlx/python/qwen3_5_text_compat.py +60 -0
- package/dist/providers/mlx/python/qwen4_ple.py +159 -0
- package/dist/providers/mlx/python/spec_decode.py +775 -0
- package/dist/providers/mlx/python/template_stability.py +133 -0
- package/dist/providers/mlx/python/think_budget.py +113 -0
- package/dist/providers/mlx/python/tool_args_json.py +297 -0
- package/dist/providers/mlx/python/tool_call_stream.py +265 -0
- package/dist/providers/mlx/python/tool_grammar.py +794 -0
- package/dist/providers/mlx/python/vision_inputs.py +64 -0
- package/dist/providers/mlx/python/wave_policy.py +147 -0
- package/dist/providers/mlx/reasoning-stream.d.ts +85 -0
- package/dist/providers/mlx/reasoning-stream.js +196 -0
- package/dist/providers/mlx/request-shape.d.ts +34 -0
- package/dist/providers/mlx/request-shape.js +42 -0
- package/dist/providers/mlx/runtime-diagnostics.d.ts +29 -0
- package/dist/providers/mlx/runtime-diagnostics.js +162 -0
- package/dist/providers/mlx/spec-drafter.d.ts +25 -0
- package/dist/providers/mlx/spec-drafter.js +73 -0
- package/dist/providers/mlx/stdout-parser.d.ts +60 -0
- package/dist/providers/mlx/stdout-parser.js +254 -0
- package/dist/providers/mlx/textual-tool-call-salvage.d.ts +46 -0
- package/dist/providers/mlx/textual-tool-call-salvage.js +396 -0
- package/dist/providers/mlx/tool-call-protocol.d.ts +65 -0
- package/dist/providers/mlx/tool-call-protocol.js +140 -0
- package/dist/providers/mlx/tool-call-stripper.d.ts +68 -0
- package/dist/providers/mlx/tool-call-stripper.js +153 -0
- package/dist/providers/mlx/tool-image-retention.d.ts +23 -0
- package/dist/providers/mlx/tool-image-retention.js +43 -0
- package/dist/providers/mlx/turn-telemetry.d.ts +22 -0
- package/dist/providers/mlx/turn-telemetry.js +45 -0
- package/dist/providers/mlx/venv.d.ts +91 -0
- package/dist/providers/mlx/venv.js +111 -0
- package/dist/providers/mlx/vision-mode.d.ts +92 -0
- package/dist/providers/mlx/vision-mode.js +187 -0
- package/dist/providers/mlx/vision.d.ts +2 -0
- package/dist/providers/mlx/vision.js +12 -0
- package/dist/providers/mlx/wire-transcript.d.ts +14 -0
- package/dist/providers/mlx/wire-transcript.js +43 -0
- package/dist/providers/native/capacity-broker.d.ts +812 -0
- package/dist/providers/native/capacity-broker.js +1058 -0
- package/dist/providers/native/capacity-budget.d.ts +133 -0
- package/dist/providers/native/capacity-budget.js +265 -0
- package/dist/providers/native/device-capacity-ledger.d.ts +31 -0
- package/dist/providers/native/device-capacity-ledger.js +196 -0
- package/dist/providers/native/device-capacity.d.ts +84 -0
- package/dist/providers/native/device-capacity.js +431 -0
- package/dist/providers/native/engine-api-key.d.ts +57 -0
- package/dist/providers/native/engine-api-key.js +72 -0
- package/dist/providers/native/engine-key.d.ts +18 -0
- package/dist/providers/native/engine-key.js +41 -0
- package/dist/providers/native/engine-router.d.ts +145 -0
- package/dist/providers/native/engine-router.js +191 -0
- package/dist/providers/native/gpu-panic-guard.d.ts +54 -0
- package/dist/providers/native/gpu-panic-guard.js +59 -0
- package/dist/providers/native/inference.d.ts +33 -0
- package/dist/providers/native/inference.js +49 -0
- package/dist/providers/native/local-engine-runtime.d.ts +412 -0
- package/dist/providers/native/local-engine-runtime.js +1714 -0
- package/dist/providers/native/measured-budget.d.ts +32 -0
- package/dist/providers/native/measured-budget.js +54 -0
- package/dist/providers/native/port.d.ts +11 -0
- package/dist/providers/native/port.js +29 -0
- package/dist/providers/native/provider-pool.d.ts +474 -0
- package/dist/providers/native/provider-pool.js +1166 -0
- package/dist/providers/native/supervisor.d.ts +503 -0
- package/dist/providers/native/supervisor.js +1466 -0
- package/dist/providers/observation-context.d.ts +16 -0
- package/dist/providers/observation-context.js +1 -0
- package/dist/providers/openai-compatible/sse.d.ts +1 -0
- package/dist/providers/openai-compatible/sse.js +2 -0
- package/dist/providers/patient-fetch.d.ts +36 -0
- package/dist/providers/patient-fetch.js +44 -0
- package/dist/providers/project-macro-loop-bail.d.ts +7 -0
- package/dist/providers/project-macro-loop-bail.js +21 -0
- package/dist/providers/prose-document-salvage.d.ts +1 -0
- package/dist/providers/prose-document-salvage.js +2 -0
- package/dist/providers/provider-disposal.d.ts +1 -0
- package/dist/providers/provider-disposal.js +2 -0
- package/dist/providers/queue.d.ts +15 -0
- package/dist/providers/queue.js +23 -0
- package/dist/providers/ramble-abort-message.d.ts +1 -0
- package/dist/providers/ramble-abort-message.js +2 -0
- package/dist/providers/ramble-detector.d.ts +1 -0
- package/dist/providers/ramble-detector.js +2 -0
- package/dist/providers/reasoning-depth.d.ts +1 -0
- package/dist/providers/reasoning-depth.js +2 -0
- package/dist/providers/required-input-reads.d.ts +1 -0
- package/dist/providers/required-input-reads.js +2 -0
- package/dist/providers/session-defaults.d.ts +13 -0
- package/dist/providers/session-defaults.js +49 -0
- package/dist/providers/session-hooks.d.ts +26 -0
- package/dist/providers/session-hooks.js +1 -0
- package/dist/providers/streaming-session.d.ts +1 -0
- package/dist/providers/streaming-session.js +2 -0
- package/dist/providers/terminal-tool-policy.d.ts +1 -0
- package/dist/providers/terminal-tool-policy.js +2 -0
- package/dist/providers/tool-arg-schema-coercion.d.ts +1 -0
- package/dist/providers/tool-arg-schema-coercion.js +2 -0
- package/dist/providers/tool-executor.d.ts +12 -0
- package/dist/providers/tool-executor.js +20 -0
- package/dist/providers/tool-failure-tracker.d.ts +1 -0
- package/dist/providers/tool-failure-tracker.js +2 -0
- package/dist/providers/tool-repeat-tracker.d.ts +1 -0
- package/dist/providers/tool-repeat-tracker.js +2 -0
- package/dist/providers/turn-timeout.d.ts +1 -0
- package/dist/providers/turn-timeout.js +1 -0
- package/dist/providers/types.d.ts +834 -0
- package/dist/providers/types.js +42 -0
- package/dist/providers/usage-builder.d.ts +1 -0
- package/dist/providers/usage-builder.js +2 -0
- package/dist/providers/vision-capability.d.ts +109 -0
- package/dist/providers/vision-capability.js +137 -0
- package/dist/python/mlx-runtime-status-bus.d.ts +39 -0
- package/dist/python/mlx-runtime-status-bus.js +27 -0
- package/dist/python/uv-runtime.d.ts +176 -0
- package/dist/python/uv-runtime.js +492 -0
- package/dist/relevance/install.d.ts +28 -0
- package/dist/relevance/install.js +114 -0
- package/dist/relevance/manager.d.ts +79 -0
- package/dist/relevance/manager.js +211 -0
- package/dist/relevance/registry.d.ts +11 -0
- package/dist/relevance/registry.js +158 -0
- package/dist/relevance/relevance-core.d.ts +67 -0
- package/dist/relevance/relevance-core.js +189 -0
- package/dist/relevance/relevance-model.d.ts +42 -0
- package/dist/relevance/relevance-model.js +292 -0
- package/dist/relevance/relevance-worker.d.ts +20 -0
- package/dist/relevance/relevance-worker.js +57 -0
- package/dist/relevance/settings.d.ts +30 -0
- package/dist/relevance/settings.js +81 -0
- package/dist/remotes/identity.d.ts +121 -0
- package/dist/remotes/identity.js +348 -0
- package/dist/remotes/pinned-fetch.d.ts +45 -0
- package/dist/remotes/pinned-fetch.js +193 -0
- package/dist/remotes/types.d.ts +54 -0
- package/dist/remotes/types.js +1 -0
- package/dist/runtime-lock.d.ts +29 -0
- package/dist/runtime-lock.js +85 -0
- package/dist/search/relevance-stage.d.ts +81 -0
- package/dist/search/relevance-stage.js +177 -0
- package/dist/secrets/types.d.ts +63 -0
- package/dist/secrets/types.js +64 -0
- package/dist/speech.d.ts +1 -0
- package/dist/speech.js +1 -0
- package/dist/system/darwin-memory.d.ts +26 -0
- package/dist/system/darwin-memory.js +81 -0
- package/dist/system/gezel-process-memory.d.ts +55 -0
- package/dist/system/gezel-process-memory.js +156 -0
- package/dist/system/memory.d.ts +154 -0
- package/dist/system/memory.js +501 -0
- package/dist/transformers-cache.d.ts +112 -0
- package/dist/transformers-cache.js +392 -0
- package/dist/utils/disk-space.d.ts +55 -0
- package/dist/utils/disk-space.js +72 -0
- package/dist/utils/download-common.d.ts +138 -0
- package/dist/utils/download-common.js +196 -0
- package/dist/utils/download-with-retry.d.ts +85 -0
- package/dist/utils/download-with-retry.js +522 -0
- package/dist/utils/extract-zip.d.ts +22 -0
- package/dist/utils/extract-zip.js +103 -0
- package/dist/utils/retire-model-worker.d.ts +15 -0
- package/dist/utils/retire-model-worker.js +24 -0
- package/dist/utils/service-worker-entry.d.ts +59 -0
- package/dist/utils/service-worker-entry.js +69 -0
- package/dist/utils/xet-download.d.ts +40 -0
- package/dist/utils/xet-download.js +526 -0
- package/dist/utils/xet.d.ts +86 -0
- package/dist/utils/xet.js +201 -0
- package/package.json +103 -3
- package/scripts/embedding-packaging.cjs +264 -0
- package/scripts/embedding-packaging.d.cts +16 -0
|
@@ -0,0 +1,1011 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local llama.cpp model storage + install pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Storage layout:
|
|
5
|
+
*
|
|
6
|
+
* <home>/engines/llama-cpp/
|
|
7
|
+
* └── models/
|
|
8
|
+
* └── <model-id>/
|
|
9
|
+
* ├── manifest.json (snapshot of catalog metadata + install info)
|
|
10
|
+
* └── <weights>.gguf (the actual weights, original filename preserved)
|
|
11
|
+
*
|
|
12
|
+
* Install flow:
|
|
13
|
+
* 1. Look up the chat-model entry in the catalog.
|
|
14
|
+
* 2. Stream the GGUF from
|
|
15
|
+
* `huggingface.co/<repo>/resolve/<revision>/<filename>` (the pinned
|
|
16
|
+
* commit SHA, or `main` for legacy manifests) to a `.partial`
|
|
17
|
+
* file, hashing as we go.
|
|
18
|
+
* 3. Verify the computed sha256 against the manifest's expected value.
|
|
19
|
+
* 4. Run the GGUF header parser to extract context window + chat-template
|
|
20
|
+
* presence. Surface a non-fatal warning when `tokenizer.chat_template`
|
|
21
|
+
* is missing — llama-server otherwise silently uses the wrong
|
|
22
|
+
* template (the gemma4 footgun the Phase-0 spike caught).
|
|
23
|
+
* 5. Atomically rename `.partial` → final filename and write
|
|
24
|
+
* `manifest.json`.
|
|
25
|
+
*
|
|
26
|
+
* Delete flow:
|
|
27
|
+
* - Remove the per-model directory in one shot.
|
|
28
|
+
*
|
|
29
|
+
* Resolve-current flow:
|
|
30
|
+
* - Pick the first installed model (alphabetical) when ChatManager
|
|
31
|
+
* wants a default model path. Phase 2 keeps "current" implicit; a
|
|
32
|
+
* proper picker lives in the UI.
|
|
33
|
+
*/
|
|
34
|
+
import { createHash } from 'node:crypto';
|
|
35
|
+
import { createReadStream } from 'node:fs';
|
|
36
|
+
import { mkdir, readFile, readdir, rename, rm, stat, writeFile } from 'node:fs/promises';
|
|
37
|
+
import { basename, join, resolve } from 'node:path';
|
|
38
|
+
import { createLogger } from '@bendyline/gezel';
|
|
39
|
+
import { listBundleModelFiles, publishStagedModel, safeBundleModelPath, } from '../../models/bundle-storage.js';
|
|
40
|
+
import { evaluateCatalogDrift } from '../../models/catalog-drift.js';
|
|
41
|
+
import { catalogPayloadFingerprint, describeCatalogPayload, } from '../../models/catalog-payload-identity.js';
|
|
42
|
+
import { MODEL_HASH_READ_BUFFER_BYTES, assertModelStorePathSafe, findModelRoot, findRenamedModelId, hashModelPayloadFiles, inspectModelDirectory, listIncompleteModelDownloads, listOverlayModelIds, makeSharedModelReadable, modelExistsOnlyReadOnly, modelStorageRoots, pruneModelPayloadFiles, readOnlyModelError, removeModelDir, verifyReadOnlyModelPayload, } from '../../models/storage-roots.js';
|
|
43
|
+
import { checkDiskSpace, describeDiskShortfall } from '../../utils/disk-space.js';
|
|
44
|
+
import { downloadWithRetry } from '../../utils/download-with-retry.js';
|
|
45
|
+
import { ggufQuantizationTag, readGgufSummary } from './gguf-metadata.js';
|
|
46
|
+
import { backfillGgufQuantization } from './gguf-quantization-backfill.js';
|
|
47
|
+
/**
|
|
48
|
+
* How often to emit a `progress` event during a download. Anything
|
|
49
|
+
* shorter than 250ms wastes CPU on JSON serialization for the SSE
|
|
50
|
+
* stream; anything longer feels laggy in the UI's progress bar.
|
|
51
|
+
*/
|
|
52
|
+
const PROGRESS_INTERVAL_MS = 250;
|
|
53
|
+
const log = createLogger('models');
|
|
54
|
+
export class LlamaCppModelManager {
|
|
55
|
+
modelsRoot;
|
|
56
|
+
storageRoots;
|
|
57
|
+
catalog;
|
|
58
|
+
fetchImpl;
|
|
59
|
+
engine;
|
|
60
|
+
onInstalled;
|
|
61
|
+
/**
|
|
62
|
+
* In-flight installs. `install()` registers an entry on first yield
|
|
63
|
+
* and clears it in the iterator's `finally` block, so consumers
|
|
64
|
+
* (HTTP `/active-installs`, polling React UI) always see the live
|
|
65
|
+
* subset regardless of which code path drove the install.
|
|
66
|
+
*/
|
|
67
|
+
activeInstalls = new Map();
|
|
68
|
+
/**
|
|
69
|
+
* Model directories we've already warned about skipping. `listInstalled`
|
|
70
|
+
* runs on every picker/settings poll; a broken directory should be loud
|
|
71
|
+
* exactly once per process, not once per poll.
|
|
72
|
+
*/
|
|
73
|
+
skipWarned = new Set();
|
|
74
|
+
constructor(opts) {
|
|
75
|
+
this.engine = opts.engine ?? 'llama-cpp';
|
|
76
|
+
this.storageRoots = modelStorageRoots({ home: opts.home, engine: this.engine });
|
|
77
|
+
this.modelsRoot = this.storageRoots.writableRoot;
|
|
78
|
+
this.catalog = opts.catalog;
|
|
79
|
+
this.fetchImpl = opts.fetchImpl ?? fetch;
|
|
80
|
+
this.onInstalled = opts.onInstalled;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The catalog source block this manager downloads from — `ds4` for the
|
|
84
|
+
* DwarfStar engine, `llamaCpp` otherwise. Cast to the llama.cpp source
|
|
85
|
+
* shape. The common downloader accepts the union directly so engine-specific
|
|
86
|
+
* sidecars (`mmproj` versus `visionEncoder`) keep their honest catalog names.
|
|
87
|
+
*/
|
|
88
|
+
srcBlock(manifest) {
|
|
89
|
+
return this.engine === 'ds4' ? manifest.ds4 : manifest.llamaCpp;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Snapshot of installs currently running. Used by the Settings UI to
|
|
93
|
+
* mirror background bootstrap installs into its progress view — the
|
|
94
|
+
* first-run download fires server-side via direct method call (not
|
|
95
|
+
* the HTTP install route), so the React component has no live SSE
|
|
96
|
+
* stream to consume; polling this surface fills the gap.
|
|
97
|
+
*/
|
|
98
|
+
getActiveInstalls() {
|
|
99
|
+
// Return shallow copies so the caller can't mutate our state.
|
|
100
|
+
return Array.from(this.activeInstalls.values()).map((entry) => ({ ...entry }));
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* List installed models in alphabetical order. Tolerates malformed or
|
|
104
|
+
* partial directories — they're skipped, not surfaced as errors.
|
|
105
|
+
*/
|
|
106
|
+
async listInstalled() {
|
|
107
|
+
const entries = await listOverlayModelIds(this.storageRoots);
|
|
108
|
+
const out = [];
|
|
109
|
+
for (const id of entries) {
|
|
110
|
+
const summary = await this.loadInstalled(id);
|
|
111
|
+
if (!summary) {
|
|
112
|
+
this.warnSkip(id, 'no readable manifest.json (incomplete or interrupted download?)');
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
// Drift flag: does the catalog now describe different weights than the
|
|
116
|
+
// ones on disk? Best-effort — a catalog miss (third-party / removed
|
|
117
|
+
// entry) leaves it un-flagged.
|
|
118
|
+
const status = await this.evaluateDrift(id, summary).catch(() => null);
|
|
119
|
+
if (status?.updateAvailable) {
|
|
120
|
+
summary.updateAvailable = true;
|
|
121
|
+
if (status.availableVersion)
|
|
122
|
+
summary.availableVersion = status.availableVersion;
|
|
123
|
+
if (status.reason)
|
|
124
|
+
summary.updateReason = status.reason;
|
|
125
|
+
}
|
|
126
|
+
out.push(summary);
|
|
127
|
+
}
|
|
128
|
+
out.sort((a, b) => a.name.localeCompare(b.name));
|
|
129
|
+
return out;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* List incomplete downloads for this engine — interrupted or unverified
|
|
133
|
+
* downloads that hold bytes on disk but have no `manifest.json`, so they
|
|
134
|
+
* never appear in {@link listInstalled}. Each is tagged `resumable` when
|
|
135
|
+
* its id still resolves to a catalog entry this engine can source, so the
|
|
136
|
+
* UI can offer resume (re-install picks up from the `.partial`) vs
|
|
137
|
+
* delete-only for stale ids. In-flight installs are excluded.
|
|
138
|
+
*/
|
|
139
|
+
async listIncomplete() {
|
|
140
|
+
const activeIds = new Set(this.activeInstalls.keys());
|
|
141
|
+
const rows = await listIncompleteModelDownloads({ writableRoot: this.modelsRoot, activeIds });
|
|
142
|
+
const out = [];
|
|
143
|
+
for (const row of rows) {
|
|
144
|
+
let resumable = false;
|
|
145
|
+
let name;
|
|
146
|
+
if (isSafeId(row.id)) {
|
|
147
|
+
const detail = await this.catalog.get('chat-model', row.id).catch(() => null);
|
|
148
|
+
if (detail && detail.manifest.kind === 'chat-model' && this.srcBlock(detail.manifest)) {
|
|
149
|
+
resumable = true;
|
|
150
|
+
name = detail.manifest.name;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
out.push({ ...row, resumable, ...(name ? { name } : {}) });
|
|
154
|
+
}
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Model directories that do have a manifest, but whose metadata cannot be
|
|
159
|
+
* loaded by this build. These used to disappear from every inventory
|
|
160
|
+
* surface: `listInstalled()` correctly refused to run them, while the
|
|
161
|
+
* incomplete-download scan correctly ignored anything with a manifest.
|
|
162
|
+
* Keep that safety boundary, but return a management-only row so Settings
|
|
163
|
+
* can update a known catalog id or explicitly remove the held bytes.
|
|
164
|
+
*/
|
|
165
|
+
async listUnrecognized() {
|
|
166
|
+
const rows = [];
|
|
167
|
+
for (const id of await listOverlayModelIds(this.storageRoots)) {
|
|
168
|
+
if (!isSafeId(id))
|
|
169
|
+
continue;
|
|
170
|
+
const root = await findModelRoot(this.storageRoots, id);
|
|
171
|
+
// Manifestless directories belong to listIncomplete(), not this state.
|
|
172
|
+
if (!root)
|
|
173
|
+
continue;
|
|
174
|
+
if (await this.loadInstalled(id))
|
|
175
|
+
continue;
|
|
176
|
+
const profile = await inspectModelDirectory(join(root, id));
|
|
177
|
+
if (!profile || profile.bytes === 0)
|
|
178
|
+
continue;
|
|
179
|
+
const raw = await readFile(join(root, id, 'manifest.json'), 'utf8').catch(() => null);
|
|
180
|
+
let legacyName;
|
|
181
|
+
let reason = "Gezel couldn't read this model's metadata.";
|
|
182
|
+
if (raw !== null) {
|
|
183
|
+
try {
|
|
184
|
+
const parsed = JSON.parse(raw);
|
|
185
|
+
if (typeof parsed.name === 'string' && parsed.name.trim())
|
|
186
|
+
legacyName = parsed.name;
|
|
187
|
+
reason =
|
|
188
|
+
typeof parsed.filename === 'string' && typeof parsed.weightsFilename !== 'string'
|
|
189
|
+
? 'This model was installed by an older version of Gezel and its metadata needs updating.'
|
|
190
|
+
: 'This model metadata is incomplete or does not match the current format.';
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
reason = "This model's metadata file is not valid JSON.";
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
const detail = await this.catalog.get('chat-model', id).catch(() => null);
|
|
197
|
+
const catalogManifest = detail?.manifest.kind === 'chat-model' ? detail.manifest : undefined;
|
|
198
|
+
const canUpdate = Boolean(catalogManifest && this.srcBlock(catalogManifest));
|
|
199
|
+
const name = catalogManifest?.name ?? legacyName;
|
|
200
|
+
rows.push({
|
|
201
|
+
id,
|
|
202
|
+
...(name ? { name } : {}),
|
|
203
|
+
bytes: profile.bytes,
|
|
204
|
+
updatedAt: profile.updatedAt,
|
|
205
|
+
reason,
|
|
206
|
+
canUpdate,
|
|
207
|
+
...(resolve(root) !== resolve(this.storageRoots.writableRoot) ? { readOnly: true } : {}),
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
rows.sort((a, b) => b.bytes - a.bytes);
|
|
211
|
+
return rows;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Path of the first installed model, or null when none exist. Phase 2
|
|
215
|
+
* uses this to pick a default `--model` arg for the supervised
|
|
216
|
+
* llama-server when the user hasn't explicitly chosen one. A "default
|
|
217
|
+
* model" UI lives in Phase 3.
|
|
218
|
+
*/
|
|
219
|
+
async resolveDefaultModelPath() {
|
|
220
|
+
const model = await this.resolveDefaultModel();
|
|
221
|
+
return model?.weightsPath ?? null;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Summary of the first installed model (or null). Same fall-through
|
|
225
|
+
* rule as {@link resolveDefaultModelPath}; returns the full summary
|
|
226
|
+
* so callers like `buildLlamaCppProvider` can pick up the manifest's
|
|
227
|
+
* `contextWindow` along with the path.
|
|
228
|
+
*/
|
|
229
|
+
async resolveDefaultModel() {
|
|
230
|
+
const models = await this.listInstalled();
|
|
231
|
+
return models[0] ?? null;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Path of a specific installed model, or null when not installed.
|
|
235
|
+
* Used by ChatManager when the user has picked a model explicitly.
|
|
236
|
+
*/
|
|
237
|
+
async resolveModelPath(id) {
|
|
238
|
+
const summary = await this.loadInstalled(id);
|
|
239
|
+
return summary?.weightsPath ?? null;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Full summary for a specific installed model, or null when not
|
|
243
|
+
* installed. Used when the user has pinned a default model via
|
|
244
|
+
* `config.defaultModel['llama-cpp']` — `buildLlamaCppProvider`
|
|
245
|
+
* needs the `contextWindow` to set `--ctx-size` correctly.
|
|
246
|
+
*/
|
|
247
|
+
async resolveModel(id) {
|
|
248
|
+
return this.loadInstalled(id);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Whether a genuinely newer build of one installed model exists. Null when
|
|
252
|
+
* the id isn't installed for this engine. Shared with the chat manager's
|
|
253
|
+
* per-session staleness notice so a user is never told to re-download for a
|
|
254
|
+
* change that only touched metadata.
|
|
255
|
+
*/
|
|
256
|
+
async getUpdateStatus(id) {
|
|
257
|
+
const summary = await this.loadInstalled(id);
|
|
258
|
+
if (!summary)
|
|
259
|
+
return null;
|
|
260
|
+
return this.evaluateDrift(id, summary).catch(() => ({ updateAvailable: false }));
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Compare one installed copy against the live catalog. The catalog lookup
|
|
264
|
+
* runs for every model on every inventory poll; the manifest re-read only
|
|
265
|
+
* happens for the few whose version actually moved.
|
|
266
|
+
*/
|
|
267
|
+
async evaluateDrift(id, summary) {
|
|
268
|
+
const installedVersion = summary.catalogVersion;
|
|
269
|
+
if (!installedVersion)
|
|
270
|
+
return { updateAvailable: false };
|
|
271
|
+
const detail = await this.catalog.get('chat-model', id).catch(() => null);
|
|
272
|
+
if (!detail || detail.manifest.kind !== 'chat-model')
|
|
273
|
+
return { updateAvailable: false };
|
|
274
|
+
if (detail.manifest.version === installedVersion)
|
|
275
|
+
return { updateAvailable: false };
|
|
276
|
+
const root = await findModelRoot(this.storageRoots, id);
|
|
277
|
+
if (!root)
|
|
278
|
+
return { updateAvailable: false };
|
|
279
|
+
const modelDir = join(root, id);
|
|
280
|
+
const parsed = await readFile(join(modelDir, 'manifest.json'), 'utf8')
|
|
281
|
+
.then((raw) => JSON.parse(raw))
|
|
282
|
+
.catch(() => null);
|
|
283
|
+
if (!parsed)
|
|
284
|
+
return { updateAvailable: false };
|
|
285
|
+
return evaluateCatalogDrift({
|
|
286
|
+
engine: this.engine,
|
|
287
|
+
id,
|
|
288
|
+
modelDir,
|
|
289
|
+
manifest: detail.manifest,
|
|
290
|
+
installedVersion,
|
|
291
|
+
installed: {
|
|
292
|
+
...(parsed.huggingfaceRepo ? { huggingfaceRepo: parsed.huggingfaceRepo } : {}),
|
|
293
|
+
...(parsed.payloadFingerprint ? { payloadFingerprint: parsed.payloadFingerprint } : {}),
|
|
294
|
+
...(parsed.fileSha256 ? { fileSha256: parsed.fileSha256 } : {}),
|
|
295
|
+
},
|
|
296
|
+
healable: !summary.readOnly && !this.activeInstalls.has(id),
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
async delete(id) {
|
|
300
|
+
if (!isSafeId(id))
|
|
301
|
+
throw new Error(`refusing to delete with unsafe id: ${id}`);
|
|
302
|
+
if (await modelExistsOnlyReadOnly(this.storageRoots, id)) {
|
|
303
|
+
throw readOnlyModelError(id);
|
|
304
|
+
}
|
|
305
|
+
await removeModelDir(join(this.modelsRoot, id), this.modelsRoot);
|
|
306
|
+
}
|
|
307
|
+
/** Provider-owned snapshot used by the streaming `.gezmodel` exporter. */
|
|
308
|
+
async getModelBundleSource(id) {
|
|
309
|
+
if (!isSafeId(id))
|
|
310
|
+
throw new Error(`unsafe model id: ${id}`);
|
|
311
|
+
const summary = await this.loadInstalled(id);
|
|
312
|
+
if (!summary)
|
|
313
|
+
throw new Error(`model "${id}" is not available locally for ${this.engine}`);
|
|
314
|
+
const root = await findModelRoot(this.storageRoots, id);
|
|
315
|
+
if (!root)
|
|
316
|
+
throw new Error(`model "${id}" is not available locally for ${this.engine}`);
|
|
317
|
+
const modelDir = join(root, id);
|
|
318
|
+
const installedManifest = JSON.parse(await readFile(join(modelDir, 'manifest.json'), 'utf8'));
|
|
319
|
+
return {
|
|
320
|
+
id,
|
|
321
|
+
name: summary.name,
|
|
322
|
+
modelDir,
|
|
323
|
+
installedManifest,
|
|
324
|
+
modelFiles: await listBundleModelFiles(modelDir),
|
|
325
|
+
...(summary.catalogVersion ? { catalogVersion: summary.catalogVersion } : {}),
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Validate provider-specific invariants, write the local install manifest,
|
|
330
|
+
* and atomically publish a security-scanned staged bundle.
|
|
331
|
+
*/
|
|
332
|
+
async importModelBundle(opts) {
|
|
333
|
+
if (!isSafeId(opts.id))
|
|
334
|
+
throw new Error(`unsafe model id: ${opts.id}`);
|
|
335
|
+
const parsed = opts.installedManifest;
|
|
336
|
+
if (parsed.id !== opts.id || !parsed.name || !parsed.weightsFilename || !parsed.installedAt) {
|
|
337
|
+
throw new Error('installed manifest does not describe the bundled model');
|
|
338
|
+
}
|
|
339
|
+
const files = await listBundleModelFiles(opts.stagedModelDir);
|
|
340
|
+
if (files.length === 0 || files.some((file) => !file.toLowerCase().endsWith('.gguf'))) {
|
|
341
|
+
throw new Error(`${this.engine} bundles may contain only GGUF model files`);
|
|
342
|
+
}
|
|
343
|
+
if (!files.includes(parsed.weightsFilename)) {
|
|
344
|
+
throw new Error(`installed manifest references missing weights: ${parsed.weightsFilename}`);
|
|
345
|
+
}
|
|
346
|
+
if (parsed.shards?.some((shard) => !files.includes(shard.filename))) {
|
|
347
|
+
throw new Error('installed manifest references a missing GGUF shard');
|
|
348
|
+
}
|
|
349
|
+
if (parsed.mmprojFilename && !files.includes(parsed.mmprojFilename)) {
|
|
350
|
+
throw new Error('installed manifest references a missing multimodal projector');
|
|
351
|
+
}
|
|
352
|
+
if (parsed.visionEncoderFilename && !files.includes(parsed.visionEncoderFilename)) {
|
|
353
|
+
throw new Error('installed manifest references a missing ds4 vision encoder');
|
|
354
|
+
}
|
|
355
|
+
if (parsed.draftModelFilename && !files.includes(parsed.draftModelFilename)) {
|
|
356
|
+
throw new Error('installed manifest references a missing speculative draft model');
|
|
357
|
+
}
|
|
358
|
+
// Parsing the GGUF header is the same final usability check a network
|
|
359
|
+
// install performs after checksum verification.
|
|
360
|
+
readGgufSummary(safeBundleModelPath(opts.stagedModelDir, parsed.weightsFilename));
|
|
361
|
+
const importedManifest = {
|
|
362
|
+
...parsed,
|
|
363
|
+
fileSha256: await hashModelPayloadFiles(opts.stagedModelDir),
|
|
364
|
+
};
|
|
365
|
+
await writeFile(join(opts.stagedModelDir, 'manifest.json'), `${JSON.stringify(importedManifest, null, 2)}\n`, 'utf8');
|
|
366
|
+
await publishStagedModel({
|
|
367
|
+
modelsRoot: this.modelsRoot,
|
|
368
|
+
id: opts.id,
|
|
369
|
+
stagedModelDir: opts.stagedModelDir,
|
|
370
|
+
replace: opts.replace,
|
|
371
|
+
});
|
|
372
|
+
await makeSharedModelReadable(join(this.modelsRoot, opts.id));
|
|
373
|
+
try {
|
|
374
|
+
this.onInstalled?.({ engine: this.engine, id: opts.id });
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
// A post-install fitness hook is best-effort, as in the download path.
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Install a model from the catalog. Yields progress / verifying /
|
|
382
|
+
* extracting-metadata / done events. Yields exactly one terminal
|
|
383
|
+
* event (`done` or `error`) and is safe to consume to completion.
|
|
384
|
+
*
|
|
385
|
+
* Existing weights at the target id are atomically replaced — the
|
|
386
|
+
* download writes to a `.partial` sibling and renames into place
|
|
387
|
+
* only after sha256 verification passes. Failed installs leave the
|
|
388
|
+
* previous weights untouched.
|
|
389
|
+
*/
|
|
390
|
+
async *install(catalogId, options) {
|
|
391
|
+
const skipSha = options?.skipSha === true;
|
|
392
|
+
// Default ON — see `planDownloads`. ds4 passes `false` because it has no
|
|
393
|
+
// llama.cpp mmproj; its own `visionEncoder` remains mandatory and is not
|
|
394
|
+
// governed by this flag.
|
|
395
|
+
const includeMmproj = options?.includeMmproj !== false;
|
|
396
|
+
if (!isSafeId(catalogId)) {
|
|
397
|
+
yield { type: 'error', error: `unsafe catalog id: ${catalogId}` };
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
// Two concurrent installs of the same catalog id would both write
|
|
401
|
+
// to the same `weights.gguf.partial` and produce a corrupt
|
|
402
|
+
// (sha-mismatched) file. Claim the slot SYNCHRONOUSLY (before any
|
|
403
|
+
// `await`) so a parallel call observing `has(...) === false` and
|
|
404
|
+
// entering the same window can't slip in between our check and
|
|
405
|
+
// set. The placeholder snapshot is filled in once the catalog
|
|
406
|
+
// lookup succeeds. Hits when the first-run bootstrap and the
|
|
407
|
+
// Home banner's limbo recovery fire on the same boot.
|
|
408
|
+
if (this.activeInstalls.has(catalogId)) {
|
|
409
|
+
yield {
|
|
410
|
+
type: 'error',
|
|
411
|
+
error: `install for "${catalogId}" is already in progress`,
|
|
412
|
+
};
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
const tracked = {
|
|
416
|
+
catalogId,
|
|
417
|
+
bytesWritten: 0,
|
|
418
|
+
totalBytes: 0,
|
|
419
|
+
phase: 'downloading',
|
|
420
|
+
startedAt: new Date().toISOString(),
|
|
421
|
+
};
|
|
422
|
+
this.activeInstalls.set(catalogId, tracked);
|
|
423
|
+
try {
|
|
424
|
+
const detail = await this.catalog.get('chat-model', catalogId);
|
|
425
|
+
if (!detail || detail.manifest.kind !== 'chat-model') {
|
|
426
|
+
yield { type: 'error', error: `chat-model "${catalogId}" not in catalog` };
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
const manifest = detail.manifest;
|
|
430
|
+
const installSrc = this.srcBlock(manifest);
|
|
431
|
+
if (!installSrc) {
|
|
432
|
+
yield {
|
|
433
|
+
type: 'error',
|
|
434
|
+
error: `chat-model "${catalogId}" has no ${this.engine} source`,
|
|
435
|
+
};
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
tracked.totalBytes = installSrc.approxSizeBytes;
|
|
439
|
+
yield* this.runInstall(catalogId, manifest, tracked, skipSha, includeMmproj);
|
|
440
|
+
}
|
|
441
|
+
finally {
|
|
442
|
+
this.activeInstalls.delete(catalogId);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Inner install loop. Splitting it out lets {@link install} wrap the
|
|
447
|
+
* generator in a `try/finally` that clears the active-install
|
|
448
|
+
* registration on every exit path, including caller break/throw —
|
|
449
|
+
* the equivalent inline construction would require interleaving the
|
|
450
|
+
* cleanup with each early `return` and silently rot.
|
|
451
|
+
*/
|
|
452
|
+
async *runInstall(catalogId, manifest, tracked, skipSha, includeMmproj) {
|
|
453
|
+
const src = this.srcBlock(manifest);
|
|
454
|
+
if (!src) {
|
|
455
|
+
yield { type: 'error', error: `chat-model "${catalogId}" has no ${this.engine} source` };
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
const itemDir = join(this.modelsRoot, catalogId);
|
|
459
|
+
await mkdir(this.modelsRoot, { recursive: true });
|
|
460
|
+
await assertModelStorePathSafe(this.modelsRoot, itemDir);
|
|
461
|
+
await mkdir(itemDir, { recursive: true });
|
|
462
|
+
await assertModelStorePathSafe(this.modelsRoot, itemDir);
|
|
463
|
+
const plan = planDownloads(src, includeMmproj);
|
|
464
|
+
if (plan.length === 0) {
|
|
465
|
+
yield {
|
|
466
|
+
type: 'error',
|
|
467
|
+
error: `chat-model "${catalogId}" ${this.engine} source has neither filename nor shards`,
|
|
468
|
+
};
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
const totalPlanned = plan.reduce((sum, e) => sum + e.sizeBytes, 0) || src.approxSizeBytes;
|
|
472
|
+
tracked.totalBytes = totalPlanned;
|
|
473
|
+
// sha256 of each verified file, keyed by its final relative path (flat,
|
|
474
|
+
// since planDownloads uses basename). Reused to build the fileSha256 map
|
|
475
|
+
// after publish so we don't re-hash the whole payload from disk a second
|
|
476
|
+
// time. `actual` (not the catalog hash) is stored so the skipSha path
|
|
477
|
+
// still records the true on-disk identity.
|
|
478
|
+
const verifiedDigests = {};
|
|
479
|
+
// Files this update doesn't have to fetch because the copy on disk is
|
|
480
|
+
// already the copy the catalog pins. They count as completed bytes from
|
|
481
|
+
// the start, keep their digests, and are left untouched by the publish
|
|
482
|
+
// rename below.
|
|
483
|
+
const reusable = await this.planReusableFiles(itemDir, plan);
|
|
484
|
+
let bytesCompleted = 0;
|
|
485
|
+
for (const entry of plan) {
|
|
486
|
+
const sha = reusable.get(entry.destFilename);
|
|
487
|
+
if (!sha)
|
|
488
|
+
continue;
|
|
489
|
+
verifiedDigests[entry.destFilename] = sha;
|
|
490
|
+
bytesCompleted += entry.sizeBytes;
|
|
491
|
+
}
|
|
492
|
+
if (reusable.size > 0) {
|
|
493
|
+
log.info(`[models] [${this.engine}] "${catalogId}": ${reusable.size} of ${plan.length} file(s) already match the catalog and will not be downloaded`);
|
|
494
|
+
tracked.bytesWritten = bytesCompleted;
|
|
495
|
+
}
|
|
496
|
+
const toFetch = plan.filter((entry) => !reusable.has(entry.destFilename));
|
|
497
|
+
// Preflight the disk before writing a byte. ds4 GGUFs run to 200+ GiB, so
|
|
498
|
+
// discovering ENOSPC at 95% costs hours and leaves a `.partial` occupying
|
|
499
|
+
// the disk it just filled. Only what we actually have to fetch is charged,
|
|
500
|
+
// less any `.partial` already holding part of it, so a resumed install
|
|
501
|
+
// isn't refused for space it already holds. A file being REPLACED is
|
|
502
|
+
// charged in full: its `.partial` lives beside the old copy and the old
|
|
503
|
+
// copy is only deleted at publish, so the update transiently needs room
|
|
504
|
+
// for both.
|
|
505
|
+
const remainingBytes = Math.max(0, toFetch.reduce((sum, e) => sum + e.sizeBytes, 0) -
|
|
506
|
+
(await partialBytesOnDisk(itemDir, toFetch)));
|
|
507
|
+
const space = await checkDiskSpace(itemDir, remainingBytes);
|
|
508
|
+
if (!space.ok) {
|
|
509
|
+
yield { type: 'error', error: describeDiskShortfall(space, manifest.name) };
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
for (let i = 0; i < plan.length; i++) {
|
|
513
|
+
const entry = plan[i];
|
|
514
|
+
if (!entry)
|
|
515
|
+
continue;
|
|
516
|
+
if (reusable.has(entry.destFilename)) {
|
|
517
|
+
yield { type: 'progress', bytesWritten: bytesCompleted, totalBytes: totalPlanned };
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
const destPath = join(itemDir, entry.destFilename);
|
|
521
|
+
const tmpPath = `${destPath}.partial`;
|
|
522
|
+
// Pin to this payload's catalog revision when present. A model-matched
|
|
523
|
+
// vision encoder may live in a different repository from the language
|
|
524
|
+
// GGUF and therefore carries its own repo + revision. Fall back to the
|
|
525
|
+
// parent source and finally `main` for legacy manifests.
|
|
526
|
+
const repo = entry.huggingfaceRepo ?? src.huggingfaceRepo;
|
|
527
|
+
const ref = entry.revision ?? src.revision ?? 'main';
|
|
528
|
+
const url = `https://huggingface.co/${repo}/resolve/${encodeURIComponent(ref)}/${entry.repoPath.split('/').map(encodeURIComponent).join('/')}?download=true`;
|
|
529
|
+
const dlGen = downloadWithRetry({
|
|
530
|
+
url,
|
|
531
|
+
destPath,
|
|
532
|
+
approxSizeBytes: entry.sizeBytes,
|
|
533
|
+
fetchImpl: this.fetchImpl,
|
|
534
|
+
});
|
|
535
|
+
let entryBytesWritten = 0;
|
|
536
|
+
let inlineSha;
|
|
537
|
+
while (true) {
|
|
538
|
+
const step = await dlGen.next();
|
|
539
|
+
if (step.done) {
|
|
540
|
+
if (step.value.kind === 'aborted') {
|
|
541
|
+
yield { type: 'error', error: 'download aborted' };
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
if (step.value.kind === 'error') {
|
|
545
|
+
yield {
|
|
546
|
+
type: 'error',
|
|
547
|
+
error: plan.length > 1
|
|
548
|
+
? `shard ${i + 1}/${plan.length} (${entry.destFilename}): ${step.value.error}`
|
|
549
|
+
: step.value.error,
|
|
550
|
+
};
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
entryBytesWritten = step.value.bytesWritten || entryBytesWritten;
|
|
554
|
+
inlineSha = step.value.sha256;
|
|
555
|
+
break;
|
|
556
|
+
}
|
|
557
|
+
const ev = step.value;
|
|
558
|
+
if (ev.type === 'progress') {
|
|
559
|
+
entryBytesWritten = ev.bytesWritten;
|
|
560
|
+
tracked.bytesWritten = bytesCompleted + entryBytesWritten;
|
|
561
|
+
yield {
|
|
562
|
+
type: 'progress',
|
|
563
|
+
bytesWritten: bytesCompleted + entryBytesWritten,
|
|
564
|
+
totalBytes: totalPlanned,
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
else if (ev.type === 'retrying') {
|
|
568
|
+
yield {
|
|
569
|
+
type: 'retrying',
|
|
570
|
+
attempt: ev.attempt,
|
|
571
|
+
maxAttempts: ev.maxAttempts,
|
|
572
|
+
delayMs: ev.delayMs,
|
|
573
|
+
reason: ev.reason,
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
tracked.phase = 'verifying';
|
|
578
|
+
yield { type: 'verifying' };
|
|
579
|
+
// Prefer the digest the downloader computed inline while streaming —
|
|
580
|
+
// a clean single-pass (HTTP 200) transfer already hashed every byte,
|
|
581
|
+
// so re-reading a multi-GB file off disk just to hash it again is pure
|
|
582
|
+
// waste. Only fall back to the read-back pass when the inline digest
|
|
583
|
+
// is absent (a resumed/appended download, or the Xet path, where the
|
|
584
|
+
// hasher never saw the earlier bytes).
|
|
585
|
+
let actual = inlineSha;
|
|
586
|
+
if (!actual) {
|
|
587
|
+
const hasher = createHash('sha256');
|
|
588
|
+
await new Promise((resolve, reject) => {
|
|
589
|
+
// Big read buffer: a 64 KB stream starves inside the busy daemon
|
|
590
|
+
// event loop (~110k turns for a 7 GB file → 15+ min). See
|
|
591
|
+
// MODEL_HASH_READ_BUFFER_BYTES.
|
|
592
|
+
const stream = createReadStream(tmpPath, {
|
|
593
|
+
highWaterMark: MODEL_HASH_READ_BUFFER_BYTES,
|
|
594
|
+
});
|
|
595
|
+
stream.on('data', (chunk) => hasher.update(chunk));
|
|
596
|
+
stream.on('end', () => resolve());
|
|
597
|
+
stream.on('error', reject);
|
|
598
|
+
});
|
|
599
|
+
actual = hasher.digest('hex');
|
|
600
|
+
}
|
|
601
|
+
verifiedDigests[entry.destFilename] = actual;
|
|
602
|
+
if (actual !== entry.sha256.toLowerCase()) {
|
|
603
|
+
if (skipSha) {
|
|
604
|
+
// User opted in after a previous mismatch surfaced. Keep the
|
|
605
|
+
// `.partial` so the post-loop rename still has something to
|
|
606
|
+
// commit; just stop treating the catalog sha as authoritative.
|
|
607
|
+
}
|
|
608
|
+
else {
|
|
609
|
+
await rm(tmpPath, { force: true });
|
|
610
|
+
yield {
|
|
611
|
+
type: 'error',
|
|
612
|
+
error: `The file '${entry.destFilename}' on Hugging Face has changed since this version of Gezel was published. Expected sha256 ${entry.sha256}, got ${actual}.`,
|
|
613
|
+
mismatch: { file: entry.destFilename, expected: entry.sha256, actual },
|
|
614
|
+
};
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
bytesCompleted += entryBytesWritten;
|
|
619
|
+
tracked.bytesWritten = bytesCompleted;
|
|
620
|
+
// Reset phase back to downloading for the next shard (or stays as
|
|
621
|
+
// verifying if this was the last; the next yielded phase is
|
|
622
|
+
// extracting-metadata below). Keeps the UI's phase pill accurate
|
|
623
|
+
// mid-iteration.
|
|
624
|
+
if (i < plan.length - 1)
|
|
625
|
+
tracked.phase = 'downloading';
|
|
626
|
+
}
|
|
627
|
+
// Parse metadata from the first weights entry (first shard for a
|
|
628
|
+
// sharded install, or the only file for single-file). Sidecars have
|
|
629
|
+
// their own GGUF headers but aren't what llama-server probes for the
|
|
630
|
+
// target model's context length / chat template.
|
|
631
|
+
tracked.phase = 'extracting-metadata';
|
|
632
|
+
yield { type: 'extracting-metadata' };
|
|
633
|
+
const firstWeights = plan.find((e) => e.role === 'weights');
|
|
634
|
+
if (!firstWeights) {
|
|
635
|
+
// Unreachable: planDownloads always emits at least one weights
|
|
636
|
+
// entry when the source is well-formed, and we already errored
|
|
637
|
+
// above when it returned [].
|
|
638
|
+
yield { type: 'error', error: 'internal: download plan has no weights entry' };
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
// A reused file was never re-downloaded, so it has no `.partial` — read
|
|
642
|
+
// the published copy instead.
|
|
643
|
+
const firstWeightsPath = join(itemDir, firstWeights.destFilename);
|
|
644
|
+
const firstTmpPath = reusable.has(firstWeights.destFilename)
|
|
645
|
+
? firstWeightsPath
|
|
646
|
+
: `${firstWeightsPath}.partial`;
|
|
647
|
+
let summary = null;
|
|
648
|
+
try {
|
|
649
|
+
summary = readGgufSummary(firstTmpPath);
|
|
650
|
+
}
|
|
651
|
+
catch (err) {
|
|
652
|
+
// Hash matched but the parser couldn't read the metadata — this
|
|
653
|
+
// should not happen with a real GGUF, but we don't want to leave
|
|
654
|
+
// downloaded-but-unusable files around. Bail loudly.
|
|
655
|
+
for (const entry of plan) {
|
|
656
|
+
await rm(`${join(itemDir, entry.destFilename)}.partial`, { force: true });
|
|
657
|
+
}
|
|
658
|
+
yield {
|
|
659
|
+
type: 'error',
|
|
660
|
+
error: `GGUF metadata parse failed (file is unusable): ${describeError(err)}`,
|
|
661
|
+
};
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
// Atomic publish: rename each .partial into place. If a rename
|
|
665
|
+
// fails partway through, the renamed-already weights stay, the
|
|
666
|
+
// remaining .partials stay; the next install attempt resumes the
|
|
667
|
+
// rest. We bail loudly rather than try to roll back, because
|
|
668
|
+
// partial state is what we already accept on download failure.
|
|
669
|
+
try {
|
|
670
|
+
for (const entry of plan) {
|
|
671
|
+
if (reusable.has(entry.destFilename))
|
|
672
|
+
continue;
|
|
673
|
+
const finalPath = join(itemDir, entry.destFilename);
|
|
674
|
+
await rm(finalPath, { force: true });
|
|
675
|
+
await rename(`${finalPath}.partial`, finalPath);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
catch (err) {
|
|
679
|
+
yield { type: 'error', error: `rename failed: ${describeError(err)}` };
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
// Drop weights left behind by a previous install of this id that used a
|
|
683
|
+
// different quant/filename — otherwise the old GGUF lingers alongside the
|
|
684
|
+
// new one (tens of GB for one slot). Runs before the fileSha256 map is
|
|
685
|
+
// built so the map describes exactly the current payload.
|
|
686
|
+
const pruned = await pruneModelPayloadFiles(itemDir, new Set(plan.map((entry) => entry.destFilename)));
|
|
687
|
+
if (pruned.length > 0) {
|
|
688
|
+
log.info(`[models] [${this.engine}] pruned ${pruned.length} stale file(s) from "${catalogId}": ${pruned.join(', ')}`);
|
|
689
|
+
}
|
|
690
|
+
const weightsShards = plan.filter((e) => e.role === 'weights' || e.role === 'weights-shard');
|
|
691
|
+
const mmprojEntry = plan.find((e) => e.role === 'mmproj');
|
|
692
|
+
const visionEncoderEntry = plan.find((e) => e.role === 'vision-encoder');
|
|
693
|
+
const draftModelEntry = plan.find((e) => e.role === 'draft-model');
|
|
694
|
+
// Snapshot what the catalog said this payload IS, so a later version bump
|
|
695
|
+
// that only edits metadata can be recognized as such without re-reading a
|
|
696
|
+
// byte. Skipped for a skipSha install: those bytes are knowingly not the
|
|
697
|
+
// ones the catalog describes.
|
|
698
|
+
const catalogPayload = describeCatalogPayload(manifest, this.engine);
|
|
699
|
+
const payloadFingerprint = catalogPayload && !skipSha ? catalogPayloadFingerprint(catalogPayload) : undefined;
|
|
700
|
+
// Recorded next to the catalog's tag, never instead of it: the catalog
|
|
701
|
+
// names the build a user chose, the header names what the bytes are.
|
|
702
|
+
const declaredQuantization = ggufQuantizationTag(summary);
|
|
703
|
+
const installed = {
|
|
704
|
+
id: catalogId,
|
|
705
|
+
name: manifest.name,
|
|
706
|
+
// Language weights only. Sidecars are surfaced and budgeted separately;
|
|
707
|
+
// folding them in here makes every vision launch count the encoder twice.
|
|
708
|
+
approxSizeBytes: src.approxSizeBytes,
|
|
709
|
+
weightsFilename: firstWeights.destFilename,
|
|
710
|
+
sha256: firstWeights.sha256.toLowerCase(),
|
|
711
|
+
installedAt: new Date().toISOString(),
|
|
712
|
+
catalogId,
|
|
713
|
+
catalogVersion: manifest.version,
|
|
714
|
+
huggingfaceRepo: src.huggingfaceRepo,
|
|
715
|
+
...(weightsShards.length > 1
|
|
716
|
+
? {
|
|
717
|
+
shards: weightsShards.map((entry) => ({
|
|
718
|
+
filename: entry.destFilename,
|
|
719
|
+
sha256: entry.sha256.toLowerCase(),
|
|
720
|
+
sizeBytes: entry.sizeBytes,
|
|
721
|
+
})),
|
|
722
|
+
}
|
|
723
|
+
: {}),
|
|
724
|
+
...(mmprojEntry ? { mmprojFilename: mmprojEntry.destFilename } : {}),
|
|
725
|
+
...(visionEncoderEntry ? { visionEncoderFilename: visionEncoderEntry.destFilename } : {}),
|
|
726
|
+
...(draftModelEntry ? { draftModelFilename: draftModelEntry.destFilename } : {}),
|
|
727
|
+
...(src.quantization ? { quantization: src.quantization } : {}),
|
|
728
|
+
...(declaredQuantization ? { ggufQuantization: declaredQuantization } : {}),
|
|
729
|
+
...(summary.contextLength ? { contextWindow: Number(summary.contextLength) } : {}),
|
|
730
|
+
...(summary.architecture ? { architecture: summary.architecture } : {}),
|
|
731
|
+
chatTemplatePresent: !summary.chatTemplateMissing,
|
|
732
|
+
...(payloadFingerprint ? { payloadFingerprint } : {}),
|
|
733
|
+
};
|
|
734
|
+
installed.fileSha256 = await hashModelPayloadFiles(itemDir, verifiedDigests);
|
|
735
|
+
await writeFile(join(itemDir, 'manifest.json'), JSON.stringify(installed, null, 2), 'utf8');
|
|
736
|
+
await makeSharedModelReadable(itemDir);
|
|
737
|
+
const warning = summary.chatTemplateMissing
|
|
738
|
+
? 'Model has no embedded chat template (tokenizer.chat_template is missing). llama-server will fall back to a generic template that may not match this model — replies may be incoherent. Consider a different quant of the same model.'
|
|
739
|
+
: undefined;
|
|
740
|
+
try {
|
|
741
|
+
this.onInstalled?.({ engine: this.engine, id: catalogId });
|
|
742
|
+
}
|
|
743
|
+
catch {
|
|
744
|
+
// Fire-and-forget: a hook failure must never fail a completed install.
|
|
745
|
+
}
|
|
746
|
+
yield { type: 'done', id: catalogId, ...(warning ? { warning } : {}) };
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Files the plan asks for that are already on disk as exactly the bytes the
|
|
750
|
+
* catalog pins, keyed by filename with the digest to carry forward.
|
|
751
|
+
*
|
|
752
|
+
* An update usually rotates one thing — a quant, one shard, an added draft
|
|
753
|
+
* companion — and re-fetching the rest is pure waste. The install manifest
|
|
754
|
+
* records a sha256 for every file it published, each verified against the
|
|
755
|
+
* catalog when it landed; where that digest equals the pin we are about to
|
|
756
|
+
* download and the file is still its full length, the bytes on disk ARE the
|
|
757
|
+
* bytes we would fetch. Same trust model as the shared-store adoption cache:
|
|
758
|
+
* a recorded digest plus an unchanged stat is identity.
|
|
759
|
+
*/
|
|
760
|
+
async planReusableFiles(itemDir, plan) {
|
|
761
|
+
const reusable = new Map();
|
|
762
|
+
const parsed = await readFile(join(itemDir, 'manifest.json'), 'utf8')
|
|
763
|
+
.then((raw) => JSON.parse(raw))
|
|
764
|
+
.catch(() => null);
|
|
765
|
+
const recorded = parsed?.fileSha256;
|
|
766
|
+
if (!recorded)
|
|
767
|
+
return reusable;
|
|
768
|
+
for (const entry of plan) {
|
|
769
|
+
const sha = recorded[entry.destFilename]?.toLowerCase();
|
|
770
|
+
if (!sha || sha !== entry.sha256.toLowerCase())
|
|
771
|
+
continue;
|
|
772
|
+
const size = await stat(join(itemDir, entry.destFilename))
|
|
773
|
+
.then((info) => (info.isFile() ? info.size : -1))
|
|
774
|
+
.catch(() => -1);
|
|
775
|
+
if (size !== entry.sizeBytes)
|
|
776
|
+
continue;
|
|
777
|
+
reusable.set(entry.destFilename, sha);
|
|
778
|
+
}
|
|
779
|
+
return reusable;
|
|
780
|
+
}
|
|
781
|
+
/** Warn once per model directory per process, then stay quiet. */
|
|
782
|
+
warnSkip(id, reason) {
|
|
783
|
+
if (this.skipWarned.has(id))
|
|
784
|
+
return;
|
|
785
|
+
this.skipWarned.add(id);
|
|
786
|
+
log.warn(`[${this.engine}] model directory "${id}" is not runnable: ${reason}`);
|
|
787
|
+
}
|
|
788
|
+
async loadInstalled(requestedId) {
|
|
789
|
+
let id = requestedId;
|
|
790
|
+
let root = await findModelRoot(this.storageRoots, id);
|
|
791
|
+
if (!root) {
|
|
792
|
+
// A pin written before the quant-suffix rename still names the old id.
|
|
793
|
+
// Config, gezel frontmatter, eval caches, and session records all hold
|
|
794
|
+
// whatever id was current when they were written.
|
|
795
|
+
const renamed = await findRenamedModelId(this.storageRoots, requestedId);
|
|
796
|
+
if (!renamed)
|
|
797
|
+
return null;
|
|
798
|
+
id = renamed;
|
|
799
|
+
root = await findModelRoot(this.storageRoots, id);
|
|
800
|
+
if (!root)
|
|
801
|
+
return null;
|
|
802
|
+
}
|
|
803
|
+
const metaPath = join(root, id, 'manifest.json');
|
|
804
|
+
let raw;
|
|
805
|
+
try {
|
|
806
|
+
raw = await readFile(metaPath, 'utf8');
|
|
807
|
+
}
|
|
808
|
+
catch {
|
|
809
|
+
this.warnSkip(id, `manifest.json is unreadable at ${metaPath}`);
|
|
810
|
+
return null;
|
|
811
|
+
}
|
|
812
|
+
let parsed;
|
|
813
|
+
try {
|
|
814
|
+
parsed = JSON.parse(raw);
|
|
815
|
+
}
|
|
816
|
+
catch {
|
|
817
|
+
this.warnSkip(id, `manifest.json is not valid JSON at ${metaPath}`);
|
|
818
|
+
return null;
|
|
819
|
+
}
|
|
820
|
+
if (!parsed.id || !parsed.name || !parsed.weightsFilename || !parsed.installedAt) {
|
|
821
|
+
this.warnSkip(id, 'manifest.json is missing required fields (id/name/weightsFilename/installedAt)');
|
|
822
|
+
return null;
|
|
823
|
+
}
|
|
824
|
+
if (!(await verifyReadOnlyModelPayload(this.storageRoots, root, id, parsed.fileSha256, (reason) => this.warnSkip(id, reason)))) {
|
|
825
|
+
return null;
|
|
826
|
+
}
|
|
827
|
+
// Read from disk, not the manifest: `approxSizeBytes` recorded at install
|
|
828
|
+
// is the weights alone whenever the payload was adopted or resumed rather
|
|
829
|
+
// than freshly downloaded, so it cannot be trusted to include the projector.
|
|
830
|
+
const mmprojSizeBytes = parsed.mmprojFilename
|
|
831
|
+
? await stat(join(root, id, parsed.mmprojFilename))
|
|
832
|
+
.then((s) => s.size)
|
|
833
|
+
.catch(() => 0)
|
|
834
|
+
: 0;
|
|
835
|
+
const visionEncoderSizeBytes = parsed.visionEncoderFilename
|
|
836
|
+
? await stat(join(root, id, parsed.visionEncoderFilename))
|
|
837
|
+
.then((s) => s.size)
|
|
838
|
+
.catch(() => 0)
|
|
839
|
+
: 0;
|
|
840
|
+
// Absent on every copy installed before the field existed, and on those
|
|
841
|
+
// the catalog tag is the only thing the table has to show.
|
|
842
|
+
const ggufQuantization = parsed.ggufQuantization ??
|
|
843
|
+
(await backfillGgufQuantization({
|
|
844
|
+
engine: this.engine,
|
|
845
|
+
id,
|
|
846
|
+
modelDir: join(root, id),
|
|
847
|
+
weightsFilename: parsed.weightsFilename,
|
|
848
|
+
...(parsed.quantization ? { catalogQuantization: parsed.quantization } : {}),
|
|
849
|
+
writable: resolve(root) === resolve(this.storageRoots.writableRoot),
|
|
850
|
+
}));
|
|
851
|
+
return {
|
|
852
|
+
id: parsed.id,
|
|
853
|
+
name: parsed.name,
|
|
854
|
+
approxSizeBytes: parsed.approxSizeBytes ?? 0,
|
|
855
|
+
installedAt: parsed.installedAt,
|
|
856
|
+
weightsPath: join(root, id, parsed.weightsFilename),
|
|
857
|
+
...(parsed.mmprojFilename
|
|
858
|
+
? {
|
|
859
|
+
mmprojPath: join(root, id, parsed.mmprojFilename),
|
|
860
|
+
...(mmprojSizeBytes > 0 ? { mmprojSizeBytes } : {}),
|
|
861
|
+
}
|
|
862
|
+
: {}),
|
|
863
|
+
...(parsed.visionEncoderFilename
|
|
864
|
+
? {
|
|
865
|
+
visionEncoderPath: join(root, id, parsed.visionEncoderFilename),
|
|
866
|
+
...(visionEncoderSizeBytes > 0 ? { visionEncoderSizeBytes } : {}),
|
|
867
|
+
}
|
|
868
|
+
: {}),
|
|
869
|
+
...(parsed.draftModelFilename
|
|
870
|
+
? { draftModelPath: join(root, id, parsed.draftModelFilename) }
|
|
871
|
+
: {}),
|
|
872
|
+
...(parsed.contextWindow ? { contextWindow: parsed.contextWindow } : {}),
|
|
873
|
+
...(parsed.quantization ? { quantization: parsed.quantization } : {}),
|
|
874
|
+
...(ggufQuantization ? { ggufQuantization } : {}),
|
|
875
|
+
chatTemplatePresent: parsed.chatTemplatePresent ?? true,
|
|
876
|
+
...(parsed.architecture ? { architecture: parsed.architecture } : {}),
|
|
877
|
+
...(parsed.catalogVersion ? { catalogVersion: parsed.catalogVersion } : {}),
|
|
878
|
+
...(parsed.sha256 ? { sha256: parsed.sha256 } : {}),
|
|
879
|
+
// Read-only when it lives in a machine/shared overlay rather than this
|
|
880
|
+
// daemon's writable root — the delete endpoint refuses it, so the UI
|
|
881
|
+
// must not offer a Delete action that can only 400.
|
|
882
|
+
...(resolve(root) !== resolve(this.storageRoots.writableRoot) ? { readOnly: true } : {}),
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
function describeError(err) {
|
|
887
|
+
return err instanceof Error ? err.message : String(err);
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* Translate a catalog `llamaCpp` source into the ordered list of files
|
|
891
|
+
* to download. Single-file sources collapse to one entry. Sharded
|
|
892
|
+
* sources expand to one entry per shard, flattening any subdirectory
|
|
893
|
+
* in the HF tree to a basename on disk (so `Q4_K_M/foo-00001-of-NNN.gguf`
|
|
894
|
+
* lands as `foo-00001-of-NNN.gguf` next to its siblings — llama-server
|
|
895
|
+
* needs them all in the same directory to auto-discover splits).
|
|
896
|
+
*/
|
|
897
|
+
function planDownloads(src,
|
|
898
|
+
/**
|
|
899
|
+
* Whether to also fetch the vision projector. On by default: fetch what the
|
|
900
|
+
* catalog ships, and let the *runtime* decide whether to load it.
|
|
901
|
+
*
|
|
902
|
+
* This used to be off, on the reasoning that an mmproj-backed server 501s
|
|
903
|
+
* on slot save/restore and so shouldn't be imposed by an install. But the
|
|
904
|
+
* cost is paid at `--mmproj` on the command line, not at download — so
|
|
905
|
+
* withholding the file bought nothing and cost a lot: a user who enabled
|
|
906
|
+
* vision got a model that silently could not see, because the projector
|
|
907
|
+
* had never been fetched and nothing re-fetched it. Turning the toggle on
|
|
908
|
+
* now works immediately instead of requiring a re-install nobody knew to
|
|
909
|
+
* run.
|
|
910
|
+
*
|
|
911
|
+
* This option only governs llama.cpp's `mmproj`; a declared ds4
|
|
912
|
+
* `visionEncoder` is part of that model's install and is always fetched.
|
|
913
|
+
*/
|
|
914
|
+
includeMmproj = true) {
|
|
915
|
+
const out = [];
|
|
916
|
+
if (src.shards && src.shards.length > 0) {
|
|
917
|
+
src.shards.forEach((shard, i) => {
|
|
918
|
+
out.push({
|
|
919
|
+
repoPath: shard.name,
|
|
920
|
+
destFilename: basename(shard.name),
|
|
921
|
+
sha256: shard.sha256,
|
|
922
|
+
sizeBytes: shard.sizeBytes,
|
|
923
|
+
role: i === 0 ? 'weights' : 'weights-shard',
|
|
924
|
+
});
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
else if (src.filename && src.sha256) {
|
|
928
|
+
out.push({
|
|
929
|
+
repoPath: src.filename,
|
|
930
|
+
destFilename: basename(src.filename),
|
|
931
|
+
sha256: src.sha256,
|
|
932
|
+
sizeBytes: src.approxSizeBytes,
|
|
933
|
+
role: 'weights',
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
else {
|
|
937
|
+
return [];
|
|
938
|
+
}
|
|
939
|
+
if (src.mmproj && includeMmproj) {
|
|
940
|
+
out.push({
|
|
941
|
+
repoPath: src.mmproj.filename,
|
|
942
|
+
destFilename: basename(src.mmproj.filename),
|
|
943
|
+
sha256: src.mmproj.sha256,
|
|
944
|
+
sizeBytes: src.mmproj.sizeBytes,
|
|
945
|
+
role: 'mmproj',
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
if (src.visionEncoder) {
|
|
949
|
+
out.push({
|
|
950
|
+
...(src.visionEncoder.huggingfaceRepo
|
|
951
|
+
? { huggingfaceRepo: src.visionEncoder.huggingfaceRepo }
|
|
952
|
+
: {}),
|
|
953
|
+
...(src.visionEncoder.revision ? { revision: src.visionEncoder.revision } : {}),
|
|
954
|
+
repoPath: src.visionEncoder.filename,
|
|
955
|
+
destFilename: basename(src.visionEncoder.filename),
|
|
956
|
+
sha256: src.visionEncoder.sha256,
|
|
957
|
+
sizeBytes: src.visionEncoder.sizeBytes,
|
|
958
|
+
role: 'vision-encoder',
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
// Draft companions are part of the model's selected decoding path, not
|
|
962
|
+
// an optional modality. Download them whenever the catalog ships one so
|
|
963
|
+
// an explicitly selected `draft-mtp`/other draft mode can work immediately
|
|
964
|
+
// after install without a second download.
|
|
965
|
+
if (src.draftModel) {
|
|
966
|
+
out.push({
|
|
967
|
+
repoPath: src.draftModel.filename,
|
|
968
|
+
destFilename: basename(src.draftModel.filename),
|
|
969
|
+
sha256: src.draftModel.sha256,
|
|
970
|
+
sizeBytes: src.draftModel.sizeBytes,
|
|
971
|
+
role: 'draft-model',
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
return out;
|
|
975
|
+
}
|
|
976
|
+
/**
|
|
977
|
+
* Bytes of a still-to-fetch download that a `.partial` already holds — resume
|
|
978
|
+
* credit, so retrying a 200 GiB download that's 90% done isn't refused for
|
|
979
|
+
* space it is already occupying.
|
|
980
|
+
*
|
|
981
|
+
* Deliberately blind to finished files. A previous install's copy of the same
|
|
982
|
+
* filename is NOT credit: the new bytes stream into a `.partial` beside it and
|
|
983
|
+
* the old copy is only removed at publish, so both are on disk at once. (This
|
|
984
|
+
* counted the finished file, which meant an in-place replacement was preflighted
|
|
985
|
+
* as needing nothing at all, and a half-full disk failed with ENOSPC deep into
|
|
986
|
+
* the transfer instead of being refused up front.) Files that don't need
|
|
987
|
+
* fetching at all are excluded by the caller, not credited here.
|
|
988
|
+
*/
|
|
989
|
+
async function partialBytesOnDisk(itemDir, plan) {
|
|
990
|
+
let total = 0;
|
|
991
|
+
for (const entry of plan) {
|
|
992
|
+
const size = await stat(`${join(itemDir, entry.destFilename)}.partial`)
|
|
993
|
+
.then((st) => st.size)
|
|
994
|
+
.catch(() => 0);
|
|
995
|
+
if (size > 0)
|
|
996
|
+
total += Math.min(size, entry.sizeBytes);
|
|
997
|
+
}
|
|
998
|
+
return total;
|
|
999
|
+
}
|
|
1000
|
+
/**
|
|
1001
|
+
* Permissive id check — must be a relative single-segment id, no
|
|
1002
|
+
* traversal. Catalog ids match `[a-z0-9][a-z0-9.\-:]{1,63}` per the
|
|
1003
|
+
* core schema, so anything that flunks this is malicious.
|
|
1004
|
+
*/
|
|
1005
|
+
function isSafeId(id) {
|
|
1006
|
+
if (id.length === 0 || id.length > 64)
|
|
1007
|
+
return false;
|
|
1008
|
+
if (id.includes('/') || id.includes('\\') || id.startsWith('.'))
|
|
1009
|
+
return false;
|
|
1010
|
+
return /^[a-z0-9][a-z0-9.\-:]{0,63}$/i.test(id);
|
|
1011
|
+
}
|