21 KiB
title, version, lastUpdated
| title | version | lastUpdated |
|---|---|---|
| Checklista wydania | 3.8.40 | 2026-06-28 |
Checklista wydania
Ostatnia aktualizacja: 2026-06-28 — v3.8.40 Uproszczony przepływ wydania wykorzystujący skill-e Claude Code do automatyzacji.
Utrzymuj kolejkę/gałąź na zielono między wydaniami: zobacz RELEASE_GREEN.md (rodzina
/green-prs+npm run check:release-green+/babysit+ nightly). Uruchamianie tego okresowo — a zwłaszcza przed tą checklistą — sprawia, że PR wydania startuje na zielono.
TL;DR
# 1. Bump version + generate CHANGELOG (skill)
/version-bump-cc patch # or minor/major
# 2. Run quality gate locally
npm run check # lint + tests
npm run test:coverage # full coverage gate (60/60/60/60)
# 3. Build & smoke
npm run build
npm run test:e2e # optional but recommended
# 4. Generate release (skill)
/generate-release-cc
# 5. Deploy (skill)
/deploy-vps-both-cc # or akamai-cc / local-cc
# 6. Capture release evidences (skill)
/capture-release-evidences-cc
Publikacja etapowa npm (domyślnie od v3.8.49 — WS1.3/D2)
Workflow npm-publish nie publikuje już bezpośrednio: bootuje spakowany tarball
(check:pack-boot), a następnie uruchamia npm stage publish — dokładne bajty są parkowane w
rejestrze, nie da się ich zainstalować, dopóki właściciel nie zatwierdzi. Ludzka bramka 2FA
przeniosła się na PO dowodzie, a nie przed nim.
Przepływ właściciela po zejściu workflow na zielono:
npm stage list omniroute— znajdź stage id (wypisywany też w podsumowaniu workflow).- Zweryfikuj zaparkowane bajty (zalecane):
npm stage download <id>, potem zainstaluj pobrany tarball do tymczasowego prefiksu i zbootuj go (npm run check:pack-bootautomatyzuje ten sam werdykt pack→install→boot w CI). npm stage approve <id>— monity 2FA TO jest publikacja.npm stage reject <id>odrzuca.- Siatka po publikacji: weryfikator post-publish (WS1.4 planu v3.8.49) instaluje opublikowaną wersję z publicznego rejestru w czystym kontenerze i ją bootuje.
Awaryjny fallback: workflow_dispatch z publish_mode=direct przywraca
legacy natychmiastowe npm publish (używaj tylko gdy sam staging się psuje; zanotuj dlaczego).
Jednorazowe utwardzenie (właściciel, npmjs.com): skonfiguruj Trusted Publisher dla
omniroute w trybie stage-only, żeby wycieknięty długotrwały token nie mógł npm publish
bezpośrednio skądkolwiek — CI może tylko stage'ować; tylko 2FA właściciela wypuszcza.
Playbook zepsutego artefaktu (bez zmian): npm deprecate omniroute@<bad> "<reason> — use <fixed>"
jako domyślny odruch (minuty, odwracalne); npm unpublish tylko w oknie 72h/no-dependents
i nigdy jako pierwszy ruch. Docker: nigdy nie nadpisuj tagu wersji — rollback to
przepięcie latest na ostatni dobry digest.
Szybki pas hotfix (etykieta hotfix)
PR z etykietą hotfix pomija ciężką macierz CI (9-shard E2E, coverage ratchet,
quality-gate, quality-extended) i zostawia szybkie, wysokosygnałowe bramki: build,
unit shards, integration, vitest, lint/typecheck, docs-sync, check:pack-artifact
oraz tarball boot-smoke (check:pack-boot). Cel: zieleń w ≤15 min zamiast ~33 min.
Polityka wejścia — wszystkie cztery wymagane (wzorowane na pasach awaryjnych Chromium/VS Code/Node):
- Severity: produkcja jest zepsuta — opublikowany artefakt pada przy bootcie / poprawka bezpieczeństwa / każdy użytkownik wydania jest dotknięty. „Ważne” to nie „zepsute”.
- Authority: tylko właściciel repozytorium nakłada etykietę
hotfix. Etykieta JEST zatwierdzeniem — nigdy self-serve na PR-ze kampanii. - Evidence: treść PR linkuje poprzedni w pełni zielony heavy run (suite, którą pominięte joby by ponownie walidowały) plus własny test poprawki failing-then-passing.
- Scope: wyłącznie cherry-pick — minimalna poprawka, bez refaktorów, bez ride-alongów.
Pominięta powierzchnia coverage/ratchet jest ponownie walidowana przez kolejny pełny run na
gałęzi release (continuous release-green) — pas pomija OCZEKIWANIE, nigdy walidację.
Diffy tylko-testowe (wszystkie pliki pod tests/, żaden pod tests/e2e/) pomijają macierz E2E
automatycznie, bez żadnej etykiety.
Szczegółowa checklista
Przed wydaniem
- Wszystkie PR-y celujące w to wydanie są zmergowane do
release/vX.Y.0 - Wszystkie otwarte pozycje Linear/issue dla tej wersji są zamknięte lub przeniesione do następnego milestone
- CI zielone na gałęzi
release/vX.Y.0 - Brak markerów
TODO(release)w kodzie:grep -r "TODO(release)" src/ open-sse/ - Obraz bazowy Docker aktualny (obecnie
node:24.15.0-trixie-slim)
Wersja i changelog
- Uruchom
/version-bump-cc <patch|minor|major>(skill Claude Code)- Podbija
package.json,electron/package.json - Regeneruje
CHANGELOG.mdz commitów gita od ostatniego tagu - Aktualizuje badge'e w README.md
- Podbija
- Ręcznie przejrzyj CHANGELOG.md i w razie potrzeby wyczyść komunikaty commitów
- Upewnij się, że najnowsza sekcja semver w
CHANGELOG.mdrówna się wersji zpackage.json - Zachowaj
## [Unreleased]jako pierwszą sekcję changelogu na nadchodzącą pracę - Zaktualizuj
docs/openapi.yaml→info.versionmusi równać się wersji zpackage.json
Jakość kodu
npm run lint— 0 błędów (ostrzeżenia są preexisting)npm run typecheck:core— czystonpm run typecheck:noimplicit:core— czysto (strict)npm run check:cycles— brak cyklicznych zależnościnpm run check:any-budget:t11— w budżecienpm run check:route-validation:t06— czystonpm run check:node-runtime— spełnione minimum wspieranego runtime (>=22.22.2 <23,>=24.0.0 <27, wgSUPPORTED_NODE_RANGEwsrc/shared/utils/nodeRuntimeSupport.ts; zgodne zengineswpackage.json)
Testy
npm run test:unit— passnpm run test:vitest— pass (MCP server, autoCombo, cache)npm run test:coverage— bramka 60/60/60/60 spełniona (statements/lines/functions/branches)npm run test:integration— pass (jeśli zmiany dotykają DB / handlerów)npm run test:combo:matrix— pass (macierz strategii combo: deterministycznie dowodzi decyzji selekcji wszystkich 17 strategii routingu; uruchamiaj przy zmianach combo routing, strategy resolution lub logiki fallback)RUN_COMBO_LIVE=1 npm run test:combo:live— opcjonalne/ręczne (bramkowany smoke na realnym upstreamie; bierze snapshot DB tylko do odczytu z VPSroot@192.168.0.15; uderza w realnych providerów, zużywa kredyty; nigdy nie biegnie w CI; bez bramki pomija się czysto)npm run test:combo:live:vps— opcjonalne/ręczne (Phase-3 VPS live smoke: 7 scenariuszy HTTP przeciw żywemu serwerowi.15przez plain Node ESM; wymagassh root@192.168.0.15; tworzy/usuwa tylko combo__live_test__*; uderza w realnych providerów; nigdy nie biegnie w CI)npm run test:e2e— pass (zmiany UI)npm run test:protocols:e2e— pass (zmiany MCP/A2A)npm run test:ecosystem— pass
Hooki (walidowane Husky)
Hooki Husky leżą w .husky/ i uruchamiają się automatycznie przy operacjach gita.
- pre-commit:
npx lint-staged + node scripts/check/check-docs-sync.mjs + npm run check:any-budget:t11 - pre-push: szybkie deterministyczne bramki —
npm run check:any-budget:t11 && npm run check:tracked-artifacts(aktywowane 2026-06-13). Celowo wykluczatest:unit(wolne; pokryte przez job CItest-unit).- Uruchom
npm run test:unitręcznie przed pushem gałęzi release.
- Uruchom
Jeśli hook padnie: napraw przyczynę, nie omijaj przez --no-verify.
Conventional Commits
Wszystkie commity idące do wydania muszą mieć format type(scope): subject.
Dozwolone typy: feat, fix, refactor, docs, test, chore, perf, style, ci
Dozwolone scope'y: db, sse, oauth, dashboard, api, cli, docker, ci, mcp, a2a, memory, skills, cloud-agent, guardrails, compression, auto-combo, resilience, providers, executors, translator, domain, authz
Breaking changes: dodaj stopkę BREAKING CHANGE: albo ! po scope (np. feat(api)!: drop /v0).
Dokumentacja
npm run check:docs-syncprzechodzi (auto-run w pre-commit)npm run check:docs-allprzechodzi (parasol: docs-sync + docs-counts + env-doc-sync + deprecated-versions + doc-links)npm run check:env-doc-synckończy się kodem 0 — kontrakt env code ↔.env.example↔docs/reference/ENVIRONMENT.mdjest nienaruszonynpm run check:doc-linkskończy się kodem 0 — brak zepsutych wewnętrznych referencji markdown po restrukturyzacjidocs/architecture/ARCHITECTURE.mdprzejrzany pod dryf storage/runtimedocs/guides/TROUBLESHOOTING.mdprzejrzany pod dryf env var i operacyjny- Jeśli
.env.examplesię zmienił: zaktualizowanodocs/reference/ENVIRONMENT.md - Jeśli nowa funkcja ma UI:
docs/guides/USER_GUIDE.mdo niej wspomina - Jeśli nowa funkcja ma API: zaktualizowano
docs/reference/API_REFERENCE.md+docs/openapi.yaml - Jeśli nowa funkcja to moduł: istnieje dedykowany
docs/<MODULE>.md - Jeśli breaking change:
docs/guides/TROUBLESHOOTING.mdma notatkę migracyjną
i18n
npm run i18n:checkkończy się kodem 0 — stan tłumaczeń (.i18n-state.json) zsynchronizowany ze źródłowymi docs (brak dryfujących źródeł w trybie strict; doradztwo warn-mode jest akceptowalne przy last-minute poprawkach docs, ale przed tagowaniem powinno być 0)npm run i18n:check-ui-coveragekończy się kodem 0 — każdy locale UI na lub powyżej progu pokrycia 80%npm run i18n:sync-ui:dryraportuje 0 brakujących kluczy we wszystkich 42 locale- Jeśli źródłowe angielskie docs się zmieniły, uruchom
npm run i18n:run(wymagaOMNIROUTE_TRANSLATION_API_KEYw.env) przed tagowaniem - Wkłady tłumaczeniowe można odłożyć na następne wydanie, jeśli drobne (śledź w CHANGELOG)
Migracje bazy danych
- Jeśli
src/lib/db/migrations/ma nowe pliki:- Każda migracja jest idempotentna (
CREATE TABLE IF NOT EXISTSitd.) - Migracje owinięte w transakcje
- Ponumerowane poprawnie (bez luk w sekwencji)
- Każda migracja jest idempotentna (
- Test na świeżej instalacji: usuń
~/.omniroute/omniroute.dbi uruchomnpm run dev - Test na istniejącej instalacji: backup DB, uruchom migrację, zweryfikuj schemat
- Pliki WAL (
-wal,-shm) obsłużone poprawnie, jeśli migracja przepisuje tabele
Katalog providerów (walidowany Zod)
- Schemat Zod
src/shared/constants/providers.tspoprawny w czasie ładowania- Wszyscy providerzy mają wymagane pola (
id,label,kinditd.) freeNotepodane dla nowych darmowych providerów- Providerzy OAuth mają
oauthConfigzarejestrowany wsrc/lib/oauth/constants/oauth.ts
- Wszyscy providerzy mają wymagane pola (
- Jeśli dodano nowego providera: odpowiadający executor w
open-sse/executors/ - Jeśli format inny niż OpenAI: translator w
open-sse/translator/ - Modele zarejestrowane w
open-sse/config/providerRegistry.ts - Testy jednostkowe w
tests/unit/pokrywają klasyfikację i routing providerów
Desktop (Electron)
Jeśli zmieniło się electron/:
npm run electron:smoke:packagedprzechodzi- Buildy przetestowane dla co najmniej jednego z
:win,:mac,:linux - Certyfikaty code signing nie wygasły (jeśli signing)
- Wersja
electron/package.jsonzgadza się z rootpackage.json - Wskaźnik kanału auto-update zaktualizowany, jeśli wypuszczasz na
stable
Układ buildu
Repozytorium używa trzech odrębnych katalogów wyjściowych — nigdy ich nie myl:
| Directory | Purpose | Tracked? |
|---|---|---|
src/ |
Application source (TypeScript / TSX) | Yes |
.build/ |
Build intermediates — next build output (distDir) |
No (gitignored) |
dist/ |
Shippable npm bundle — assembled by assembleStandalone |
No (gitignored) |
Notatka operatorska: zdalny katalog obrazu VPS pozostaje
/usr/lib/node_modules/omniroute/app/. Przeniesione zostało tylko wyjście buildu w repo (app/→dist/). Skill-e deploy rsyncują zawartośćdist/do zdalnego kataloguapp/— nie wymagane żadne zmiany ścieżek VPS.
Przepływ single-build:
npm run build:release
└─ rm -rf .build dist (clean)
└─ next build → .build/next/ (intermediates)
└─ assembleStandalone (copies standalone + static + public + natives → dist/)
└─ writes dist/BUILD_SHA (HEAD sentinel)
NIE uruchamiaj npm run build a potem osobnego npm run build:cli pod deploy — użyj
npm run build:release, które robi czysty rebuild + sentinel w jednej komendzie.
Walidacja artefaktów
npm run build:releasekończy się sukcesem idist/BUILD_SHA==git rev-parse --short HEADnpm run check:pack-artifactczysto — brakapp.__qa_backup,scripts/scratch,package-lock.jsonani innego lokalnego residualudist/server.jsistnieje po buildzie
Tagowanie i release
- Uruchom
/generate-release-cc(skill Claude Code):- Tworzy tag
vX.Y.Z - Pushuje tag i gałąź
- Otwiera GitHub Release z ciałem changelogu
- Dołącza instalatory Electron (jeśli zbudowane)
- Tworzy tag
- Albo ręcznie:
git tag -a vX.Y.Z -m "Release vX.Y.Z" git push origin vX.Y.Z gh release create vX.Y.Z --notes-from-tag
Deploy
Skill-e deploy używają lekkiego przepływu rsync — bez npm pack, bez npm i -g:
- Użyj skill-a deploy pasującego do celu:
/deploy-vps-local-cc— lokalny VPS (192.168.0.15)/deploy-vps-akamai-cc— Akamai VPS (69.164.221.35)/deploy-vps-both-cc— oba
- Przed deployem potwierdź
dist/BUILD_SHA==git rev-parse --short HEAD - Build musi iść tam, gdzie
node_modulesjest realne (główny checkout lub worktree ponpm ci— NIE zlinkowany symlinkami worktree) - Smoke test wdrożonej instancji:
- Otwórz
/dashboard/health→ sprawdź, że string wersji pasuje do wydania - Uruchom request
/v1/chat/completionsprzeciw znanemu providerowi - Zweryfikuj, że
/api/monitoring/healthzwraca circuit breakeryCLOSED - Potwierdź, że transporty MCP odpowiadają (
/mcpHTTP,/mcp-sseSSE)
- Otwórz
Po wydaniu
- Uruchom
/capture-release-evidences-cc(skill Claude Code)- Przechwytuje zrzuty/nagrania WebP nowych funkcji
- Dołącza do release notes / posta na blogu
- Zaktualizuj GitHub Discussions / Discord ogłoszeniem wydania
- Otwórz milestone na następną wersję
- Jeśli krytyczne: przypnij dyskusję lub wrzuć do
news.jsonbaner in-app
Smoke embedded services (v3.8.4+)
Przed wypuszczeniem dowolnego wydania zawierającego zmiany embedded services zweryfikuj:
Boot na świeżej DB (łapie kolizje migracji — dodane po hotfixie v3.8.4)
DATA_DIR=$(mktemp -d) npm start &— poczekaj 10 s na bootcurl -s http://127.0.0.1:20128/api/services/9router/status | jq '.tool'zwraca"9router"(NIE 404, NIE 500). Potwierdza, że migracja071_services.sqlsię zastosowała + wiersz zaseedowany.sqlite3 $DATA_DIR/storage.sqlite "PRAGMA table_info(version_manager);" | grep -E "provider_expose|logs_buffer_path|last_sync_at"zwraca 3 wiersze.sqlite3 $DATA_DIR/storage.sqlite "PRAGMA table_info(webhooks);" | grep -E "kind|metadata_encrypted"zwraca 2 wiersze (waliduje zastosowanie070_webhooks_kind_metadata.sql).node --import tsx/esm --test tests/unit/db/no-migration-collisions.test.tsprzechodzi — strzeże przed przyszłymi kolizjami.
9Router
POST /api/services/9router/installzwraca 200 zinstalledVersionw poniżej 2 minPOST /api/services/9router/startzwraca 200 istate: "running"w poniżej 30 sGET /api/services/9router/statusraportujehealth: "healthy"POST /v1/chat/completionsz"model": "9router/auto/..."zwraca 200 (routing end-to-end przez 9Router)GET /dashboard/providers/services/9router/embed/dashboardrenderuje natywne UI 9Router wewnątrz proxy (bez bezpośredniego iframe127.0.0.1:port)POST /api/services/9router/rotate-keyzwraca{ keyRotated: true }i usługa restartuje się czystoPOST /api/services/9router/stopzwraca 200 istate: "stopped"GET /api/services/9router/logs?tail=50zwraca stream SSE z eventemsnapshotzawierającym ostatnie linie- Instalacja w środowisku bez
npmw PATH zwraca 500 z przyjaznym (bez stack-trace) komunikatem błędu
CLIProxyAPI
POST /api/services/cliproxy/installzwraca 200 w poniżej 2 minPOST /api/services/cliproxy/startzwraca 200 istate: "running"w poniżej 30 sGET /api/services/cliproxy/statusraportujehealth: "healthy"POST /api/services/cliproxy/stopzwraca 200 istate: "stopped"GET /api/services/cliproxy/logs?tail=50zwraca stream SSE
Regresja bezpieczeństwa
curl -H "X-Forwarded-For: 1.2.3.4" http://localhost:20128/api/services/9router/startzwraca403 LOCAL_ONLYcurl -H "X-Forwarded-For: 1.2.3.4" http://localhost:20128/api/services/cliproxy/startzwraca403 LOCAL_ONLY- Odpowiedzi błędów z
/api/services/*nie zawierająerr.stackani bezwzględnych ścieżek plików
Kontrole v3.8.0+
Przed wypuszczeniem dowolnego wydania v3.8.x zweryfikuj te dodatkowe pozycje:
omniroute --traybootuje na macOS (systray2 instalowany do~/.omniroute/runtime/)omniroute --traybootuje na Linux (wymaga DISPLAY; graceful error jeśli nie ustawione)omniroute --traybootuje na Windows (PowerShell NotifyIcon, bez dodatkowych binarek)omniroute config tray enabletworzy wpis autostart; disable go usuwanpm install -g omniroute@<this-version>uruchamia postinstall bez fatalnego wyjścia- Ścieżka update zachowuje optional deps:
omniroute update --applyi auto-updater uruchamiająnpm install -g … --include=optional, żebyoptionalDependencies(better-sqlite3, keytar, tls-client oraz stack SLM llmlingua:@atjsh/llmlingua-2,@huggingface/transformers@3.5.2,@tensorflow/tfjs,js-tiktoken) przeżyły update.@huggingface/transformerszostaje optional, żeby jego postinstall providera CUDAonnxruntime-nodenie mógł przerwać instalacji na hostach CUDA 11. Tier ultramodelPathSLM potrzebuje też modelu tinybert, auto-pobieranego do${DATA_DIR}/models/llmlinguaprzy pierwszym użyciu. Postinstall (scripts/build/colocateOptionals.mjs) następnie ko-lokuje opcjonalne zamknięcie SLM dodist/node_modules, żeby worker rozwiązywał JEDNĄ opcjonalną instancję@huggingface/transformers3.5.2 — standalone trace bundluje tylko transformers, nie dynamicznie importowane optionals, więc bez tego worker załadowałby llmlingua-2 przeciw transformers z roota i tier SLM cicho fail-openowałby. omniroute statusdziała bez.env(ścieżka tokenu CLI, tylko loopback)curl http://localhost:20128/api/shutdownzwraca 401 (trasa zawsze chroniona)curl -H "host: evil.com" http://localhost:20128/api/mcp/ssezwraca 401 (strażnik loopback)- Runtime SQLite resolvuje do
bundledprzy pierwszym uruchomieniu (bundlowana binarka poprawna dla platformy) - Runtime SQLite spada na
runtime, gdynode_modules/better-sqlite3jest usunięte - Smart MCP filter kompresuje realny output
playwright-mcp browser_snapshot(redukcja ≥50%) - Wszystkie 10 plików
skills/omniroute*/SKILL.mdsą publicznie pobieralne przez raw GitHub URL - Kreator onboardingu pokazuje krok tour „How It Works” tier na świeżym setupie
- Widget pokrycia tierów na home dashboard pokazuje liczby configured/active
Rollback
Jeśli wydanie ma krytyczny problem:
gh release edit vX.Y.Z --prerelease(oznacza jako nie-latest)git tag -d vX.Y.Z && git push --delete origin vX.Y.Z(tylko jeśli użytkownicy jeszcze nie adoptowali)- Albo: hotfix na
release/vX.Y.0→ patch releasevX.Y.(Z+1) - Natychmiast zakomunikuj w GitHub Discussions i Discord
Twarde reguły
- Nigdy nie commituj bezpośrednio do
main - Nigdy nie używaj
git push --forcena gałęziemainanirelease/* - Nigdy nie pomijaj hooków Husky (
--no-verify) - Nigdy nie commituj sekretów, credentials ani plików
.env - Coverage musi zostać ≥60/60/60/60 (statements/lines/functions/branches)
- Zawsze dołączaj lub aktualizuj testy przy zmianie kodu produkcyjnego w
src/,open-sse/,electron/lubbin/
Automatyczna kontrola synchronizacji
Uruchom lokalnie strażnika sync docs przed otwarciem PR:
npm run check:docs-sync
CI też uruchamia tę kontrolę w .github/workflows/ci.yml (job lint).