diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c52feae..94eb280 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -22,7 +22,7 @@ jobs: - uses: docker/metadata-action@v5 id: meta with: - images: ghcr.io/${{ github.repository_owner }}/gaggibot + images: ghcr.io/${{ github.repository_owner }}/matebot tags: | type=raw,value=latest,enable={{is_default_branch}} type=semver,pattern={{version}} diff --git a/Dockerfile b/Dockerfile index 5a01df3..f8bb317 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,10 +10,10 @@ COPY pyproject.toml README.md LICENSE ./ COPY src ./src RUN pip install --no-cache-dir ".[all]" -RUN useradd -m -u 1000 gaggibot -USER gaggibot -ENV GAGGIBOT_STATE_DIR=/data +RUN useradd -m -u 1000 matebot +USER matebot +ENV MATEBOT_STATE_DIR=/data VOLUME /data -ENTRYPOINT ["gaggibot"] +ENTRYPOINT ["matebot"] CMD ["run"] diff --git a/README.md b/README.md index 417cf3a..497686d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# gaggibot +# matebot A post-shot companion for [GaggiMate](https://gaggimate.eu) espresso machines. @@ -7,14 +7,14 @@ shot the ritual was: pull out the phone, open the web UI, find Shot History, tap edit, type everything in. Most days that didn't happen, and by 23:47, lying in bed, the grind setting of today's best shot was gone for good. -gaggibot turns the workflow around: when a shot finishes, the machine messages +matebot turns the workflow around: when a shot finishes, the machine messages *you* and asks the few things you'd otherwise forget — rating, taste, beans, grind, doses. Thirty seconds of tapping while you sip. The answers are written straight back into GaggiMate's own Shot Notes, exactly as if you'd typed them into the web UI.

- gaggibot asking for a shot rating on Telegram right after the shot finished + matebot asking for a shot rating on Telegram right after the shot finished

