The machine you develop on stops being written into the repo
Every device address, login, key path, password and local venv path in the .claude/ skills moves to dev.env at the repo root: gitignored, with a tracked dev.env.example showing the shape. The skills now name $DEV_* keys and say to read dev.env first, so they still run -- against whoever's hardware. Two of the values were not secrets so much as a wrong assumption. The device paths under that home directory are now $HOME-relative in run_instrumented.sh, instrument.py and drive_console.py, and the deploy docs point at $DEPLOY_USER and $KEY_PATH, which those scripts already parameterised. Hardcoding a home directory was only ever correct for one machine. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
4d8ba0fc5e
commit
892aefa11b
12 files changed
+83
-28
No files matched your search
@@ -34,8 +34,11 @@ the commonest answer to "please add this one".
|
||||
|
||||
1. **Classify the emoji.** Run, from the repo root:
|
||||
|
||||
```
|
||||
$DEV_VENV_PYTHON .claude\skills\add-narrow-emoji\classify.py <emoji>
|
||||
The interpreter below is `$DEV_VENV_PYTHON` from `dev.env` at the repo root (gitignored;
|
||||
`dev.env.example` shows the shape) — read it first.
|
||||
|
||||
```
|
||||
$DEV_VENV_PYTHON .claude/skills/add-narrow-emoji/classify.py <emoji>
|
||||
```
|
||||
|
||||
It prints the codepoints, how each authority measures it now (`Rich now`, `pt now`)
|
||||
|
||||
@@ -15,9 +15,12 @@ stays exactly where it was, so the file's length never changes.
|
||||
|
||||
## Run
|
||||
|
||||
The interpreter below is `$DEV_VENV_PYTHON` from `dev.env` at the repo root (gitignored;
|
||||
`dev.env.example` shows the shape) — read it first.
|
||||
|
||||
```
|
||||
$DEV_VENV_PYTHON .claude\skills\fix-ans-nulls\denul.py --dry-run --width 71 meshterm/assets/splash/logo.71.ans
|
||||
$DEV_VENV_PYTHON .claude\skills\fix-ans-nulls\denul.py --width 71 meshterm/assets/splash/logo.71.ans
|
||||
$DEV_VENV_PYTHON .claude/skills/fix-ans-nulls/denul.py --dry-run --width 71 meshterm/assets/splash/logo.71.ans
|
||||
$DEV_VENV_PYTHON .claude/skills/fix-ans-nulls/denul.py --width 71 meshterm/assets/splash/logo.71.ans
|
||||
```
|
||||
|
||||
- Always `--dry-run` first and read the counts.
|
||||
|
||||
@@ -14,18 +14,23 @@ on came from the real app on `/dev/tty1`.
|
||||
|
||||
## Reaching the device
|
||||
|
||||
`ssh -i $DEV_PICOCALC_SSH_KEY $DEV_PICOCALC_USER@$DEV_PICOCALC_HOST` (key installed; `scp` with the same flags
|
||||
pushes files byte-exact). Password fallback: `plink -batch -pw $DEV_PICOCALC_PASSWORD`. `sudo` needs the
|
||||
password piped: `echo $DEV_PICOCALC_PASSWORD | sudo -S …`.
|
||||
The address, login, key and password are **not in this file**. Read `dev.env` at the
|
||||
repo root first (gitignored; `dev.env.example` shows the shape) — the `$DEV_*` names
|
||||
below are its keys, and everything here is written to be run with them substituted.
|
||||
|
||||
The repo lives at `$HOME/MeshTerm`, venv at `.venv`. Push changed modules with `scp`
|
||||
`ssh -i $DEV_PICOCALC_SSH_KEY $DEV_PICOCALC_USER@$DEV_PICOCALC_HOST` (key installed;
|
||||
`scp` with the same flags pushes files byte-exact). Password fallback:
|
||||
`plink -batch -pw "$DEV_PICOCALC_PASSWORD"`. `sudo` needs the password piped:
|
||||
`echo "$DEV_PICOCALC_PASSWORD" | sudo -S …`.
|
||||
|
||||
The repo lives at `$DEV_PICOCALC_REPO`, venv at `.venv`. Push changed modules with `scp`
|
||||
straight into the tree — no reinstall, it is a `pip install -e .`.
|
||||
|
||||
**One-time**: reading the console back needs the `tty` group. Busybox's `addgroup $DEV_PICOCALC_USER tty`
|
||||
misparses; edit `/etc/group` instead:
|
||||
misparses; edit `/etc/group` instead (the trailing name is the deploy user):
|
||||
|
||||
```sh
|
||||
echo $DEV_PICOCALC_PASSWORD | sudo -S sed -i 's/^tty:\(.*\):\(.*\)$/tty:\1:\2,$DEV_PICOCALC_USER/' /etc/group
|
||||
echo "$DEV_PICOCALC_PASSWORD" | sudo -S sed -i 's/^tty:\(.*\):\(.*\)$/tty:\1:\2,'"$DEV_PICOCALC_USER"'/' /etc/group
|
||||
```
|
||||
|
||||
Re-open the SSH session for it to take effect. Verify: `dd if=/dev/vcs1 bs=1378 count=1 | wc -c`
|
||||
@@ -34,9 +39,9 @@ should print `1378` (53×26).
|
||||
## Running a tour
|
||||
|
||||
```sh
|
||||
scp -i $DEV_PICOCALC_SSH_KEY scripts/drive_console.py tours/nav_all.txt $DEV_PICOCALC_USER@…:$HOME/MeshTerm/
|
||||
ssh -i … $DEV_PICOCALC_USER@… 'cd $HOME/MeshTerm && .venv/bin/python drive_console.py \
|
||||
--script nav_all.txt --boot-wait 20 --shots $HOME/tmp/shots'
|
||||
scp -i $DEV_PICOCALC_SSH_KEY scripts/drive_console.py tours/nav_all.txt "$DEV_PICOCALC_USER@$DEV_PICOCALC_HOST:$DEV_PICOCALC_REPO/"
|
||||
ssh -i $DEV_PICOCALC_SSH_KEY "$DEV_PICOCALC_USER@$DEV_PICOCALC_HOST" "cd $DEV_PICOCALC_REPO && .venv/bin/python drive_console.py \
|
||||
--script nav_all.txt --boot-wait 20 --shots ~/tmp/shots"
|
||||
```
|
||||
|
||||
`drive_console.py` forks a pty sized to the panel, runs MeshTerm inside it, mirrors every
|
||||
@@ -106,12 +111,12 @@ When a page is slow and you need to know *which stage*, run the app under `instr
|
||||
instead of the binary:
|
||||
|
||||
```sh
|
||||
ssh … 'cd $HOME/MeshTerm && .venv/bin/python drive_console.py --script nav_all.txt \
|
||||
--exe $HOME/MeshTerm/run_instrumented.sh --boot-wait 20'
|
||||
ssh … "cd $DEV_PICOCALC_REPO && .venv/bin/python drive_console.py --script nav_all.txt \
|
||||
--exe $DEV_PICOCALC_REPO/run_instrumented.sh --boot-wait 20"
|
||||
```
|
||||
|
||||
where `run_instrumented.sh` is a two-line wrapper `exec .venv/bin/python instrument.py "$@"`.
|
||||
It appends a CSV row per repaint to `$HOME/tmp/keytrace.csv`: handle, header, compose,
|
||||
It appends a CSV row per repaint to `~/tmp/keytrace.csv` on the device: handle, header, compose,
|
||||
dialog, parse, paint, total, and the `render_to_ansi` call count. Rows tagged `~tick` are
|
||||
idle repaints — what the app burns doing nothing.
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ def main():
|
||||
ap.add_argument("--mock", action="store_true")
|
||||
ap.add_argument("--boot-wait", type=float, default=12.0)
|
||||
ap.add_argument("--out", default="")
|
||||
ap.add_argument("--exe", default="$HOME/MeshTerm/.venv/bin/meshterm")
|
||||
ap.add_argument("--exe", default=os.path.expanduser("~/MeshTerm/.venv/bin/meshterm"))
|
||||
ap.add_argument("--quiet-ms", type=float, default=QUIET_S * 1000,
|
||||
help="silence that ends a keystroke; raise it to time screen opens")
|
||||
ap.add_argument("--tee", default="", help="also copy the app's output to this file")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Run the real MeshTerm with per-keystroke stage timing, logged to a CSV.
|
||||
|
||||
Wraps the stages a keystroke passes through and appends one row per repaint to
|
||||
$MESHTERM_TRACE (default $HOME/tmp/keytrace.csv):
|
||||
$MESHTERM_TRACE (default ~/tmp/keytrace.csv):
|
||||
|
||||
t, screen, action, dispatch_ms, handle_ms, header_ms, compose_ms, dialog_ms,
|
||||
parse_ms, render_ms, flush_ms, total_ms, out_bytes, rta_calls, rta_ms
|
||||
@@ -19,7 +19,7 @@ import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
TRACE = os.environ.get("MESHTERM_TRACE", "$HOME/tmp/keytrace.csv")
|
||||
TRACE = os.environ.get("MESHTERM_TRACE") or os.path.expanduser("~/tmp/keytrace.csv")
|
||||
|
||||
_acc: dict[str, float] = {}
|
||||
_rows: list[str] = []
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#!/bin/sh
|
||||
# Hand this to drive_console.py as --exe to get a per-repaint stage breakdown.
|
||||
# It runs MeshTerm through instrument.py, which appends CSV rows to
|
||||
# $MESHTERM_TRACE (default $HOME/tmp/keytrace.csv).
|
||||
cd $HOME/MeshTerm
|
||||
exec $HOME/MeshTerm/.venv/bin/python $HOME/MeshTerm/instrument.py "$@"
|
||||
# $MESHTERM_TRACE (default ~/tmp/keytrace.csv).
|
||||
#
|
||||
# The checkout is $MESHTERM_REPO, or ~/MeshTerm -- never a hardcoded /home/<someone>,
|
||||
# since this runs as whatever user the device deployed under.
|
||||
REPO="${MESHTERM_REPO:-$HOME/MeshTerm}"
|
||||
cd "$REPO" || exit 1
|
||||
exec "$REPO/.venv/bin/python" "$REPO/instrument.py" "$@"
|
||||
@@ -13,9 +13,12 @@ carrying the simulator's fingerprints and nothing else.
|
||||
|
||||
## Run
|
||||
|
||||
The interpreter below is `$DEV_VENV_PYTHON` from `dev.env` at the repo root (gitignored;
|
||||
`dev.env.example` shows the shape) — read it first.
|
||||
|
||||
```
|
||||
$DEV_VENV_PYTHON .claude\skills\purge-test-data\purge.py --dry-run
|
||||
$DEV_VENV_PYTHON .claude\skills\purge-test-data\purge.py
|
||||
$DEV_VENV_PYTHON .claude/skills/purge-test-data/purge.py --dry-run
|
||||
$DEV_VENV_PYTHON .claude/skills/purge-test-data/purge.py
|
||||
```
|
||||
|
||||
- Always `--dry-run` first and sanity-check the counts (real-session tables
|
||||
|
||||
@@ -8,13 +8,16 @@ model: haiku
|
||||
|
||||
## Launch
|
||||
|
||||
- Machine-specific values (this venv, the BLE companions below) live in `dev.env` at
|
||||
the repo root — gitignored, with `dev.env.example` showing the shape. Read it first;
|
||||
the `$DEV_*` names here are its keys.
|
||||
- Venv interpreter: `$DEV_VENV_PYTHON`
|
||||
- Run the app as a module: `python -m meshterm …` (no install step needed).
|
||||
- `--mock` swaps in the `MockDevice` simulator (four fake nodes streaming
|
||||
adverts/telemetry, packets within a second) — no hardware required. It still
|
||||
writes to the **real default database**, so expect run ids / totals to grow.
|
||||
- Real hardware is available too: two BLE MeshCore companions
|
||||
(`$DEV_BLE_COMPANION_PAIRED` is PIN-protected, `$DEV_BLE_COMPANION_OPEN` is open).
|
||||
- Real hardware is available too: two BLE MeshCore companions —
|
||||
`$DEV_BLE_COMPANION_PAIRED` is PIN-protected, `$DEV_BLE_COMPANION_OPEN` is open.
|
||||
|
||||
## Surfaces
|
||||
|
||||
|
||||
@@ -22,6 +22,10 @@ venv/
|
||||
*.db
|
||||
output/
|
||||
|
||||
# Developer environment: the machine-specific half of the .claude/ skills (device
|
||||
# addresses, logins, the local venv path). dev.env.example is tracked and shows the shape.
|
||||
dev.env
|
||||
|
||||
# Built radio firmware (scripts/xiao-radio/build-firmware.sh writes it here)
|
||||
scripts/xiao-radio/*.uf2
|
||||
scripts/xiao-radio/_meshcore-build/
|
||||
@@ -0,0 +1,28 @@
|
||||
# MeshTerm developer environment — the machine-specific half of the .claude/ skills.
|
||||
#
|
||||
# Copy to `dev.env` (gitignored) and fill in your own values. Nothing in here is read by
|
||||
# the app: `meshterm` is configured by `config.toml` and its own `MESHTERM_*` variables.
|
||||
# These are only for driving *your* hardware from a dev session, so every name is
|
||||
# `DEV_`-prefixed and cannot collide with the app's.
|
||||
#
|
||||
# set -a; . ./dev.env; set +a # sh/bash
|
||||
# Get-Content dev.env | ... # or just read the values; nothing sources it for you
|
||||
|
||||
# --- this workstation ---------------------------------------------------------------
|
||||
# Full path to the venv interpreter, so a skill can run the app without an install step.
|
||||
DEV_VENV_PYTHON=/path/to/MeshTerm/.venv/bin/python
|
||||
|
||||
# --- the PicoCalc / Luckfox Lyra profiling device -----------------------------------
|
||||
# Reachable over the LAN; see the `profile-picocalc` skill for what is done with it.
|
||||
DEV_PICOCALC_HOST=192.0.2.10
|
||||
DEV_PICOCALC_USER=youruser
|
||||
DEV_PICOCALC_SSH_KEY=~/.ssh/your_key_ed25519
|
||||
# Fallback only — key auth is installed. Rotate this if it ever reaches a shared machine.
|
||||
DEV_PICOCALC_PASSWORD=changeme
|
||||
# Where the repo is checked out on the device (a `pip install -e .` tree).
|
||||
DEV_PICOCALC_REPO=/home/youruser/MeshTerm
|
||||
|
||||
# --- BLE test companions ------------------------------------------------------------
|
||||
# Two MeshCore companions to verify against: one paired/PIN-protected, one open.
|
||||
DEV_BLE_COMPANION_PAIRED=MeshCore-Example
|
||||
DEV_BLE_COMPANION_OPEN=Example-Open
|
||||
+3
-1
@@ -32,7 +32,9 @@ sh calculinux-setup.sh
|
||||
|
||||
Two prerequisites the setup script checks for but cannot embed:
|
||||
|
||||
- **Deploy key** — place the read-only GitHub deploy key at `$HOME/.ssh/id_ed25519`
|
||||
- **Deploy key** — place the read-only GitHub deploy key at
|
||||
`/home/$DEPLOY_USER/.ssh/id_ed25519` (`DEPLOY_USER` defaults to `meshterm`; `KEY_PATH`
|
||||
overrides the location outright)
|
||||
(mode 600) before running; the clone uses it over SSH.
|
||||
- **Wi-Fi credentials** — the kick only nudges a network iwd already knows. Either connect
|
||||
once by hand (`iwctl station wlan0 connect <SSID>`) or export `WIFI_SSID` and `WIFI_PSK`
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
# rounded frame corners + the list cursor the bare console can't draw).
|
||||
#
|
||||
# Two prerequisites this script cannot safely embed and will check for / guide you through:
|
||||
# * the read-only deploy key at $HOME/.ssh/id_ed25519 (never commit a private key);
|
||||
# * the read-only deploy key at $KEY_PATH (never commit a private key);
|
||||
# * Wi-Fi credentials known to iwd. The kick only nudges an ALREADY-known network. Either
|
||||
# provision it once by hand (`iwctl station wlan0 connect <SSID>`), or export
|
||||
# WIFI_SSID and WIFI_PSK before running and this script writes the iwd config for you.
|
||||
|
||||
Reference in new issue
Block a user