diff --git a/CHANGELOG.md b/CHANGELOG.md index d1fe864..204a5c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## 2.1.2, 2026-07-18 + +### Neu + +- Native Linux-Titelleiste mit Minimieren, Maximieren und Schließen +- Abgesicherter Fenster-Patch für bestehende und neu aufgebaute Laufzeiten +- Sofortige Inhaltsanpassung beim Maximieren und Ändern der Fenstergröße +- Nutzbare Mindestgröße von 900 × 650 Pixeln für normale Kimi-Fenster + +### Geändert + +- Der native Aufbau aktiviert die Linux-Systemdekoration nach dem Entpacken der Kimi-Anwendung +- Die Inhaltsgröße wird sofort, im nächsten Ereigniszyklus und nach Abschluss der Größenänderung synchronisiert + +### Behoben + +- Fehlende Fensterknöpfe unter Linux +- Verzögerte oder unvollständige Inhaltsanpassung nach Maximieren und manueller Größenänderung +- Unbrauchbar kleines Zusammenschieben der normalen Kimi-Fenster + +### Entfernt + +- Keine Änderungen + ## 2.1.1, 2026-07-18 ### Neu diff --git a/README.md b/README.md index d8eb278..6ae8f0f 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,9 @@ Bei jeder vollständigen Installation wird die aktuell von Moonshot AI angeboten - Start über das Programmmenü und als systemd-Benutzerdienst - Sicheres Update-Skript mit Versionsprüfung und atomarem Austausch - Kimi K3 über die aktuelle Kimi-Work-Modellauswahl +- Native Linux-Fensterknöpfe für Minimieren, Maximieren und Schließen +- Sofortige Inhaltsanpassung beim Maximieren und Ändern der Fenstergröße +- Mindestgröße von 900 × 650 Pixeln für normale Kimi-Fenster ## Unterstützter Stand @@ -32,7 +35,7 @@ Bei jeder vollständigen Installation wird die aktuell von Moonshot AI angeboten | --- | --- | | Kimi Work | 3.1.2 | | Kimi-Modell | Kimi K3 verfügbar | -| Kimi Work Linux | 2.1.1 | +| Kimi Work Linux | 2.1.2 | | Electron | 41.7.2 | | Kimi Node-Laufzeit | 24.15.0 | | Plattform | Linux x86_64 mit glibc und systemd | diff --git a/package-lock.json b/package-lock.json index 2a1ecab..f09dc02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "kimi-work-linux", - "version": "2.1.1", + "version": "2.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "kimi-work-linux", - "version": "2.1.1", + "version": "2.1.2", "license": "MIT", "devDependencies": { "@electron/asar": "^4.2.0", diff --git a/package.json b/package.json index cce130d..e5db294 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "kimi-work-linux", - "version": "2.1.1", + "version": "2.1.2", "private": true, "description": "Unofficial native Linux runtime for Kimi Work", "license": "MIT", diff --git a/scripts/native-setup.sh b/scripts/native-setup.sh index 265cbbb..ba81d1a 100644 --- a/scripts/native-setup.sh +++ b/scripts/native-setup.sh @@ -12,6 +12,17 @@ OFFICIAL_DOWNLOAD_URL='https://appsupport.moonshot.cn/api/app/pkg/latest/windows NODE_VERSION='v24.15.0' NODE_ARCHIVE_NAME="node-${NODE_VERSION}-linux-x64.tar.gz" NODE_ARCHIVE_SHA='44836872d9aec49f1e6b52a9a922872db9a2b02d235a616a5681b6a85fec8d89' +PATCH_ONLY=false + +# Erlaubt eine abgesicherte Aktualisierung der vorhandenen Fensterintegration. +if [[ "${1:-}" == '--patch-linux-window-only' ]]; then + PATCH_ONLY=true + shift +fi +[[ "$#" -eq 0 ]] || { + printf 'Fehler: Unbekanntes Argument: %s\n' "$1" >&2 + exit 64 +} # Gibt Fehler vollständig aus und beendet den Aufbau. fail() { @@ -34,6 +45,160 @@ cleanup() { } trap cleanup EXIT +# Aktiviert die native Titelleiste und synchronisiert den Inhalt mit der Fenstergröße. +patch_linux_window() { + local app_archive="$1" + local patch_dir="${temporary_dir}/linux-window" + local source_dir="${patch_dir}/source" + local main_process_file="${source_dir}/out/main/index.js" + local patched_archive="${patch_dir}/app.asar" + + [[ -f "$app_archive" ]] || fail "Das Kimi Anwendungsarchiv fehlt: ${app_archive}" + rm -rf -- "$patch_dir" + mkdir -p "$source_dir" + "${PROJECT_DIR}/node_modules/.bin/asar" extract "$app_archive" "$source_dir" + [[ -f "$main_process_file" ]] || fail 'Der Kimi Hauptprozess für die Fensteranpassung fehlt.' + + # Ersetzt ausschließlich die in Kimi 3.1.2 geprüften Fensteroptionen und Ereignisse. + node - "$main_process_file" <<'NODE' +const fs = require('fs') + +const mainProcessFile = process.argv[2] +let patched = fs.readFileSync(mainProcessFile, 'utf8') +const count = (text, value) => text.split(value).length - 1 + +const titlebarOriginal = + 'titleBarStyle: process.platform === "darwin" ? "hiddenInset" : "hidden",' +const titlebarReplacement = + 'titleBarStyle: process.platform === "darwin" ? "hiddenInset" : process.platform === "linux" ? "default" : "hidden",' +const titlebarOriginalCount = count(patched, titlebarOriginal) +const titlebarReplacementCount = count(patched, titlebarReplacement) + +if (titlebarOriginalCount === 2 && titlebarReplacementCount === 0) { + patched = patched.split(titlebarOriginal).join(titlebarReplacement) +} else if (titlebarOriginalCount !== 0 || titlebarReplacementCount !== 2) { + process.stderr.write( + `Fehler: Unerwartete Kimi Titelleistenkonfiguration. Original: ${titlebarOriginalCount}, Linux: ${titlebarReplacementCount}.\n`, + ) + process.exit(1) +} + +const resizeOriginal = ` setupResizeHandler() { + if (!this.baseWindow) { + return; + } + this.baseWindow.on("resized", () => { + this.contentSurface.updateViewBounds(); + this.kimiAgentBrowser.syncVisibility(); + }); + this.baseWindow.on("resize", () => { + this.contentSurface.updateViewBounds(); + this.kimiAgentBrowser.syncVisibility(); + }); + }` +const resizeReplacement = ` setupResizeHandler() { + if (!this.baseWindow) { + return; + } + let resizeRefreshPending = false; + let resizeSettleTimer; + const refreshContentBounds = () => { + if (!this.baseWindow) { + return; + } + this.contentSurface.updateViewBounds(); + this.kimiAgentBrowser.syncVisibility(); + }; + const scheduleContentBoundsRefresh = () => { + refreshContentBounds(); + if (!resizeRefreshPending) { + resizeRefreshPending = true; + setImmediate(() => { + resizeRefreshPending = false; + refreshContentBounds(); + }); + } + if (resizeSettleTimer) { + clearTimeout(resizeSettleTimer); + } + resizeSettleTimer = setTimeout(() => { + resizeSettleTimer = void 0; + refreshContentBounds(); + }, 80); + }; + for (const eventName of [ + "resize", + "resized", + "maximize", + "unmaximize", + "restore", + "enter-full-screen", + "leave-full-screen" + ]) { + this.baseWindow.on(eventName, scheduleContentBoundsRefresh); + } + }` +const resizeOriginalCount = count(patched, resizeOriginal) +const resizeReplacementCount = count(patched, resizeReplacement) + +if (resizeOriginalCount === 1 && resizeReplacementCount === 0) { + patched = patched.replace(resizeOriginal, resizeReplacement) +} else if (resizeOriginalCount !== 0 || resizeReplacementCount !== 1) { + process.stderr.write( + `Fehler: Unerwartete Kimi Größenlogik. Original: ${resizeOriginalCount}, Linux: ${resizeReplacementCount}.\n`, + ) + process.exit(1) +} + +const minimumSizeOriginal = ` minWidth: 400, + minHeight: 600,` +const minimumSizeReplacement = ` minWidth: process.platform === "linux" ? 900 : 400, + minHeight: process.platform === "linux" ? 650 : 600,` +const minimumSizeOriginalCount = count(patched, minimumSizeOriginal) +const minimumSizeReplacementCount = count(patched, minimumSizeReplacement) + +if (minimumSizeOriginalCount === 2 && minimumSizeReplacementCount === 0) { + patched = patched.split(minimumSizeOriginal).join(minimumSizeReplacement) +} else if (minimumSizeOriginalCount !== 0 || minimumSizeReplacementCount !== 2) { + process.stderr.write( + `Fehler: Unerwartete Kimi Mindestgröße. Original: ${minimumSizeOriginalCount}, Linux: ${minimumSizeReplacementCount}.\n`, + ) + process.exit(1) +} + +if ( + count(patched, titlebarReplacement) !== 2 || + count(patched, titlebarOriginal) !== 0 || + count(patched, resizeReplacement) !== 1 || + count(patched, resizeOriginal) !== 0 || + count(patched, minimumSizeReplacement) !== 2 || + count(patched, minimumSizeOriginal) !== 0 +) { + process.stderr.write('Fehler: Die Linux Fensteranpassung konnte nicht eindeutig geprüft werden.\n') + process.exit(1) +} + +fs.writeFileSync(mainProcessFile, patched) +process.stdout.write('Die native Linux Titelleiste, Größenanpassung und Mindestgröße wurden aktiviert.\n') +NODE + + "${PROJECT_DIR}/node_modules/.bin/asar" pack "$source_dir" "$patched_archive" + "${PROJECT_DIR}/node_modules/.bin/asar" list "$patched_archive" \ + | grep -qx '/out/main/index.js' \ + || fail 'Das neu gepackte Kimi Archiv enthält keinen Hauptprozess.' + install -m 0644 "$patched_archive" "${app_archive}.tmp" + mv "${app_archive}.tmp" "$app_archive" +} + +# Passt auf ausdrücklichen internen Aufruf nur die vorhandene Laufzeit an. +if [[ "$PATCH_ONLY" == true ]]; then + systemctl --user is-active --quiet kimi-work-native.service \ + && fail 'Kimi Work muss vor der Fensteranpassung beendet werden.' + patch_linux_window "${APP_DIR}/resources/app.asar" + printf '%s\n' 'Die vorhandene Kimi Linux Laufzeit wurde erfolgreich angepasst.' + exit 0 +fi + # Lädt das unveränderte aktuelle Kimi Originalpaket herunter. mkdir -p "$CACHE_DIR" installer_path="${CACHE_DIR}/kimi-work-latest.exe" @@ -70,6 +235,7 @@ new_app_dir="${temporary_dir}/app" cp -a "${PROJECT_DIR}/node_modules/electron/dist" "$new_app_dir" mv "${new_app_dir}/electron" "${new_app_dir}/kimi-desktop" install -m 0644 "${official_dir}/resources/app.asar" "${new_app_dir}/resources/app.asar" +patch_linux_window "${new_app_dir}/resources/app.asar" resource_dir="${new_app_dir}/resources/resources" mkdir -p "${resource_dir}/runtime" "${resource_dir}/skills"