## What it does @@ -24,17 +24,17 @@ into the web UI. - Runs a short questionnaire via **Telegram** or **Discord** (Matrix planned), with one-tap "same as last shot" defaults for beans, grind and dose. - Saves the answers into the machine's shot history — GaggiMate stays the - source of truth, with or without gaggibot. + source of truth, with or without matebot. - Optionally archives every shot (`.slog` + notes), your brew profiles and machine settings (credentials redacted) to a git repository after each shot. - Generates a static **shot journal** from that archive, ready for GitHub Pages. Because the journal lives outside the machine, it survives firmware updates and downgrades, a dying SD card, or a water-damaged machine. -- Ships a standalone `.slog` decoder (`gaggibot decode shot.slog --csv`). +- Ships a standalone `.slog` decoder (`matebot decode shot.slog --csv`). - After a sour, bitter or low-rated shot it suggests the next dial-in step (grind → ratio → temperature, one variable at a time), following [modsmthng's Automatic Pro cheat sheet](https://modsmthng.github.io/Automatic-Pro/) - — disable with `GAGGIBOT_HINTS=0`. + — disable with `MATEBOT_HINTS=0`. ## The shot journal @@ -52,34 +52,34 @@ and notes. ### Docker ```bash -mkdir gaggibot && cd gaggibot -curl -O https://raw.githubusercontent.com/AlexNly/gaggibot/main/docker-compose.example.yml +mkdir matebot && cd matebot +curl -O https://raw.githubusercontent.com/AlexNly/matebot/main/docker-compose.example.yml cp docker-compose.example.yml docker-compose.yml # edit: machine host, bot token, chat id docker compose up -d ``` Images are multi-arch (`amd64` + `arm64`, so a Raspberry Pi works): -`ghcr.io/alexnly/gaggibot:latest`. There is no cloud service behind this — +`ghcr.io/alexnly/matebot:latest`. There is no cloud service behind this — the bot needs to run on something in your home network that is always on. A Pi Zero 2 W and a USB charger is the whole data center. ### pip ```bash -pip install "gaggibot[telegram] @ git+https://github.com/AlexNly/gaggibot" -gaggibot run +pip install "matebot[telegram] @ git+https://github.com/AlexNly/matebot" +matebot run ``` ### NixOS (flake) ```nix -inputs.gaggibot.url = "github:AlexNly/gaggibot"; +inputs.matebot.url = "github:AlexNly/matebot"; -services.gaggibot = { +services.matebot = { enable = true; machineHost = "192.168.1.50"; - environmentFile = "/etc/secrets/gaggibot"; # TELEGRAM_BOT_TOKEN=... / TELEGRAM_CHAT_ID=... + environmentFile = "/etc/secrets/matebot"; # TELEGRAM_BOT_TOKEN=... / TELEGRAM_CHAT_ID=... dataRepo = "/var/lib/gaggimate-journal"; # optional }; ``` @@ -91,7 +91,7 @@ services.gaggibot = { from `https://api.telegram.org/bot/getUpdates`. Discord: create an application + bot, invite it to a server, enable the *message content* intent, copy the channel id. -2. Point `GAGGIBOT_MACHINE_HOST` at your GaggiMate. A DHCP reservation is more +2. Point `MATEBOT_MACHINE_HOST` at your GaggiMate. A DHCP reservation is more reliable than `gaggimate.local`. 3. Pull a shot. @@ -110,35 +110,35 @@ Besides the post-shot questionnaire, the bot answers commands (any messenger): ## Configuration -Environment variables, or the same keys in `~/.config/gaggibot/config.toml`: +Environment variables, or the same keys in `~/.config/matebot/config.toml`: | Variable | Default | Meaning | |---|---|---| -| `GAGGIBOT_MACHINE_HOST` | `gaggimate.local` | GaggiMate hostname/IP | -| `GAGGIBOT_MESSENGER` | `telegram` | `telegram` or `discord` | +| `MATEBOT_MACHINE_HOST` | `gaggimate.local` | GaggiMate hostname/IP | +| `MATEBOT_MESSENGER` | `telegram` | `telegram` or `discord` | | `TELEGRAM_BOT_TOKEN` / `TELEGRAM_CHAT_ID` | — | Telegram credentials | | `DISCORD_BOT_TOKEN` / `DISCORD_CHANNEL_ID` | — | Discord credentials | -| `GAGGIBOT_DATA_REPO` | — | Path to a git clone; enables archive + journal | -| `GAGGIBOT_SITE_TITLE` | `Shot Journal` | Title of the generated journal | -| `GAGGIBOT_JOURNAL_URL` | — | Public journal URL, used for `/last` deep links | -| `GAGGIBOT_HINTS` | `1` | Dial-in hints after sour/bitter/low-rated shots | -| `GAGGIBOT_STATE_DIR` | `~/.local/state/gaggibot` | Bot state (defaults, resume) | -| `GAGGIBOT_MIN_SHOT_S` | `10` | Ignore shots shorter than this | -| `GAGGIBOT_IGNORE_PROFILES` | `(?i)backflush\|descale\|flush\|clean` | Profile regex to skip | +| `MATEBOT_DATA_REPO` | — | Path to a git clone; enables archive + journal | +| `MATEBOT_SITE_TITLE` | `Shot Journal` | Title of the generated journal | +| `MATEBOT_JOURNAL_URL` | — | Public journal URL, used for `/last` deep links | +| `MATEBOT_HINTS` | `1` | Dial-in hints after sour/bitter/low-rated shots | +| `MATEBOT_STATE_DIR` | `~/.local/state/matebot` | Bot state (defaults, resume) | +| `MATEBOT_MIN_SHOT_S` | `10` | Ignore shots shorter than this | +| `MATEBOT_IGNORE_PROFILES` | `(?i)backflush\|descale\|flush\|clean` | Profile regex to skip | ## CLI ``` -gaggibot run # the bot (--replay frames.jsonl --dry-run to test) -gaggibot decode SHOT.slog # .slog -> JSON (--csv for CSV) -gaggibot sitegen shots/ -o docs/ --title "My Shot Journal" -gaggibot sync # one-off journal sync (shots, profiles, settings, site) +matebot run # the bot (--replay frames.jsonl --dry-run to test) +matebot decode SHOT.slog # .slog -> JSON (--csv for CSV) +matebot sitegen shots/ -o docs/ --title "My Shot Journal" +matebot sync # one-off journal sync (shots, profiles, settings, site) ``` ## Publishing your journal on GitHub Pages -1. Create a repo for your data, clone it where gaggibot runs, set - `GAGGIBOT_DATA_REPO` to the clone. +1. Create a repo for your data, clone it where matebot runs, set + `MATEBOT_DATA_REPO` to the clone. 2. On GitHub: Settings → Pages → Deploy from branch → `main` / `/docs`. 3. Every shot now updates `https://.github.io//`. @@ -154,7 +154,7 @@ your own git remote. Requires GaggiMate firmware ≥ v1.7 (binary shot logs). are redacted before anything is written to disk The `.slog` v5 binary format (512-byte header, 26-byte samples at 250 ms) is -documented in [`src/gaggibot/slog.py`](src/gaggibot/slog.py). +documented in [`src/matebot/slog.py`](src/matebot/slog.py). ### WhatsApp? diff --git a/docker-compose.example.yml b/docker-compose.example.yml index 2a7ed46..db4d36e 100644 --- a/docker-compose.example.yml +++ b/docker-compose.example.yml @@ -1,19 +1,19 @@ -# gaggibot — minimal deployment. +# matebot — minimal deployment. # 1. copy to docker-compose.yml 2. fill in the env vars 3. docker compose up -d services: - gaggibot: - image: ghcr.io/alexnly/gaggibot:latest + matebot: + image: ghcr.io/alexnly/matebot:latest restart: unless-stopped environment: - GAGGIBOT_MACHINE_HOST: gaggimate.local # or the machine's IP (recommended) - GAGGIBOT_MESSENGER: telegram # telegram | discord + MATEBOT_MACHINE_HOST: gaggimate.local # or the machine's IP (recommended) + MATEBOT_MESSENGER: telegram # telegram | discord TELEGRAM_BOT_TOKEN: "123456:ABC..." # from @BotFather TELEGRAM_CHAT_ID: "12345678" # your chat with the bot # DISCORD_BOT_TOKEN: "..." # DISCORD_CHANNEL_ID: "..." # --- optional: git-backed shot journal + GitHub Pages site --- - # GAGGIBOT_DATA_REPO: /journal + # MATEBOT_DATA_REPO: /journal volumes: - ./data:/data # bot state (last shot, defaults) # - ./journal:/journal # your data repo (git clone) - # - ~/.ssh:/home/gaggibot/.ssh:ro # ssh key for git push + # - ~/.ssh:/home/matebot/.ssh:ro # ssh key for git push diff --git a/flake.nix b/flake.nix index 92895fd..5ef8d61 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,5 @@ { - description = "gaggibot — the proactive companion for GaggiMate espresso machines"; + description = "matebot — the proactive companion for GaggiMate espresso machines"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05"; @@ -10,9 +10,9 @@ { packages = forAllSystems (system: let pkgs = nixpkgs.legacyPackages.${system}; in rec { - default = gaggibot; - gaggibot = pkgs.python3Packages.buildPythonApplication { - pname = "gaggibot"; + default = matebot; + matebot = pkgs.python3Packages.buildPythonApplication { + pname = "matebot"; version = "0.1.0"; pyproject = true; src = self; @@ -23,18 +23,18 @@ # discord.py is optional at runtime; add it when using the discord messenger ] ++ pkgs.lib.optional (pkgs.python3Packages ? discordpy) pkgs.python3Packages.discordpy; nativeCheckInputs = with pkgs.python3Packages; [ pytestCheckHook pytest-asyncio ]; - pythonImportsCheck = [ "gaggibot" ]; + pythonImportsCheck = [ "matebot" ]; }; }); nixosModules.default = { config, lib, pkgs, ... }: let - cfg = config.services.gaggibot; + cfg = config.services.matebot; pkg = self.packages.${pkgs.system}.default; in { - options.services.gaggibot = { - enable = lib.mkEnableOption "gaggibot, the GaggiMate shot companion"; + options.services.matebot = { + enable = lib.mkEnableOption "matebot, the GaggiMate shot companion"; machineHost = lib.mkOption { type = lib.types.str; description = "Hostname/IP of the GaggiMate controller."; @@ -54,12 +54,12 @@ }; user = lib.mkOption { type = lib.types.str; - default = "gaggibot"; + default = "matebot"; description = "User to run as (needs git+ssh identity when dataRepo is set)."; }; stateDir = lib.mkOption { type = lib.types.str; - default = "/var/lib/gaggibot"; + default = "/var/lib/matebot"; }; minShotDuration = lib.mkOption { type = lib.types.int; default = 10; }; ignoreProfiles = lib.mkOption { @@ -69,32 +69,32 @@ }; config = lib.mkIf cfg.enable { - users.users = lib.mkIf (cfg.user == "gaggibot") { - gaggibot = { isSystemUser = true; group = "gaggibot"; home = cfg.stateDir; }; + users.users = lib.mkIf (cfg.user == "matebot") { + matebot = { isSystemUser = true; group = "matebot"; home = cfg.stateDir; }; }; - users.groups = lib.mkIf (cfg.user == "gaggibot") { gaggibot = { }; }; + users.groups = lib.mkIf (cfg.user == "matebot") { matebot = { }; }; - systemd.services.gaggibot = { - description = "gaggibot — GaggiMate shot companion"; + systemd.services.matebot = { + description = "matebot — GaggiMate shot companion"; wantedBy = [ "multi-user.target" ]; after = [ "network-online.target" ]; wants = [ "network-online.target" ]; path = [ pkgs.git pkgs.openssh ]; environment = { - GAGGIBOT_MACHINE_HOST = cfg.machineHost; - GAGGIBOT_MESSENGER = cfg.messenger; - GAGGIBOT_STATE_DIR = cfg.stateDir; - GAGGIBOT_MIN_SHOT_S = toString cfg.minShotDuration; - GAGGIBOT_IGNORE_PROFILES = cfg.ignoreProfiles; + MATEBOT_MACHINE_HOST = cfg.machineHost; + MATEBOT_MESSENGER = cfg.messenger; + MATEBOT_STATE_DIR = cfg.stateDir; + MATEBOT_MIN_SHOT_S = toString cfg.minShotDuration; + MATEBOT_IGNORE_PROFILES = cfg.ignoreProfiles; } // lib.optionalAttrs (cfg.dataRepo != null) { - GAGGIBOT_DATA_REPO = toString cfg.dataRepo; - GAGGIBOT_SYNC = "1"; + MATEBOT_DATA_REPO = toString cfg.dataRepo; + MATEBOT_SYNC = "1"; }; serviceConfig = { - ExecStart = "${pkg}/bin/gaggibot run"; + ExecStart = "${pkg}/bin/matebot run"; EnvironmentFile = cfg.environmentFile; User = cfg.user; - StateDirectory = lib.mkIf (cfg.stateDir == "/var/lib/gaggibot") "gaggibot"; + StateDirectory = lib.mkIf (cfg.stateDir == "/var/lib/matebot") "matebot"; Restart = "always"; RestartSec = "10"; NoNewPrivileges = true; diff --git a/pyproject.toml b/pyproject.toml index 6258d91..6c34cf0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["hatchling"] build-backend = "hatchling.build" [project] -name = "gaggibot" +name = "matebot" version = "0.1.0" description = "The proactive companion for GaggiMate espresso machines: post-shot logging bot, .slog decoder, shot-journal site generator" readme = "README.md" @@ -22,18 +22,18 @@ dependencies = ["aiohttp>=3.9"] telegram = ["python-telegram-bot>=21,<23"] discord = ["discord.py>=2.3"] matrix = ["matrix-nio>=0.24"] -all = ["gaggibot[telegram,discord,matrix]"] +all = ["matebot[telegram,discord,matrix]"] dev = ["pytest>=8", "pytest-asyncio>=0.23", "ruff>=0.4"] [project.urls] -Homepage = "https://github.com/AlexNly/gaggibot" -Issues = "https://github.com/AlexNly/gaggibot/issues" +Homepage = "https://github.com/AlexNly/matebot" +Issues = "https://github.com/AlexNly/matebot/issues" [project.scripts] -gaggibot = "gaggibot.cli:main" +matebot = "matebot.cli:main" [tool.hatch.build.targets.wheel] -packages = ["src/gaggibot"] +packages = ["src/matebot"] [tool.ruff] line-length = 100 diff --git a/src/gaggibot/__init__.py b/src/gaggibot/__init__.py deleted file mode 100644 index d471660..0000000 --- a/src/gaggibot/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -"""gaggibot — the proactive companion for GaggiMate espresso machines.""" - -__version__ = "0.1.0" diff --git a/src/matebot/__init__.py b/src/matebot/__init__.py new file mode 100644 index 0000000..c660aa2 --- /dev/null +++ b/src/matebot/__init__.py @@ -0,0 +1,3 @@ +"""matebot — the proactive companion for GaggiMate espresso machines.""" + +__version__ = "0.1.0" diff --git a/src/gaggibot/bags.py b/src/matebot/bags.py similarity index 100% rename from src/gaggibot/bags.py rename to src/matebot/bags.py diff --git a/src/gaggibot/cli.py b/src/matebot/cli.py similarity index 97% rename from src/gaggibot/cli.py rename to src/matebot/cli.py index b8a3e40..9d6802f 100644 --- a/src/gaggibot/cli.py +++ b/src/matebot/cli.py @@ -1,4 +1,4 @@ -"""gaggibot CLI: run / decode / sitegen / sync.""" +"""matebot CLI: run / decode / sitegen / sync.""" from __future__ import annotations @@ -15,10 +15,10 @@ def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser( - prog="gaggibot", + prog="matebot", description="The proactive companion for GaggiMate espresso machines.", ) - parser.add_argument("--version", action="version", version=f"gaggibot {__version__}") + parser.add_argument("--version", action="version", version=f"matebot {__version__}") parser.add_argument("--config", help="path to config.toml") parser.add_argument("-v", "--verbose", action="store_true") sub = parser.add_subparsers(dest="cmd", required=True) @@ -72,7 +72,7 @@ async def _sync(config: Config) -> int: from .sync import sync if not config.data_repo: - print("error: GAGGIBOT_DATA_REPO / data_repo not configured", file=sys.stderr) + print("error: MATEBOT_DATA_REPO / data_repo not configured", file=sys.stderr) return 1 async with GaggiMateClient(config.machine_host) as client: # WS connection (for profiles) is optional here; HTTP does the rest. @@ -90,7 +90,7 @@ async def _run(config: Config, *, replay: str | None, dry_run: bool) -> int: from .sync import sync_soon from .watcher import ShotWatcher, replay_frames - log = logging.getLogger("gaggibot") + log = logging.getLogger("matebot") state = State(pathlib.Path(config.state_dir) / "state.json") async with GaggiMateClient(config.machine_host) as client: diff --git a/src/gaggibot/commands.py b/src/matebot/commands.py similarity index 98% rename from src/gaggibot/commands.py rename to src/matebot/commands.py index dd2c8e6..6907200 100644 --- a/src/gaggibot/commands.py +++ b/src/matebot/commands.py @@ -52,7 +52,7 @@ async def handle(self, text: str) -> bool: handler = getattr(self, f"_cmd_{cmd}", None) if handler is None: if cmd == "start": - await self.messenger.send("☕ gaggibot at your service.\n\n" + HELP) + await self.messenger.send("☕ matebot at your service.\n\n" + HELP) return True return False try: diff --git a/src/gaggibot/config.py b/src/matebot/config.py similarity index 81% rename from src/gaggibot/config.py rename to src/matebot/config.py index 9d607bc..b12dffe 100644 --- a/src/gaggibot/config.py +++ b/src/matebot/config.py @@ -9,26 +9,26 @@ DEFAULT_CONFIG = Path( os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")) -) / "gaggibot" / "config.toml" +) / "matebot" / "config.toml" # dataclass field -> environment variable ENV_MAP = { - "machine_host": "GAGGIBOT_MACHINE_HOST", - "messenger": "GAGGIBOT_MESSENGER", + "machine_host": "MATEBOT_MACHINE_HOST", + "messenger": "MATEBOT_MESSENGER", "telegram_token": "TELEGRAM_BOT_TOKEN", "telegram_chat_id": "TELEGRAM_CHAT_ID", "discord_token": "DISCORD_BOT_TOKEN", "discord_channel_id": "DISCORD_CHANNEL_ID", - "data_repo": "GAGGIBOT_DATA_REPO", - "state_dir": "GAGGIBOT_STATE_DIR", - "min_shot_s": "GAGGIBOT_MIN_SHOT_S", - "ignore_profiles": "GAGGIBOT_IGNORE_PROFILES", - "sync_enabled": "GAGGIBOT_SYNC", - "site_title": "GAGGIBOT_SITE_TITLE", - "journal_url": "GAGGIBOT_JOURNAL_URL", - "hints_enabled": "GAGGIBOT_HINTS", - "digest_enabled": "GAGGIBOT_DIGEST", - "clean_every": "GAGGIBOT_CLEAN_EVERY", + "data_repo": "MATEBOT_DATA_REPO", + "state_dir": "MATEBOT_STATE_DIR", + "min_shot_s": "MATEBOT_MIN_SHOT_S", + "ignore_profiles": "MATEBOT_IGNORE_PROFILES", + "sync_enabled": "MATEBOT_SYNC", + "site_title": "MATEBOT_SITE_TITLE", + "journal_url": "MATEBOT_JOURNAL_URL", + "hints_enabled": "MATEBOT_HINTS", + "digest_enabled": "MATEBOT_DIGEST", + "clean_every": "MATEBOT_CLEAN_EVERY", } @@ -45,7 +45,7 @@ class Config: default_factory=lambda: os.environ.get( "XDG_STATE_HOME", os.path.expanduser("~/.local/state") ) - + "/gaggibot" + + "/matebot" ) min_shot_s: float = 10.0 ignore_profiles: str = r"(?i)backflush|descale|flush|clean" diff --git a/src/gaggibot/conversation.py b/src/matebot/conversation.py similarity index 100% rename from src/gaggibot/conversation.py rename to src/matebot/conversation.py diff --git a/src/gaggibot/digest.py b/src/matebot/digest.py similarity index 100% rename from src/gaggibot/digest.py rename to src/matebot/digest.py diff --git a/src/gaggibot/hints.py b/src/matebot/hints.py similarity index 100% rename from src/gaggibot/hints.py rename to src/matebot/hints.py diff --git a/src/gaggibot/machine.py b/src/matebot/machine.py similarity index 100% rename from src/gaggibot/machine.py rename to src/matebot/machine.py diff --git a/src/gaggibot/messengers/__init__.py b/src/matebot/messengers/__init__.py similarity index 100% rename from src/gaggibot/messengers/__init__.py rename to src/matebot/messengers/__init__.py diff --git a/src/gaggibot/messengers/base.py b/src/matebot/messengers/base.py similarity index 100% rename from src/gaggibot/messengers/base.py rename to src/matebot/messengers/base.py diff --git a/src/gaggibot/messengers/discord.py b/src/matebot/messengers/discord.py similarity index 100% rename from src/gaggibot/messengers/discord.py rename to src/matebot/messengers/discord.py diff --git a/src/gaggibot/messengers/telegram.py b/src/matebot/messengers/telegram.py similarity index 100% rename from src/gaggibot/messengers/telegram.py rename to src/matebot/messengers/telegram.py diff --git a/src/gaggibot/sitegen.py b/src/matebot/sitegen.py similarity index 96% rename from src/gaggibot/sitegen.py rename to src/matebot/sitegen.py index 2186f76..010507c 100644 --- a/src/gaggibot/sitegen.py +++ b/src/matebot/sitegen.py @@ -1,7 +1,7 @@ """Generate the static shot-explorer site (GitHub Pages friendly). Input: a folder of ``NNNNNN.slog`` + optional ``NNNNNN.json`` notes files - (the layout of a gaggibot/GaggiMate data repo's ``shots/`` dir). + (the layout of a matebot/GaggiMate data repo's ``shots/`` dir). Output: ``docs/`` with a self-contained viewer (no CDN): index.html + app.js + style.css + index.json + shots/.json """ @@ -105,7 +105,7 @@ def generate(shots_dir: str | Path, out_dir: str | Path, *, title: str = "Shot J index.sort(key=lambda e: e["id"], reverse=True) (out_dir / "index.json").write_text(json.dumps({"title": title, "shots": index})) - web = importlib.resources.files("gaggibot") / "web" + web = importlib.resources.files("matebot") / "web" for name in WEB_ASSETS: (out_dir / name).write_text((web / name).read_text()) log.info("site generated: %d shots -> %s", len(index), out_dir) diff --git a/src/gaggibot/slog.py b/src/matebot/slog.py similarity index 100% rename from src/gaggibot/slog.py rename to src/matebot/slog.py diff --git a/src/gaggibot/state.py b/src/matebot/state.py similarity index 100% rename from src/gaggibot/state.py rename to src/matebot/state.py diff --git a/src/gaggibot/sync.py b/src/matebot/sync.py similarity index 99% rename from src/gaggibot/sync.py rename to src/matebot/sync.py index a2275c6..98b0e81 100644 --- a/src/gaggibot/sync.py +++ b/src/matebot/sync.py @@ -50,7 +50,7 @@ async def sync( shots_dir = repo / "shots" shots_dir.mkdir(parents=True, exist_ok=True) - with open(repo / ".gaggibot.lock", "w") as lock: + with open(repo / ".matebot.lock", "w") as lock: try: fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB) except BlockingIOError: diff --git a/src/gaggibot/watcher.py b/src/matebot/watcher.py similarity index 100% rename from src/gaggibot/watcher.py rename to src/matebot/watcher.py diff --git a/src/gaggibot/web/app.js b/src/matebot/web/app.js similarity index 100% rename from src/gaggibot/web/app.js rename to src/matebot/web/app.js diff --git a/src/gaggibot/web/index.html b/src/matebot/web/index.html similarity index 83% rename from src/gaggibot/web/index.html rename to src/matebot/web/index.html index 2519f68..514279f 100644 --- a/src/gaggibot/web/index.html +++ b/src/matebot/web/index.html @@ -10,7 +10,7 @@

