max / makenotwork
14 files changed,
+95 insertions,
-95 deletions
| @@ -1,7 +1,7 @@ | |||
| 1 | 1 | # Workspace root so `cargo build`/`cargo test` at sando/ covers the daemon. | |
| 2 | 2 | # Kept as a workspace (rather than a flat crate) so future sando-side crates can | |
| 3 | 3 | # join without a restructure. The sando-tui member was retired 2026-07-22 when | |
| 4 | - | # the shared ops-viewer replaced it; see wiki [[release-viewer-overview]]. | |
| 4 | + | # the shared magicmirror replaced it; see wiki [[magicmirror-overview]]. | |
| 5 | 5 | [workspace] | |
| 6 | 6 | resolver = "3" | |
| 7 | 7 | members = ["daemon"] |
| @@ -82,7 +82,7 @@ | |||
| 82 | 82 | ||
| 83 | 83 | **Errors**: `anyhow`, `thiserror`. | |
| 84 | 84 | ||
| 85 | - | **CLI and TUI** (mnw-cli, ops-viewer, wam): `clap`, `ratatui`, `crossterm`, `russh`, `russh-sftp`, `dirs`. | |
| 85 | + | **CLI and TUI** (mnw-cli, magicmirror, wam): `clap`, `ratatui`, `crossterm`, `russh`, `russh-sftp`, `dirs`. | |
| 86 | 86 | ||
| 87 | 87 | **MCP**: `rmcp`. | |
| 88 | 88 |
| @@ -1,16 +1,16 @@ | |||
| 1 | - | //! Which theme the viewer renders in, and where it loads from. | |
| 1 | + | //! Which theme magicmirror renders in, and where it loads from. | |
| 2 | 2 | //! | |
| 3 | 3 | //! No hex value is written anywhere in this crate. There is deliberately no | |
| 4 | 4 | //! built-in fallback palette: a missing or malformed theme is an error the | |
| 5 | 5 | //! operator sees, not something papered over by rendering in colors that exist | |
| 6 | 6 | //! nowhere in the theme files. | |
| 7 | 7 | //! | |
| 8 | - | //! The shared app convention is wiki `makeover-app-convention`. The viewer is | |
| 8 | + | //! The shared app convention is wiki `makeover-app-convention`. magicmirror is | |
| 9 | 9 | //! one of the store-less apps that note describes, with one difference worth | |
| 10 | - | //! knowing: it already owns a config file, so `viewer.toml` *is* the | |
| 10 | + | //! knowing: it already owns a config file, so `magicmirror.toml` *is* the | |
| 11 | 11 | //! file-backed store and the convention's unprefixed `theme` key lives there. | |
| 12 | 12 | //! There is no picker and nothing writes the key back, which is why this | |
| 13 | - | //! module has no `remember`: the viewer displays, and choosing a theme is an | |
| 13 | + | //! module has no `remember`: magicmirror displays, and choosing a theme is an | |
| 14 | 14 | //! edit to the same file that says what to display. | |
| 15 | 15 | ||
| 16 | 16 | use std::path::PathBuf; | |
| @@ -19,34 +19,34 @@ | |||
| 19 | 19 | use makeover::{ThemeDefaults, ThemeDirs, ThemeMeta, ThemeSelection, Variant}; | |
| 20 | 20 | use makeover_tui::{Fidelity, Theme}; | |
| 21 | 21 | ||
| 22 | - | /// The viewer's own light theme: the platform's titular skin. | |
| 22 | + | /// magicmirror's own light theme: the platform's titular skin. | |
| 23 | 23 | const DEFAULT_LIGHT: &str = "makenotwork"; | |
| 24 | 24 | ||
| 25 | - | /// The viewer's own dark theme. | |
| 25 | + | /// magicmirror's own dark theme. | |
| 26 | 26 | /// | |
| 27 | 27 | /// MNW authors no dark skin of its own, so this is the nearest thing in the | |
| 28 | 28 | /// bundled set: near-neutral greys on the same axis as `makenotwork`'s | |
| 29 | 29 | /// parchment, rather than a theme with a hue of its own to bring. It is a | |
| 30 | 30 | /// fallback and not a pin — `ThemeSelection::resolve` reaches any installed | |
| 31 | 31 | /// dark theme when this one is missing, and the operator names the theme they | |
| 32 | - | /// want in `viewer.toml`. | |
| 32 | + | /// want in `magicmirror.toml`. | |
| 33 | 33 | const DEFAULT_DARK: &str = "carbonfox"; | |
| 34 | 34 | ||
| 35 | 35 | /// Theme search path: the operator's own themes win, then makeover's bundled | |
| 36 | 36 | /// set. | |
| 37 | 37 | /// | |
| 38 | 38 | /// Two tiers and not three. There is no packaged `/usr/share` tier because | |
| 39 | - | /// nothing packages the viewer — it is an operator binary run out of a build, | |
| 39 | + | /// nothing packages magicmirror — it is an operator binary run out of a build, | |
| 40 | 40 | /// so a system tier would be a directory that never exists. | |
| 41 | 41 | fn search_path() -> Vec<(PathBuf, bool)> { | |
| 42 | 42 | ThemeDirs::new() | |
| 43 | 43 | .bundled(makeover::bundled_themes_dir()) | |
| 44 | - | .custom(config_home().map(|config| config.join("ops-viewer").join("themes"))) | |
| 44 | + | .custom(config_home().map(|config| config.join("magicmirror").join("themes"))) | |
| 45 | 45 | .build() | |
| 46 | 46 | } | |
| 47 | 47 | ||
| 48 | - | /// `$XDG_CONFIG_HOME`, else `~/.config`, matching where the viewer already | |
| 49 | - | /// looks for `viewer.toml`. | |
| 48 | + | /// `$XDG_CONFIG_HOME`, else `~/.config`, matching where magicmirror already | |
| 49 | + | /// looks for `magicmirror.toml`. | |
| 50 | 50 | fn config_home() -> Option<PathBuf> { | |
| 51 | 51 | if let Some(xdg) = std::env::var_os("XDG_CONFIG_HOME").filter(|v| !v.is_empty()) { | |
| 52 | 52 | return Some(PathBuf::from(xdg)); | |
| @@ -54,12 +54,12 @@ | |||
| 54 | 54 | std::env::var_os("HOME").map(|home| PathBuf::from(home).join(".config")) | |
| 55 | 55 | } | |
| 56 | 56 | ||
| 57 | - | /// The themes the viewer falls back to when nothing has been chosen. | |
| 57 | + | /// The themes magicmirror falls back to when nothing has been chosen. | |
| 58 | 58 | fn defaults() -> ThemeDefaults { | |
| 59 | 59 | ThemeDefaults::new(DEFAULT_LIGHT, DEFAULT_DARK) | |
| 60 | 60 | } | |
| 61 | 61 | ||
| 62 | - | /// Every theme the viewer can render, from the same search path it loads from. | |
| 62 | + | /// Every theme magicmirror can render, from the same search path it loads from. | |
| 63 | 63 | /// | |
| 64 | 64 | /// makeover's own scan rather than a second one: a list here that disagreed | |
| 65 | 65 | /// with [`load`] would resolve to an id that then failed to load. | |
| @@ -67,7 +67,7 @@ | |||
| 67 | 67 | makeover::list_themes_from_dirs(&search_path()) | |
| 68 | 68 | } | |
| 69 | 69 | ||
| 70 | - | /// What the viewer is being drawn on, as makeover's vocabulary. | |
| 70 | + | /// What magicmirror is being drawn on, as makeover's vocabulary. | |
| 71 | 71 | /// | |
| 72 | 72 | /// The terminal's answer to a `prefers-color-scheme` media query, and the only | |
| 73 | 73 | /// one available without writing an OSC query and waiting for a reply before | |
| @@ -133,7 +133,7 @@ | |||
| 133 | 133 | pub(crate) fn fixed() -> Theme { | |
| 134 | 134 | let (_, source) = makeover::embedded_themes() | |
| 135 | 135 | .find(|(id, _)| *id == DEFAULT_LIGHT) | |
| 136 | - | .expect("makeover embeds the viewer's default theme"); | |
| 136 | + | .expect("makeover embeds magicmirror's default theme"); | |
| 137 | 137 | let colors = makeover::parse_theme_str(DEFAULT_LIGHT, source, false) | |
| 138 | 138 | .expect("the embedded default theme parses"); | |
| 139 | 139 | Theme::from_theme(&colors).expect("the embedded default theme is complete") | |
| @@ -160,7 +160,7 @@ | |||
| 160 | 160 | } | |
| 161 | 161 | } | |
| 162 | 162 | ||
| 163 | - | // Nothing in `viewer.toml` is Follow, not a pin on whatever the first run | |
| 163 | + | // Nothing in `magicmirror.toml` is Follow, not a pin on whatever the first run | |
| 164 | 164 | // guessed. | |
| 165 | 165 | #[test] | |
| 166 | 166 | fn an_unset_key_follows_the_terminal() { | |
| @@ -187,7 +187,7 @@ | |||
| 187 | 187 | } | |
| 188 | 188 | ||
| 189 | 189 | // Following resolves to the theme matching the terminal rather than to a | |
| 190 | - | // fixed default, and both ids the viewer names are ones makeover ships. | |
| 190 | + | // fixed default, and both ids magicmirror names are ones makeover ships. | |
| 191 | 191 | #[test] | |
| 192 | 192 | fn following_resolves_to_the_theme_matching_the_terminal() { | |
| 193 | 193 | let available = available(); |
| @@ -1054,6 +1054,25 @@ | |||
| 1054 | 1054 | "winapi", | |
| 1055 | 1055 | ] | |
| 1056 | 1056 | ||
| 1057 | + | [[package]] | |
| 1058 | + | name = "magicmirror" | |
| 1059 | + | version = "0.1.0" | |
| 1060 | + | dependencies = [ | |
| 1061 | + | "anyhow", | |
| 1062 | + | "chrono", | |
| 1063 | + | "makeover", | |
| 1064 | + | "makeover-tui", | |
| 1065 | + | "ops-status", | |
| 1066 | + | "ratatui", | |
| 1067 | + | "reqwest", | |
| 1068 | + | "rustls", | |
| 1069 | + | "serde", | |
| 1070 | + | "serde_json", | |
| 1071 | + | "tempfile", | |
| 1072 | + | "tokio", | |
| 1073 | + | "toml", | |
| 1074 | + | ] | |
| 1075 | + | ||
| 1057 | 1076 | [[package]] | |
| 1058 | 1077 | name = "makeover" | |
| 1059 | 1078 | version = "2.5.0" | |
| @@ -1200,25 +1219,6 @@ | |||
| 1200 | 1219 | "serde_json", | |
| 1201 | 1220 | ] | |
| 1202 | 1221 | ||
| 1203 | - | [[package]] | |
| 1204 | - | name = "ops-viewer" | |
| 1205 | - | version = "0.1.0" | |
| 1206 | - | dependencies = [ | |
| 1207 | - | "anyhow", | |
| 1208 | - | "chrono", | |
| 1209 | - | "makeover", | |
| 1210 | - | "makeover-tui", | |
| 1211 | - | "ops-status", | |
| 1212 | - | "ratatui", | |
| 1213 | - | "reqwest", | |
| 1214 | - | "rustls", | |
| 1215 | - | "serde", | |
| 1216 | - | "serde_json", | |
| 1217 | - | "tempfile", | |
| 1218 | - | "tokio", | |
| 1219 | - | "toml", | |
| 1220 | - | ] | |
| 1221 | - | ||
| 1222 | 1222 | [[package]] | |
| 1223 | 1223 | name = "ordered-float" | |
| 1224 | 1224 | version = "4.6.0" | |
| @@ -2903,20 +2903,12 @@ | |||
| 2903 | 2903 | checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" | |
| 2904 | 2904 | ||
| 2905 | 2905 | [[patch.unused]] | |
| 2906 | - | name = "kberg" | |
| 2907 | - | version = "0.1.0" | |
| 2906 | + | name = "synckit-client" | |
| 2907 | + | version = "0.8.0" | |
| 2908 | 2908 | ||
| 2909 | 2909 | [[patch.unused]] | |
| 2910 | - | name = "painhours" | |
| 2911 | - | version = "0.1.0" | |
| 2912 | - | ||
| 2913 | - | [[patch.unused]] | |
| 2914 | - | name = "tagtree" | |
| 2915 | - | version = "0.4.0" | |
| 2916 | - | ||
| 2917 | - | [[patch.unused]] | |
| 2918 | - | name = "docengine" | |
| 2919 | - | version = "0.7.0" | |
| 2910 | + | name = "synckit-config" | |
| 2911 | + | version = "0.2.0" | |
| 2920 | 2912 | ||
| 2921 | 2913 | [[patch.unused]] | |
| 2922 | 2914 | name = "quasi-axum" | |
| @@ -2943,9 +2935,17 @@ | |||
| 2943 | 2935 | version = "0.1.0" | |
| 2944 | 2936 | ||
| 2945 | 2937 | [[patch.unused]] | |
| 2946 | - | name = "synckit-client" | |
| 2947 | - | version = "0.8.0" | |
| 2938 | + | name = "docengine" | |
| 2939 | + | version = "0.7.0" | |
| 2948 | 2940 | ||
| 2949 | 2941 | [[patch.unused]] | |
| 2950 | - | name = "synckit-config" | |
| 2951 | - | version = "0.2.0" | |
| 2942 | + | name = "kberg" | |
| 2943 | + | version = "0.1.0" | |
| 2944 | + | ||
| 2945 | + | [[patch.unused]] | |
| 2946 | + | name = "painhours" | |
| 2947 | + | version = "0.1.0" | |
| 2948 | + | ||
| 2949 | + | [[patch.unused]] | |
| 2950 | + | name = "tagtree" | |
| 2951 | + | version = "0.4.0" |
| @@ -1,4 +1,4 @@ | |||
| 1 | - | //! What the viewer knows, and the rollup derived from it. | |
| 1 | + | //! What magicmirror knows, and the rollup derived from it. | |
| 2 | 2 | //! | |
| 3 | 3 | //! The model holds one [`SourceState`] per configured source and nothing about | |
| 4 | 4 | //! what any of them mean. Everything the rollup shows is computed from the | |
| @@ -270,8 +270,8 @@ | |||
| 270 | 270 | /// Enter on a source node: open the action picker, or explain why not. | |
| 271 | 271 | /// | |
| 272 | 272 | /// A node with no actions does nothing. A source with actions disabled says | |
| 273 | - | /// so rather than silently ignoring the key, because a viewer that looks | |
| 274 | - | /// like it should be able to act and does not is worse than one that says it | |
| 273 | + | /// so rather than silently ignoring the key, because a panel that looks like | |
| 274 | + | /// it should be able to act and does not is worse than one that says it | |
| 275 | 275 | /// cannot. | |
| 276 | 276 | pub(crate) fn open_actions(&mut self) { | |
| 277 | 277 | let Tab::Source(i) = self.tab else { return }; |
| @@ -1,12 +1,12 @@ | |||
| 1 | 1 | [package] | |
| 2 | - | name = "ops-viewer" | |
| 2 | + | name = "magicmirror" | |
| 3 | 3 | version = "0.1.0" | |
| 4 | 4 | edition = "2024" | |
| 5 | 5 | license = "MIT" | |
| 6 | 6 | description = "One terminal surface over every operator daemon that emits an ops-status payload. Tabs per source plus a worst-first rollup." | |
| 7 | 7 | ||
| 8 | 8 | [[bin]] | |
| 9 | - | name = "ops-viewer" | |
| 9 | + | name = "magicmirror" | |
| 10 | 10 | path = "src/main.rs" | |
| 11 | 11 | ||
| 12 | 12 | [dependencies] |
| @@ -1,17 +1,17 @@ | |||
| 1 | - | # ops-viewer: which daemons to watch. | |
| 1 | + | # magicmirror: which daemons to watch. | |
| 2 | 2 | # | |
| 3 | - | # Install at ~/.config/ops-viewer/viewer.toml, or pass a path as the first | |
| 3 | + | # Install at ~/.config/magicmirror/magicmirror.toml, or pass a path as the first | |
| 4 | 4 | # argument, or set $OPS_VIEWER_CONFIG. | |
| 5 | 5 | # | |
| 6 | - | # Adding a service is an edit to this file and nothing else. The viewer knows | |
| 6 | + | # Adding a service is an edit to this file and nothing else. magicmirror knows | |
| 7 | 7 | # nothing about tiers, gates, apps or targets; it renders whatever the source | |
| 8 | 8 | # emits at GET /status.json. A new daemon gets a UI by emitting the payload. | |
| 9 | 9 | # | |
| 10 | - | # The viewer is read-only until a source sets allow_actions = true. A source | |
| 10 | + | # magicmirror is read-only until a source sets allow_actions = true. A source | |
| 11 | 11 | # with it off still shows the actions its nodes declare; it just refuses to | |
| 12 | 12 | # fire them. With it on, Enter on a node opens a picker of that node's actions; | |
| 13 | 13 | # a plain action fires, a confirm action asks for 'y', and a danger action | |
| 14 | - | # (sando's rollback-b) asks you to type its key. This keeps a viewer that is | |
| 14 | + | # (sando's rollback-b) asks you to type its key. This keeps magicmirror that is | |
| 15 | 15 | # merely pointed at a daemon from ever moving it by accident. | |
| 16 | 16 | ||
| 17 | 17 | # Age past which a source's answer stops counting as current, for any source | |
| @@ -21,22 +21,22 @@ | |||
| 21 | 21 | # snapshot nobody had refreshed in forty days. | |
| 22 | 22 | stale_after_secs = 60 | |
| 23 | 23 | ||
| 24 | - | # Which theme to render in. Unset means follow the terminal: the viewer reads | |
| 24 | + | # Which theme to render in. Unset means follow the terminal: magicmirror reads | |
| 25 | 25 | # COLORFGBG and picks a light or dark theme to match, so it does not paint a | |
| 26 | 26 | # light palette onto a night session. Set it to a theme id to pin one instead, | |
| 27 | 27 | # e.g. "makenotwork", "carbonfox", "nord". Own themes go in | |
| 28 | - | # ~/.config/ops-viewer/themes/ and outrank the bundled set of the same id. | |
| 28 | + | # ~/.config/magicmirror/themes/ and outrank the bundled set of the same id. | |
| 29 | 29 | # | |
| 30 | 30 | # theme = "system" | |
| 31 | 31 | ||
| 32 | 32 | # Each URL below is the address that daemon's own deploy example binds, which is | |
| 33 | 33 | # the file to check when a source reads as unreachable. A daemon bound to | |
| 34 | - | # loopback is only visible to a viewer on the same host. | |
| 34 | + | # loopback is only visible to magicmirror on the same host. | |
| 35 | 35 | # | |
| 36 | - | # A tailnet bind is necessary but not sufficient for a viewer on another machine: | |
| 36 | + | # A tailnet bind is necessary but not sufficient for magicmirror on another machine: | |
| 37 | 37 | # the tailnet ACL decides separately whether that machine may open the port. As | |
| 38 | 38 | # of 2026-07-29 the ACL is one-directional between the user-owned hosts and the | |
| 39 | - | # tagged ones, so a viewer on astra cannot reach fw13's daemons at any port even | |
| 39 | + | # tagged ones, so magicmirror on astra cannot reach fw13's daemons at any port even | |
| 40 | 40 | # though both sit on the tailnet. Check the ACL, not just `listen`, when a source | |
| 41 | 41 | # reads unreachable from one host and fine from another. | |
| 42 | 42 | [[source]] | |
| @@ -56,7 +56,7 @@ | |||
| 56 | 56 | [[source]] | |
| 57 | 57 | name = "bento" | |
| 58 | 58 | # Matches `listen` in bento/deploy/bento-daemon.toml.example. Loopback, so this | |
| 59 | - | # source only works for a viewer running on the same host as bentod. A viewer | |
| 59 | + | # source only works for magicmirror running on the same host as bentod. magicmirror | |
| 60 | 60 | # elsewhere needs bentod moved to its tailnet address, which turns its auth on. | |
| 61 | 61 | url = "http://127.0.0.1:8765" | |
| 62 | 62 | # Bento leaves its reads open, so no token is needed. Set token_env anyway if | |
| @@ -67,7 +67,7 @@ | |||
| 67 | 67 | # limit rather than flagging it degraded between its own checks. Each target PoM | |
| 68 | 68 | # watches is a node; the rollup shows the worst of them. PoM gates /status.json | |
| 69 | 69 | # behind the same bearer token as its /api/* reads, so name the token here — it | |
| 70 | - | # is the value in pom's serve.api_token, supplied to the viewer via the | |
| 70 | + | # is the value in pom's serve.api_token, supplied to magicmirror via the | |
| 71 | 71 | # environment, never pasted into this file. | |
| 72 | 72 | [[source]] | |
| 73 | 73 | name = "pom" |
| @@ -1,7 +1,7 @@ | |||
| 1 | - | //! What the viewer is pointed at. | |
| 1 | + | //! What magicmirror is pointed at. | |
| 2 | 2 | //! | |
| 3 | 3 | //! Adding a service is a config edit and nothing else — no code change, no new | |
| 4 | - | //! tab type, no widget. That property is what makes the viewer modular rather | |
| 4 | + | //! tab type, no widget. That property is what makes magicmirror modular rather | |
| 5 | 5 | //! than merely tabbed, and it is worth defending: the moment a source needs a | |
| 6 | 6 | //! special case here, the shell has started learning domain vocabulary. | |
| 7 | 7 | ||
| @@ -30,8 +30,8 @@ | |||
| 30 | 30 | /// id to pin. | |
| 31 | 31 | /// | |
| 32 | 32 | /// Unprefixed `theme`, which is the family convention's key name (wiki | |
| 33 | - | /// `makeover-app-convention`) — this file is already scoped to the viewer, | |
| 34 | - | /// so a `viewer-theme` would be saying it twice. Absent reads as "follow | |
| 33 | + | /// `makeover-app-convention`) — this file is already scoped to magicmirror, | |
| 34 | + | /// so a `magicmirror-theme` would be saying it twice. Absent reads as "follow | |
| 35 | 35 | /// the terminal" rather than as a pin on whatever the first run guessed. | |
| 36 | 36 | #[serde(default)] | |
| 37 | 37 | pub theme: Option<String>, | |
| @@ -58,11 +58,11 @@ | |||
| 58 | 58 | pub poll_secs: u64, | |
| 59 | 59 | #[serde(default)] | |
| 60 | 60 | pub stale_after_secs: Option<u64>, | |
| 61 | - | /// Whether this source's declared actions may be fired from the viewer. | |
| 61 | + | /// Whether this source's declared actions may be fired from magicmirror. | |
| 62 | 62 | /// | |
| 63 | - | /// Defaults off. A viewer is a display first, and some declared actions | |
| 63 | + | /// Defaults off. magicmirror is a display first, and some declared actions | |
| 64 | 64 | /// (sando's `promote-b`, `rollback-b`) move production. Firing is opt-in per | |
| 65 | - | /// source so that pointing the viewer at a daemon can never move it by | |
| 65 | + | /// source so that pointing magicmirror at a daemon can never move it by | |
| 66 | 66 | /// accident: the operator turns a source's actions on deliberately, the same | |
| 67 | 67 | /// place they already name its token. A source with this off still renders | |
| 68 | 68 | /// its actions; it just refuses to issue them. | |
| @@ -91,7 +91,7 @@ | |||
| 91 | 91 | /// | |
| 92 | 92 | /// An action carries a path (`/rollback/b`); a producer that instead gives a | |
| 93 | 93 | /// full URL is honored as-is, so a daemon can point an action at somewhere | |
| 94 | - | /// other than itself without the viewer second-guessing it. | |
| 94 | + | /// other than itself without magicmirror second-guessing it. | |
| 95 | 95 | pub(crate) fn action_url(&self, path: &str) -> String { | |
| 96 | 96 | if path.starts_with("http://") || path.starts_with("https://") { | |
| 97 | 97 | return path.to_string(); | |
| @@ -115,9 +115,9 @@ | |||
| 115 | 115 | impl Config { | |
| 116 | 116 | pub(crate) fn load(path: &Path) -> Result<Self> { | |
| 117 | 117 | let raw = std::fs::read_to_string(path) | |
| 118 | - | .with_context(|| format!("reading viewer config at {}", path.display()))?; | |
| 118 | + | .with_context(|| format!("reading magicmirror config at {}", path.display()))?; | |
| 119 | 119 | let cfg: Config = toml::from_str(&raw) | |
| 120 | - | .with_context(|| format!("parsing viewer config at {}", path.display()))?; | |
| 120 | + | .with_context(|| format!("parsing magicmirror config at {}", path.display()))?; | |
| 121 | 121 | cfg.validate()?; | |
| 122 | 122 | Ok(cfg) | |
| 123 | 123 | } | |
| @@ -125,7 +125,7 @@ | |||
| 125 | 125 | fn validate(&self) -> Result<()> { | |
| 126 | 126 | anyhow::ensure!( | |
| 127 | 127 | !self.sources.is_empty(), | |
| 128 | - | "no [[source]] entries: the viewer would have nothing to show" | |
| 128 | + | "no [[source]] entries: magicmirror would have nothing to show" | |
| 129 | 129 | ); | |
| 130 | 130 | let mut seen = std::collections::HashSet::new(); | |
| 131 | 131 | for source in &self.sources { | |
| @@ -163,7 +163,7 @@ | |||
| 163 | 163 | ||
| 164 | 164 | fn write(body: &str) -> (tempfile::TempDir, std::path::PathBuf) { | |
| 165 | 165 | let dir = tempfile::tempdir().unwrap(); | |
| 166 | - | let path = dir.path().join("viewer.toml"); | |
| 166 | + | let path = dir.path().join("magicmirror.toml"); | |
| 167 | 167 | std::fs::write(&path, body).unwrap(); | |
| 168 | 168 | (dir, path) | |
| 169 | 169 | } |
| @@ -181,7 +181,7 @@ | |||
| 181 | 181 | ||
| 182 | 182 | /// Every source at once, worst first. | |
| 183 | 183 | /// | |
| 184 | - | /// Without this the viewer is N tabs you still have to visit one at a time, | |
| 184 | + | /// Without this magicmirror is N tabs you still have to visit one at a time, | |
| 185 | 185 | /// which is the situation it replaces, with extra steps. | |
| 186 | 186 | fn render_rollup(model: &Model, theme: &Theme, now: DateTime<Utc>, frame: &mut Frame, area: Rect) { | |
| 187 | 187 | let order = model.rollup_order(now); |
| @@ -23,7 +23,7 @@ | |||
| 23 | 23 | /// data with no inherent meaning (a project's color, a series on a chart), and | |
| 24 | 24 | /// a theme is free to author them as the status hues restated — `makenotwork` | |
| 25 | 25 | /// gives `category.six` and `status.info` the same value, which collapsed | |
| 26 | - | /// `undistributed` onto `pending` in exactly the theme the viewer ships with. | |
| 26 | + | /// `undistributed` onto `pending` in exactly the theme magicmirror ships with. | |
| 27 | 27 | /// | |
| 28 | 28 | /// So the two extra states are carried by a modifier on the nearest intent, | |
| 29 | 29 | /// which is the renderer's own doctrine: a terminal's real constraint is | |
| @@ -45,7 +45,7 @@ | |||
| 45 | 45 | Status::Pending => Style::default().fg(theme.status_info), | |
| 46 | 46 | // Muted, and inverted so it is anything but quiet. An unreachable | |
| 47 | 47 | // source is a real absence — no status intent is honest about it — but | |
| 48 | - | // it is the loudest thing a viewer can fail to tell you, so it is drawn | |
| 48 | + | // it is the loudest thing magicmirror can fail to tell you, so it is drawn | |
| 49 | 49 | // as a filled block rather than as gray text. | |
| 50 | 50 | Status::Unknown => Style::default() | |
| 51 | 51 | .fg(theme.content_muted) | |
| @@ -288,7 +288,7 @@ | |||
| 288 | 288 | ||
| 289 | 289 | #[test] | |
| 290 | 290 | fn progress_survives_nonsense_without_panicking() { | |
| 291 | - | // A producer bug must not take the viewer down. | |
| 291 | + | // A producer bug must not take magicmirror down. | |
| 292 | 292 | assert!(progress(5.0, 0.0, None, 40).contains("5/0")); | |
| 293 | 293 | assert!(progress(-1.0, 10.0, None, 40).starts_with('[')); | |
| 294 | 294 | assert!(progress(99.0, 10.0, None, 40).starts_with('[')); | |
| @@ -396,8 +396,8 @@ | |||
| 396 | 396 | // The failure this guards is silent: a theme free to author its intents | |
| 397 | 397 | // however it likes can hand two statuses the same hue, and the one | |
| 398 | 398 | // screen whose whole job is telling them apart stops doing it. Checked | |
| 399 | - | // over every theme makeover ships, not only the viewer's own default, | |
| 400 | - | // since an operator can name any of them in `viewer.toml`. | |
| 399 | + | // over every theme makeover ships, not only magicmirror's own default, | |
| 400 | + | // since an operator can name any of them in `magicmirror.toml`. | |
| 401 | 401 | for (id, source) in makeover::embedded_themes() { | |
| 402 | 402 | let colors = makeover::parse_theme_str(id, source, false) | |
| 403 | 403 | .unwrap_or_else(|e| panic!("bundled theme `{id}` does not parse: {e}")); |
| @@ -2,14 +2,14 @@ | |||
| 2 | 2 | //! payload. | |
| 3 | 3 | //! | |
| 4 | 4 | //! Design + rationale: maintainer wiki. | |
| 5 | - | //! <!-- wiki: release-viewer-overview --> | |
| 5 | + | //! <!-- wiki: magicmirror-overview --> | |
| 6 | 6 | //! | |
| 7 | 7 | //! Tabs, one per hooked-in source, plus a rollup that shows every source at | |
| 8 | 8 | //! once, worst first. The rollup is the reason the product exists: without it | |
| 9 | 9 | //! this is N tabs you still have to visit one at a time, which is the situation | |
| 10 | 10 | //! it replaces. | |
| 11 | 11 | //! | |
| 12 | - | //! The viewer knows nothing about tiers, gates, apps, or targets. It renders | |
| 12 | + | //! magicmirror knows nothing about tiers, gates, apps, or targets. It renders | |
| 13 | 13 | //! the shared contract in `ops-status` and nothing else, which is what lets a | |
| 14 | 14 | //! new daemon arrive with a UI already written. | |
| 15 | 15 | //! | |
| @@ -97,7 +97,7 @@ | |||
| 97 | 97 | return Ok(PathBuf::from(path)); | |
| 98 | 98 | } | |
| 99 | 99 | let home = std::env::var("HOME").context("HOME is unset and no config path was given")?; | |
| 100 | - | Ok(PathBuf::from(home).join(".config/ops-viewer/viewer.toml")) | |
| 100 | + | Ok(PathBuf::from(home).join(".config/magicmirror/magicmirror.toml")) | |
| 101 | 101 | } | |
| 102 | 102 | ||
| 103 | 103 | // The TUI run loop owns model/sources/channels for the app's lifetime. |
| @@ -63,7 +63,7 @@ | |||
| 63 | 63 | ticker.tick().await; | |
| 64 | 64 | let result = fetch(&client, &url, source.token().as_deref()).await; | |
| 65 | 65 | // The token is read per request rather than captured once, so rotating | |
| 66 | - | // it does not require restarting the viewer. | |
| 66 | + | // it does not require restarting magicmirror. | |
| 67 | 67 | if tx | |
| 68 | 68 | .send(Update { | |
| 69 | 69 | index, |
| @@ -6,7 +6,7 @@ | |||
| 6 | 6 | //! lives at the edge, off the render loop, so a slow or hung daemon cannot | |
| 7 | 7 | //! freeze the surface you are trying to read. | |
| 8 | 8 | //! | |
| 9 | - | //! The viewer never learns what an action *means*. It has a method, a URL, an | |
| 9 | + | //! magicmirror never learns what an action *means*. It has a method, a URL, an | |
| 10 | 10 | //! optional body, and a bearer token, all declared by the producer, and it | |
| 11 | 11 | //! issues exactly that. `promote` and `rollback` are opaque strings here. | |
| 12 | 12 | ||
| @@ -33,7 +33,7 @@ | |||
| 33 | 33 | /// early would abort work the server is mid-way through. Still bounded, so a | |
| 34 | 34 | /// daemon that never answers does not leak a task forever. A synchronous | |
| 35 | 35 | /// operation that genuinely outlasts this is a daemon-shape problem, not a | |
| 36 | - | /// viewer one; the next poll still shows the true resulting state. | |
| 36 | + | /// magicmirror one; the next poll still shows the true resulting state. | |
| 37 | 37 | const ACTION_TIMEOUT: Duration = Duration::from_mins(2); | |
| 38 | 38 | ||
| 39 | 39 | /// Body text kept from a failed response, past which it is noise in a one-line |