You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Zero as any casts: all ~71 as any occurrences eliminated across 30+ TypeScript files. Replaced with proper typed intersections (HTMLElement & { selected: boolean }, HTMLButtonElement), union types (type: 'success' | 'error' | 'info' | 'warning'), and explicit type assertions
ChildProcess overloads: on('exit') and on('error') events now have proper parameter types instead of (...args: unknown[]) => void
tsconfig.json strictness: enabled noUncheckedIndexedAccess, noUnusedLocals, noUnusedParameters — codebase compiles cleanly with zero errors
window-global.ts helper: single typed abstraction for dynamic window property access (getGlobal<T>, setGlobal, deleteGlobal), eliminating all window as unknown as Record<string, unknown> patterns from consumer modules
Typed error hierarchy: SpecterError (base) → BridgeError / ScriptError / TimeoutError / ConfigError with machine-readable .code and optional .context payload — replaces bare Error throws throughout bridge.ts
TSDoc documentation: all public API exports across 6 core modules (bridge.ts, cfg.ts, toast.ts, utils.ts, color-utils.ts, window-global.ts) now have typedoc-style comments
Shell
version_ge(): pure POSIX-sh implementation (IFS splitting + arithmetic comparison) — no longer depends on awk, fixing compatibility with KernelSU/APatch environments where toybox lacks awk
bridge.ts callback system: rewritten from fragile window[cbName] global namespace pollution to a private Map<string, callback> registry with individually-named __sp_* globals and explicit cleanup on completion/timeout/error
Testing
vitest infrastructure: 7 test files, 65 tests covering bridge integration (KernelSU mock with exec/runScript/spawnScript), config caching, toast notification lifecycle, colour preset matching, utility functions, window-global helper, and accessibility patterns
CI integration: vitest step added to .github/workflows/build-test.yml alongside existing shell test runner
Shell tests: 16 tests across 12 test files, all passing
Infrastructure
vitest.config.ts with happy-dom environment for DOM-dependent tests
package.json — npm test and npm run test:watch scripts added
CI badge added to README
Removed
Recovery feature deleted entirely: src/features/recovery.sh, hide_recovery_folders() from props.sh, recovery toggle from WebUI (index.html, constants.ts, all lang files), recovery_detected from device-info JSON + TypeScript types + mock, stale references in cleanup.sh, boot_core.sh dispatch, and all recovery tests
Prop handler removed from scheduler: boot state props are one-time at boot, no need for hourly re-runs (scheduler.sh prop_handler task deleted)
Added
Scheduler system (src/lib/scheduler.sh): central periodic task daemon — runs keybox_info.sh every 6h and auto_target.sh every 5min; uses inotifyd for app-install triggered scans; manages PID/task lifecycle
Region props (props.sh): detect_region() + apply_region_props() sets IMS/locale props per region (CN, IN, RU, JP, KR, BR), gated by region_props config
Boot logging: boot_core.sh now logs to $SPECTER_DIR/log/boot.log with rotation; log.sh writes to Android logcat + added log_rotate() helper
Denylist merge at boot: target.sh --merge-denylist imports magisk denylist packages into target.txt
post-fs-data.sh async boot_core.sh: sleep-15 fallback for KSU/APatch module managers that skip boot-completed.sh
Changed
Keybox boot race fixed: keybox_info.sh delayed 60s (sleep 60; sh ...) so network is ready before catalog download
Auto Target → one-shot scan: daemon loop replaced with single-pass scan tracking seen packages via auto_known_packages.txt; no longer checks TEE status for ? suffix; no PID file, no interval loop; now defaults to ON
WebUI target-apps.ts — click split: row click toggles unchecked↔bare (target) or unchecked↔blacklisted (blacklist); circle click cycles bare→conditional→force→bare. Removed unused TARGET_STATE_ORDER
Target merge helpers extracted: _merge_setup, _merge_cleanup, _merge_load_existing, _normalize_pkg, _append_missing moved from target.sh into target_common.sh; teeBroken→? default suffix fallback removed
Props: sp_try() saves originals to PERSIST_RESTORE_FILE for uninstall restore; apply_boot_props now includes ro.boot.warranty_bit:0; hexpatch_deleteprop() simplified (no more magiskboot hexpatch, always resetprop -p --delete)
rom_fingerprint.sh: LineageOS camera packagelist scrub (vendor.camera.aux.packagelist, persist.vendor.camera.privapp.list), vendor.lineage_health service kill, ro.product.vendor.name added to prefix list, hexpatch calls → direct resetprop --delete
action.sh: full pipeline wrapped with tee -a "$ACTION_LOG" + log rotation
desc.sh: removed "skip if unchanged" optimization (always writes new description)
device.ts: added missing t() helper (getTranslation(key) || fallback) so TEE labels render correctly
WebUI i18n: 10 new keys (tee_broken, tee_normal, dialog_confirm, boot_harden_dialog_*, kb_refresh_btn, clear_history_btn, home_events_initial, auto_target_interval_aria) synced across all 5 languages
package.json: zip filename now Specter-v{version}.zip (v prefix)