Shot Journal

-

Logged by gaggibot, straight from a GaggiMate.

+

Logged by matebot, straight from a GaggiMate.

@@ -34,7 +34,7 @@

-

Generated by gaggibot · data lives in this repo, no trackers, no cloud.

+

Generated by matebot · data lives in this repo, no trackers, no cloud.

diff --git a/src/gaggibot/web/style.css b/src/matebot/web/style.css similarity index 100% rename from src/gaggibot/web/style.css rename to src/matebot/web/style.css diff --git a/tests/test_bags.py b/tests/test_bags.py index 131ebe8..e3844fa 100644 --- a/tests/test_bags.py +++ b/tests/test_bags.py @@ -1,5 +1,5 @@ -from gaggibot.bags import bag_status, open_bag, track_shot -from gaggibot.state import State +from matebot.bags import bag_status, open_bag, track_shot +from matebot.state import State def make_state(tmp_path): diff --git a/tests/test_cleaning.py b/tests/test_cleaning.py index 239eb8b..130fe98 100644 --- a/tests/test_cleaning.py +++ b/tests/test_cleaning.py @@ -3,8 +3,8 @@ import pytest -from gaggibot.slog import parse_index -from gaggibot.watcher import ShotWatcher, replay_frames +from matebot.slog import parse_index +from matebot.watcher import ShotWatcher, replay_frames FIXTURE = pathlib.Path(__file__).parent / "fixtures" / "status_frames.jsonl" diff --git a/tests/test_commands.py b/tests/test_commands.py index 16fee66..50e93e9 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -1,9 +1,9 @@ import pytest -from gaggibot.commands import CommandRouter, make_frame_cache -from gaggibot.config import Config -from gaggibot.machine import MachineError -from gaggibot.state import State +from matebot.commands import CommandRouter, make_frame_cache +from matebot.config import Config +from matebot.machine import MachineError +from matebot.state import State class FakeMessenger: diff --git a/tests/test_conversation.py b/tests/test_conversation.py index ad6e3e4..260b095 100644 --- a/tests/test_conversation.py +++ b/tests/test_conversation.py @@ -1,8 +1,8 @@ import pytest -from gaggibot.conversation import Conversation -from gaggibot.messengers.base import Messenger, Option, OptionSelected, TextReply -from gaggibot.state import State +from matebot.conversation import Conversation +from matebot.messengers.base import Messenger, Option, OptionSelected, TextReply +from matebot.state import State class FakeMessenger(Messenger): diff --git a/tests/test_digest.py b/tests/test_digest.py index 88c591b..561afa5 100644 --- a/tests/test_digest.py +++ b/tests/test_digest.py @@ -1,6 +1,6 @@ from datetime import datetime -from gaggibot.digest import compute, seconds_until_sunday_evening +from matebot.digest import compute, seconds_until_sunday_evening NOW = datetime(2026, 7, 5, 20, 0) # a Sunday evening TS = NOW.timestamp() diff --git a/tests/test_hints.py b/tests/test_hints.py index 00bfc4a..3084e1f 100644 --- a/tests/test_hints.py +++ b/tests/test_hints.py @@ -1,4 +1,4 @@ -from gaggibot.hints import make_hint +from matebot.hints import make_hint def test_good_shot_no_hint(): diff --git a/tests/test_sitegen.py b/tests/test_sitegen.py index d91f664..13eec62 100644 --- a/tests/test_sitegen.py +++ b/tests/test_sitegen.py @@ -2,7 +2,7 @@ import pathlib import shutil -from gaggibot.sitegen import generate +from matebot.sitegen import generate FIXTURES = pathlib.Path(__file__).parent / "fixtures" diff --git a/tests/test_slog.py b/tests/test_slog.py index af0fa75..516e6c2 100644 --- a/tests/test_slog.py +++ b/tests/test_slog.py @@ -4,7 +4,7 @@ import pytest -from gaggibot.slog import SlogError, is_slog, parse_index, parse_slog +from matebot.slog import SlogError, is_slog, parse_index, parse_slog FIXTURES = pathlib.Path(__file__).parent / "fixtures" GOLDEN = FIXTURES / "000004.slog" diff --git a/tests/test_watcher.py b/tests/test_watcher.py index 333e11c..c5f59b6 100644 --- a/tests/test_watcher.py +++ b/tests/test_watcher.py @@ -3,8 +3,8 @@ import pytest -from gaggibot.slog import parse_index -from gaggibot.watcher import ShotWatcher, replay_frames +from matebot.slog import parse_index +from matebot.watcher import ShotWatcher, replay_frames FIXTURE = pathlib.Path(__file__).parent / "fixtures" / "status_frames.jsonl"