Merge remote-tracking branch 'origin/v2' into feat/router-design

This commit is contained in:
MyPrototypeWhat 2025-12-23 15:00:42 +08:00
commit e63397d5c2
301 changed files with 11418 additions and 3157 deletions

View File

@ -54,7 +54,7 @@ jobs:
yarn install
- name: 🏃‍♀️ Translate
run: yarn sync:i18n && yarn auto:i18n
run: yarn i18n:sync && yarn i18n:translate
- name: 🔍 Format
run: yarn format

View File

@ -58,7 +58,7 @@ jobs:
run: yarn typecheck
- name: i18n Check
run: yarn check:i18n
run: yarn i18n:check
- name: Test
run: yarn test

305
.github/workflows/sync-to-gitcode.yml vendored Normal file
View File

@ -0,0 +1,305 @@
name: Sync Release to GitCode
on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: 'Release tag (e.g. v1.0.0)'
required: true
clean:
description: 'Clean node_modules before build'
type: boolean
default: false
permissions:
contents: read
jobs:
build-and-sync-to-gitcode:
runs-on: [self-hosted, windows-signing]
steps:
- name: Get tag name
id: get-tag
shell: bash
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "tag=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT
else
echo "tag=${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
fi
- name: Check out Git repository
uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ steps.get-tag.outputs.tag }}
- name: Set package.json version
shell: bash
run: |
TAG="${{ steps.get-tag.outputs.tag }}"
VERSION="${TAG#v}"
npm version "$VERSION" --no-git-tag-version --allow-same-version
- name: Install Node.js
uses: actions/setup-node@v6
with:
node-version: 22
- name: Install corepack
shell: bash
run: corepack enable && corepack prepare yarn@4.9.1 --activate
- name: Clean node_modules
if: ${{ github.event.inputs.clean == 'true' }}
shell: bash
run: rm -rf node_modules
- name: Install Dependencies
shell: bash
run: yarn install
- name: Build Windows with code signing
shell: bash
run: yarn build:win
env:
WIN_SIGN: true
CHERRY_CERT_PATH: ${{ secrets.CHERRY_CERT_PATH }}
CHERRY_CERT_KEY: ${{ secrets.CHERRY_CERT_KEY }}
CHERRY_CERT_CSP: ${{ secrets.CHERRY_CERT_CSP }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NODE_OPTIONS: --max-old-space-size=8192
MAIN_VITE_CHERRYAI_CLIENT_SECRET: ${{ secrets.MAIN_VITE_CHERRYAI_CLIENT_SECRET }}
MAIN_VITE_MINERU_API_KEY: ${{ secrets.MAIN_VITE_MINERU_API_KEY }}
RENDERER_VITE_AIHUBMIX_SECRET: ${{ secrets.RENDERER_VITE_AIHUBMIX_SECRET }}
RENDERER_VITE_PPIO_APP_SECRET: ${{ secrets.RENDERER_VITE_PPIO_APP_SECRET }}
- name: List built Windows artifacts
shell: bash
run: |
echo "Built Windows artifacts:"
ls -la dist/*.exe dist/*.blockmap dist/latest*.yml
- name: Download GitHub release assets
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG_NAME: ${{ steps.get-tag.outputs.tag }}
run: |
echo "Downloading release assets for $TAG_NAME..."
mkdir -p release-assets
cd release-assets
# Download all assets from the release
gh release download "$TAG_NAME" \
--repo "${{ github.repository }}" \
--pattern "*" \
--skip-existing
echo "Downloaded GitHub release assets:"
ls -la
- name: Replace Windows files with signed versions
shell: bash
run: |
echo "Replacing Windows files with signed versions..."
# Verify signed files exist first
if ! ls dist/*.exe 1>/dev/null 2>&1; then
echo "ERROR: No signed .exe files found in dist/"
exit 1
fi
# Remove unsigned Windows files from downloaded assets
# *.exe, *.exe.blockmap, latest.yml (Windows only)
rm -f release-assets/*.exe release-assets/*.exe.blockmap release-assets/latest.yml 2>/dev/null || true
# Copy signed Windows files with error checking
cp dist/*.exe release-assets/ || { echo "ERROR: Failed to copy .exe files"; exit 1; }
cp dist/*.exe.blockmap release-assets/ || { echo "ERROR: Failed to copy .blockmap files"; exit 1; }
cp dist/latest.yml release-assets/ || { echo "ERROR: Failed to copy latest.yml"; exit 1; }
echo "Final release assets:"
ls -la release-assets/
- name: Get release info
id: release-info
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG_NAME: ${{ steps.get-tag.outputs.tag }}
LANG: C.UTF-8
LC_ALL: C.UTF-8
run: |
# Always use gh cli to avoid special character issues
RELEASE_NAME=$(gh release view "$TAG_NAME" --repo "${{ github.repository }}" --json name -q '.name')
# Use delimiter to safely handle special characters in release name
{
echo 'name<<EOF'
echo "$RELEASE_NAME"
echo 'EOF'
} >> $GITHUB_OUTPUT
# Extract releaseNotes from electron-builder.yml (from releaseNotes: | to end of file, remove 4-space indent)
sed -n '/releaseNotes: |/,$ { /releaseNotes: |/d; s/^ //; p }' electron-builder.yml > release_body.txt
- name: Create GitCode release and upload files
shell: bash
env:
GITCODE_TOKEN: ${{ secrets.GITCODE_TOKEN }}
GITCODE_OWNER: ${{ vars.GITCODE_OWNER }}
GITCODE_REPO: ${{ vars.GITCODE_REPO }}
GITCODE_API_URL: ${{ vars.GITCODE_API_URL }}
TAG_NAME: ${{ steps.get-tag.outputs.tag }}
RELEASE_NAME: ${{ steps.release-info.outputs.name }}
LANG: C.UTF-8
LC_ALL: C.UTF-8
run: |
# Validate required environment variables
if [ -z "$GITCODE_TOKEN" ]; then
echo "ERROR: GITCODE_TOKEN is not set"
exit 1
fi
if [ -z "$GITCODE_OWNER" ]; then
echo "ERROR: GITCODE_OWNER is not set"
exit 1
fi
if [ -z "$GITCODE_REPO" ]; then
echo "ERROR: GITCODE_REPO is not set"
exit 1
fi
API_URL="${GITCODE_API_URL:-https://api.gitcode.com/api/v5}"
echo "Creating GitCode release..."
echo "Tag: $TAG_NAME"
echo "Repo: $GITCODE_OWNER/$GITCODE_REPO"
# Step 1: Create release
# Use --rawfile to read body directly from file, avoiding shell variable encoding issues
jq -n \
--arg tag "$TAG_NAME" \
--arg name "$RELEASE_NAME" \
--rawfile body release_body.txt \
'{
tag_name: $tag,
name: $name,
body: $body,
target_commitish: "main"
}' > /tmp/release_payload.json
RELEASE_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \
--connect-timeout 30 --max-time 60 \
"${API_URL}/repos/${GITCODE_OWNER}/${GITCODE_REPO}/releases" \
-H "Content-Type: application/json; charset=utf-8" \
-H "Authorization: Bearer ${GITCODE_TOKEN}" \
--data-binary "@/tmp/release_payload.json")
HTTP_CODE=$(echo "$RELEASE_RESPONSE" | tail -n1)
RESPONSE_BODY=$(echo "$RELEASE_RESPONSE" | sed '$d')
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
echo "Release created successfully"
else
echo "Warning: Release creation returned HTTP $HTTP_CODE"
echo "$RESPONSE_BODY"
exit 1
fi
# Step 2: Upload files to release
echo "Uploading files to GitCode release..."
# Function to upload a single file with retry
upload_file() {
local file="$1"
local filename=$(basename "$file")
local max_retries=3
local retry=0
local curl_status=0
echo "Uploading: $filename"
# URL encode the filename
encoded_filename=$(printf '%s' "$filename" | jq -sRr @uri)
while [ $retry -lt $max_retries ]; do
# Get upload URL
curl_status=0
UPLOAD_INFO=$(curl -s --connect-timeout 30 --max-time 60 \
-H "Authorization: Bearer ${GITCODE_TOKEN}" \
"${API_URL}/repos/${GITCODE_OWNER}/${GITCODE_REPO}/releases/${TAG_NAME}/upload_url?file_name=${encoded_filename}") || curl_status=$?
if [ $curl_status -eq 0 ]; then
UPLOAD_URL=$(echo "$UPLOAD_INFO" | jq -r '.url // empty')
if [ -n "$UPLOAD_URL" ]; then
# Write headers to temp file to avoid shell escaping issues
echo "$UPLOAD_INFO" | jq -r '.headers | to_entries[] | "header = \"" + .key + ": " + .value + "\""' > /tmp/upload_headers.txt
# Upload file using PUT with headers from file
curl_status=0
UPLOAD_RESPONSE=$(curl -s -w "\n%{http_code}" -X PUT \
-K /tmp/upload_headers.txt \
--data-binary "@${file}" \
"$UPLOAD_URL") || curl_status=$?
if [ $curl_status -eq 0 ]; then
HTTP_CODE=$(echo "$UPLOAD_RESPONSE" | tail -n1)
RESPONSE_BODY=$(echo "$UPLOAD_RESPONSE" | sed '$d')
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
echo " Uploaded: $filename"
return 0
else
echo " Failed (HTTP $HTTP_CODE), retry $((retry + 1))/$max_retries"
echo " Response: $RESPONSE_BODY"
fi
else
echo " Upload request failed (curl exit $curl_status), retry $((retry + 1))/$max_retries"
fi
else
echo " Failed to get upload URL, retry $((retry + 1))/$max_retries"
echo " Response: $UPLOAD_INFO"
fi
else
echo " Failed to get upload URL (curl exit $curl_status), retry $((retry + 1))/$max_retries"
echo " Response: $UPLOAD_INFO"
fi
retry=$((retry + 1))
[ $retry -lt $max_retries ] && sleep 3
done
echo " Failed: $filename after $max_retries retries"
exit 1
}
# Upload non-yml/json files first
for file in release-assets/*; do
if [ -f "$file" ]; then
filename=$(basename "$file")
if [[ ! "$filename" =~ \.(yml|yaml|json)$ ]]; then
upload_file "$file"
fi
fi
done
# Upload yml/json files last
for file in release-assets/*; do
if [ -f "$file" ]; then
filename=$(basename "$file")
if [[ "$filename" =~ \.(yml|yaml|json)$ ]]; then
upload_file "$file"
fi
fi
done
echo "GitCode release sync completed!"
- name: Cleanup temp files
if: always()
shell: bash
run: |
rm -f /tmp/release_payload.json /tmp/upload_headers.txt release_body.txt
rm -rf release-assets/

View File

@ -1,5 +1,5 @@
diff --git a/dist/index.js b/dist/index.js
index 51ce7e423934fb717cb90245cdfcdb3dae6780e6..0f7f7009e2f41a79a8669d38c8a44867bbff5e1f 100644
index d004b415c5841a1969705823614f395265ea5a8a..6b1e0dad4610b0424393ecc12e9114723bbe316b 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -474,7 +474,7 @@ function convertToGoogleGenerativeAIMessages(prompt, options) {
@ -12,7 +12,7 @@ index 51ce7e423934fb717cb90245cdfcdb3dae6780e6..0f7f7009e2f41a79a8669d38c8a44867
// src/google-generative-ai-options.ts
diff --git a/dist/index.mjs b/dist/index.mjs
index f4b77e35c0cbfece85a3ef0d4f4e67aa6dde6271..8d2fecf8155a226006a0bde72b00b6036d4014b6 100644
index 1780dd2391b7f42224a0b8048c723d2f81222c44..1f12ed14399d6902107ce9b435d7d8e6cc61e06b 100644
--- a/dist/index.mjs
+++ b/dist/index.mjs
@@ -480,7 +480,7 @@ function convertToGoogleGenerativeAIMessages(prompt, options) {
@ -24,3 +24,14 @@ index f4b77e35c0cbfece85a3ef0d4f4e67aa6dde6271..8d2fecf8155a226006a0bde72b00b603
}
// src/google-generative-ai-options.ts
@@ -1909,8 +1909,7 @@ function createGoogleGenerativeAI(options = {}) {
}
var google = createGoogleGenerativeAI();
export {
- VERSION,
createGoogleGenerativeAI,
- google
+ google, VERSION
};
//# sourceMappingURL=index.mjs.map
\ No newline at end of file

View File

@ -1,8 +1,8 @@
diff --git a/dist/index.js b/dist/index.js
index bf900591bf2847a3253fe441aad24c06da19c6c1..c1d9bb6fefa2df1383339324073db0a70ea2b5a2 100644
index 130094d194ea1e8e7d3027d07d82465741192124..4d13dcee8c962ca9ee8f1c3d748f8ffe6a3cfb47 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -274,6 +274,7 @@ var openaiChatResponseSchema = (0, import_provider_utils3.lazyValidator)(
@@ -290,6 +290,7 @@ var openaiChatResponseSchema = (0, import_provider_utils3.lazyValidator)(
message: import_v42.z.object({
role: import_v42.z.literal("assistant").nullish(),
content: import_v42.z.string().nullish(),
@ -10,7 +10,7 @@ index bf900591bf2847a3253fe441aad24c06da19c6c1..c1d9bb6fefa2df1383339324073db0a7
tool_calls: import_v42.z.array(
import_v42.z.object({
id: import_v42.z.string().nullish(),
@@ -340,6 +341,7 @@ var openaiChatChunkSchema = (0, import_provider_utils3.lazyValidator)(
@@ -356,6 +357,7 @@ var openaiChatChunkSchema = (0, import_provider_utils3.lazyValidator)(
delta: import_v42.z.object({
role: import_v42.z.enum(["assistant"]).nullish(),
content: import_v42.z.string().nullish(),
@ -18,7 +18,7 @@ index bf900591bf2847a3253fe441aad24c06da19c6c1..c1d9bb6fefa2df1383339324073db0a7
tool_calls: import_v42.z.array(
import_v42.z.object({
index: import_v42.z.number(),
@@ -795,6 +797,13 @@ var OpenAIChatLanguageModel = class {
@@ -814,6 +816,13 @@ var OpenAIChatLanguageModel = class {
if (text != null && text.length > 0) {
content.push({ type: "text", text });
}
@ -32,7 +32,7 @@ index bf900591bf2847a3253fe441aad24c06da19c6c1..c1d9bb6fefa2df1383339324073db0a7
for (const toolCall of (_a = choice.message.tool_calls) != null ? _a : []) {
content.push({
type: "tool-call",
@@ -876,6 +885,7 @@ var OpenAIChatLanguageModel = class {
@@ -895,6 +904,7 @@ var OpenAIChatLanguageModel = class {
};
let metadataExtracted = false;
let isActiveText = false;
@ -40,7 +40,7 @@ index bf900591bf2847a3253fe441aad24c06da19c6c1..c1d9bb6fefa2df1383339324073db0a7
const providerMetadata = { openai: {} };
return {
stream: response.pipeThrough(
@@ -933,6 +943,21 @@ var OpenAIChatLanguageModel = class {
@@ -952,6 +962,21 @@ var OpenAIChatLanguageModel = class {
return;
}
const delta = choice.delta;
@ -62,7 +62,7 @@ index bf900591bf2847a3253fe441aad24c06da19c6c1..c1d9bb6fefa2df1383339324073db0a7
if (delta.content != null) {
if (!isActiveText) {
controller.enqueue({ type: "text-start", id: "0" });
@@ -1045,6 +1070,9 @@ var OpenAIChatLanguageModel = class {
@@ -1064,6 +1089,9 @@ var OpenAIChatLanguageModel = class {
}
},
flush(controller) {

View File

@ -1,5 +1,5 @@
diff --git a/sdk.mjs b/sdk.mjs
index bf429a344b7d59f70aead16b639f949b07688a81..f77d50cc5d3fb04292cb3ac7fa7085d02dcc628f 100755
index dea7766a3432a1e809f12d6daba4f2834a219689..e0b02ef73da177ba32b903887d7bbbeaa08cc6d3 100755
--- a/sdk.mjs
+++ b/sdk.mjs
@@ -6250,7 +6250,7 @@ function createAbortController(maxListeners = DEFAULT_MAX_LISTENERS) {
@ -11,7 +11,7 @@ index bf429a344b7d59f70aead16b639f949b07688a81..f77d50cc5d3fb04292cb3ac7fa7085d0
import { createInterface } from "readline";
// ../src/utils/fsOperations.ts
@@ -6619,18 +6619,11 @@ class ProcessTransport {
@@ -6644,18 +6644,11 @@ class ProcessTransport {
const errorMessage = isNativeBinary(pathToClaudeCodeExecutable) ? `Claude Code native binary not found at ${pathToClaudeCodeExecutable}. Please ensure Claude Code is installed via native installer or specify a valid path with options.pathToClaudeCodeExecutable.` : `Claude Code executable not found at ${pathToClaudeCodeExecutable}. Is options.pathToClaudeCodeExecutable set?`;
throw new ReferenceError(errorMessage);
}

View File

@ -0,0 +1,145 @@
diff --git a/dist/index.d.ts b/dist/index.d.ts
index 8dd9b498050dbecd8dd6b901acf1aa8ca38a49af..ed644349c9d38fe2a66b2fb44214f7c18eb97f89 100644
--- a/dist/index.d.ts
+++ b/dist/index.d.ts
@@ -4,7 +4,7 @@ import { z } from 'zod/v4';
type OllamaChatModelId = "athene-v2" | "athene-v2:72b" | "aya-expanse" | "aya-expanse:8b" | "aya-expanse:32b" | "codegemma" | "codegemma:2b" | "codegemma:7b" | "codellama" | "codellama:7b" | "codellama:13b" | "codellama:34b" | "codellama:70b" | "codellama:code" | "codellama:python" | "command-r" | "command-r:35b" | "command-r-plus" | "command-r-plus:104b" | "command-r7b" | "command-r7b:7b" | "deepseek-r1" | "deepseek-r1:1.5b" | "deepseek-r1:7b" | "deepseek-r1:8b" | "deepseek-r1:14b" | "deepseek-r1:32b" | "deepseek-r1:70b" | "deepseek-r1:671b" | "deepseek-coder-v2" | "deepseek-coder-v2:16b" | "deepseek-coder-v2:236b" | "deepseek-v3" | "deepseek-v3:671b" | "devstral" | "devstral:24b" | "dolphin3" | "dolphin3:8b" | "exaone3.5" | "exaone3.5:2.4b" | "exaone3.5:7.8b" | "exaone3.5:32b" | "falcon2" | "falcon2:11b" | "falcon3" | "falcon3:1b" | "falcon3:3b" | "falcon3:7b" | "falcon3:10b" | "firefunction-v2" | "firefunction-v2:70b" | "gemma" | "gemma:2b" | "gemma:7b" | "gemma2" | "gemma2:2b" | "gemma2:9b" | "gemma2:27b" | "gemma3" | "gemma3:1b" | "gemma3:4b" | "gemma3:12b" | "gemma3:27b" | "granite3-dense" | "granite3-dense:2b" | "granite3-dense:8b" | "granite3-guardian" | "granite3-guardian:2b" | "granite3-guardian:8b" | "granite3-moe" | "granite3-moe:1b" | "granite3-moe:3b" | "granite3.1-dense" | "granite3.1-dense:2b" | "granite3.1-dense:8b" | "granite3.1-moe" | "granite3.1-moe:1b" | "granite3.1-moe:3b" | "llama2" | "llama2:7b" | "llama2:13b" | "llama2:70b" | "llama3" | "llama3:8b" | "llama3:70b" | "llama3-chatqa" | "llama3-chatqa:8b" | "llama3-chatqa:70b" | "llama3-gradient" | "llama3-gradient:8b" | "llama3-gradient:70b" | "llama3.1" | "llama3.1:8b" | "llama3.1:70b" | "llama3.1:405b" | "llama3.2" | "llama3.2:1b" | "llama3.2:3b" | "llama3.2-vision" | "llama3.2-vision:11b" | "llama3.2-vision:90b" | "llama3.3" | "llama3.3:70b" | "llama4" | "llama4:16x17b" | "llama4:128x17b" | "llama-guard3" | "llama-guard3:1b" | "llama-guard3:8b" | "llava" | "llava:7b" | "llava:13b" | "llava:34b" | "llava-llama3" | "llava-llama3:8b" | "llava-phi3" | "llava-phi3:3.8b" | "marco-o1" | "marco-o1:7b" | "mistral" | "mistral:7b" | "mistral-large" | "mistral-large:123b" | "mistral-nemo" | "mistral-nemo:12b" | "mistral-small" | "mistral-small:22b" | "mixtral" | "mixtral:8x7b" | "mixtral:8x22b" | "moondream" | "moondream:1.8b" | "openhermes" | "openhermes:v2.5" | "nemotron" | "nemotron:70b" | "nemotron-mini" | "nemotron-mini:4b" | "olmo" | "olmo:7b" | "olmo:13b" | "opencoder" | "opencoder:1.5b" | "opencoder:8b" | "phi3" | "phi3:3.8b" | "phi3:14b" | "phi3.5" | "phi3.5:3.8b" | "phi4" | "phi4:14b" | "qwen" | "qwen:7b" | "qwen:14b" | "qwen:32b" | "qwen:72b" | "qwen:110b" | "qwen2" | "qwen2:0.5b" | "qwen2:1.5b" | "qwen2:7b" | "qwen2:72b" | "qwen2.5" | "qwen2.5:0.5b" | "qwen2.5:1.5b" | "qwen2.5:3b" | "qwen2.5:7b" | "qwen2.5:14b" | "qwen2.5:32b" | "qwen2.5:72b" | "qwen2.5-coder" | "qwen2.5-coder:0.5b" | "qwen2.5-coder:1.5b" | "qwen2.5-coder:3b" | "qwen2.5-coder:7b" | "qwen2.5-coder:14b" | "qwen2.5-coder:32b" | "qwen3" | "qwen3:0.6b" | "qwen3:1.7b" | "qwen3:4b" | "qwen3:8b" | "qwen3:14b" | "qwen3:30b" | "qwen3:32b" | "qwen3:235b" | "qwq" | "qwq:32b" | "sailor2" | "sailor2:1b" | "sailor2:8b" | "sailor2:20b" | "shieldgemma" | "shieldgemma:2b" | "shieldgemma:9b" | "shieldgemma:27b" | "smallthinker" | "smallthinker:3b" | "smollm" | "smollm:135m" | "smollm:360m" | "smollm:1.7b" | "tinyllama" | "tinyllama:1.1b" | "tulu3" | "tulu3:8b" | "tulu3:70b" | (string & {});
declare const ollamaProviderOptions: z.ZodObject<{
- think: z.ZodOptional<z.ZodBoolean>;
+ think: z.ZodOptional<z.ZodUnion<[z.ZodBoolean, z.ZodEnum<['low', 'medium', 'high']>]>>;
options: z.ZodOptional<z.ZodObject<{
num_ctx: z.ZodOptional<z.ZodNumber>;
repeat_last_n: z.ZodOptional<z.ZodNumber>;
@@ -27,9 +27,11 @@ interface OllamaCompletionSettings {
* the model's thinking from the model's output. When disabled, the model will not think
* and directly output the content.
*
+ * For gpt-oss models, you can also use 'low', 'medium', or 'high' to control the depth of thinking.
+ *
* Only supported by certain models like DeepSeek R1 and Qwen 3.
*/
- think?: boolean;
+ think?: boolean | 'low' | 'medium' | 'high';
/**
* Echo back the prompt in addition to the completion.
*/
@@ -146,7 +148,7 @@ declare const ollamaEmbeddingProviderOptions: z.ZodObject<{
type OllamaEmbeddingProviderOptions = z.infer<typeof ollamaEmbeddingProviderOptions>;
declare const ollamaCompletionProviderOptions: z.ZodObject<{
- think: z.ZodOptional<z.ZodBoolean>;
+ think: z.ZodOptional<z.ZodUnion<[z.ZodBoolean, z.ZodEnum<['low', 'medium', 'high']>]>>;
user: z.ZodOptional<z.ZodString>;
suffix: z.ZodOptional<z.ZodString>;
echo: z.ZodOptional<z.ZodBoolean>;
diff --git a/dist/index.js b/dist/index.js
index 35b5142ce8476ce2549ed7c2ec48e7d8c46c90d9..2ef64dc9a4c2be043e6af608241a6a8309a5a69f 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -158,7 +158,7 @@ function getResponseMetadata({
// src/completion/ollama-completion-language-model.ts
var ollamaCompletionProviderOptions = import_v42.z.object({
- think: import_v42.z.boolean().optional(),
+ think: import_v42.z.union([import_v42.z.boolean(), import_v42.z.enum(['low', 'medium', 'high'])]).optional(),
user: import_v42.z.string().optional(),
suffix: import_v42.z.string().optional(),
echo: import_v42.z.boolean().optional()
@@ -662,7 +662,7 @@ function convertToOllamaChatMessages({
const images = content.filter((part) => part.type === "file" && part.mediaType.startsWith("image/")).map((part) => part.data);
messages.push({
role: "user",
- content: userText.length > 0 ? userText : [],
+ content: userText.length > 0 ? userText : '',
images: images.length > 0 ? images : void 0
});
break;
@@ -813,9 +813,11 @@ var ollamaProviderOptions = import_v44.z.object({
* the model's thinking from the model's output. When disabled, the model will not think
* and directly output the content.
*
+ * For gpt-oss models, you can also use 'low', 'medium', or 'high' to control the depth of thinking.
+ *
* Only supported by certain models like DeepSeek R1 and Qwen 3.
*/
- think: import_v44.z.boolean().optional(),
+ think: import_v44.z.union([import_v44.z.boolean(), import_v44.z.enum(['low', 'medium', 'high'])]).optional(),
options: import_v44.z.object({
num_ctx: import_v44.z.number().optional(),
repeat_last_n: import_v44.z.number().optional(),
@@ -929,14 +931,16 @@ var OllamaRequestBuilder = class {
prompt,
systemMessageMode: "system"
}),
- temperature,
- top_p: topP,
max_output_tokens: maxOutputTokens,
...(responseFormat == null ? void 0 : responseFormat.type) === "json" && {
format: responseFormat.schema != null ? responseFormat.schema : "json"
},
think: (_a = ollamaOptions == null ? void 0 : ollamaOptions.think) != null ? _a : false,
- options: (_b = ollamaOptions == null ? void 0 : ollamaOptions.options) != null ? _b : void 0
+ options: {
+ ...temperature !== void 0 && { temperature },
+ ...topP !== void 0 && { top_p: topP },
+ ...((_b = ollamaOptions == null ? void 0 : ollamaOptions.options) != null ? _b : {})
+ }
};
}
};
diff --git a/dist/index.mjs b/dist/index.mjs
index e2a634a78d80ac9542f2cc4f96cf2291094b10cf..67b23efce3c1cf4f026693d3ff9246988a3ef26e 100644
--- a/dist/index.mjs
+++ b/dist/index.mjs
@@ -144,7 +144,7 @@ function getResponseMetadata({
// src/completion/ollama-completion-language-model.ts
var ollamaCompletionProviderOptions = z2.object({
- think: z2.boolean().optional(),
+ think: z2.union([z2.boolean(), z2.enum(['low', 'medium', 'high'])]).optional(),
user: z2.string().optional(),
suffix: z2.string().optional(),
echo: z2.boolean().optional()
@@ -662,7 +662,7 @@ function convertToOllamaChatMessages({
const images = content.filter((part) => part.type === "file" && part.mediaType.startsWith("image/")).map((part) => part.data);
messages.push({
role: "user",
- content: userText.length > 0 ? userText : [],
+ content: userText.length > 0 ? userText : '',
images: images.length > 0 ? images : void 0
});
break;
@@ -815,9 +815,11 @@ var ollamaProviderOptions = z4.object({
* the model's thinking from the model's output. When disabled, the model will not think
* and directly output the content.
*
+ * For gpt-oss models, you can also use 'low', 'medium', or 'high' to control the depth of thinking.
+ *
* Only supported by certain models like DeepSeek R1 and Qwen 3.
*/
- think: z4.boolean().optional(),
+ think: z4.union([z4.boolean(), z4.enum(['low', 'medium', 'high'])]).optional(),
options: z4.object({
num_ctx: z4.number().optional(),
repeat_last_n: z4.number().optional(),
@@ -931,14 +933,16 @@ var OllamaRequestBuilder = class {
prompt,
systemMessageMode: "system"
}),
- temperature,
- top_p: topP,
max_output_tokens: maxOutputTokens,
...(responseFormat == null ? void 0 : responseFormat.type) === "json" && {
format: responseFormat.schema != null ? responseFormat.schema : "json"
},
think: (_a = ollamaOptions == null ? void 0 : ollamaOptions.think) != null ? _a : false,
- options: (_b = ollamaOptions == null ? void 0 : ollamaOptions.options) != null ? _b : void 0
+ options: {
+ ...temperature !== void 0 && { temperature },
+ ...topP !== void 0 && { top_p: topP },
+ ...((_b = ollamaOptions == null ? void 0 : ollamaOptions.options) != null ? _b : {})
+ }
};
}
};

View File

@ -29,7 +29,7 @@ When creating a Pull Request, you MUST:
- **Development**: `yarn dev` - Runs Electron app in development mode with hot reload
- **Debug**: `yarn debug` - Starts with debugging enabled, use `chrome://inspect` to attach debugger
- **Build Check**: `yarn build:check` - **REQUIRED** before commits (lint + test + typecheck)
- If having i18n sort issues, run `yarn sync:i18n` first to sync template
- If having i18n sort issues, run `yarn i18n:sync` first to sync template
- If having formatting issues, run `yarn format` first
- **Test**: `yarn test` - Run all tests (Vitest) across main and renderer processes
- **Single Test**:
@ -41,12 +41,14 @@ When creating a Pull Request, you MUST:
## Project Architecture
### Electron Structure
- **Main Process** (`src/main/`): Node.js backend with services (MCP, Knowledge, Storage, etc.)
- **Renderer Process** (`src/renderer/`): React UI with Redux state management
- **Preload Scripts** (`src/preload/`): Secure IPC bridge
### Key Architectural Components
#### Main Process Services (`src/main/services/`)
- **MCPService**: Model Context Protocol server management
@ -152,9 +154,10 @@ The application uses three distinct data management systems. Choose the appropri
### Usage
```typescript
import { loggerService } from '@logger'
const logger = loggerService.withContext('moduleName')
import { loggerService } from "@logger";
const logger = loggerService.withContext("moduleName");
// Renderer: loggerService.initWindowSource('windowName') first
logger.info('message', CONTEXT)
logger.info("message", CONTEXT);
```

View File

@ -23,7 +23,7 @@
},
"files": {
"ignoreUnknown": false,
"includes": ["**", "!**/.claude/**", "!**/.vscode/**"],
"includes": ["**", "!**/.claude/**", "!**/.vscode/**", "!**/.conductor/**"],
"maxSize": 2097152
},
"formatter": {

View File

@ -12,8 +12,13 @@
; https://github.com/electron-userland/electron-builder/issues/1122
!ifndef BUILD_UNINSTALLER
; Check VC++ Redistributable based on architecture stored in $1
Function checkVCRedist
ReadRegDWORD $0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64" "Installed"
${If} $1 == "arm64"
ReadRegDWORD $0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\ARM64" "Installed"
${Else}
ReadRegDWORD $0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64" "Installed"
${EndIf}
FunctionEnd
Function checkArchitectureCompatibility
@ -97,29 +102,47 @@
Call checkVCRedist
${If} $0 != "1"
MessageBox MB_YESNO "\
NOTE: ${PRODUCT_NAME} requires $\r$\n\
'Microsoft Visual C++ Redistributable'$\r$\n\
to function properly.$\r$\n$\r$\n\
Download and install now?" /SD IDYES IDYES InstallVCRedist IDNO DontInstall
InstallVCRedist:
inetc::get /CAPTION " " /BANNER "Downloading Microsoft Visual C++ Redistributable..." "https://aka.ms/vs/17/release/vc_redist.x64.exe" "$TEMP\vc_redist.x64.exe"
ExecWait "$TEMP\vc_redist.x64.exe /install /norestart"
;IfErrors InstallError ContinueInstall ; vc_redist exit code is unreliable :(
Call checkVCRedist
${If} $0 == "1"
Goto ContinueInstall
${EndIf}
; VC++ is required - install automatically since declining would abort anyway
; Select download URL based on system architecture (stored in $1)
${If} $1 == "arm64"
StrCpy $2 "https://aka.ms/vs/17/release/vc_redist.arm64.exe"
StrCpy $3 "$TEMP\vc_redist.arm64.exe"
${Else}
StrCpy $2 "https://aka.ms/vs/17/release/vc_redist.x64.exe"
StrCpy $3 "$TEMP\vc_redist.x64.exe"
${EndIf}
;InstallError:
MessageBox MB_ICONSTOP "\
There was an unexpected error installing$\r$\n\
Microsoft Visual C++ Redistributable.$\r$\n\
The installation of ${PRODUCT_NAME} cannot continue."
DontInstall:
inetc::get /CAPTION " " /BANNER "Downloading Microsoft Visual C++ Redistributable..." \
$2 $3 /END
Pop $0 ; Get download status from inetc::get
${If} $0 != "OK"
MessageBox MB_ICONSTOP|MB_YESNO "\
Failed to download Microsoft Visual C++ Redistributable.$\r$\n$\r$\n\
Error: $0$\r$\n$\r$\n\
Would you like to open the download page in your browser?$\r$\n\
$2" IDYES openDownloadUrl IDNO skipDownloadUrl
openDownloadUrl:
ExecShell "open" $2
skipDownloadUrl:
Abort
${EndIf}
ExecWait "$3 /install /quiet /norestart"
; Note: vc_redist exit code is unreliable, verify via registry check instead
Call checkVCRedist
${If} $0 != "1"
MessageBox MB_ICONSTOP|MB_YESNO "\
Microsoft Visual C++ Redistributable installation failed.$\r$\n$\r$\n\
Would you like to open the download page in your browser?$\r$\n\
$2$\r$\n$\r$\n\
The installation of ${PRODUCT_NAME} cannot continue." IDYES openInstallUrl IDNO skipInstallUrl
openInstallUrl:
ExecShell "open" $2
skipInstallUrl:
Abort
${EndIf}
${EndIf}
ContinueInstall:
Pop $4
Pop $3
Pop $2

View File

@ -71,7 +71,7 @@ Tools like i18n Ally cannot parse dynamic content within template strings, resul
```javascript
// Not recommended - Plugin cannot resolve
const message = t(`fruits.${fruit}`)
const message = t(`fruits.${fruit}`);
```
#### 2. **No Real-time Rendering in Editor**
@ -91,14 +91,14 @@ For example:
```ts
// src/renderer/src/i18n/label.ts
const themeModeKeyMap = {
dark: 'settings.theme.dark',
light: 'settings.theme.light',
system: 'settings.theme.system'
} as const
dark: "settings.theme.dark",
light: "settings.theme.light",
system: "settings.theme.system",
} as const;
export const getThemeModeLabel = (key: string): string => {
return themeModeKeyMap[key] ? t(themeModeKeyMap[key]) : key
}
return themeModeKeyMap[key] ? t(themeModeKeyMap[key]) : key;
};
```
By avoiding template strings, you gain better developer experience, more reliable translation checks, and a more maintainable codebase.
@ -107,7 +107,7 @@ By avoiding template strings, you gain better developer experience, more reliabl
The project includes several scripts to automate i18n-related tasks:
### `check:i18n` - Validate i18n Structure
### `i18n:check` - Validate i18n Structure
This script checks:
@ -116,10 +116,10 @@ This script checks:
- Whether keys are properly sorted
```bash
yarn check:i18n
yarn i18n:check
```
### `sync:i18n` - Synchronize JSON Structure and Sort Order
### `i18n:sync` - Synchronize JSON Structure and Sort Order
This script uses `zh-cn.json` as the source of truth to sync structure across all language files, including:
@ -128,14 +128,14 @@ This script uses `zh-cn.json` as the source of truth to sync structure across al
3. Sorting keys automatically
```bash
yarn sync:i18n
yarn i18n:sync
```
### `auto:i18n` - Automatically Translate Pending Texts
### `i18n:translate` - Automatically Translate Pending Texts
This script fills in texts marked as `[to be translated]` using machine translation.
Typically, after adding new texts in `zh-cn.json`, run `sync:i18n`, then `auto:i18n` to complete translations.
Typically, after adding new texts in `zh-cn.json`, run `i18n:sync`, then `i18n:translate` to complete translations.
Before using this script, set the required environment variables:
@ -148,30 +148,20 @@ MODEL="qwen-plus-latest"
Alternatively, add these variables directly to your `.env` file.
```bash
yarn auto:i18n
```
### `update:i18n` - Object-level Translation Update
Updates translations in language files under `src/renderer/src/i18n/translate` at the object level, preserving existing translations and only updating new content.
**Not recommended** — prefer `auto:i18n` for translation tasks.
```bash
yarn update:i18n
yarn i18n:translate
```
### Workflow
1. During development, first add the required text in `zh-cn.json`
2. Confirm it displays correctly in the Chinese environment
3. Run `yarn sync:i18n` to propagate the keys to other language files
4. Run `yarn auto:i18n` to perform machine translation
3. Run `yarn i18n:sync` to propagate the keys to other language files
4. Run `yarn i18n:translate` to perform machine translation
5. Grab a coffee and let the magic happen!
## Best Practices
1. **Use Chinese as Source Language**: All development starts in Chinese, then translates to other languages.
2. **Run Check Script Before Commit**: Use `yarn check:i18n` to catch i18n issues early.
2. **Run Check Script Before Commit**: Use `yarn i18n:check` to catch i18n issues early.
3. **Translate in Small Increments**: Avoid accumulating a large backlog of untranslated content.
4. **Keep Keys Semantically Clear**: Keys should clearly express their purpose, e.g., `user.profile.avatar.upload.error`

View File

@ -1,17 +1,17 @@
# 如何优雅地做好 i18n
## 使用i18n ally插件提升开发体验
## 使用 i18n ally 插件提升开发体验
i18n ally是一个强大的VSCode插件它能在开发阶段提供实时反馈帮助开发者更早发现文案缺失和错译问题。
i18n ally 是一个强大的 VSCode 插件,它能在开发阶段提供实时反馈,帮助开发者更早发现文案缺失和错译问题。
项目中已经配置好了插件设置,直接安装即可。
### 开发时优势
- **实时预览**:翻译文案会直接显示在编辑器中
- **错误检测**自动追踪标记出缺失的翻译或未使用的key
- **快速跳转**可通过key直接跳转到定义处Ctrl/Cmd + click)
- **自动补全**输入i18n key时提供自动补全建议
- **错误检测**:自动追踪标记出缺失的翻译或未使用的 key
- **快速跳转**:可通过 key 直接跳转到定义处Ctrl/Cmd + click)
- **自动补全**:输入 i18n key 时提供自动补全建议
### 效果展示
@ -23,9 +23,9 @@ i18n ally是一个强大的VSCode插件它能在开发阶段提供实时反
## i18n 约定
### **绝对避免使用flat格式**
### **绝对避免使用 flat 格式**
绝对避免使用flat格式如`"add.button.tip": "添加"`。应采用清晰的嵌套结构:
绝对避免使用 flat 格式,如`"add.button.tip": "添加"`。应采用清晰的嵌套结构:
```json
// 错误示例 - flat结构
@ -52,14 +52,14 @@ i18n ally是一个强大的VSCode插件它能在开发阶段提供实时反
#### 为什么要使用嵌套结构
1. **自然分组**:通过对象结构天然能将相关上下文的文案分到一个组别中
2. **插件要求**i18n ally 插件需要嵌套或flat格式其一的文件才能正常分析
2. **插件要求**i18n ally 插件需要嵌套或 flat 格式其一的文件才能正常分析
### **避免在`t()`中使用模板字符串**
**强烈建议避免使用模板字符串**进行动态插值。虽然模板字符串在JavaScript开发中非常方便但在国际化场景下会带来一系列问题。
**强烈建议避免使用模板字符串**进行动态插值。虽然模板字符串在 JavaScript 开发中非常方便,但在国际化场景下会带来一系列问题。
1. **插件无法跟踪**
i18n ally等工具无法解析模板字符串中的动态内容导致
i18n ally 等工具无法解析模板字符串中的动态内容,导致:
- 无法正确显示实时预览
- 无法检测翻译缺失
@ -67,11 +67,11 @@ i18n ally是一个强大的VSCode插件它能在开发阶段提供实时反
```javascript
// 不推荐 - 插件无法解析
const message = t(`fruits.${fruit}`)
const message = t(`fruits.${fruit}`);
```
2. **编辑器无法实时渲染**
在IDE中模板字符串会显示为原始代码而非最终翻译结果降低了开发体验。
IDE 中,模板字符串会显示为原始代码而非最终翻译结果,降低了开发体验。
3. **更难以维护**
由于插件无法跟踪这样的文案,编辑器中也无法渲染,开发者必须人工确认语言文件中是否存在相应的文案。
@ -85,36 +85,36 @@ i18n ally是一个强大的VSCode插件它能在开发阶段提供实时反
```ts
// src/renderer/src/i18n/label.ts
const themeModeKeyMap = {
dark: 'settings.theme.dark',
light: 'settings.theme.light',
system: 'settings.theme.system'
} as const
dark: "settings.theme.dark",
light: "settings.theme.light",
system: "settings.theme.system",
} as const;
export const getThemeModeLabel = (key: string): string => {
return themeModeKeyMap[key] ? t(themeModeKeyMap[key]) : key
}
return themeModeKeyMap[key] ? t(themeModeKeyMap[key]) : key;
};
```
通过避免模板字符串,可以获得更好的开发体验、更可靠的翻译检查以及更易维护的代码库。
## 自动化脚本
项目中有一系列脚本来自动化i18n相关任务
项目中有一系列脚本来自动化 i18n 相关任务:
### `check:i18n` - 检查i18n结构
### `i18n:check` - 检查 i18n 结构
此脚本会检查:
- 所有语言文件是否为嵌套结构
- 是否存在缺失的key
- 是否存在多余的key
- 是否存在缺失的 key
- 是否存在多余的 key
- 是否已经有序
```bash
yarn check:i18n
yarn i18n:check
```
### `sync:i18n` - 同步json结构与排序
### `i18n:sync` - 同步 json 结构与排序
此脚本以`zh-cn.json`文件为基准,将结构同步到其他语言文件,包括:
@ -123,14 +123,14 @@ yarn check:i18n
3. 自动排序
```bash
yarn sync:i18n
yarn i18n:sync
```
### `auto:i18n` - 自动翻译待翻译文本
### `i18n:translate` - 自动翻译待翻译文本
次脚本自动将标记为待翻译的文本通过机器翻译填充。
通常,在`zh-cn.json`中添加所需文案后,执行`sync:i18n`即可自动完成翻译。
通常,在`zh-cn.json`中添加所需文案后,执行`i18n:sync`即可自动完成翻译。
使用该脚本前,需要配置环境变量,例如:
@ -143,29 +143,19 @@ MODEL="qwen-plus-latest"
你也可以通过直接编辑`.env`文件来添加环境变量。
```bash
yarn auto:i18n
```
### `update:i18n` - 对象级别翻译更新
对`src/renderer/src/i18n/translate`中的语言文件进行对象级别的翻译更新,保留已有翻译,只更新新增内容。
**不建议**使用该脚本,更推荐使用`auto:i18n`进行翻译。
```bash
yarn update:i18n
yarn i18n:translate
```
### 工作流
1. 开发阶段,先在`zh-cn.json`中添加所需文案
2. 确认在中文环境下显示无误后,使用`yarn sync:i18n`将文案同步到其他语言文件
3. 使用`yarn auto:i18n`进行自动翻译
2. 确认在中文环境下显示无误后,使用`yarn i18n:sync`将文案同步到其他语言文件
3. 使用`yarn i18n:translate`进行自动翻译
4. 喝杯咖啡,等翻译完成吧!
## 最佳实践
1. **以中文为源语言**:所有开发首先使用中文,再翻译为其他语言
2. **提交前运行检查脚本**:使用`yarn check:i18n`检查i18n是否有问题
2. **提交前运行检查脚本**:使用`yarn i18n:check`检查 i18n 是否有问题
3. **小步提交翻译**:避免积累大量未翻译文本
4. **保持key语义明确**key应能清晰表达其用途如`user.profile.avatar.upload.error`
4. **保持 key 语义明确**key 应能清晰表达其用途,如`user.profile.avatar.upload.error`

View File

@ -135,66 +135,38 @@ artifactBuildCompleted: scripts/artifact-build-completed.js
releaseInfo:
releaseNotes: |
<!--LANG:en-->
Cherry Studio 1.7.2 - Stability & Enhancement Update
Cherry Studio 1.7.6 - New Models & MCP Enhancements
This release focuses on stability improvements, bug fixes, and quality-of-life enhancements.
This release adds support for new AI models and includes a new MCP server for memory management.
🔧 Improvements
- Enhanced update dialog functionality and state management
- Improved ImageViewer context menu UX
- Better temperature and top_p parameter handling
- User-configurable stream options for OpenAI API
- Translation feature now supports document files
🤖 AI & Models
- Added explicit thinking token support for Gemini 3 Pro Image
- Updated DeepSeek logic to match DeepSeek v3.2
- Updated AiOnly default models
- Updated AI model configurations to latest versions
♿ Accessibility
- Improved screen reader (NVDA) support with aria-label attributes
- Added Slovak language support for spell check
✨ New Features
- [Models] Add support for Xiaomi MiMo model
- [Models] Add support for Gemini 3 Flash and Pro model detection
- [Models] Add support for Volcengine Doubao-Seed-1.8 model
- [MCP] Add Nowledge Mem builtin MCP server for memory management
- [Settings] Add default reasoning effort option to resolve confusion between undefined and none
🐛 Bug Fixes
- Fixed Quick Assistant shortcut registration issue
- Fixed UI freeze on multi-file selection via batch processing
- Fixed assistant default model update when editing model capabilities
- Fixed provider handling and API key rotation logic
- Fixed OVMS API URL path formation
- Fixed custom parameters placement for Vercel AI Gateway
- Fixed topic message blocks clearing
- Fixed input bar blocking enter send while generating
- [Azure] Restore deployment-based URLs for non-v1 apiVersion
- [Translation] Disable reasoning mode for translation to improve efficiency
- [Image] Update API path for image generation requests in OpenAIBaseClient
- [Windows] Auto-discover and persist Git Bash path on Windows for scoop users
<!--LANG:zh-CN-->
Cherry Studio 1.7.2 - 稳定性与功能增强更新
Cherry Studio 1.7.6 - 新模型与 MCP 增强
本次更新专注于稳定性改进、问题修复和用户体验提升
本次更新添加了多个新 AI 模型支持,并新增记忆管理 MCP 服务器
🔧 功能改进
- 增强更新对话框功能和状态管理
- 优化图片查看器右键菜单体验
- 改进温度和 top_p 参数处理逻辑
- 支持用户自定义 OpenAI API 流式选项
- 翻译功能现已支持文档文件
🤖 AI 与模型
- 为 Gemini 3 Pro Image 添加显式思考 token 支持
- 更新 DeepSeek 逻辑以适配 DeepSeek v3.2
- 更新 AiOnly 默认模型
- 更新 AI 模型配置至最新版本
♿ 无障碍支持
- 改进屏幕阅读器 (NVDA) 支持,添加 aria-label 属性
- 新增斯洛伐克语拼写检查支持
✨ 新功能
- [模型] 添加小米 MiMo 模型支持
- [模型] 添加 Gemini 3 Flash 和 Pro 模型检测支持
- [模型] 添加火山引擎 Doubao-Seed-1.8 模型支持
- [MCP] 新增 Nowledge Mem 内置 MCP 服务器,用于记忆管理
- [设置] 添加默认推理强度选项,解决 undefined 和 none 之间的混淆
🐛 问题修复
- 修复快捷助手无法注册快捷键的问题
- 修复多文件选择时 UI 冻结问题(通过批处理优化)
- 修复编辑模型能力时助手默认模型更新问题
- 修复服务商处理和 API 密钥轮换逻辑
- 修复 OVMS API URL 路径格式问题
- 修复 Vercel AI Gateway 自定义参数位置问题
- 修复话题消息块清理问题
- 修复生成时输入框阻止回车发送的问题
- [Azure] 修复非 v1 apiVersion 的部署 URL 问题
- [翻译] 禁用翻译时的推理模式以提高效率
- [图像] 更新 OpenAIBaseClient 中图像生成请求的 API 路径
- [Windows] 自动发现并保存 Windows scoop 用户的 Git Bash 路径
<!--LANG:END-->

View File

@ -61,6 +61,7 @@ export default defineConfig([
'tests/**',
'.yarn/**',
'.gitignore',
'.conductor/**',
'scripts/cloudflare-worker.js',
'src/main/integration/nutstore/sso/lib/**',
'src/main/integration/cherryai/index.js',

View File

@ -50,14 +50,13 @@
"generate:icons": "electron-icon-builder --input=./build/logo.png --output=build",
"analyze:renderer": "VISUALIZER_RENDERER=true yarn build",
"analyze:main": "VISUALIZER_MAIN=true yarn build",
"typecheck": "concurrently -n \"node,web,ui\" -c \"cyan,magenta,green\" \"npm run typecheck:node\" \"npm run typecheck:web\" \"npm run typecheck:ui\"",
"typecheck": "concurrently -n \"node,web\" -c \"cyan,magenta\" \"npm run typecheck:node\" \"npm run typecheck:web\"",
"typecheck:node": "tsgo --noEmit -p tsconfig.node.json --composite false",
"typecheck:web": "tsgo --noEmit -p tsconfig.web.json --composite false",
"typecheck:ui": "cd packages/ui && npm run type-check",
"check:i18n": "dotenv -e .env -- tsx scripts/check-i18n.ts",
"sync:i18n": "dotenv -e .env -- tsx scripts/sync-i18n.ts",
"update:i18n": "dotenv -e .env -- tsx scripts/update-i18n.ts",
"auto:i18n": "dotenv -e .env -- tsx scripts/auto-translate-i18n.ts",
"i18n:check": "dotenv -e .env -- tsx scripts/check-i18n.ts",
"i18n:sync": "dotenv -e .env -- tsx scripts/sync-i18n.ts",
"i18n:translate": "dotenv -e .env -- tsx scripts/auto-translate-i18n.ts",
"i18n:all": "yarn i18n:check && yarn i18n:sync && yarn i18n:translate",
"update:languages": "tsx scripts/update-languages.ts",
"update:upgrade-config": "tsx scripts/update-app-upgrade-config.ts",
"test": "vitest run --silent",
@ -71,8 +70,7 @@
"test:e2e": "yarn playwright test",
"test:lint": "oxlint --deny-warnings && eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --cache",
"test:scripts": "vitest scripts",
"lint": "oxlint --fix && eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --cache && biome lint --write && biome format --write && yarn typecheck && yarn check:i18n && yarn format:check",
"lint:ox": "oxlint --fix && biome lint --write && biome format --write",
"lint": "oxlint --fix && eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --cache && biome lint --write && biome format --write && yarn typecheck && yarn i18n:check && yarn format:check",
"format": "biome format --write && biome lint --write",
"format:check": "biome format && biome lint",
"prepare": "git config blame.ignoreRevsFile .git-blame-ignore-revs && husky",
@ -84,7 +82,7 @@
"release:ai-sdk-provider": "yarn workspace @cherrystudio/ai-sdk-provider version patch --immediate && yarn workspace @cherrystudio/ai-sdk-provider build && yarn workspace @cherrystudio/ai-sdk-provider npm publish --access public"
},
"dependencies": {
"@anthropic-ai/claude-agent-sdk": "patch:@anthropic-ai/claude-agent-sdk@npm%3A0.1.53#~/.yarn/patches/@anthropic-ai-claude-agent-sdk-npm-0.1.53-4b77f4cf29.patch",
"@anthropic-ai/claude-agent-sdk": "patch:@anthropic-ai/claude-agent-sdk@npm%3A0.1.62#~/.yarn/patches/@anthropic-ai-claude-agent-sdk-npm-0.1.62-23ae56f8c8.patch",
"@libsql/client": "0.14.0",
"@libsql/win32-x64-msvc": "^0.4.7",
"@napi-rs/system-ocr": "patch:@napi-rs/system-ocr@npm%3A1.0.2#~/.yarn/patches/@napi-rs-system-ocr-npm-1.0.2-59e7a78e8b.patch",
@ -118,11 +116,11 @@
"@ai-sdk/anthropic": "^2.0.49",
"@ai-sdk/cerebras": "^1.0.31",
"@ai-sdk/gateway": "^2.0.15",
"@ai-sdk/google": "patch:@ai-sdk/google@npm%3A2.0.43#~/.yarn/patches/@ai-sdk-google-npm-2.0.43-689ed559b3.patch",
"@ai-sdk/google-vertex": "^3.0.79",
"@ai-sdk/google": "patch:@ai-sdk/google@npm%3A2.0.49#~/.yarn/patches/@ai-sdk-google-npm-2.0.49-84720f41bd.patch",
"@ai-sdk/google-vertex": "^3.0.94",
"@ai-sdk/huggingface": "^0.0.10",
"@ai-sdk/mistral": "^2.0.24",
"@ai-sdk/openai": "patch:@ai-sdk/openai@npm%3A2.0.72#~/.yarn/patches/@ai-sdk-openai-npm-2.0.72-234e68da87.patch",
"@ai-sdk/openai": "patch:@ai-sdk/openai@npm%3A2.0.85#~/.yarn/patches/@ai-sdk-openai-npm-2.0.85-27483d1d6a.patch",
"@ai-sdk/perplexity": "^2.0.20",
"@ai-sdk/test-server": "^0.0.1",
"@ant-design/v5-patch-for-react-19": "^1.0.3",
@ -146,7 +144,7 @@
"@cherrystudio/embedjs-ollama": "^0.1.31",
"@cherrystudio/embedjs-openai": "^0.1.31",
"@cherrystudio/extension-table-plus": "workspace:^",
"@cherrystudio/openai": "^6.9.0",
"@cherrystudio/openai": "^6.12.0",
"@cherrystudio/ui": "workspace:*",
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/modifiers": "^9.0.0",
@ -326,7 +324,7 @@
"motion": "^12.10.5",
"notion-helper": "^1.3.22",
"npx-scope-finder": "^1.2.0",
"ollama-ai-provider-v2": "^1.5.5",
"ollama-ai-provider-v2": "patch:ollama-ai-provider-v2@npm%3A1.5.5#~/.yarn/patches/ollama-ai-provider-v2-npm-1.5.5-8bef249af9.patch",
"oxlint": "^1.22.0",
"oxlint-tsgolint": "^0.2.0",
"p-queue": "^8.1.0",
@ -420,9 +418,10 @@
"@langchain/openai@npm:>=0.1.0 <0.6.0": "patch:@langchain/openai@npm%3A1.0.0#~/.yarn/patches/@langchain-openai-npm-1.0.0-474d0ad9d4.patch",
"@langchain/openai@npm:^0.3.16": "patch:@langchain/openai@npm%3A1.0.0#~/.yarn/patches/@langchain-openai-npm-1.0.0-474d0ad9d4.patch",
"@langchain/openai@npm:>=0.2.0 <0.7.0": "patch:@langchain/openai@npm%3A1.0.0#~/.yarn/patches/@langchain-openai-npm-1.0.0-474d0ad9d4.patch",
"@ai-sdk/openai@npm:^2.0.42": "patch:@ai-sdk/openai@npm%3A2.0.72#~/.yarn/patches/@ai-sdk-openai-npm-2.0.72-234e68da87.patch",
"@ai-sdk/openai@npm:^2.0.42": "patch:@ai-sdk/openai@npm%3A2.0.85#~/.yarn/patches/@ai-sdk-openai-npm-2.0.85-27483d1d6a.patch",
"@ai-sdk/google@npm:^2.0.40": "patch:@ai-sdk/google@npm%3A2.0.40#~/.yarn/patches/@ai-sdk-google-npm-2.0.40-47e0eeee83.patch",
"@ai-sdk/openai-compatible@npm:^1.0.27": "patch:@ai-sdk/openai-compatible@npm%3A1.0.27#~/.yarn/patches/@ai-sdk-openai-compatible-npm-1.0.27-06f74278cf.patch"
"@ai-sdk/openai-compatible@npm:^1.0.27": "patch:@ai-sdk/openai-compatible@npm%3A1.0.27#~/.yarn/patches/@ai-sdk-openai-compatible-npm-1.0.27-06f74278cf.patch",
"@ai-sdk/google@npm:2.0.49": "patch:@ai-sdk/google@npm%3A2.0.49#~/.yarn/patches/@ai-sdk-google-npm-2.0.49-84720f41bd.patch"
},
"packageManager": "yarn@4.9.1",
"lint-staged": {

View File

@ -40,7 +40,7 @@
},
"dependencies": {
"@ai-sdk/anthropic": "^2.0.49",
"@ai-sdk/azure": "^2.0.74",
"@ai-sdk/azure": "^2.0.87",
"@ai-sdk/deepseek": "^1.0.31",
"@ai-sdk/openai-compatible": "patch:@ai-sdk/openai-compatible@npm%3A1.0.27#~/.yarn/patches/@ai-sdk-openai-compatible-npm-1.0.27-06f74278cf.patch",
"@ai-sdk/provider": "^2.0.0",

View File

@ -62,7 +62,7 @@ export class StreamEventManager {
const recursiveResult = await context.recursiveCall(recursiveParams)
if (recursiveResult && recursiveResult.fullStream) {
await this.pipeRecursiveStream(controller, recursiveResult.fullStream, context)
await this.pipeRecursiveStream(controller, recursiveResult.fullStream)
} else {
console.warn('[MCP Prompt] No fullstream found in recursive result:', recursiveResult)
}
@ -74,11 +74,7 @@ export class StreamEventManager {
/**
*
*/
private async pipeRecursiveStream(
controller: StreamController,
recursiveStream: ReadableStream,
context?: AiRequestContext
): Promise<void> {
private async pipeRecursiveStream(controller: StreamController, recursiveStream: ReadableStream): Promise<void> {
const reader = recursiveStream.getReader()
try {
while (true) {
@ -86,18 +82,14 @@ export class StreamEventManager {
if (done) {
break
}
if (value.type === 'start') {
continue
}
if (value.type === 'finish') {
// 迭代的流不发finish但需要累加其 usage
if (value.usage && context?.accumulatedUsage) {
this.accumulateUsage(context.accumulatedUsage, value.usage)
}
break
}
// 对于 finish-step 类型,累加其 usage
if (value.type === 'finish-step' && value.usage && context?.accumulatedUsage) {
this.accumulateUsage(context.accumulatedUsage, value.usage)
}
// 将递归流的数据传递到当前流
controller.enqueue(value)
}
} finally {
@ -135,10 +127,8 @@ export class StreamEventManager {
// 构建新的对话消息
const newMessages: ModelMessage[] = [
...(context.originalParams.messages || []),
{
role: 'assistant',
content: textBuffer
},
// 只有当 textBuffer 有内容时才添加 assistant 消息,避免空消息导致 API 错误
...(textBuffer ? [{ role: 'assistant' as const, content: textBuffer }] : []),
{
role: 'user',
content: toolResultsText
@ -161,7 +151,7 @@ export class StreamEventManager {
/**
* usage
*/
private accumulateUsage(target: any, source: any): void {
accumulateUsage(target: any, source: any): void {
if (!target || !source) return
// 累加各种 token 类型

View File

@ -411,7 +411,10 @@ export const createPromptToolUsePlugin = (config: PromptToolUseConfig = {}) => {
}
}
// 如果没有执行工具调用直接传递原始finish-step事件
// 如果没有执行工具调用,累加 usage 后透传 finish-step 事件
if (chunk.usage && context.accumulatedUsage) {
streamEventManager.accumulateUsage(context.accumulatedUsage, chunk.usage)
}
controller.enqueue(chunk)
// 清理状态

View File

@ -5,6 +5,7 @@ import type { InferToolInput, InferToolOutput, Tool } from 'ai'
import { createOpenRouterOptions, createXaiOptions, mergeProviderOptions } from '../../../options'
import type { ProviderOptionsMap } from '../../../options/types'
import type { AiRequestContext } from '../../'
import type { OpenRouterSearchConfig } from './openrouter'
/**
@ -94,28 +95,84 @@ export type WebSearchToolInputSchema = {
'openai-chat': InferToolInput<OpenAIChatWebSearchTool>
}
export const switchWebSearchTool = (config: WebSearchPluginConfig, params: any) => {
if (config.openai) {
if (!params.tools) params.tools = {}
params.tools.web_search = openai.tools.webSearch(config.openai)
} else if (config['openai-chat']) {
if (!params.tools) params.tools = {}
params.tools.web_search_preview = openai.tools.webSearchPreview(config['openai-chat'])
} else if (config.anthropic) {
if (!params.tools) params.tools = {}
params.tools.web_search = anthropic.tools.webSearch_20250305(config.anthropic)
} else if (config.google) {
// case 'google-vertex':
if (!params.tools) params.tools = {}
params.tools.web_search = google.tools.googleSearch(config.google || {})
} else if (config.xai) {
const searchOptions = createXaiOptions({
searchParameters: { ...config.xai, mode: 'on' }
})
params.providerOptions = mergeProviderOptions(params.providerOptions, searchOptions)
} else if (config.openrouter) {
const searchOptions = createOpenRouterOptions(config.openrouter)
params.providerOptions = mergeProviderOptions(params.providerOptions, searchOptions)
/**
* Helper function to ensure params.tools object exists
*/
const ensureToolsObject = (params: any) => {
if (!params.tools) params.tools = {}
}
/**
* Helper function to apply tool-based web search configuration
*/
const applyToolBasedSearch = (params: any, toolName: string, toolInstance: any) => {
ensureToolsObject(params)
params.tools[toolName] = toolInstance
}
/**
* Helper function to apply provider options-based web search configuration
*/
const applyProviderOptionsSearch = (params: any, searchOptions: any) => {
params.providerOptions = mergeProviderOptions(params.providerOptions, searchOptions)
}
export const switchWebSearchTool = (config: WebSearchPluginConfig, params: any, context?: AiRequestContext) => {
const providerId = context?.providerId
// Provider-specific configuration map
const providerHandlers: Record<string, () => void> = {
openai: () => {
const cfg = config.openai ?? DEFAULT_WEB_SEARCH_CONFIG.openai
applyToolBasedSearch(params, 'web_search', openai.tools.webSearch(cfg))
},
'openai-chat': () => {
const cfg = (config['openai-chat'] ?? DEFAULT_WEB_SEARCH_CONFIG['openai-chat']) as OpenAISearchPreviewConfig
applyToolBasedSearch(params, 'web_search_preview', openai.tools.webSearchPreview(cfg))
},
anthropic: () => {
const cfg = config.anthropic ?? DEFAULT_WEB_SEARCH_CONFIG.anthropic
applyToolBasedSearch(params, 'web_search', anthropic.tools.webSearch_20250305(cfg))
},
google: () => {
const cfg = (config.google ?? DEFAULT_WEB_SEARCH_CONFIG.google) as GoogleSearchConfig
applyToolBasedSearch(params, 'web_search', google.tools.googleSearch(cfg))
},
xai: () => {
const cfg = config.xai ?? DEFAULT_WEB_SEARCH_CONFIG.xai
const searchOptions = createXaiOptions({ searchParameters: { ...cfg, mode: 'on' } })
applyProviderOptionsSearch(params, searchOptions)
},
openrouter: () => {
const cfg = (config.openrouter ?? DEFAULT_WEB_SEARCH_CONFIG.openrouter) as OpenRouterSearchConfig
const searchOptions = createOpenRouterOptions(cfg)
applyProviderOptionsSearch(params, searchOptions)
}
}
// Try provider-specific handler first
const handler = providerId && providerHandlers[providerId]
if (handler) {
handler()
return params
}
// Fallback: apply based on available config keys (prioritized order)
const fallbackOrder: Array<keyof WebSearchPluginConfig> = [
'openai',
'openai-chat',
'anthropic',
'google',
'xai',
'openrouter'
]
for (const key of fallbackOrder) {
if (config[key]) {
providerHandlers[key]()
break
}
}
return params
}

View File

@ -17,8 +17,22 @@ export const webSearchPlugin = (config: WebSearchPluginConfig = DEFAULT_WEB_SEAR
name: 'webSearch',
enforce: 'pre',
transformParams: async (params: any) => {
switchWebSearchTool(config, params)
transformParams: async (params: any, context) => {
let { providerId } = context
// For cherryin providers, extract the actual provider from the model's provider string
// Expected format: "cherryin.{actualProvider}" (e.g., "cherryin.gemini")
if (providerId === 'cherryin' || providerId === 'cherryin-chat') {
const provider = params.model?.provider
if (provider && typeof provider === 'string' && provider.includes('.')) {
const extractedProviderId = provider.split('.')[1]
if (extractedProviderId) {
providerId = extractedProviderId
}
}
}
switchWebSearchTool(config, params, { ...context, providerId })
return params
}
})

View File

@ -55,6 +55,8 @@ export enum IpcChannel {
Webview_SetOpenLinkExternal = 'webview:set-open-link-external',
Webview_SetSpellCheckEnabled = 'webview:set-spell-check-enabled',
Webview_SearchHotkey = 'webview:search-hotkey',
Webview_PrintToPDF = 'webview:print-to-pdf',
Webview_SaveAsHTML = 'webview:save-as-html',
// Open
Open_Path = 'open:path',
@ -90,6 +92,8 @@ export enum IpcChannel {
Mcp_AbortTool = 'mcp:abort-tool',
Mcp_GetServerVersion = 'mcp:get-server-version',
Mcp_Progress = 'mcp:progress',
Mcp_GetServerLogs = 'mcp:get-server-logs',
Mcp_ServerLog = 'mcp:server-log',
// Python
Python_Execute = 'python:execute',
@ -255,6 +259,9 @@ export enum IpcChannel {
System_GetHostname = 'system:getHostname',
System_GetCpuName = 'system:getCpuName',
System_CheckGitBash = 'system:checkGitBash',
System_GetGitBashPath = 'system:getGitBashPath',
System_GetGitBashPathInfo = 'system:getGitBashPathInfo',
System_SetGitBashPath = 'system:setGitBashPath',
// DevTools
System_ToggleDevTools = 'system:toggleDevTools',

View File

@ -88,16 +88,11 @@ export function getSdkClient(
}
})
}
let baseURL =
const baseURL =
provider.type === 'anthropic'
? provider.apiHost
: (provider.anthropicApiHost && provider.anthropicApiHost.trim()) || provider.apiHost
// Anthropic SDK automatically appends /v1 to all endpoints (like /v1/messages, /v1/models)
// We need to strip api version from baseURL to avoid duplication (e.g., /v3/v1/models)
// formatProviderApiHost adds /v1 for AI SDK compatibility, but Anthropic SDK needs it removed
baseURL = baseURL.replace(/\/v\d+(?:alpha|beta)?(?=\/|$)/i, '')
logger.debug('Anthropic API baseURL', { baseURL, providerId: provider.id })
if (provider.id === 'aihubmix') {

View File

@ -488,3 +488,11 @@ export const MACOS_TERMINALS_WITH_COMMANDS: TerminalConfigWithCommand[] = [
// resources/scripts should be maintained manually
export const HOME_CHERRY_DIR = '.cherrystudio'
// Git Bash path configuration types
export type GitBashPathSource = 'manual' | 'auto'
export interface GitBashPathInfo {
path: string | null
source: GitBashPathSource | null
}

View File

@ -306,7 +306,7 @@ export const SEARCH_SUMMARY_PROMPT_KNOWLEDGE_ONLY = `
**Use user's language to rephrase the question.**
Follow these guidelines:
1. If the question is a simple writing task, greeting (e.g., Hi, Hello, How are you), or does not require searching for information (unless the greeting contains a follow-up question), return 'not_needed' in the 'question' XML block. This indicates that no search is required.
2. For knowledge, You need rewrite user query into 'rewrite' XML block with one alternative version while preserving the original intent and meaning. Also include the original question in the 'question' block.
2. For knowledge, You need rewrite user query into 'rewrite' XML block with one alternative version while preserving the original intent and meaning. Also include the rephrased or decomposed question(s) in the 'question' block.
3. Always return the rephrased question inside the 'question' XML block.
4. Always wrap the rephrased question in the appropriate XML blocks: use <knowledge></knowledge> for queries that can be answered from a pre-existing knowledge base. Ensure that the rephrased question is always contained within a <question></question> block inside the wrapper.
5. *use knowledge to rephrase the question*

View File

@ -23,6 +23,14 @@ export type MCPProgressEvent = {
progress: number // 0-1 range
}
export type MCPServerLogEntry = {
timestamp: number
level: 'debug' | 'info' | 'warn' | 'error' | 'stderr' | 'stdout'
message: string
data?: any
source?: string
}
export type WebviewKeyEvent = {
webviewId: number
key: string

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.0889 6.03756C16.6389 6.00079 16.0566 6.00001 15.2 6.00001H14C13.4477 6.00001 13 5.55229 13 5.00001C13 4.44772 13.4477 4.00001 14 4.00001L15.2413 4.00001C16.0463 3.99999 16.7106 3.99998 17.2518 4.0442C17.8139 4.09013 18.3306 4.18869 18.8159 4.43598C19.5686 4.81948 20.1805 5.4314 20.564 6.18405C20.8113 6.66938 20.9099 7.18608 20.9558 7.74818C21 8.28937 21 8.95373 21 9.75869V13.2408C21 14.0457 21 14.7101 20.9558 15.2513C20.9099 15.8134 20.8113 16.3301 20.564 16.8154C20.1805 17.5681 19.5686 18.18 18.8159 18.5635C18.3306 18.8108 17.8139 18.9093 17.2518 18.9553C16.7106 18.9995 16.0462 18.9995 15.2413 18.9994H15.0314L12.7593 21.6507C12.5693 21.8724 12.2919 22 12 22C11.708 22 11.4306 21.8724 11.2407 21.6507L8.96858 18.9994H8.46542C7.79577 18.9995 7.24301 18.9995 6.79049 18.9686C6.32129 18.9366 5.88727 18.8681 5.46952 18.6951C4.48919 18.2891 3.71034 17.5102 3.30435 16.5299C3.13135 16.1122 3.06285 15.6781 3.03084 15.2089C2.99997 14.7564 2.99998 14.2037 2.99999 13.534L2.99999 13.4997C2.99999 12.9474 3.4477 12.4997 3.99999 12.4997C4.55227 12.4997 4.99999 12.9474 4.99999 13.4997C4.99999 14.2122 5.00053 14.6965 5.0262 15.0728C5.05126 15.4402 5.09689 15.6312 5.15217 15.7647C5.35516 16.2548 5.74459 16.6443 6.23475 16.8473C6.36823 16.9025 6.55922 16.9482 6.9266 16.9732C7.30297 16.9989 7.78724 16.9994 8.4997 16.9994H9.42857C9.72053 16.9994 9.9979 17.127 10.1879 17.3487L12 19.4633L13.8121 17.3487C14.0021 17.127 14.2795 16.9994 14.5714 16.9994H15.2C16.0566 16.9994 16.6389 16.9987 17.0889 16.9619C17.5274 16.9261 17.7516 16.8611 17.908 16.7815C18.2843 16.5897 18.5903 16.2838 18.782 15.9074C18.8617 15.751 18.9266 15.5268 18.9624 15.0884C18.9992 14.6383 19 14.056 19 13.1995V9.80001C19 8.94343 18.9992 8.36114 18.9624 7.91105C18.9266 7.47263 18.8617 7.24843 18.782 7.09203C18.5903 6.7157 18.2843 6.40974 17.908 6.21799C17.7516 6.13831 17.5274 6.07338 17.0889 6.03756Z" fill="black" fill-opacity="0.9"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.5 0C5.93043 0 6.31257 0.27543 6.44868 0.683772L7.41557 3.58443L10.3162 4.55132C10.7246 4.68743 11 5.06957 11 5.5C11 5.93043 10.7246 6.31257 10.3162 6.44868L7.41557 7.41557L6.44868 10.3162C6.31257 10.7246 5.93043 11 5.5 11C5.06957 11 4.68743 10.7246 4.55132 10.3162L3.58443 7.41557L0.683772 6.44868C0.27543 6.31257 0 5.93043 0 5.5C0 5.06957 0.27543 4.68743 0.683772 4.55132L3.58443 3.58443L4.55132 0.683772C4.68743 0.27543 5.06957 0 5.5 0ZM5.5 4.16228L5.32368 4.69123C5.22415 4.98983 4.98983 5.22415 4.69123 5.32368L4.16228 5.5L4.69123 5.67632C4.98983 5.77585 5.22415 6.01017 5.32368 6.30877L5.5 6.83772L5.67632 6.30877C5.77585 6.01017 6.01017 5.77585 6.30877 5.67632L6.83772 5.5L6.30877 5.32368C6.01017 5.22415 5.77585 4.98983 5.67632 4.69123L5.5 4.16228Z" fill="black" fill-opacity="0.9"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 8.4C12.2583 8.4 12.4875 8.56526 12.5692 8.81026L13.2243 10.7757L15.1897 11.4308C15.4347 11.5125 15.6 11.7417 15.6 12C15.6 12.2583 15.4347 12.4875 15.1897 12.5692L13.2243 13.2243L12.5692 15.1897C12.4875 15.4347 12.2583 15.6 12 15.6C11.7417 15.6 11.5125 15.4347 11.4308 15.1897L10.7757 13.2243L8.81026 12.5692C8.56526 12.4875 8.4 12.2583 8.4 12C8.4 11.7417 8.56526 11.5125 8.81026 11.4308L10.7757 10.7757L11.4308 8.81026C11.5125 8.56526 11.7417 8.4 12 8.4Z" fill="black" fill-opacity="0.9"/>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.7527 2.20502C6.67539 2.20502 2.75 5.67733 2.75 11.0466C2.75 16.4158 6.67539 19.8881 12.7527 19.8881C12.796 19.8881 12.8392 19.8881 12.8825 19.8881C12.8392 20.3275 12.7311 20.8098 12.5581 21.3295C12.3634 21.9083 12.5581 22.5245 13.0393 22.8996C13.3042 23.1032 13.6124 23.205 13.9206 23.205C14.1855 23.205 14.4505 23.13 14.6884 22.98C16.6619 21.7368 17.8838 20.2846 18.338 18.6556C21.1496 17.1713 22.75 14.4224 22.75 11.0519C22.75 5.68269 18.8246 2.21038 12.7473 2.21038L12.7527 2.20502ZM17.2891 17.3803C17.0566 17.4875 16.8944 17.7018 16.8457 17.9483C16.6078 19.154 15.7103 20.3221 14.2504 21.3403C14.4883 20.4829 14.5748 19.6898 14.5045 18.9772C14.4613 18.5645 14.1098 18.2484 13.6989 18.2484C13.6773 18.2484 13.6611 18.2484 13.6394 18.2484C13.3529 18.2698 13.0609 18.2805 12.7581 18.2805C7.58915 18.2805 4.37747 15.5102 4.37747 11.0466C4.37747 6.58292 7.58915 3.81257 12.7581 3.81257C17.9271 3.81257 21.1388 6.58292 21.1388 11.0466C21.1388 13.9562 19.7762 16.2014 17.2945 17.3803H17.2891Z" fill="black" fill-opacity="0.9"/>
<path d="M11.5308 10.725L11.4605 10.6929C11.1901 10.5536 10.9684 10.3339 10.8279 10.066L10.7954 9.99629C10.6602 9.73372 10.2818 9.73372 10.1466 9.99629L10.1142 10.066C9.97357 10.3339 9.75189 10.5536 9.48155 10.6929L9.41126 10.725C9.14632 10.859 9.14632 11.2341 9.41126 11.3681L9.48155 11.4002C9.75189 11.5395 9.97357 11.7592 10.1142 12.0272L10.1466 12.0968C10.2818 12.3594 10.6602 12.3594 10.7954 12.0968L10.8279 12.0272C10.9684 11.7592 11.1901 11.5395 11.4605 11.4002L11.5308 11.3681C11.7957 11.2341 11.7957 10.859 11.5308 10.725Z" fill="black" fill-opacity="0.9"/>
<path d="M8.42721 10.5964L8.32989 10.5482C7.95141 10.3553 7.63781 10.0499 7.44316 9.66942L7.3945 9.57297C7.20526 9.20323 6.67538 9.20323 6.48614 9.57297L6.43748 9.66942C6.24284 10.0445 5.93464 10.3553 5.55076 10.5482L5.45343 10.5964C5.08036 10.784 5.08036 11.3091 5.45343 11.4967L5.55076 11.5449C5.92924 11.7378 6.24284 12.0432 6.43748 12.4237L6.48614 12.5201C6.67538 12.8899 7.20526 12.8899 7.3945 12.5201L7.44316 12.4237C7.63781 12.0486 7.946 11.7378 8.32989 11.5449L8.42721 11.4967C8.80028 11.3091 8.80028 10.784 8.42721 10.5964Z" fill="black" fill-opacity="0.9"/>
<path d="M19.5545 9.51402L19.3815 9.42829C18.8408 9.155 18.4083 8.72632 18.1325 8.19047L18.046 8.019C17.7486 7.44028 17.1539 7.08126 16.4997 7.08126C15.8454 7.08126 15.2507 7.44028 14.9479 8.019L14.8614 8.19047C14.5856 8.72632 14.1531 9.155 13.6124 9.42829L13.4394 9.51402C12.8554 9.80874 12.4932 10.3982 12.4932 11.0519C12.4932 11.7057 12.8554 12.2897 13.4394 12.5898L13.6124 12.6755C14.1531 12.9488 14.5856 13.3775 14.8614 13.9134L14.9479 14.0848C15.2453 14.6636 15.84 15.0226 16.4997 15.0226C17.1593 15.0226 17.7486 14.6636 18.0514 14.0848L18.1379 13.9134C18.4137 13.3775 18.8462 12.9488 19.3869 12.6755L19.5599 12.5898C20.1439 12.2951 20.5061 11.7057 20.5061 11.0573C20.5061 10.4089 20.1439 9.81946 19.5599 9.51938L19.5545 9.51402ZM18.8192 11.1537L18.6462 11.2395C17.7973 11.6681 17.1215 12.338 16.6889 13.1792L16.6024 13.3507C16.6024 13.3507 16.57 13.415 16.4997 13.415C16.4294 13.415 16.4023 13.3668 16.3969 13.3507L16.3104 13.1792C15.8779 12.338 15.202 11.6681 14.3531 11.2395L14.1801 11.1537C14.1801 11.1537 14.1152 11.1216 14.1152 11.0519C14.1152 10.9823 14.1639 10.9555 14.1801 10.9501L14.3531 10.8644C15.202 10.4357 15.8779 9.76588 16.3104 8.92459L16.3969 8.75312C16.3969 8.75312 16.4294 8.68881 16.4997 8.68881C16.57 8.68881 16.597 8.73168 16.6024 8.75312L16.6889 8.92459C17.1215 9.76588 17.7973 10.4357 18.6462 10.8644L18.8192 10.9501C18.8192 10.9501 18.8841 10.9823 18.8841 11.0519C18.8841 11.1216 18.8354 11.1484 18.8192 11.1537Z" fill="black" fill-opacity="0.9"/>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.7587 4H15.2413C16.0463 3.99999 16.7106 3.99998 17.2518 4.04419C17.8139 4.09012 18.3306 4.18868 18.816 4.43597C19.5686 4.81947 20.1805 5.43139 20.564 6.18404C20.8113 6.66937 20.9099 7.18608 20.9558 7.74818C21 8.28936 21 8.95372 21 9.75868V13.2408C21 14.0457 21 14.7101 20.9558 15.2513C20.9099 15.8134 20.8113 16.3301 20.564 16.8154C20.1805 17.568 19.5686 18.18 18.816 18.5635C18.3306 18.8108 17.8139 18.9093 17.2518 18.9552C16.7106 18.9995 16.0463 18.9995 15.2413 18.9994H15.0314L12.7593 21.6507C12.5693 21.8724 12.292 22 12 22C11.708 22 11.4307 21.8724 11.2407 21.6507L8.96859 18.9994H8.75872C7.95374 18.9995 7.28938 18.9995 6.74817 18.9552C6.18608 18.9093 5.66937 18.8108 5.18404 18.5635C4.43139 18.18 3.81947 17.568 3.43597 16.8154C3.18868 16.3301 3.09012 15.8134 3.04419 15.2513C2.99998 14.7101 2.99999 14.0457 3 13.2407V9.7587C2.99999 8.95373 2.99998 8.28937 3.04419 7.74818C3.09012 7.18608 3.18868 6.66937 3.43597 6.18404C3.81947 5.43139 4.43139 4.81947 5.18404 4.43597C5.66937 4.18868 6.18608 4.09012 6.74817 4.04419C7.28937 3.99998 7.95373 3.99999 8.7587 4ZM6.91104 6.03755C6.47262 6.07337 6.24842 6.1383 6.09202 6.21799C5.7157 6.40973 5.40973 6.7157 5.21799 7.09202C5.1383 7.24842 5.07337 7.47262 5.03755 7.91104C5.00078 8.36113 5 8.94342 5 9.8V13.1994C5 14.056 5.00078 14.6383 5.03755 15.0884C5.07337 15.5268 5.1383 15.751 5.21799 15.9074C5.40973 16.2837 5.7157 16.5897 6.09202 16.7815C6.24842 16.8611 6.47262 16.9261 6.91104 16.9619C7.36113 16.9987 7.94342 16.9994 8.8 16.9994H9.42858C9.72054 16.9994 9.99792 17.127 10.1879 17.3487L12 19.4632L13.8121 17.3487C14.0021 17.127 14.2795 16.9994 14.5714 16.9994H15.2C16.0566 16.9994 16.6389 16.9987 17.089 16.9619C17.5274 16.9261 17.7516 16.8611 17.908 16.7815C18.2843 16.5897 18.5903 16.2837 18.782 15.9074C18.8617 15.751 18.9266 15.5268 18.9624 15.0884C18.9992 14.6383 19 14.056 19 13.1994V9.8C19 8.94342 18.9992 8.36113 18.9624 7.91104C18.9266 7.47262 18.8617 7.24842 18.782 7.09202C18.5903 6.7157 18.2843 6.40973 17.908 6.21799C17.7516 6.1383 17.5274 6.07337 17.089 6.03755C16.6389 6.00078 16.0566 6 15.2 6H8.8C7.94342 6 7.36113 6.00078 6.91104 6.03755Z" fill="black" fill-opacity="0.9"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.29291 8.29289C8.68343 7.90236 9.3166 7.90236 9.70712 8.29289L11.7071 10.2929C12.0976 10.6834 12.0976 11.3166 11.7071 11.7071L9.70712 13.7071C9.3166 14.0976 8.68343 14.0976 8.29291 13.7071C7.90238 13.3166 7.90238 12.6834 8.29291 12.2929L9.5858 11L8.29291 9.7071C7.90238 9.31658 7.90238 8.68341 8.29291 8.29289Z" fill="black" fill-opacity="0.9"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 14C12 13.4477 12.4477 13 13 13H15C15.5523 13 16 13.4477 16 14C16 14.5523 15.5523 15 15 15H13C12.4477 15 12 14.5523 12 14Z" fill="black" fill-opacity="0.9"/>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18.0492 3.6969C18.814 5.44119 20.2075 6.83398 21.9515 7.59924C20.2077 8.36426 18.8142 9.75772 18.0492 11.5016C17.2839 9.75756 15.8911 8.36405 14.1469 7.59924C15.8913 6.83418 17.2841 5.44135 18.0492 3.6969Z" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linejoin="round"/>
<path d="M3.2 9.25003C3.13449 9.25003 3.06898 9.28295 3.03622 9.35976L2.9598 9.56824C2.67593 10.3253 2.08635 10.9288 1.32208 11.2141L1.11464 11.2909C0.961787 11.3458 0.961787 11.5543 1.11464 11.6091L1.32208 11.6859C2.07543 11.9712 2.67593 12.5637 2.9598 13.3318L3.03622 13.5403C3.06898 13.6171 3.13449 13.65 3.2 13.65C3.2655 13.65 3.33101 13.6171 3.36377 13.5403L3.44019 13.3318C3.72406 12.5747 4.31364 11.9712 5.07791 11.6859L5.28535 11.6091C5.4382 11.5543 5.4382 11.3458 5.28535 11.2909L5.07791 11.2141C4.32456 10.9288 3.72406 10.3363 3.44019 9.56824L3.36377 9.35976C3.33101 9.28295 3.2655 9.25003 3.2 9.25003Z" fill="black" fill-opacity="0.9"/>
<path d="M12 14.75C8.44345 14.75 5.32495 16.6254 3.57944 19.4413C3.03402 20.3211 3.74922 21.35 4.78444 21.35H19.2155C20.2507 21.35 20.9659 20.3211 20.4205 19.4413C18.675 16.6254 15.5565 14.75 12 14.75Z" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round"/>
<path d="M14.2 3.23867C13.5528 2.86429 12.8014 2.65002 12 2.65002C9.56992 2.65002 7.59998 4.61997 7.59998 7.05003C7.59998 9.48008 9.56992 11.45 12 11.45C12.3798 11.45 12.7484 11.4019 13.1 11.3114" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.00295 5.12505C5.98511 4.72548 6.04735 4.32637 6.186 3.9512C6.32466 3.57604 6.53694 3.23238 6.81035 2.94045C7.08377 2.64853 7.4128 2.41422 7.77809 2.25132C8.14338 2.08841 8.53756 2.0002 8.93745 1.99186C9.33733 1.98353 9.73485 2.05524 10.1066 2.20278C10.4784 2.35032 10.8169 2.57072 11.1022 2.851C11.3876 3.13128 11.614 3.46579 11.7681 3.83485C11.9223 4.20391 12.0011 4.60008 12 5.00005V18M6.00295 5.12505C5.41515 5.27619 4.86945 5.5591 4.40718 5.95236C3.94491 6.34562 3.57819 6.83892 3.3348 7.3949C3.0914 7.95087 2.97771 8.55494 3.00234 9.16136C3.02697 9.76778 3.18927 10.3606 3.47695 10.8951M6.00295 5.12505C6.02273 5.60878 6.15938 6.0805 6.40105 6.5M3.47695 10.8951C2.97113 11.306 2.57338 11.8343 2.31829 12.434C2.0632 13.0337 1.95851 13.6866 2.01332 14.336C2.06812 14.9854 2.28077 15.6116 2.63276 16.1601C2.98475 16.7085 3.46542 17.1627 4.03295 17.4831M3.47695 10.8951C3.65989 10.7461 3.85575 10.6145 4.06205 10.5M4.03295 17.4831C3.96287 18.0253 4.00469 18.5761 4.15584 19.1016C4.30699 19.627 4.56425 20.1159 4.91174 20.538C5.25923 20.9601 5.68956 21.3065 6.17617 21.5558C6.66278 21.8051 7.19533 21.952 7.74093 21.9874C8.28653 22.0228 8.83359 21.946 9.34834 21.7617C9.86309 21.5774 10.3346 21.2895 10.7337 20.9158C11.1328 20.5421 11.4511 20.0906 11.6689 19.5891C11.8867 19.0876 11.9994 18.5468 12 18M4.03295 17.4831C4.63322 17.8216 5.31079 18.0002 5.99996 17.9999M12 18L18 18C18.5304 18 19.0391 18.2107 19.4142 18.5858C19.7893 18.9609 20 19.4696 20 20V21M9 13C9.83956 12.7047 10.5727 12.167 11.1067 11.455C11.6407 10.743 11.9515 9.88867 12 9M12 13H16M12 8H20M16 8V5C16 4.46957 16.2107 3.96086 16.5858 3.58579C16.9609 3.21071 17.4696 3 18 3M16.5 13C16.5 13.2761 16.2761 13.5 16 13.5C15.7239 13.5 15.5 13.2761 15.5 13C15.5 12.7239 15.7239 12.5 16 12.5C16.2761 12.5 16.5 12.7239 16.5 13ZM18.5 3C18.5 3.27614 18.2761 3.5 18 3.5C17.7239 3.5 17.5 3.27614 17.5 3C17.5 2.72386 17.7239 2.5 18 2.5C18.2761 2.5 18.5 2.72386 18.5 3ZM20.5 21C20.5 21.2761 20.2761 21.5 20 21.5C19.7239 21.5 19.5 21.2761 19.5 21C19.5 20.7239 19.7239 20.5 20 20.5C20.2761 20.5 20.5 20.7239 20.5 21ZM20.5 8C20.5 8.27614 20.2761 8.5 20 8.5C19.7239 8.5 19.5 8.27614 19.5 8C19.5 7.72386 19.7239 7.5 20 7.5C20.2761 7.5 20.5 7.72386 20.5 8Z" stroke="black" stroke-opacity="0.9" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.852 14.772L10.469 15.695M10.852 9.22793L10.469 8.30493M13.1479 14.772L13.5299 15.696M13.5309 8.30493L13.1479 9.22793M14.772 10.852L15.695 10.469M14.772 13.1479L15.695 13.5309M17.598 6.50002C17.8281 6.10151 17.9635 5.65541 17.9936 5.19622C18.0237 4.73703 17.9478 4.27707 17.7717 3.85192C17.5956 3.42677 17.3241 3.04782 16.9781 2.7444C16.6321 2.44098 16.221 2.22122 15.7765 2.10212C15.332 1.98301 14.8661 1.96776 14.4147 2.05754C13.9634 2.14732 13.5388 2.33972 13.1737 2.61987C12.8086 2.90001 12.5129 3.26039 12.3094 3.67311C12.1059 4.08584 12 4.53985 12 5.00002C12.0006 4.33382 11.7795 3.68636 11.3714 3.15976C10.9633 2.63315 10.3916 2.25735 9.74633 2.09162C9.10107 1.9259 8.41899 1.97966 7.80767 2.24445C7.19634 2.50924 6.69055 2.96998 6.37004 3.55402C6.1062 4.03426 5.97893 4.57758 6.00204 5.12502M6.00204 5.12502C5.41418 5.27624 4.86846 5.55926 4.40619 5.95264C3.94393 6.34602 3.57726 6.83944 3.33395 7.39553C3.09064 7.95162 2.97708 8.55579 3.00187 9.16228C3.02666 9.76876 3.18915 10.3616 3.47704 10.896M6.00204 5.12502C6.02242 5.60893 6.15958 6.08068 6.40195 6.5M17.998 5.125C18.5859 5.27622 19.1316 5.55923 19.5939 5.95261C20.0562 6.34599 20.4228 6.83942 20.6661 7.39551C20.9094 7.9516 21.023 8.55577 20.9982 9.16225C20.9734 9.76874 20.8109 10.3616 20.523 10.896M19.505 10.2939C20.3642 10.6429 21.0754 11.2795 21.5171 12.095C21.9587 12.9104 22.1033 13.854 21.9261 14.7642C21.749 15.6745 21.261 16.4949 20.5457 17.0851C19.8305 17.6754 18.9324 17.9987 18.005 17.9999M4.03203 17.4829C3.91165 18.4006 4.11325 19.3317 4.60248 20.1174C5.09171 20.9031 5.83829 21.4949 6.71496 21.7918C7.59163 22.0887 8.54414 22.0724 9.41013 21.7456C10.2761 21.4189 11.002 20.8019 11.464 19.9999C11.644 19.6889 12.356 19.6889 12.536 19.9999C12.9981 20.8018 13.7238 21.4186 14.5897 21.7453C15.4556 22.072 16.4079 22.0884 17.2845 21.7916C18.161 21.4949 18.9076 20.9034 19.3969 20.1179C19.8863 19.3324 20.0881 18.4015 19.968 17.4839M4.50004 10.291C3.63893 10.6387 2.92565 11.2753 2.48253 12.0914C2.03941 12.9075 1.89407 13.8524 2.07145 14.764C2.24882 15.6756 2.73785 16.497 3.45465 17.0875C4.17146 17.6779 5.07137 18.0005 6.00004 18M9.22805 10.852L8.30505 10.469M9.22805 13.1479L8.30505 13.5309M15 12C15 13.6569 13.6569 15 12 15C10.3431 15 9 13.6569 9 12C9 10.3431 10.3431 9 12 9C13.6569 9 15 10.3431 15 12Z" stroke="black" stroke-opacity="0.9" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 18V5M12 18C12.0006 18.5467 12.1132 19.0875 12.331 19.589C12.5488 20.0905 12.8671 20.542 13.2662 20.9157C13.6654 21.2893 14.1369 21.5772 14.6516 21.7615C15.1664 21.9458 15.7134 22.0227 16.259 21.9872C16.8046 21.9518 17.3372 21.805 17.8238 21.5557C18.3104 21.3064 18.7407 20.96 19.0882 20.5379C19.4357 20.1157 19.693 19.6269 19.8441 19.1014C19.9953 18.576 20.0371 18.0251 19.967 17.4829M12 18C11.9994 18.5467 11.8867 19.0875 11.669 19.589C11.4512 20.0905 11.1329 20.542 10.7338 20.9157C10.3346 21.2893 9.86313 21.5772 9.34838 21.7615C8.83364 21.9458 8.28657 22.0227 7.74097 21.9872C7.19537 21.9518 6.66283 21.805 6.17622 21.5557C5.68961 21.3064 5.25927 20.96 4.91178 20.5379C4.56429 20.1157 4.30703 19.6269 4.15588 19.1014C4.00474 18.576 3.96291 18.0251 4.033 17.4829M12 5C12 4.53983 12.1058 4.0857 12.3093 3.67298C12.5129 3.26025 12.8086 2.89988 13.1737 2.61973C13.5387 2.33959 13.9634 2.14718 14.4147 2.0574C14.866 1.96763 15.332 1.98288 15.7765 2.10198C16.221 2.22108 16.6321 2.44085 16.9781 2.74427C17.324 3.04769 17.5956 3.42663 17.7717 3.85178C17.9478 4.27693 18.0237 4.73689 17.9936 5.19608C17.9635 5.65527 17.8281 6.10138 17.598 6.49989M12 5C12 4.53983 11.8942 4.0857 11.6907 3.67298C11.4871 3.26025 11.1914 2.89988 10.8263 2.61973C10.4613 2.33959 10.0366 2.14718 9.5853 2.0574C9.13396 1.96763 8.66803 1.98288 8.22353 2.10198C7.77904 2.22108 7.3679 2.44085 7.02193 2.74427C6.67596 3.04769 6.40442 3.42663 6.22833 3.85178C6.05224 4.27693 5.97632 4.73689 6.00643 5.19608C6.03655 5.65527 6.17189 6.10138 6.402 6.49989M15 13C14.1348 12.7471 13.3748 12.2206 12.834 11.4995C12.2932 10.7784 12.0005 9.90141 12 9C11.9995 9.90141 11.7068 10.7784 11.166 11.4995C10.6252 12.2206 9.8652 12.7471 9 13M17.9969 5.125C18.5847 5.27614 19.1304 5.55905 19.5927 5.95231C20.055 6.34557 20.4217 6.83887 20.6651 7.39485C20.9085 7.95082 21.0222 8.55489 20.9976 9.16131C20.9729 9.76773 20.8106 10.3606 20.5229 10.895M18 17.9999C18.8805 17.9999 19.7364 17.7093 20.4349 17.1733C21.1335 16.6372 21.6356 15.8857 21.8635 15.0352C22.0914 14.1847 22.0323 13.2827 21.6954 12.4693C21.3585 11.6558 20.7625 10.9762 20 10.5359M5.99995 17.9999C5.11944 17.9999 4.26355 17.7093 3.56501 17.1733C2.86647 16.6372 2.36432 15.8857 2.13642 15.0352C1.90853 14.1847 1.96763 13.2827 2.30456 12.4693C2.6415 11.6558 3.23743 10.9762 3.99995 10.5359M6.00305 5.125C5.41525 5.27614 4.86955 5.55905 4.40728 5.95231C3.94501 6.34557 3.57829 6.83887 3.3349 7.39485C3.0915 7.95082 2.97781 8.55489 3.00244 9.16131C3.02707 9.76773 3.18937 10.3606 3.47705 10.895" stroke="black" stroke-opacity="0.9" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20.25 10.9688V17.1563C20.25 18.8649 18.8649 20.25 17.1562 20.25H6.84375C5.13512 20.25 3.75 18.8649 3.75 17.1562V6.84375C3.75 5.13512 5.13512 3.75 6.84375 3.75H13.0312" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M18.3369 8.68764L17.6721 10.7136C17.5383 11.1213 16.9617 11.1213 16.8279 10.7136L16.1631 8.68764C16.031 8.28489 15.7151 7.96902 15.3124 7.83687L13.2864 7.17209C12.8787 7.03833 12.8787 6.46167 13.2864 6.32791L15.3124 5.66313C15.7151 5.53098 16.031 5.21511 16.1631 4.81236L16.8279 2.78637C16.9617 2.37872 17.5383 2.37872 17.6721 2.78637L18.3369 4.81236C18.469 5.21511 18.7849 5.53098 19.1876 5.66313L21.2136 6.32791C21.6213 6.46167 21.6213 7.03833 21.2136 7.17209L19.1876 7.83687C18.7849 7.96902 18.469 8.28489 18.3369 8.68764Z" fill="black" fill-opacity="0.9"/>
<path d="M13 16L15 16" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 12L10 14L8 16" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,7 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.9126 15.9331C10.1709 16.2485 11.5985 16.2487 13.0351 15.8638C14.4717 15.4788 15.7079 14.7649 16.64 13.8626" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round"/>
<ellipse cx="14.5094" cy="9.77454" rx="1" ry="1.5" transform="rotate(-15 14.5094 9.77454)" fill="black" fill-opacity="0.9"/>
<ellipse cx="8.71402" cy="11.3278" rx="1" ry="1.5" transform="rotate(-15 8.71402 11.3278)" fill="black" fill-opacity="0.9"/>
<path d="M3.20356 14.357C2.09246 10.2103 1.53691 8.13698 2.47995 6.50359C3.42298 4.87021 5.49632 4.31466 9.643 3.20356C13.7897 2.09246 15.863 1.53691 17.4964 2.47995C19.1298 3.42298 19.6853 5.49632 20.7964 9.643C21.9075 13.7897 22.4631 15.863 21.5201 17.4964C20.577 19.1298 18.5037 19.6853 14.357 20.7964C10.2103 21.9075 8.13698 22.4631 6.50359 21.5201C4.87021 20.577 4.31466 18.5037 3.20356 14.357Z" stroke="black" stroke-opacity="0.9" stroke-width="1.5"/>
<path d="M13 15.9999L13.478 16.9737C13.8393 17.7099 14.7249 18.0193 15.4661 17.6685C16.2223 17.3105 16.5394 16.403 16.1708 15.6519L15.7115 14.7163" stroke="black" stroke-opacity="0.9" stroke-width="1.5"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.9241 9.14973C21.8575 9.00501 21.7509 8.8824 21.6167 8.79643C21.4826 8.71046 21.3267 8.66473 21.1674 8.66466H12.2346L13.6415 3.03215C13.6861 2.85036 13.6682 2.65885 13.5907 2.48845C13.5133 2.31806 13.3807 2.17871 13.2143 2.09285C13.048 2.00699 12.8576 1.97962 12.6739 2.01515C12.4901 2.05068 12.3236 2.14704 12.2013 2.2887L2.20008 13.9571C2.09661 14.0781 2.02995 14.2262 2.00798 14.3838C1.98601 14.5415 2.00964 14.7021 2.07609 14.8468C2.14254 14.9915 2.24903 15.114 2.38295 15.2001C2.51688 15.2861 2.67264 15.332 2.83182 15.3323H11.7646L10.3577 20.9648C10.3125 21.1469 10.33 21.339 10.4074 21.5099C10.4848 21.6808 10.6177 21.8206 10.7844 21.9066C10.9022 21.9684 11.0332 22.0004 11.1662 22C11.2863 21.9998 11.4049 21.9736 11.5139 21.9232C11.623 21.8729 11.7198 21.7996 11.7979 21.7083L21.7991 10.0399C21.9028 9.91896 21.9697 9.77085 21.9919 9.6131C22.0141 9.45534 21.9905 9.29454 21.9241 9.14973Z" fill="black" fill-opacity="0.9"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20.25 13.5139C20.25 14.9505 20.25 15.6689 20.0153 16.2355C19.7024 16.991 19.1021 17.5912 18.3466 17.9042C17.78 18.1389 17.0617 18.1389 15.625 18.1389H12.8543C12.3073 18.1389 11.7827 18.3555 11.3959 18.7409L9.93258 20.1993C9.17217 20.9572 7.875 20.4186 7.875 19.345C7.875 18.6789 7.33499 18.1389 6.66885 18.1389H5.8125C4.67341 18.1389 3.75 17.2155 3.75 16.0764V8.68333C3.75 6.95651 3.75 6.09309 4.08606 5.43353C4.38167 4.85336 4.85336 4.38167 5.43353 4.08606C6.09309 3.75 6.95651 3.75 8.68334 3.75H11.3959" stroke="black" stroke-opacity="0.9" stroke-width="1.54167" stroke-linecap="round"/>
<path d="M18.3369 8.68764L17.6721 10.7136C17.5383 11.1213 16.9617 11.1213 16.8279 10.7136L16.1631 8.68764C16.031 8.28489 15.7151 7.96902 15.3124 7.83687L13.2864 7.17209C12.8787 7.03833 12.8787 6.46167 13.2864 6.32791L15.3124 5.66313C15.7151 5.53098 16.031 5.21511 16.1631 4.81236L16.8279 2.78637C16.9617 2.37872 17.5383 2.37872 17.6721 2.78637L18.3369 4.81236C18.469 5.21511 18.7849 5.53098 19.1876 5.66313L21.2136 6.32791C21.6213 6.46167 21.6213 7.03833 21.2136 7.17209L19.1876 7.83687C18.7849 7.96902 18.469 8.28489 18.3369 8.68764Z" fill="black" fill-opacity="0.9"/>
<path d="M14 13H8" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11 10H8" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.5 12.25C21.5 17.3586 17.3586 21.5 12.25 21.5C10.624 21.5 9.09603 21.0805 7.76837 20.3438L6.18274 20.5832C5.30385 20.7159 4.86441 20.7822 4.57835 20.6363C4.32872 20.509 4.14396 20.2829 4.06904 20.0129C3.98318 19.7034 4.13588 19.2861 4.44128 18.4513L4.73599 17.6458C3.64346 16.1271 3 14.2637 3 12.25C3 7.14137 7.14137 3 12.25 3" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M18.3369 8.68764L17.6721 10.7136C17.5383 11.1213 16.9617 11.1213 16.8279 10.7136L16.1631 8.68764C16.031 8.28489 15.7151 7.96902 15.3124 7.83687L13.2864 7.17209C12.8787 7.03833 12.8787 6.46167 13.2864 6.32791L15.3124 5.66313C15.7151 5.53098 16.031 5.21511 16.1631 4.81236L16.8279 2.78637C16.9617 2.37872 17.5383 2.37872 17.6721 2.78637L18.3369 4.81236C18.469 5.21511 18.7849 5.53098 19.1876 5.66313L21.2136 6.32791C21.6213 6.46167 21.6213 7.03833 21.2136 7.17209L19.1876 7.83687C18.7849 7.96902 18.469 8.28489 18.3369 8.68764Z" fill="black" fill-opacity="0.9"/>
<path d="M15 14H9" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 11H9" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,7 @@
<svg width="18" height="21" viewBox="0 0 18 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.7587 5H12.2413C13.0463 4.99999 13.7106 4.99998 14.2518 5.04419C14.8139 5.09012 15.3306 5.18868 15.816 5.43597C16.5686 5.81947 17.1805 6.43139 17.564 7.18404C17.8113 7.66937 17.9099 8.18608 17.9558 8.74817C18 9.28936 18 9.95372 18 10.7587V15.2413C18 16.0463 18 16.7106 17.9558 17.2518C17.9099 17.8139 17.8113 18.3306 17.564 18.816C17.1805 19.5686 16.5686 20.1805 15.816 20.564C15.3306 20.8113 14.8139 20.9099 14.2518 20.9558C13.7106 21 13.0463 21 12.2413 21H5.75873C4.95374 21 4.28938 21 3.74817 20.9558C3.18608 20.9099 2.66937 20.8113 2.18404 20.564C1.43139 20.1805 0.819468 19.5686 0.435975 18.816C0.188684 18.3306 0.0901197 17.8139 0.0441945 17.2518C-2.28137e-05 16.7106 -1.23241e-05 16.0463 4.31291e-07 15.2413V10.7587C-1.23241e-05 9.95373 -2.28137e-05 9.28937 0.0441945 8.74817C0.0901197 8.18608 0.188684 7.66937 0.435975 7.18404C0.819468 6.43139 1.43139 5.81947 2.18404 5.43597C2.66937 5.18868 3.18608 5.09012 3.74817 5.04419C4.28937 4.99998 4.95373 4.99999 5.7587 5ZM3.91104 7.03755C3.47262 7.07337 3.24842 7.1383 3.09202 7.21799C2.7157 7.40973 2.40973 7.71569 2.21799 8.09202C2.1383 8.24842 2.07337 8.47262 2.03755 8.91104C2.00078 9.36113 2 9.94342 2 10.8V15.2C2 16.0566 2.00078 16.6389 2.03755 17.089C2.07337 17.5274 2.1383 17.7516 2.21799 17.908C2.40973 18.2843 2.7157 18.5903 3.09202 18.782C3.24842 18.8617 3.47262 18.9266 3.91104 18.9624C4.36113 18.9992 4.94342 19 5.8 19H12.2C13.0566 19 13.6389 18.9992 14.089 18.9624C14.5274 18.9266 14.7516 18.8617 14.908 18.782C15.2843 18.5903 15.5903 18.2843 15.782 17.908C15.8617 17.7516 15.9266 17.5274 15.9624 17.089C15.9992 16.6389 16 16.0566 16 15.2V10.8C16 9.94342 15.9992 9.36113 15.9624 8.91104C15.9266 8.47262 15.8617 8.24842 15.782 8.09202C15.5903 7.71569 15.2843 7.40973 14.908 7.21799C14.7516 7.1383 14.5274 7.07337 14.089 7.03755C13.6389 7.00078 13.0566 7 12.2 7H5.8C4.94342 7 4.36113 7.00078 3.91104 7.03755Z" fill="black" fill-opacity="0.9"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.00004 2.43L7 3.00006C6.99997 3.55235 6.55222 4.00003 5.99994 4C5.44766 3.99997 4.99997 3.55222 5 2.99994L5.00006 1.99994C5.00008 1.74201 5.09975 1.49407 5.27826 1.3079C5.52078 1.05498 5.88254 0.687155 6.51489 0.412789C7.12646 0.147442 7.91511 0 9.00005 0C10.085 0 10.8736 0.147454 11.4852 0.412808C12.1175 0.687178 12.4793 1.055 12.7218 1.30788C12.9003 1.49406 13 1.74204 13 2V3C13 3.55228 12.5523 4 12 4C11.4477 4 11 3.55228 11 3V2.42998C10.9115 2.36092 10.8144 2.30192 10.6891 2.24754C10.4093 2.12611 9.91506 2 9.00005 2C8.08502 2 7.59082 2.12611 7.31095 2.24754C7.18561 2.30192 7.08855 2.36092 7.00004 2.43Z" fill="black" fill-opacity="0.9"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.2 14.4C5.53137 13.9582 6.15817 13.8686 6.6 14.2C7.40663 14.805 8.18856 15.0004 8.99946 15C9.81035 14.9996 10.594 14.8045 11.4 14.2C11.8418 13.8686 12.4686 13.9582 12.8 14.4C13.1314 14.8418 13.0418 15.4686 12.6 15.8C11.406 16.6955 10.1879 16.9994 9.00054 17C7.80971 17.0006 6.59337 16.695 5.4 15.8C4.95817 15.4686 4.86863 14.8418 5.2 14.4Z" fill="black" fill-opacity="0.9"/>
<path d="M4 11.5C4 10.6716 4.67157 10 5.5 10C6.32843 10 7 10.6716 7 11.5C7 12.3284 6.32843 13 5.5 13C4.67157 13 4 12.3284 4 11.5Z" fill="black" fill-opacity="0.9"/>
<path d="M11 11.5C11 10.6716 11.6716 10 12.5 10C13.3284 10 14 10.6716 14 11.5C14 12.3284 13.3284 13 12.5 13C11.6716 13 11 12.3284 11 11.5Z" fill="black" fill-opacity="0.9"/>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 140 KiB

View File

Before

Width:  |  Height:  |  Size: 866 B

After

Width:  |  Height:  |  Size: 866 B

View File

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 655 B

After

Width:  |  Height:  |  Size: 655 B

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

Before

Width:  |  Height:  |  Size: 714 B

After

Width:  |  Height:  |  Size: 714 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 992 B

After

Width:  |  Height:  |  Size: 992 B

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 428 B

After

Width:  |  Height:  |  Size: 428 B

View File

Before

Width:  |  Height:  |  Size: 943 B

After

Width:  |  Height:  |  Size: 943 B

View File

Before

Width:  |  Height:  |  Size: 921 B

After

Width:  |  Height:  |  Size: 921 B

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 470 B

After

Width:  |  Height:  |  Size: 470 B

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 564 B

After

Width:  |  Height:  |  Size: 564 B

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 865 B

After

Width:  |  Height:  |  Size: 865 B

View File

Before

Width:  |  Height:  |  Size: 889 B

After

Width:  |  Height:  |  Size: 889 B

View File

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Some files were not shown because too many files have changed in this diff Show More