mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-09-11 02:14:29 +00:00
rename: implement advertised backward-compat + prune dead community plugins
Address gaps where PR #537's "Backward compatibility" section was advertised but not implemented, and clean up the community plugin list. Env vars (FEEDBACK_* canonical, legacy SLOPSMITH_* honoured): - New lib/env_compat.py (getenv_compat / env_flag_compat) + tests. server.py (_env_flag + all FEEDBACK_* reads), diagnostics_hardware, gp2midi and tailwind_rebuild now resolve the legacy alias, so existing SLOPSMITH_UI / SLOPSMITH_PLUGINS_DIR / etc. deployments keep working. - Fix the rename collapsing plugins/__init__.py and minigames/routes.py from `FEEDBACK_PLUGINS_DIR or SLOPSMITH_PLUGINS_DIR` into a redundant `FEEDBACK_ or FEEDBACK_` (the fallback was silently lost). Storage (app.js update-channel): - Read feedBack-update-channel, fall back to legacy slopsmith-update-channel, and clear the legacy key on write — so a user's update-channel preference survives the rename instead of resetting to "stable". Community plugin list (README): the rename rewrote third-party repo URLs we don't own. Probed every one; their owners never renamed, so: - Restore the 13 live community plugins to their real slopsmith-* names. - Prune 6 that are 404 to the public (topkoa splitscreen/stems, OmikronApex tuner, Jafz2001 nam-rig-builder, DeathlySin song-preview, Erikcb91 shuffle). - Fix a pre-existing Guitar Theory clone-command typo (nam-tone -> guitar-theory). Verified: env_compat 7/7, JS 819/819, pytest 1690 collected / 0 import errors, rename-sensitive + startup suites green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
1cf3dcba67
commit
932c0b28ac
@@ -15,34 +15,28 @@
|
||||
| [MIDI Amp Control](https://github.com/got-feedback/feedBack-plugin-midi) | Auto-switch amp/modeler presets via MIDI on tone changes | `git clone ...feedBack-plugin-midi.git midi_amp` |
|
||||
| [Section Map](https://github.com/got-feedback/feedBack-plugin-sectionmap) | Color-coded song structure minimap with clickable navigation | `git clone ...feedBack-plugin-sectionmap.git section_map` |
|
||||
| [Arrangement Editor](https://github.com/got-feedback/feedBack-plugin-editor) | DAW-like visual editor for creating and editing song note charts | `git clone ...feedBack-plugin-editor.git editor` |
|
||||
| [MIDI Capo](https://github.com/masc0t/feedBack-plugin-midi-capo) | MIDI capo control for real-time transposition | `git clone ...feedBack-plugin-midi-capo.git midi_capo` |
|
||||
| [MIDI Capo](https://github.com/masc0t/slopsmith-plugin-midi-capo) | MIDI capo control for real-time transposition | `git clone ...slopsmith-plugin-midi-capo.git midi_capo` |
|
||||
| [Note Detection](https://github.com/got-feedback/feedBack-plugin-notedetect) | Real-time pitch detection and scoring against highway notes | `git clone ...feedBack-plugin-notedetect.git note_detect` |
|
||||
| [Find More](https://github.com/masc0t/feedBack-plugin-find-more) | Search for more songs by the same artist | `git clone ...feedBack-plugin-find-more.git find_more` |
|
||||
| [Find More](https://github.com/masc0t/slopsmith-plugin-find-more) | Search for more songs by the same artist | `git clone ...slopsmith-plugin-find-more.git find_more` |
|
||||
| [Piano Highway](https://github.com/got-feedback/feedBack-plugin-piano) | Scrolling piano/keyboard view for Keys arrangements with MIDI input | `git clone ...feedBack-plugin-piano.git piano` |
|
||||
| [Studio](https://github.com/got-feedback/feedBack-plugin-studio) | Collaborative band recording and multi-track mixing | `git clone ...feedBack-plugin-studio.git studio` |
|
||||
| [Drum Highway](https://github.com/got-feedback/feedBack-plugin-drums) | Lane-based drum highway with MIDI drum pad input and built-in sounds | `git clone ...feedBack-plugin-drums.git drums` |
|
||||
| [Split Screen](https://github.com/topkoa/feedBack-plugin-splitscreen) | 2-4 highway panels side-by-side for multi-arrangement practice | `git clone ...feedBack-plugin-splitscreen.git splitscreen` |
|
||||
| [Stems Mixer](https://github.com/topkoa/feedBack-plugin-stems) | Per-stem mute/volume controls for .sloppak songs | `git clone ...feedBack-plugin-stems.git stems` |
|
||||
| [Invert Highway](https://github.com/masc0t/feedBack-plugin-invert-highway) | Flip the highway note direction | `git clone ...feedBack-plugin-invert-highway.git invert_highway` |
|
||||
| [Jumping Tab](https://github.com/renanboni/feedBack-plugin-jumpingtab) | Yousician-style 2D horizontal tab with trajectory arcs and hopping ball | `git clone ...feedBack-plugin-jumpingtab.git jumpingtab` |
|
||||
| [Invert Highway](https://github.com/masc0t/slopsmith-plugin-invert-highway) | Flip the highway note direction | `git clone ...slopsmith-plugin-invert-highway.git invert_highway` |
|
||||
| [Jumping Tab](https://github.com/renanboni/slopsmith-plugin-jumpingtab) | Yousician-style 2D horizontal tab with trajectory arcs and hopping ball | `git clone ...slopsmith-plugin-jumpingtab.git jumpingtab` |
|
||||
| [Step Mode](https://github.com/got-feedback/feedBack-plugin-stepmode) | Step-by-step practice mode — highway freezes at each note until played (via Note Detection) or Space | `git clone ...feedBack-plugin-stepmode.git step_mode` |
|
||||
| [Lyrics Sync](https://github.com/got-feedback/feedBack-plugin-lyrics-sync) | Generate synced LRC lyrics from text + vocals stem via Whisper alignment | `git clone ...feedBack-plugin-lyrics-sync.git lyrics_sync` |
|
||||
| [Lyrics Karaoke](https://github.com/got-feedback/feedBack-plugin-lyrics-karaoke) | Per-syllable karaoke pitch ribbon for sloppak songs (Whisper alignment + librosa pYIN) | `git clone ...feedBack-plugin-lyrics-karaoke.git lyrics_karaoke` |
|
||||
| [NAM Tone Engine](https://github.com/got-feedback/feedBack-plugin-nam-tone) | In-browser amp modeling with NAM WASM, cabinet IRs, tone auto-switching | `git clone ...feedBack-plugin-nam-tone.git nam_tone` |
|
||||
| [Guitar Theory Lab](https://github.com/topkoa/feedBack-plugin-guitar-theory) | Explore scales, chords, intervals, tunings, and voicings on a fully interactive fretboard | `git clone ...feedBack-plugin-nam-tone.git guitar-theory-lab` |
|
||||
| [Themes](https://github.com/masc0t/feedBack-plugin-themes) | Offers several basic recolorings of the interface | `git clone ...feedBack-plugin-themes.git themes` |
|
||||
| [Update Manager](https://github.com/masc0t/feedBack-update-manager) | Installs, updates, and uninstalls other plugins and the feedBack core itself | `git clone ...feedBack-update-manager.git update_manager` |
|
||||
| [Tuner](https://github.com/OmikronApex/feedBack-plugin-tuner) | Floating tuner with customizable tunings | `git clone ...feedBack-plugin-tuner.git tuner` |
|
||||
| [Simplify Chords](https://github.com/bkranendonk/feedBack-plugin-simplify-chords) | Changes complex chords on the note highway to simpler ones. Inspired by Ultimate Guitar's Simplify button. | `git clone ...feedBack-plugin-simplify-chords.git simplify-chords` |
|
||||
| [Key Bindings](https://github.com/jackipicco/feedBack-plugin-key-bindings) | Highway key bindings for keyboard and TV remote | `git clone ...feedBack-plugin-key-bindings.git key_bindings` |
|
||||
| [Folder Organizer](https://github.com/Elit3d/feedBack-plugin-folder-organizer) | Organize your sloppak DLC songs into a folder tree view, grouped by subfolder name | `git clone ...feedBack-plugin-folder-organizer.git folder-organizer` |
|
||||
| [Guitar Theory Lab](https://github.com/topkoa/slopsmith-plugin-guitar-theory) | Explore scales, chords, intervals, tunings, and voicings on a fully interactive fretboard | `git clone ...slopsmith-plugin-guitar-theory.git guitar-theory-lab` |
|
||||
| [Themes](https://github.com/masc0t/slopsmith-plugin-themes) | Offers several basic recolorings of the interface | `git clone ...slopsmith-plugin-themes.git themes` |
|
||||
| [Update Manager](https://github.com/masc0t/slopsmith-update-manager) | Installs, updates, and uninstalls other plugins and the feedBack core itself | `git clone ...slopsmith-update-manager.git update_manager` |
|
||||
| [Simplify Chords](https://github.com/bkranendonk/slopsmith-plugin-simplify-chords) | Changes complex chords on the note highway to simpler ones. Inspired by Ultimate Guitar's Simplify button. | `git clone ...slopsmith-plugin-simplify-chords.git simplify-chords` |
|
||||
| [Key Bindings](https://github.com/jackipicco/slopsmith-plugin-key-bindings) | Highway key bindings for keyboard and TV remote | `git clone ...slopsmith-plugin-key-bindings.git key_bindings` |
|
||||
| [Folder Organizer](https://github.com/Elit3d/slopsmith-plugin-folder-organizer) | Organize your sloppak DLC songs into a folder tree view, grouped by subfolder name | `git clone ...slopsmith-plugin-folder-organizer.git folder-organizer` |
|
||||
| [Virtuoso](https://github.com/got-feedback/feedback-plugin-virtuoso) | Practice studio for guitar & bass — scale, technique, and rhythm drills, timed workouts, and jam backing that teach skills you take off the screen. | `git clone ...feedback-plugin-virtuoso.git virtuoso` |
|
||||
| [NAM Rig Builder](https://github.com/Jafz2001/feedBack-plugin-nam-rig-builder) | Map tones to chained NAM neural-amp rigs (tone3000 captures + IRs) — full pedal→amp→cab playback, per-stage bypass, and a gear catalog | `git clone ...feedBack-plugin-nam-rig-builder.git nam_rig_builder` |
|
||||
| [Audio Preview](https://github.com/saleemk/feedBack-plugin-audio-preview) | Quick audio previews from library cards with configurable start time, volume, and duration | `git clone ...feedBack-plugin-audio-preview.git audio_preview` |
|
||||
| [Song Mastery](https://github.com/jamesgaiser/feedBack-plugin-song-mastery) | Auto-adjusts difficulty based on your rolling note accuracy and saves the slider position per song | `git clone ...feedBack-plugin-song-mastery.git song_mastery` |
|
||||
| [Song Preview](https://github.com/DeathlySin/feedBack-plugin-song-preview) | Quickly hear previews of songs in your library with a clean visual indicator of what's playing. Supports .sloppak and loose folders song formats, with the visual indicator matching up to whatever theme you are using! | `git clone ...feedBack-plugin-song-preview.git song_preview` |
|
||||
| [Mobile Note Highway](https://github.com/saleemk/feedBack-plugin-mobile-note-highway) | Touch-optimized player with collapsible controls, highway gestures, and device-adaptive layouts for phones and tablets | `git clone ...feedBack-plugin-mobile-note-highway.git mobile_note_highway` |
|
||||
| [Shuffle](https://github.com/Erikcb91/FeedBack-Shuffle-Mode) | Random playback from your library — artist & tuning filters, auto-advance with countdown popup, note_detect compatible | `git clone https://github.com/Erikcb91/FeedBack-Shuffle-Mode.git shuffle` |
|
||||
| [Audio Preview](https://github.com/saleemk/slopsmith-plugin-audio-preview) | Quick audio previews from library cards with configurable start time, volume, and duration | `git clone ...slopsmith-plugin-audio-preview.git audio_preview` |
|
||||
| [Song Mastery](https://github.com/jamesgaiser/slopsmith-plugin-song-mastery) | Auto-adjusts difficulty based on your rolling note accuracy and saves the slider position per song | `git clone ...slopsmith-plugin-song-mastery.git song_mastery` |
|
||||
| [Mobile Note Highway](https://github.com/saleemk/slopsmith-plugin-mobile-note-highway) | Touch-optimized player with collapsible controls, highway gestures, and device-adaptive layouts for phones and tablets | `git clone ...slopsmith-plugin-mobile-note-highway.git mobile_note_highway` |
|
||||
|
||||
Install any plugin by cloning it into your `plugins/` directory and restarting:
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ import platform
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
from env_compat import getenv_compat
|
||||
|
||||
SCHEMA = "system.hardware.v1"
|
||||
|
||||
|
||||
@@ -41,7 +43,7 @@ def detect_runtime() -> dict:
|
||||
nvidia-smi / psutil CPU probes.
|
||||
"""
|
||||
out: dict = {"kind": "bare", "in_docker": False, "in_kubernetes": False}
|
||||
env_runtime = os.environ.get("FEEDBACK_RUNTIME", "").strip().lower()
|
||||
env_runtime = (getenv_compat("FEEDBACK_RUNTIME", "") or "").strip().lower()
|
||||
if env_runtime in ("electron", "docker", "bare"):
|
||||
out["kind"] = env_runtime
|
||||
if Path("/.dockerenv").exists():
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
"""Backward-compatible environment lookup for the slopsmith -> feedBack rename.
|
||||
|
||||
Canonical configuration variables are now ``FEEDBACK_*``. Deployments that
|
||||
predate the rename may still set the old ``SLOPSMITH_*`` names (docker-compose
|
||||
overrides, shell profiles, CI), so we honour those as a fallback. New code
|
||||
should always read the canonical ``FEEDBACK_*`` name and let this shim resolve
|
||||
the legacy alias.
|
||||
|
||||
Flat-importable, no import-time IO or global state (constitution P-V).
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
_CANON_PREFIX = "FEEDBACK_"
|
||||
_LEGACY_PREFIX = "SLOPSMITH_"
|
||||
_TRUE_VALUES = {"1", "true", "yes", "on"}
|
||||
|
||||
|
||||
def getenv_compat(name, default=None):
|
||||
"""``os.environ.get`` with a legacy ``SLOPSMITH_*`` fallback.
|
||||
|
||||
For a canonical ``FEEDBACK_<X>`` name, returns the value of ``FEEDBACK_<X>``
|
||||
if set, else ``SLOPSMITH_<X>`` if set, else ``default``. Names that do not
|
||||
start with ``FEEDBACK_`` behave exactly like ``os.environ.get``.
|
||||
"""
|
||||
value = os.environ.get(name)
|
||||
if value is not None:
|
||||
return value
|
||||
if name.startswith(_CANON_PREFIX):
|
||||
legacy = os.environ.get(_LEGACY_PREFIX + name[len(_CANON_PREFIX):])
|
||||
if legacy is not None:
|
||||
return legacy
|
||||
return default
|
||||
|
||||
|
||||
def env_flag_compat(name):
|
||||
"""Parse a conventional boolean env flag, honouring the legacy alias."""
|
||||
return (getenv_compat(name, "") or "").strip().lower() in _TRUE_VALUES
|
||||
+3
-1
@@ -8,6 +8,8 @@ import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
from env_compat import getenv_compat
|
||||
|
||||
log = logging.getLogger("feedBack.lib.gp2midi")
|
||||
|
||||
import guitarpro
|
||||
@@ -156,7 +158,7 @@ def _find_soundfont() -> str | None:
|
||||
2. Bundled ``<RESOURCESPATH>/soundfonts/*.sf2`` (Electron desktop builds)
|
||||
3. Common system locations per OS.
|
||||
"""
|
||||
override = os.environ.get("FEEDBACK_SOUNDFONT")
|
||||
override = getenv_compat("FEEDBACK_SOUNDFONT")
|
||||
if override:
|
||||
if os.path.isfile(override):
|
||||
return override
|
||||
|
||||
@@ -24,6 +24,8 @@ import tempfile
|
||||
import threading
|
||||
from pathlib import Path
|
||||
|
||||
from env_compat import getenv_compat
|
||||
|
||||
log = logging.getLogger("feedBack.tailwind")
|
||||
|
||||
# Pin matches scripts/build-tailwind.sh and the Dockerfile build stage so every
|
||||
@@ -45,7 +47,7 @@ APP_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
def _user_plugins_dir() -> Path | None:
|
||||
raw = os.environ.get("FEEDBACK_PLUGINS_DIR", "").strip()
|
||||
raw = (getenv_compat("FEEDBACK_PLUGINS_DIR", "") or "").strip()
|
||||
if not raw:
|
||||
return None
|
||||
p = Path(raw)
|
||||
|
||||
+1
-1
@@ -1118,7 +1118,7 @@ def load_plugins(app: FastAPI, context: dict, progress_cb=None, route_setup_fn=N
|
||||
|
||||
# Collect plugin directories — user plugins first so they override built-in
|
||||
plugin_dirs = []
|
||||
user_plugins_dir = os.environ.get("FEEDBACK_PLUGINS_DIR") or os.environ.get("FEEDBACK_PLUGINS_DIR")
|
||||
user_plugins_dir = os.environ.get("FEEDBACK_PLUGINS_DIR") or os.environ.get("SLOPSMITH_PLUGINS_DIR")
|
||||
if user_plugins_dir:
|
||||
user_path = Path(user_plugins_dir)
|
||||
if user_path.is_dir() and user_path != PLUGINS_DIR:
|
||||
|
||||
@@ -336,7 +336,7 @@ def setup(app, context):
|
||||
# Duplicates are removed via a seen-set keyed on resolved paths.
|
||||
def _resolve_plugin_dirs():
|
||||
roots = []
|
||||
env_dir = os.environ.get("FEEDBACK_PLUGINS_DIR") or os.environ.get("FEEDBACK_PLUGINS_DIR")
|
||||
env_dir = os.environ.get("FEEDBACK_PLUGINS_DIR") or os.environ.get("SLOPSMITH_PLUGINS_DIR")
|
||||
if env_dir:
|
||||
roots.append(Path(env_dir))
|
||||
# Built-in plugins/ next to server.py (one level above this file's
|
||||
|
||||
@@ -15,6 +15,7 @@ from pathlib import Path
|
||||
from typing import Any, ClassVar
|
||||
|
||||
from logging_setup import configure_logging
|
||||
from env_compat import getenv_compat
|
||||
configure_logging()
|
||||
|
||||
log = logging.getLogger("feedBack.server")
|
||||
@@ -230,7 +231,7 @@ _DEMO_BLOCKED: list[tuple[str, re.Pattern]] = [
|
||||
|
||||
@app.middleware("http")
|
||||
async def _demo_mode_guard(request: Request, call_next):
|
||||
if os.environ.get("FEEDBACK_DEMO_MODE") or os.environ.get("FEEDBACK_DEMO_MODE") == "1":
|
||||
if getenv_compat("FEEDBACK_DEMO_MODE") or getenv_compat("FEEDBACK_DEMO_MODE") == "1":
|
||||
path = request.url.path
|
||||
for method, pattern in _DEMO_BLOCKED:
|
||||
if request.method == method and pattern.match(path):
|
||||
@@ -275,8 +276,8 @@ SLOPPAK_CACHE_DIR = CONFIG_DIR / "sloppak_cache"
|
||||
|
||||
|
||||
def _env_flag(name: str) -> bool:
|
||||
"""Parse a conventional boolean env flag."""
|
||||
return os.environ.get(name, "").strip().lower() in {"1", "true", "yes", "on"}
|
||||
"""Parse a conventional boolean env flag (honours legacy SLOPSMITH_* alias)."""
|
||||
return (getenv_compat(name, "") or "").strip().lower() in {"1", "true", "yes", "on"}
|
||||
|
||||
|
||||
# Canonical Tuning-filter grouping key (feedBack#867). tuning_name collapses
|
||||
@@ -3040,7 +3041,7 @@ def _make_scan_executor():
|
||||
# A malformed override falls back to the core count rather than crashing.
|
||||
try:
|
||||
max_workers = int(
|
||||
os.environ.get("FEEDBACK_MAX_SCAN_WORKERS")
|
||||
getenv_compat("FEEDBACK_MAX_SCAN_WORKERS")
|
||||
or os.environ.get("SCAN_MAX_WORKERS")
|
||||
or (os.cpu_count() or 1)
|
||||
)
|
||||
@@ -3090,7 +3091,7 @@ def _get_progression_content() -> dict:
|
||||
with _progression_content_lock:
|
||||
if _progression_content is None:
|
||||
import progression as progression_mod
|
||||
root = os.environ.get("FEEDBACK_PROGRESSION_DATA") or (
|
||||
root = getenv_compat("FEEDBACK_PROGRESSION_DATA") or (
|
||||
_feedBack_server_root() / "data" / "progression"
|
||||
)
|
||||
content, warnings = progression_mod.load_content(root)
|
||||
@@ -3488,7 +3489,7 @@ async def startup_events():
|
||||
|
||||
# Load plugins asynchronously so HTTP routes and the desktop window can
|
||||
# come up immediately while heavy plugin imports/install steps continue.
|
||||
_sync_mode = os.environ.get("FEEDBACK_SYNC_STARTUP", "").lower() in {"1", "true", "yes", "on"}
|
||||
_sync_mode = getenv_compat("FEEDBACK_SYNC_STARTUP", "").lower() in {"1", "true", "yes", "on"}
|
||||
|
||||
def _load_plugins_background():
|
||||
try:
|
||||
@@ -3723,7 +3724,7 @@ async def startup_events():
|
||||
threading.Thread(target=_load_plugins_background, daemon=True).start()
|
||||
|
||||
global _DEMO_JANITOR_STARTED, _DEMO_JANITOR_THREAD
|
||||
if os.environ.get("FEEDBACK_DEMO_MODE") or os.environ.get("FEEDBACK_DEMO_MODE") == "1" and not _DEMO_JANITOR_STARTED:
|
||||
if getenv_compat("FEEDBACK_DEMO_MODE") or getenv_compat("FEEDBACK_DEMO_MODE") == "1" and not _DEMO_JANITOR_STARTED:
|
||||
_DEMO_JANITOR_STARTED = True
|
||||
_DEMO_JANITOR_STOP.clear()
|
||||
def _janitor():
|
||||
@@ -6183,7 +6184,7 @@ def _diag_plugins_roots() -> list[Path]:
|
||||
orphans in the external dir are reflected in the bundle.
|
||||
"""
|
||||
roots: list[Path] = []
|
||||
user_dir = os.environ.get("FEEDBACK_PLUGINS_DIR", "").strip()
|
||||
user_dir = getenv_compat("FEEDBACK_PLUGINS_DIR", "").strip()
|
||||
if user_dir:
|
||||
p = Path(user_dir)
|
||||
if p.is_dir():
|
||||
@@ -7683,7 +7684,7 @@ def index():
|
||||
# UI remains fully available as a fallback — opt back in with
|
||||
# FEEDBACK_UI=v2 (or =legacy), or hit the dedicated /v2 route below (which
|
||||
# serves it regardless of the env var).
|
||||
if os.environ.get("FEEDBACK_UI") or os.environ.get("FEEDBACK_UI") in ("v2", "legacy"):
|
||||
if getenv_compat("FEEDBACK_UI") or getenv_compat("FEEDBACK_UI") in ("v2", "legacy"):
|
||||
return FileResponse(str(STATIC_DIR / "index.html"))
|
||||
return FileResponse(str(STATIC_DIR / "v3" / "index.html"))
|
||||
|
||||
|
||||
+4
-2
@@ -3310,7 +3310,9 @@ function setupAppUpdates() {
|
||||
// iframes, privacy modes, etc.); fall back to the default channel so the
|
||||
// panel still renders rather than aborting wiring entirely.
|
||||
let storedRaw = null;
|
||||
try { storedRaw = localStorage.getItem('feedBack-update-channel'); } catch (_) { /* fall through */ }
|
||||
// Read the canonical key, falling back to the pre-rename
|
||||
// 'slopsmith-update-channel' so an existing channel preference survives.
|
||||
try { storedRaw = localStorage.getItem('feedBack-update-channel') || localStorage.getItem('slopsmith-update-channel'); } catch (_) { /* fall through */ }
|
||||
const stored = APP_UPDATE_CHANNELS.includes(storedRaw) ? storedRaw : 'stable';
|
||||
channelSelect.value = stored;
|
||||
|
||||
@@ -3395,7 +3397,7 @@ function setupAppUpdates() {
|
||||
channelSelect.addEventListener('change', async () => {
|
||||
const val = channelSelect.value;
|
||||
if (!APP_UPDATE_CHANNELS.includes(val)) return;
|
||||
try { localStorage.setItem('feedBack-update-channel', val); } catch (_) {}
|
||||
try { localStorage.setItem('feedBack-update-channel', val); localStorage.removeItem('slopsmith-update-channel'); } catch (_) {}
|
||||
try {
|
||||
// Await setChannel so the status line reflects what actually
|
||||
// happened — rendering "Channel set" unconditionally would
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
"""Coverage for the slopsmith -> feedBack env backward-compat shim."""
|
||||
|
||||
from env_compat import getenv_compat, env_flag_compat
|
||||
|
||||
|
||||
def test_canonical_wins_over_legacy(monkeypatch):
|
||||
monkeypatch.setenv("FEEDBACK_UI", "v3")
|
||||
monkeypatch.setenv("SLOPSMITH_UI", "v2")
|
||||
assert getenv_compat("FEEDBACK_UI") == "v3"
|
||||
|
||||
|
||||
def test_legacy_fallback_when_canonical_unset(monkeypatch):
|
||||
monkeypatch.delenv("FEEDBACK_UI", raising=False)
|
||||
monkeypatch.setenv("SLOPSMITH_UI", "v2")
|
||||
assert getenv_compat("FEEDBACK_UI") == "v2"
|
||||
|
||||
|
||||
def test_default_when_neither_set(monkeypatch):
|
||||
monkeypatch.delenv("FEEDBACK_UI", raising=False)
|
||||
monkeypatch.delenv("SLOPSMITH_UI", raising=False)
|
||||
assert getenv_compat("FEEDBACK_UI", "default") == "default"
|
||||
assert getenv_compat("FEEDBACK_UI") is None
|
||||
|
||||
|
||||
def test_non_feedback_names_have_no_fallback(monkeypatch):
|
||||
monkeypatch.delenv("CONFIG_DIR", raising=False)
|
||||
monkeypatch.setenv("SLOPSMITH_CONFIG_DIR", "/tmp/x")
|
||||
# A non-FEEDBACK_ name must behave like os.environ.get (no aliasing).
|
||||
assert getenv_compat("CONFIG_DIR") is None
|
||||
|
||||
|
||||
def test_empty_canonical_is_respected_not_overridden(monkeypatch):
|
||||
# An explicitly-empty canonical value is still "set" and wins.
|
||||
monkeypatch.setenv("FEEDBACK_UI", "")
|
||||
monkeypatch.setenv("SLOPSMITH_UI", "v2")
|
||||
assert getenv_compat("FEEDBACK_UI") == ""
|
||||
|
||||
|
||||
def test_flag_parses_true_values(monkeypatch):
|
||||
for raw in ("1", "true", "YES", " On "):
|
||||
monkeypatch.setenv("FEEDBACK_SYNC_STARTUP", raw)
|
||||
assert env_flag_compat("FEEDBACK_SYNC_STARTUP") is True
|
||||
|
||||
|
||||
def test_flag_false_and_legacy(monkeypatch):
|
||||
monkeypatch.delenv("FEEDBACK_SYNC_STARTUP", raising=False)
|
||||
monkeypatch.setenv("SLOPSMITH_SYNC_STARTUP", "1")
|
||||
assert env_flag_compat("FEEDBACK_SYNC_STARTUP") is True
|
||||
monkeypatch.setenv("FEEDBACK_SYNC_STARTUP", "0")
|
||||
assert env_flag_compat("FEEDBACK_SYNC_STARTUP") is False
|
||||
Reference in New Issue
Block a user