From 1af3cf75c785106eb4a186c3a0d965c421d56cba Mon Sep 17 00:00:00 2001 From: Yun Chan Date: Fri, 18 Sep 2026 15:45:03 +0900 Subject: [PATCH] fix(release): stop shipping native modules built for the wrong runtime The released installer could not start: it carried a better-sqlite3 build for the host Node runtime instead of Electron, so the app died immediately with a module version mismatch when it opened its database. Packaging now proves the Electron build of every runtime-sensitive native module before an installer or archive exists, and installers are produced only from that verified tree, so the mistake cannot pass silently. The release pipelines run the same check. The default local model also pointed at a retired model: a *.gguf name that Ollama cannot serve, while the settings, onboarding, and guide screens recommended an older model. All of them now use the model the service code already preferred. --- .forgejo/workflows/release.yml | 1 + .github/workflows/release.yml | 2 + .gitlab-ci.yml | 2 + CHANGELOG.md | 13 ++ apps/admin-swagger/openapi.json | 2 +- apps/admin/package.json | 2 +- apps/api-server/D3ROVoice.Api.csproj | 2 +- apps/desktop/electron-builder.yml | 2 + apps/desktop/package.json | 2 +- .../src/main/services/ConfigService.ts | 2 +- .../src/main/services/LocalLLMService.ts | 4 +- .../renderer/components/OllamaGuideModal.tsx | 4 +- .../renderer/components/OnboardingModal.tsx | 4 +- .../src/renderer/components/SettingsModal.tsx | 6 +- apps/mobile-rn/android/app/build.gradle | 4 +- .../ios/D3ROVoice.xcodeproj/project.pbxproj | 8 +- .../android/en-US/changelogs/1031003.txt | 1 + .../android/ko-KR/changelogs/1031003.txt | 1 + apps/mobile-rn/package-lock.json | 14 +-- apps/mobile-rn/package.json | 2 +- apps/web/package.json | 2 +- apps/web/src/components/layout/sidebar.tsx | 2 +- bucket/d3ro-voice.json | 8 +- docs/deployment/release-guide.md | 5 + docs/map/10-feature-catalog.md | 1 + docs/map/11-gap-backlog.md | 1 + memory/project_status.md | 19 +++ package-lock.json | 20 +-- package.json | 2 +- packages/api-client/package.json | 2 +- packages/core/package.json | 2 +- packages/i18n/package.json | 2 +- packages/ui-native/package.json | 2 +- packages/ui/package.json | 2 +- release/product-version.json | 6 +- scripts/ci/build-portable.mjs | 22 ++++ scripts/ci/fix-native-abi.mjs | 119 ++++++++++++++++++ scripts/ci/publish-portable-release.mjs | 49 ++++++-- scripts/ci/publish-updater-release.mjs | 89 ++++++++++--- scripts/ci/verify-native-abi.mjs | 117 +++++++++++++++++ site/package-lock.json | 4 +- site/package.json | 2 +- 42 files changed, 473 insertions(+), 83 deletions(-) create mode 100644 apps/mobile-rn/metadata/android/en-US/changelogs/1031003.txt create mode 100644 apps/mobile-rn/metadata/android/ko-KR/changelogs/1031003.txt create mode 100644 scripts/ci/fix-native-abi.mjs create mode 100644 scripts/ci/verify-native-abi.mjs diff --git a/.forgejo/workflows/release.yml b/.forgejo/workflows/release.yml index e5c3913..3159540 100644 --- a/.forgejo/workflows/release.yml +++ b/.forgejo/workflows/release.yml @@ -64,6 +64,7 @@ jobs: npm run build --workspace=@d3ro/desktop Push-Location apps/desktop npx electron-builder --win --x64 --config electron-builder.yml --publish never + node scripts/ci/verify-native-abi.mjs Pop-Location - name: Windows 산출물 검증 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7391d26..1e5c634 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -138,6 +138,7 @@ jobs: Push-Location apps/desktop try { npx electron-builder --win --x64 --config electron-builder.yml + node scripts/ci/verify-native-abi.mjs if ($LASTEXITCODE -ne 0) { throw "electron-builder failed with exit code $LASTEXITCODE." } } finally { @@ -201,6 +202,7 @@ jobs: run: | cd apps/desktop npx electron-builder --mac --arm64 --config electron-builder.yml + node scripts/ci/verify-native-abi.mjs env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} CSC_LINK: ${{ secrets.MAC_CSC_LINK }} diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fdcef83..793335c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -251,6 +251,7 @@ package-windows: - npm run build --workspace=@d3ro/desktop - cd apps/desktop - npx electron-builder --win --x64 --config electron-builder.yml + - node scripts/ci/verify-native-abi.mjs - cd ../.. - $releaseVersion = node -p "require('./release/product-version.json').version" - '& scripts/ci/verify-windows-release-artifact.ps1 -ExpectedVersion $releaseVersion -ExpectedSignerSubject $env:WIN_CSC_EXPECTED_SIGNER_SUBJECT -ReleaseDirectory "apps/desktop/release/$releaseVersion"' @@ -282,6 +283,7 @@ package-macos: - npm run build --workspace=@d3ro/desktop - cd apps/desktop - npx electron-builder --mac --arm64 --config electron-builder.yml + - node scripts/ci/verify-native-abi.mjs artifacts: name: "d3ro-voice-macos-$CI_COMMIT_TAG" paths: diff --git a/CHANGELOG.md b/CHANGELOG.md index 9373919..75062a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Cloud-optional backup (encrypted, opt-in) - Plugin system for custom pipelines +## [1.3.3] - 2026-09-18 + +### Fixed +- **The released installer could not start**: it carried a `better-sqlite3` build for the + host Node runtime instead of Electron, so the app failed immediately with a + `NODE_MODULE_VERSION` mismatch when opening its database. Packaging now guarantees and + verifies the Electron build of every runtime-sensitive native module before an installer + or archive is produced, and publishes only from that verified tree. +- **The local language model default still pointed at a retired model**: the stored default + was a `*.gguf` file name that Ollama cannot serve, and the settings, onboarding, and + Ollama guide still recommended `gemma2:2b` while the service code already preferred + `gemma4:e4b`. All surfaces now default to `gemma4:e4b`. + ## [1.3.2] - 2026-09-18 ### Changed diff --git a/apps/admin-swagger/openapi.json b/apps/admin-swagger/openapi.json index 8dce225..6c1edc1 100644 --- a/apps/admin-swagger/openapi.json +++ b/apps/admin-swagger/openapi.json @@ -3,7 +3,7 @@ "info": { "title": "D3RO-VOICE Admin API", "description": "Admin CRM Edge Functions for user management, subscription CRUD, payment history, and audit logs.", - "version": "1.3.2" + "version": "1.3.3" }, "servers": [ { diff --git a/apps/admin/package.json b/apps/admin/package.json index e2a9b30..6b80dc6 100644 --- a/apps/admin/package.json +++ b/apps/admin/package.json @@ -1,6 +1,6 @@ { "name": "@d3ro/admin", - "version": "1.3.2", + "version": "1.3.3", "private": true, "description": "D3RO Voice Admin CRM — SaaS 관리 도구", "scripts": { diff --git a/apps/api-server/D3ROVoice.Api.csproj b/apps/api-server/D3ROVoice.Api.csproj index aeb40ea..42a627f 100644 --- a/apps/api-server/D3ROVoice.Api.csproj +++ b/apps/api-server/D3ROVoice.Api.csproj @@ -2,7 +2,7 @@ net10.0 - 1.3.2 + 1.3.3 enable enable diff --git a/apps/desktop/electron-builder.yml b/apps/desktop/electron-builder.yml index 8985bbb..d762e2f 100644 --- a/apps/desktop/electron-builder.yml +++ b/apps/desktop/electron-builder.yml @@ -20,6 +20,8 @@ files: - "!out/**/*.map" # ffmpeg 정적 바이너리(61MB)는 설치본에 넣지 않는다 — 필요할 때 런타임으로 내려받는다 - "!node_modules/@ffmpeg-installer/**" + # ffmpeg 정적 바이너리(61MB)는 설치본에 넣지 않는다 — 필요할 때 런타임으로 내려받는다 + - "!node_modules/@ffmpeg-installer/**" # ──────────────────────────────────────────────────────────────────── # 자동 업데이트 feed — 이 설정이 있어야 electron-builder가 diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 3806fbd..eed0ba2 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@d3ro/desktop", - "version": "1.3.2", + "version": "1.3.3", "productName": "d3ro-voice", "description": "로컬 AI 음성 어시스턴트 (Electron)", "main": "./out/main/index.js", diff --git a/apps/desktop/src/main/services/ConfigService.ts b/apps/desktop/src/main/services/ConfigService.ts index 2f0b2e9..51d2ec9 100644 --- a/apps/desktop/src/main/services/ConfigService.ts +++ b/apps/desktop/src/main/services/ConfigService.ts @@ -42,7 +42,7 @@ const CONFIG_DEFAULTS: AppConfig = { ttsSpeed: 1.0, onlineApiUrl: 'http://127.0.0.1:5000', localModelsDir: '', - llmModelId: 'gemma-2-2b-it.Q4_K_M.gguf', + llmModelId: 'gemma4:e4b', ollamaServerUrl: 'http://127.0.0.1:11434', appUsageMode: null, authToken: null, diff --git a/apps/desktop/src/main/services/LocalLLMService.ts b/apps/desktop/src/main/services/LocalLLMService.ts index 003f31e..64bf06c 100644 --- a/apps/desktop/src/main/services/LocalLLMService.ts +++ b/apps/desktop/src/main/services/LocalLLMService.ts @@ -663,7 +663,7 @@ class LocalLLMService extends EventEmitter { return { connectionState, serverUrl: getOllamaServerUrl(), - activeModel: configGet('llmModelId') || 'gemma2:2b', + activeModel: configGet('llmModelId') || 'gemma4:e4b', serverVersion: this._serverVersion } } @@ -686,7 +686,7 @@ class LocalLLMService extends EventEmitter { } const serverUrl = getOllamaServerUrl() - const model = options?.model ?? configGet('llmModelId') ?? 'gemma2:2b' + const model = options?.model ?? configGet('llmModelId') ?? 'gemma4:e4b' this._abortController = new AbortController() this._state = LLMState.Generating diff --git a/apps/desktop/src/renderer/components/OllamaGuideModal.tsx b/apps/desktop/src/renderer/components/OllamaGuideModal.tsx index 6f8d648..d5cbf80 100644 --- a/apps/desktop/src/renderer/components/OllamaGuideModal.tsx +++ b/apps/desktop/src/renderer/components/OllamaGuideModal.tsx @@ -146,7 +146,7 @@ export function OllamaGuideModal({ open, onClose }: OllamaGuideModalProps): Reac const { t } = useI18n() const [llmStatus, setLlmStatus] = useState(null) const [installedModels, setInstalledModels] = useState([]) - const [activeModel, setActiveModel] = useState('gemma2:2b') + const [activeModel, setActiveModel] = useState('gemma4:e4b') const [checking, setChecking] = useState(false) const [starting, setStarting] = useState(false) const [startMessage, setStartMessage] = useState(null) @@ -582,7 +582,7 @@ export function OllamaGuideModal({ open, onClose }: OllamaGuideModalProps): Reac 직접 터미널에서 다운로드하려면 아래 명령어를 실행하세요: - + diff --git a/apps/desktop/src/renderer/components/OnboardingModal.tsx b/apps/desktop/src/renderer/components/OnboardingModal.tsx index a7aa845..71c87c9 100644 --- a/apps/desktop/src/renderer/components/OnboardingModal.tsx +++ b/apps/desktop/src/renderer/components/OnboardingModal.tsx @@ -49,7 +49,7 @@ export function OnboardingModal({ open, onClose }: OnboardingModalProps): React. // Local Ollama State const [ollamaStatus, setOllamaStatus] = useState(null) const [installedModels, setInstalledModels] = useState([]) - const [activeModel, setActiveModel] = useState('gemma2:2b') + const [activeModel, setActiveModel] = useState('gemma4:e4b') const [checkingOllama, setCheckingOllama] = useState(false) const [startingOllama, setStartingOllama] = useState(false) const [ollamaMsg, setOllamaMsg] = useState(null) @@ -498,7 +498,7 @@ export function OnboardingModal({ open, onClose }: OnboardingModalProps): React.