From 109a92bdd31ac9598734eecbd6d9e56aa9280437 Mon Sep 17 00:00:00 2001 From: Tim Conrad <4759569+Tim-Conrad@users.noreply.github.com> Date: Sat, 14 Nov 2026 02:35:19 +0100 Subject: [PATCH] Nix dev shell and the unified preview (wt, review.t7d.dev) - flake.nix: Python with Playwright and markdown, Node 22, gh, uv; .envrc loads it with direnv. - compose.preview.yml: the review site of the current worktree and its papercuts relay, for `wt up`. Approve writes to .review/approve/ of the main checkout, as before. - README: development in the dev VM with direnv and wt. Tests in the dev shell: 72 Python and 12 Node tests pass. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KFxuEvbkaAsJXeJAcQhGr6 --- .envrc | 1 + README.md | 25 +++++++++-------- compose.preview.yml | 66 +++++++++++++++++++++++++++++++++++++++++++++ flake.lock | 27 +++++++++++++++++++ flake.nix | 31 +++++++++++++++++++++ 5 files changed, 137 insertions(+), 13 deletions(-) create mode 100644 .envrc create mode 100644 compose.preview.yml create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/README.md b/README.md index f7d13f5..cad0e1c 100644 --- a/README.md +++ b/README.md @@ -77,19 +77,18 @@ Each page also has the papercuts widget. A papercut keeps the page, the branch, "Approve round " in the bar publishes the newest round of the branch. It writes a request to `.review/approve/`. On the host, `scripts/review/approve-host.sh` checks the head and the worktree and runs `scripts/check.py`. Then it pushes the branch, opens the PR, runs `scripts/ship.sh `, and removes the worktree and the branch. The bar shows each step from `.review/approve-status/`. An agent can do the same with `python3 scripts/review/approve.py `, also from its worktree. An agent starts Approve only when Tim tells it to, in that conversation or in a papercut. -To run it in a container behind a login proxy: - -1. Install the host side of the Approve button once: `scripts/review/approve-install.sh`. It needs `gh` on PATH. It makes `.review/approve/`, `.review/approve-status/` and a systemd user unit that starts `approve-host.sh` for each request. To keep the button working after a reboot, run `loginctl enable-linger developer` once. -2. Make the store folder and the worktrees folder: `mkdir -p .papercuts ~/code/worktrees/t7d`. - - Run steps 1 and 2 before step 4. If the folders do not exist, Docker makes them as root. -3. Write the settings into `.env`: - - `REVIEW_HOST`: the host name of the review site. - - `REVIEW_PAPERCUTS_HOST`: the host name of the relay. - - `REVIEW_MAIN`: the host path of this clone. - - `REVIEW_WORKTREES`: the host path of the folder with the site worktrees (`~/code/worktrees/t7d`, as a full path). - - `PAPERCUTS_SRC`: the folder of the relay source with its Dockerfile. -4. Start the stack: `docker-compose -p t7d-review -f docker-compose.dev.yml up -d --build`. +Run it in the dev VM: + +1. `direnv allow` (or `nix develop`) gives Python with Playwright and markdown, Node 22, gh and uv from `flake.nix`. +2. Install the host side of the Approve button once, in the main checkout: `scripts/review/approve-install.sh`. The dev VM keeps user units running after a reboot. +3. Start the preview of a checkout or worktree with `wt up`. It is defined in `compose.preview.yml`: + - `https://--t7d.review.t7d.dev`: the review site of that worktree. + - `https://pc---t7d.review.t7d.dev`: its papercuts relay (store: `.papercuts/` of the main checkout). + - `https://t7d.review.t7d.dev`: the current worktree. `wt switch ` moves it. + - `https://review.t7d.dev`: every running preview. +4. A new change: `wt new `, then `wt up` in the new worktree. `wt ls` lists them all. + +`docker-compose.dev.yml` and its `.env` are the older way and will be removed later. Tests: `python3 -m unittest discover -s scripts/review -p 'test_*.py'` and `node --test 'scripts/review/test_*.mjs'`. diff --git a/compose.preview.yml b/compose.preview.yml new file mode 100644 index 0000000..9323565 --- /dev/null +++ b/compose.preview.yml @@ -0,0 +1,66 @@ +# Preview of this worktree: `wt up` -> https://--t7d.review.t7d.dev +# (https://t7d.review.t7d.dev for the current one, see `wt switch`). +# Two services: the review site (live reload, rounds, Approve) and the papercuts relay at +# https://pc---t7d.review.t7d.dev. wt sets PREVIEW_HOST, WT_MAIN and WT_GIT_COMMON. +# Approve: the request goes to .review/approve/ of the main checkout; the host side +# (scripts/review/approve-install.sh, run once in the dev VM) publishes it. +x-preview: + name: t7d + port: 8000 + service: preview + +services: + preview: + build: + context: scripts/review + dockerfile: Dockerfile + image: t7d-review:local + restart: unless-stopped + command: [python3, /repo/scripts/review/devserver.py, --root, /repo, + --approve, /approve, --approve-status, /approve-status, + --host, 0.0.0.0, --port, "8000"] + environment: + PYTHONDONTWRITEBYTECODE: "1" + PAPERCUTS_URL: https://pc-${PREVIEW_HOST} + read_only: true + cap_drop: [ALL] + security_opt: [no-new-privileges:true] + mem_limit: 96m + tmpfs: + - /tmp:size=8m,mode=1777 + volumes: + - .:/repo:ro + - ${WT_GIT_COMMON}:${WT_GIT_COMMON}:ro + - ${WT_MAIN}/.review/approve:/approve:rw + - ${WT_MAIN}/.review/approve-status:/approve-status:ro + + papercuts: + build: ${HOME}/code/papercuts + restart: unless-stopped + environment: + PAPERCUTS_STORE: local + PAPERCUTS_DB: /data/papercuts.db + PAPERCUTS_HOST: 0.0.0.0 + PAPERCUTS_ORIGINS: https://${PREVIEW_HOST} + PAPERCUTS_REPOS: Tim-Conrad/Tim-Conrad.github.io + PAPERCUTS_PUBLIC_URL: https://pc-${PREVIEW_HOST} + read_only: true + cap_drop: [ALL] + security_opt: [no-new-privileges:true] + mem_limit: 128m + tmpfs: + - /tmp + volumes: + - ${WT_MAIN}/.papercuts:/data:rw + networks: [default, proxy] + labels: + traefik.enable: "true" + traefik.docker.network: "proxy" + traefik.http.routers.${COMPOSE_PROJECT_NAME}-pc.rule: "Host(`pc-${PREVIEW_HOST}`)" + traefik.http.routers.${COMPOSE_PROJECT_NAME}-pc.entrypoints: "websecure" + traefik.http.routers.${COMPOSE_PROJECT_NAME}-pc.tls: "true" + traefik.http.services.${COMPOSE_PROJECT_NAME}-pc.loadbalancer.server.port: "8000" + +networks: + proxy: + external: true diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..28a0c8b --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1794386569, + "narHash": "sha256-x9sADJvoVG0L6RejZB+/BB4YiGZFBZrfTlhF4uBq1tQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d4f25a3e562008648d45bcf2d70bcc7422cad84e", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..070bb38 --- /dev/null +++ b/flake.nix @@ -0,0 +1,31 @@ +{ + description = "t7d.dev (Tim-Conrad.github.io): dev shell"; + + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + outputs = + { nixpkgs, ... }: + let + system = "x86_64-linux"; + pkgs = nixpkgs.legacyPackages.${system}; + python = pkgs.python3.withPackages (ps: [ + ps.playwright # scripts/review checks + ps.markdown # scripts/gen-tools.py + ]); + in + { + # `direnv allow` (or `nix develop`). Preview: `wt up` (compose.preview.yml). + devShells.${system}.default = pkgs.mkShell { + packages = [ + python + pkgs.nodejs_22 # node --test, scripts/reels + pkgs.git + pkgs.gh # scripts/ship.sh, approve-host.sh + pkgs.uv + ]; + PLAYWRIGHT_BROWSERS_PATH = "${pkgs.playwright-driver.browsers}"; + PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS = "true"; + PYTHONDONTWRITEBYTECODE = "1"; + }; + }; +}