All notable changes to DevWatchdog are documented here. The format is based on Keep a Changelog and this project adheres to Semantic Versioning.
- cwd-basierte Projekterkennung (G2) — hinter neuem Feature-Flag
useCwdProjectDetection(Default: aus). Liest das Arbeitsverzeichnis viaproc_pidinfo(PROC_PIDVNODEPATHINFO)und löst es über einen Projekt-Root-Walker (.git,package.json,Cargo.toml,go.mod,pyproject.toml,Podfile,Package.swift) zum korrekten Projektnamen auf (leaf-wins für Monorepos). Behebt die Regressionsgrenze, dass~/Projects/Archiv/DevWatchdog/den Marker"Archiv"statt"DevWatchdog"liefert. Wirkt nur im libproc-Pfad.DevProcesshat neue FelderworkingDirectoryunddetectedProject; das bestehendeprojectNamebevorzugtdetectedProject, wenn gesetzt. Closes GitLab #35. - Signal-basierter Dev-Klassifier (G1) — hinter neuem Feature-Flag
useSignalClassifier(Default: aus). Vier orthogonale Heuristiken (Executable-Pfad, cwd, Parent-Prozess, Bundle-Identifier) ersetzen die Wortlisten-Erstklassifikation. Harter Ausschluss für Nicht-Dev-Bundles (z. B.com.slack.,com.notion., Browser) wird von einer Dev-Allowlist überschrieben (VSCode, Cursor, iTerm2, Terminal, Warp)..unknown-Urteile fallen zur Wortliste zurück — existierendedefaultInclusionPatterns/defaultExcludedAppsbleiben unverändert. Wirkt nur im libproc-Pfad. Closes #36. - Zwei neue Settings-Toggles unter „Entwickler" für die oben genannten Flags, im gleichen „Experimentell —" Muster wie der libproc-Scanner.
- 46 neue Unit-/Integrationstests (
ProcPIDInfoCwdTests,ProjectRootResolverTests,DevProcessClassifierTests,LibProcSignalClassifierTests). Test-Baseline 335 → 381. - libproc-basierter Prozess-Enumerator (opt-in, Feature-Flag) — neuer
LibProcProcessEnumeratornutztproc_listpids+proc_pidinfodirekt und ersetzt den/bin/ps-Subprocess-Pfad, wennuseLibprocEnumeratorunter Einstellungen → Entwickler aktiviert ist. Defaultfalse; gleicheDevProcess-Ausgabe wiePSParser; identische Filter-Semantik (Inclusion-Patterns, Excluded-Apps, Playwright-Ausnahme,/Applications/-Heuristik). Scan-Dauer wird auf beiden Backends für Vorher/Nachher-Vergleich geloggt. Bekannte MVP-Divergenzen:commandist nur Exec-Pfad (nicht volles argv); CPU% ist kumulativ seit Start (Delta-Sampling deferred). Closes GitLab #34 (G5).
- GitHub-Actions-CI grün auf Xcode 16.2 / Swift 6.0 strict concurrency — drei
non-sendable type-Fehler inSystemPressureMonitor.swiftwurden durch zwei neue@unchecked Sendable-Wrapper beseitigt:SendableCurrentValueSubjectkapselt CombinesCurrentValueSubject(nicht formalSendablein 6.0) undSendableDispatchSourcekapseltany DispatchSourceMemoryPressurefür den@Sendable-Handler-Closure. Lokal unter Xcode 26 / Swift 6.2 unverändert grün; CI-Runner zieht jetzt auf Xcode 16.4 (war 16.2) für konsistente Swift-6.0-GA-Baseline. - Popover bleibt offen, Buttons reagieren nicht (Regression seit v3.2.0,
NSStatusItem-Umbau). LSUIElement-App braucht explizitesNSApp.activate(ignoringOtherApps: true)bevor das Popover gezeigt wird — sonst kann das Popover-Window nicht key werden, SwiftUI-Buttons (Beenden, Einstellungen, Protokoll, Kill-CTAs) feuern nicht, und.transient-Dismissal bleibt aus. Zusätzlich verhinderteNSHostingViewüber dem Status-Button durch eigenes Hit-Testing das Toggle-Verhalten; Label-Host ist jetzt einePassthroughHostingView, die Klicks an den darunter liegendenNSButtondurchreicht. Closes GitLab #38. - ActionBar ohne Inhalt bei einem einzelnen aktiven Suspect — 16 px leeres
Padding + Divider, wenn genau ein aktiver Suspect ohne Zombies/Idle vorlag,
weil die CTA-Logik nur bei
count > 1einen Button rendert. Gate prüft jetzt viahasActionBarContentdie tatsächlichen CTA-Conditions. Closes #39. - Header-Pill abgeschnitten bei hohen CPU-Werten — Popover-Breite
380 → 400 px, Pill + Timestamp-VStack hat
minWidth: 90. Closes #40. - Swap-Zeile zeigte Compression-Rate — die
↑ x/s-Rate ist ausschließlich Compression-Rate; wird jetzt nur im "Compressed"-Modus gerendert, nicht wenn die Zeile auf "Swap" flippt. Closes #41.
- Pause/Fortsetzen jetzt auch für gruppierte Prozesse —
ProcessGroupRowViewreichtonThrottle/onResumean expandierte Kind-Rows durch. Imbun (4)- Menü stehen damit Pausieren und Fortsetzen zur Verfügung. Closes #42. - Panic-Button visuell sekundär — im Header nur noch Bolt-Icon; ab 10+
Targets erscheint der Count als kleines Badge daneben. Tooltip enthält den
aktuellen Count. Hotkey
⌘⇧⌥Punverändert. Closes #43. - Empty-State kontextsensitiv — Copy unterscheidet jetzt zwischen
normal("Alles sauber"),elevated("Vorerst sauber") undemergency("Keine Targets mehr · System-Druck noch hoch, Scanner greift sofort zu"). Behebt den visuellen Widerspruch zwischen pulsierendem Emergency-Banner und grünem "Alles sauber"-Check. Closes #44. - Footer: "Log" → "Protokoll" — einheitlich deutsch. SessionLogView-Titel entsprechend angepasst ("Session-Protokoll"). Closes #45.
- CPU-Farbskala skaliert jetzt mit
ncpu— 100 % CPU auf einer 12-Kern- Maschine ist keine Warnfarbe mehr wert; rot ab ≥ 15 % Gesamt-Kapazität, orange ab ≥ 5 %. Gilt für Einzel- und Gruppenzeilen. Closes #46. - CI-Infrastruktur modernisiert —
.github/workflows/build.ymlpinnt jetzt Xcode 16.4 (letzte Stable-16-Serie mit Swift-6.0-GA-Korrekturen) und unterstützt manuellesworkflow_dispatch. Neuer Release-Workflow (release.yml) triggert aufv*-Tags, baut Release-Konfiguration, packt.appviadittoals ZIP und erstellt GitHub Release mit CHANGELOG-Auszug +--generate-notes..gitlab-ci.ymlspiegelt Build+Release. Beide Workflows mit minimalen Token- Scopes (contents: readfür Build,contents: writefür Release) und env-var-Indirection für user-supplied Tag-Inputs (Injection-Schutz).
- Release-Workflow-Härtung —
${{ inputs.tag }}(workflow_dispatch) wird jetzt überenv:in Shell-Variablen gemappt, nie direkt inrun:-Blöcke inline-interpoliert. Gleiches Pattern für alle${{ steps.*.outputs.* }}- Referenzen. Zusätzliche Tag-Format-Validierung (^v[0-9]+\.[0-9]+\.[0-9]+$) verhindert freie-Text-Injection.build.ymlbekommt explizitespermissions: contents: read(minimal-privilege).
Triage follow-up release. User-facing UX clarity (why-badges, smart kill split, hardware-aware recommendations), new infrastructure (disk-persisted session log
- newly-orphaned detection), the Apple-Silicon-correct memory-pressure signal,
and a migration off
MenuBarExtratoNSStatusItemthat finally makes the menu-bar icon refresh without hovering.
- "Why?" signal badges per suspect row —
NEW ORPHAN,ORPHAN,IDLE Nm,ACTIVE N%,LEAK N MB,RULE …,KILL …,EXPIRED,PAUSED. Each badge is a short capsule with a German tooltip explaining the heuristic. OverallKillConfidence(high/medium/low) colors the status dot and row background so a crowded list draws the eye to real zombies first. - Smart-split kill buttons — when both idle (≈0 % CPU) and active (≥ 1 % CPU) suspects exist, the popover renders two distinct buttons: "N inaktive beenden" (green, safe) and "N aktive beenden" (red/orange, risky). Kills a running test/build only when you explicitly say so.
- Hardware-aware settings recommendations — each timing slider carries a live "Standard: X · Empfohlen: Y (für Z GB RAM)" hint scaled from the host's RAM / core count. Per-section reset button for Timing.
- Disk-persisted session log — every log entry is now streamed to
~/Library/Application Support/DevWatchdog/sessions/YYYY-MM-DD.jsonl. The log hydrates the last 24 h on launch; 14-day rotation keeps disk usage bounded. Insights finally accrues value across restarts. - Newly-orphaned detection —
PPIDhistory is tracked across scans; aX → 1transition is classified asnewlyOrphaned(high confidence), steady-statePPID == 1asadoptedByLaunchd(conservative, medium). - Memory compressor signal —
host_statistics64(HOST_VM_INFO64)fills the gap wherevm.swapusageis always zero on Apple Silicon.PressureDerivernow takesmax(swapFraction, compressorFraction)so Emergency mode triggers on the real memory signal.
- Menu-bar architecture: replaced
MenuBarExtrawith anNSStatusItem+NSHostingViewsetup owned byAppDelegate. Fixes FB11857447 — the system menu-bar server now sees@Publishedupdates immediately without requiring a hover or click on the icon. Emergency-state pulse (phaseAnimator), accessibility labels, and the panic hotkey (⌘⇧⌥P) are preserved. - UI language unified to German across every surface — previously a mix of German (MenuBar / Emergency) and English (Settings / Rules / About).
- About window version reads
CFBundleShortVersionStringat runtime instead of a hardcoded string, so release builds always display correctly.
- Menu-bar icon no longer requires a hover to reflect fresh scan results
(FB11857447 / FB12094112). A prior attempt using
TimelineView(.periodic)brokexcodebuild testwith a 5.5 min IPC hang and was reverted in favor of the NSStatusItem migration above. Swapreadout on Apple Silicon showing permanent0.0 / 0.0 GB— replaced with a Compressor-dominatedSpeicherrow;Swapstill surfaces only when the host actually has non-zero swap usage.- About tab showing hard-coded
v2.0.0regardless of the shipped build. - Various mixed DE/EN UI labels ("General" / "Rules" / "Warn:" / "Kill:") that made the app look half-finished.
See GitLab issues #34 (libproc migration), #35 (project detection via
PROC_PIDVNODEPATHINFO), #36 (signal-based dev detection), #37 (proper
i18n via Localizable.xcstrings). These are the next session's scope.
First signed release. Builds on v3.0 (Emergency Mode) with a full observability layer: structured logging, kill-reason audit, a weekly Insights summary, dev filter by path, log export, and richer rule match modes.
- Structured logger (
DWLogger) — allSessionLogcalls now flow through a level-filtered, category-tagged logger withkind → categorymapping. - Insights tab — weekly summary of kills, top projects / process types, reclaimed CPU-hours and RSS-MB; 7-day dismissal per card.
- Dev Filter (
inclusionPatterns) — narrow the watch surface to specific path patterns for single-project focus, configured in Settings. - Log export — JSON export with 6 secret-flag redactions, via pasteboard
or
NSSavePanel; entry points from the Session Log view menu. - Match modes for rules — rule patterns now support
glob,regex,substring, andexact. Migration-safe decoder keeps existing rules working. - Kill-reason audit — every kill carries a structured
KillTriggerandKillReason(orphan, maxRuntime, emergency-cpu, emergency-rss, manual, rule-override), persisted in the session log for post-hoc review. - Process-info hardening (
ProcPIDInfo) — Mach-backed PID info fallback with apstimeout watchdog, minimum-age gate, and PID-reuse guard.
SessionLog.logis now a thin adapter overDWLogger— behaviour preserved, every entry additionally gets a structured category.- Rule decoder is migration-safe: legacy rules without
matchModedecode asglob(previous behaviour).
- Swift 6 strict-concurrency issue in the kill pipeline (
withUnsafeBytes(of:)instead ofwithUnsafeMutablePointer). - PID-reuse window closed: the PID is re-validated against start-time before every kill signal.
- +136 new tests across 10 new test files (
DWLogger,InclusionPatterns,KillReason,MatchModeMigration,ProcPIDInfo,EmergencyMinAge,PIDReuse,PSFailureCounter,Insights,LogExporter). - Total: 288 tests passing, zero Swift 6 warnings, strict-concurrency clean.
- First Developer ID signed release (
G3QZ66475M) with the hardened runtime. Notarization is planned for a subsequent release — use right-click → Open orxattr -d com.apple.quarantineon first launch. - DMG artifact (
DevWatchdog-3.1.0.dmg) shipped as a GitHub Release asset.
Closes internal tracking epic #21 and sub-issues #22–#32 (minus #25, deferred).
- Emergency Mode — when 5-minute load average exceeds
emergencyLoadFactor × CPU-count, grace periods shrink andmaxRuntimethresholds compress until load returns to normal. - New per-rule
maxCPUPercentandmaxRSSMBfields for resource-aware killing. Decoder is migration-safe (old rules decode with0defaults). emergencyMinAgeSecondssetting to protect freshly-spawned processes from Emergency-triggered kills.
Closes GitLab epic #2 and sub-issues #3–#14.
- CI pipeline on GitLab (macos-15 runner).
- Process detection for Bun, Deno, and SWC toolchains.
- Expanded test coverage.
- CI: removed
sudo xcode-select(runner uses system Xcode).
- Orphan-first zombie detection.
- Process-type-specific kill limits.
- Smart action bar (Kill Zombies / Kill Suspects with traffic-light colouring).
- Menu bar app, 30-second scan, basic auto-kill with grace period.