diff options
Diffstat (limited to 'CLAUDE.md')
| -rw-r--r-- | CLAUDE.md | 38 |
1 files changed, 28 insertions, 10 deletions
@@ -32,6 +32,7 @@ meshbay/ │ ├── meshbay-common/ # Shared crypto + protocol — python3-meshbay-common RPM (LGPL; rest AGPL) │ ├── meshbay-hub/ # Hub server (FastAPI + PostgreSQL) — meshbay-hub RPM │ ├── meshbay-node/ # Node daemon + local UI — meshbay-node RPM +│ ├── meshbay-cli/ # Command-line client for members (Python) — meshbay-cli package │ ├── meshbay-client/ # Desktop client (Electron) │ └── meshbay-android/ # Android client (WebView shell, Kotlin) — README.md ├── poc/ # POC spike scripts (reference, not production) @@ -59,7 +60,7 @@ source .venv/bin/activate # All dependencies are declared in the pyproject.toml files — a single pip install is enough pip install -e "packages/meshbay-common[dev]" -e "packages/meshbay-hub[dev]" \ - -e "packages/meshbay-node[dev]" + -e "packages/meshbay-node[dev]" -e "packages/meshbay-cli[dev]" ``` The key deps (aioquic, watchdog, fastapi, blake3, etc.) are in the `pyproject.toml` files @@ -99,7 +100,7 @@ in the right `pyproject.toml`. ### Package versions (SemVer) - Format: `MAJOR.MINOR.PATCH` - Pre-1.0: breaking changes bump MINOR, not MAJOR -- All three packages share the same version number (released together) +- All Python packages share the same version number (released together) ### Protocol versions (independent) @@ -143,11 +144,12 @@ AGPL-3.0-or-later.** The protocol layer is `meshbay-common` (`COPYING.LESSER` + `// SPDX-License-Identifier: LGPL-3.0-or-later`: `keyderive.js`, `crypto.js`, `playlist-crypto.js`, `transport.js`, `transport-*.js`; `meshbay-client/src/` `keyring.js`, `transcripts.js`, `argon2-wasm.js`; Android `keys/Kdf.kt`, -`Keyring.kt`, `Transcripts.kt`. A file without that line has its package's -licence: the AGPL (`LICENSE` at the root, copied into `meshbay-hub/` and -`meshbay-node/` because a wheel's `license-files` cannot reach outside its -package; into `static/licenses/` with the LGPL and GPL, so that every client -carries all three). +`Keyring.kt`, `Transcripts.kt`; `meshbay-cli`'s `client/keys.py` (first line +`# SPDX-License-Identifier: LGPL-3.0-or-later`). A file without that line has +its package's licence: the AGPL (`LICENSE` at the root, copied into +`meshbay-hub/`, `meshbay-node/` and `meshbay-cli/` because a wheel's +`license-files` cannot reach outside its package; into `static/licenses/` with +the LGPL and GPL, so that every client carries all three). - **An LGPL file depends only on LGPL files, permissive vendored code or the platform.** One import of an AGPL module and a client using the layer is under @@ -155,9 +157,9 @@ carries all three). `window.meshbay`, a `Secrets` store) is reached as an injected interface, never imported. `test_licensing.py` checks the closure. - **The same piece has the same licence on every platform.** A port is LGPL when - its original is (Keyring.kt ↔ keyring.js ↔ keyderive.js), and stays on the AGPL - side when its original is part of a shell (DeviceKey.kt ↔ the device key in - `main.js`). A new protocol file is added to the list here, to the README, and + its original is (Keyring.kt ↔ keyring.js ↔ keyderive.js ↔ the CLI's + `client/keys.py`), and stays on the AGPL side when its original is part of a + shell (DeviceKey.kt ↔ the device key in `main.js`). A new protocol file is added to the list here, to the README, and to `LGPL_FILES` in the test, with its SPDX line. The Android application adds a §7 permission for Google Play services (`meshbay-android/LICENSE-EXCEPTION.txt`). @@ -1152,6 +1154,22 @@ which pytest also runs when `ANDROID_HOME` is set (`test_android_shell.py`). | Downloads | `save/SaveSinks.kt`, `SaveNames.kt` | `OPENABLE` is `downloads.js`'s, compared by `test_android_downloads.py` | | Casting | `cast/CastRelay.kt`, `CastControl.kt`, `CastChannels.kt`, `CastService.kt`, `shell/ShellWebView.kt` | `MeshBayCast` in logcat says what the receiver and the relay did | +### Command-line client (`packages/meshbay-cli/`) + +| Need | File | Note | +|---|---|---| +| Actions and their parsers | `meshbay_cli/__main__.py` (`ACTIONS`), `commands/*.py` | §8.6. `test_every_action_is_run_here` refuses an action with no run in `test_cli_actions.py` | +| Exit codes | `meshbay_cli/errors.py` | **a contract for scripts**; the man page explains each (`manpage.EXIT_CODES`, tested) | +| Sign-in, renewal, the store | `client/account.py`, `client/store.py`, `client/hub.py` | renewal under the store's lock; the store key in the OS keyring, else a 0600 file | +| Passphrase keys, bundle opening | `client/keys.py` | **LGPL, parity-tested** with `keyderive.js` (`test_bundle_kdf_parity.py`) | +| Connection, handshake, identity, device linking | `client/session.py`, `client/groups.py`, `client/pool.py` | §5.2, §3.3 | +| Remote paths, listing, local names | `client/paths.py`, `client/tree.py`, `client/names.py` | `names.UPLOAD_NAME` is copied from the node's `SAFE_UPLOAD_NAME` | +| Downloads and uploads | `client/transfers.py`, `client/upload_plan.py` | §5.5; `upload_plan` is shared by `put` and the interactive mode | +| Interactive mode | `meshbay_cli/tui/` | Textual; names are drawn as text, never markup | +| Man page | `meshbay_cli/manpage.py` | generated from the parser at build time; `test_manpage.py` | +| What a frozen build must load | `meshbay_cli/selftest.py` | `MESHBAY_CLI_SELFTEST=1 meshbay-cli`, run by the Windows build | +| End to end against a real hub and node | `tests/test_e2e_local.py` | opt-in, `MESHBAY_CLI_E2E=1`; `MESHBAY_CLI_E2E_BIN` runs a packaged build instead | + ### Test harnesses that drive the real thing | Need | File | |