# Application scripts This directory contains scripts coupled to RustProxy application/build/deployment behavior. External development and QA helpers live under `tools/`; external platform integrations live under `integrations/`. - `runtime/` - application-owned helpers embedded or invoked by RustProxy (`acme_provider.py`). - `build/` - build-time asset preparation used by `build.rs`. - `deploy/` - install/update and stopped source-tree upgrade implementation. - `migration/` - application migration utilities, currently the Nginx Proxy Manager importer. Keep these paths stable because Rust source, `build.rs` and shell entry points reference them directly. ## Panel stylesheet sources The dashboard stylesheet lives in `src/admin/web/css/`, with its complete cascade order declared in `manifest.json`. Edit those modules, not a generated bundle. `build.rs` invokes `build/panel_css.py` using Python 3.10+ (or `RUST_PROXY_PYTHON`) and embeds the compact `OUT_DIR/panel-style.css`. Login and the dashboard continue to load one fingerprinted stylesheet, using the existing panel compression and access rules; no npm install or runtime CSS imports are needed. The documentation page retains its separate `src/admin/web/docs.css`. ```bash python3 scripts/build/panel_css.py --check python3 tools/dev/test_panel_css.py python3 scripts/audit_css_usage.py --strict ``` The first two commands use only the Python standard library. The optional selector/structure audit needs `tinycss2` and `cssselect2`; it checks all manifest modules together and reviews the documentation stylesheet separately. Use `--json PATH` for selector references and `--structure-json PATH` for repeated selectors, conditional blocks, properties and identical declaration blocks. Missing class tokens are review candidates: classes assembled by JavaScript must be checked before deleting their styles. Strict mode also rejects identical declaration bodies within a compatible selector family. It permits separate standard/WebKit/Gecko rules only when joining them would create an incompatible vendor selector list. Choose shared-rule placement by checking the cascade, not by mechanically moving every matching block to the beginning of a module. Preflight rejects missing, repeated or unlisted CSS modules and stale monolithic `style.css` files. `./dev.sh repair` backs up only the exact original 0.34.9 monolith; custom or unknown content requires manual review and is never moved or discarded automatically. Rebuild the Rust binary after changing CSS. Keep `scripts/__init__.py` and `scripts/build/__init__.py` in the source package. They keep preflight, audit, tests and packaging imports local even when unrelated Python packages named `scripts` or `build` are installed. An older CSS-refactor archive without the build marker can fail with `ModuleNotFoundError: No module named 'build.panel_css'`; restore the marker from the complete source archive and run `bash dev.sh repair` again. Installing another Python package is not required. ### Missing generated CSS during Rust compilation `panel-style.css` is generated inside Cargo's `OUT_DIR`. `bash dev.sh repair` validates the source layout and preserves known obsolete files; it does not generate Cargo outputs. Preflight also checks that the current `build.rs` calls the panel generator from `main` and reports a mixed source tree before Cargo. After overlaying a source ZIP onto a previously built checkout, a compiler error for a missing `OUT_DIR/panel-style.css` can indicate an old cached build script or a `build.rs` from another source version. Restore the complete matching archive, including the root `build.rs`, then run from the project root: ```bash bash dev.sh repair touch build.rs bash dev.sh build ``` The source ZIP uses reproducible timestamps. Cargo's [build-script change detection](https://doc.rust-lang.org/cargo/reference/build-scripts.html#change-detection) uses file modification times, so refreshing `build.rs` forces regeneration after an archive overlay. This works with the target directory selected by `dev.sh`. The generator now also registers its output as a watched Cargo dependency and recreates a removed bundle. An identical bundle keeps its modification time. The Rust build script rejects a missing, empty or non-file output immediately after the helper returns. ## Stream TCP/UDP test helpers - `start_stream_backends.sh` — launches two TCP echo mocks (9101, 9102) and two UDP echo/probe mocks (9201, 9202), defaulting to loopback, and terminates all on Ctrl+C. - `test_stream_tcp.py`, `test_stream_udp.py` — independent `server`, `client` and `selftest` modes. See `docs/STREAMS.md` for RustProxy listener setup and test commands. The selftests test only Python mock peers, **not** RustProxy forwarding.