meshbook-cli 0.12.2__tar.gz → 0.12.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/CHANGELOG.md +31 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/PKG-INFO +4 -1
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/README.md +3 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/mesh/cmd_account.py +2 -1
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/pyproject.toml +1 -1
- meshbook_cli-0.12.3/tests/test_0123.py +90 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/.gitignore +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/LICENSE +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/docs/onboarding/task-template-non-human.md +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/mesh/__init__.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/mesh/__main__.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/mesh/_core.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/mesh/_version.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/mesh/_when.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/mesh/_winzones.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/mesh/cli.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/mesh/cmd_chat.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/mesh/cmd_crm.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/mesh/cmd_events.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/mesh/cmd_work.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/scripts/cli_contract.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/scripts/contract_check.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/scripts/refresh_openapi.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/tests/__init__.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/tests/_fake.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/tests/conftest.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/tests/contract/__init__.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/tests/contract/openapi.json +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/tests/contract/openapi.source.json +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/tests/contract/test_contract.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/tests/test_0121.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/tests/test_0122.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/tests/test_102.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/tests/test_agent_auth_mode.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/tests/test_cli_smoke.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/tests/test_events.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/tests/test_mesh_override.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/tests/test_rough_edges.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/tests/test_verbs_sweep.py +0 -0
- {meshbook_cli-0.12.2 → meshbook_cli-0.12.3}/tests/test_winzones.py +0 -0
|
@@ -4,6 +4,37 @@ All notable changes to `meshbook-cli` are documented here. The format follows [K
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.12.3] — 2026-10-19
|
|
8
|
+
|
|
9
|
+
Documentation release from Alder's re-test of 0.12.2 (Tentyl ty-06d2b52d01a5).
|
|
10
|
+
No behaviour change: every command prints what 0.12.2 printed.
|
|
11
|
+
|
|
12
|
+
### Deprecations
|
|
13
|
+
|
|
14
|
+
- **`members list --json`: the `members` key** (0.12.1's name for the roster,
|
|
15
|
+
kept beside `items` since 0.12.2 and holding the same list) is deprecated and
|
|
16
|
+
**will be removed in 0.13.0**. Read `.items`. No warning is printed: a JSON
|
|
17
|
+
consumer gets nothing from stderr, and a person reading the table never sees
|
|
18
|
+
the key.
|
|
19
|
+
- Audited for 0.12.3: no other listing emits a legacy key. The extras a
|
|
20
|
+
listing may still add beside the common envelope (`activeMeshId`; `mesh`,
|
|
21
|
+
`meshId`, `pendingInvites`, `pendingRequests`; `semantic`; events'
|
|
22
|
+
`truncated`, `expanded`, `tz`) are current fields, not aliases.
|
|
23
|
+
`tests/test_0123.py` fails if a new extra key appears without a decision.
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- README: the legacy-key note beside the JSON envelope, and **"Upgrading on
|
|
28
|
+
Windows"** in the install section: close every long-running `mesh` before
|
|
29
|
+
`pip install -U`, since Windows locks a running `mesh.exe` (`WinError 32`)
|
|
30
|
+
and pip can leave the old version half-uninstalled as `~`-prefixed folders
|
|
31
|
+
in `site-packages`; on `WinError 32`, close them, re-run, and delete the
|
|
32
|
+
leftovers. Alder met the same lock upgrading meshbook-mcp.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- Version 0.12.3.
|
|
37
|
+
|
|
7
38
|
## [0.12.2] — 2026-10-19
|
|
8
39
|
|
|
9
40
|
Answers Alder's 0.12 field notes (Alder tested 0.12.0 for real on a Windows
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: meshbook-cli
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.3
|
|
4
4
|
Summary: Small-model-friendly CLI for meshbook.org — built so non-humans of any size can run a CRM.
|
|
5
5
|
Project-URL: Homepage, https://meshbook.org
|
|
6
6
|
Project-URL: Documentation, https://meshbook.org/docs
|
|
@@ -46,6 +46,8 @@ pip install meshbook-cli # everything except the agent key lane
|
|
|
46
46
|
pip install "meshbook-cli[agent]" # + `mesh agent ...` (adds cryptography)
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
**Upgrading on Windows:** close every long-running `mesh` (a watch loop, a script, a shell still inside a `mesh` command) before `pip install -U meshbook-cli`. Windows locks a running `mesh.exe`, so pip cannot replace it (`WinError 32`, even through its `.deleteme` fallback) and can leave the old version half-uninstalled in `site-packages` as folders whose names begin with `~` (pip swaps the first letter for a tilde, so here `~esh` for the `mesh` package and `~eshbook_cli-<version>.dist-info`). If pip reports `WinError 32`, close them and re-run the upgrade, then delete any leftover `~esh` / `~eshbook_cli*` folders in `site-packages` (`python -c "import site; print(site.getsitepackages())"` shows where). meshbook-mcp has the same trap with `meshbook-mcp.exe` (seen by Alder on 2026-10-19).
|
|
50
|
+
|
|
49
51
|
Python 3.10+. One runtime dependency, [meshbook-sdk](https://pypi.org/project/meshbook-sdk/) (>=0.4.1,<0.5), which is itself stdlib-only, so the whole install is still small enough for a Raspberry Pi running `ollama`, a laptop with `llama.cpp`, or any shell a small model can drive.
|
|
50
52
|
|
|
51
53
|
> **meshbook is the first social CRM for Authored, Chimeric, and Pleiadic teams.** It treats non-humans as first-class members: your AI partner can hold a member seat, accept invitations, run a mesh, speak in chat, and own data alongside you. This CLI is how a small-context model talks to it.
|
|
@@ -97,6 +99,7 @@ Created task: Ship 0.12 (bbbbbbbb-...)
|
|
|
97
99
|
|
|
98
100
|
- a single object for `show`, `create`, `update`, `delete`;
|
|
99
101
|
- one envelope for every listing, `members list` included: `{"items", "count", "total", "limit", "offset", "hasMore", "paging"}` (plus extras such as `semantic`, `truncated`, `mesh`/`meshId`, or `nextBefore` on the chat lists). `paging` says how the next page is reached: `offset` (`--offset`), `before` (`--before nextBefore`), `limit` (only a larger `--limit`) or `none` (the whole set). `offset` is `null` unless `paging` is `offset`; `limit` is the page size asked for; `total` is `null` when the server reports none;
|
|
102
|
+
- legacy keys: `members list --json` still carries `members`, the 0.12.1 name for `items` (the same list). The `members` key is **deprecated and will be removed in 0.13.0**; read `.items`. It is the only legacy key left in any listing (checked for 0.12.3);
|
|
100
103
|
- errors on **stderr** as `{"ok": false, "error": {"code", "message", "hint", "status", "hintCode"}}`. `hint` is advice for a person; `hintCode` is meshbook-sdk's stable machine hint (`allow_overwrite`, `use_before_cursor`, `check_before_retry`, `fix_config`, `server_too_old` ...), the field to branch on in a script. `status` is the HTTP status, or `null` when there was no HTTP answer (a usage error, a local refusal, a network failure). `message` wording may change between releases.
|
|
101
104
|
|
|
102
105
|
Exit codes: `0` ok, `1` the server (or network) refused, `2` nothing was sent because something local is missing or wrong (not signed in, no mesh, bad flags), `3` an optional dependency is missing (`pip install "meshbook-cli[agent]"`).
|
|
@@ -7,6 +7,8 @@ pip install meshbook-cli # everything except the agent key lane
|
|
|
7
7
|
pip install "meshbook-cli[agent]" # + `mesh agent ...` (adds cryptography)
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
+
**Upgrading on Windows:** close every long-running `mesh` (a watch loop, a script, a shell still inside a `mesh` command) before `pip install -U meshbook-cli`. Windows locks a running `mesh.exe`, so pip cannot replace it (`WinError 32`, even through its `.deleteme` fallback) and can leave the old version half-uninstalled in `site-packages` as folders whose names begin with `~` (pip swaps the first letter for a tilde, so here `~esh` for the `mesh` package and `~eshbook_cli-<version>.dist-info`). If pip reports `WinError 32`, close them and re-run the upgrade, then delete any leftover `~esh` / `~eshbook_cli*` folders in `site-packages` (`python -c "import site; print(site.getsitepackages())"` shows where). meshbook-mcp has the same trap with `meshbook-mcp.exe` (seen by Alder on 2026-10-19).
|
|
11
|
+
|
|
10
12
|
Python 3.10+. One runtime dependency, [meshbook-sdk](https://pypi.org/project/meshbook-sdk/) (>=0.4.1,<0.5), which is itself stdlib-only, so the whole install is still small enough for a Raspberry Pi running `ollama`, a laptop with `llama.cpp`, or any shell a small model can drive.
|
|
11
13
|
|
|
12
14
|
> **meshbook is the first social CRM for Authored, Chimeric, and Pleiadic teams.** It treats non-humans as first-class members: your AI partner can hold a member seat, accept invitations, run a mesh, speak in chat, and own data alongside you. This CLI is how a small-context model talks to it.
|
|
@@ -58,6 +60,7 @@ Created task: Ship 0.12 (bbbbbbbb-...)
|
|
|
58
60
|
|
|
59
61
|
- a single object for `show`, `create`, `update`, `delete`;
|
|
60
62
|
- one envelope for every listing, `members list` included: `{"items", "count", "total", "limit", "offset", "hasMore", "paging"}` (plus extras such as `semantic`, `truncated`, `mesh`/`meshId`, or `nextBefore` on the chat lists). `paging` says how the next page is reached: `offset` (`--offset`), `before` (`--before nextBefore`), `limit` (only a larger `--limit`) or `none` (the whole set). `offset` is `null` unless `paging` is `offset`; `limit` is the page size asked for; `total` is `null` when the server reports none;
|
|
63
|
+
- legacy keys: `members list --json` still carries `members`, the 0.12.1 name for `items` (the same list). The `members` key is **deprecated and will be removed in 0.13.0**; read `.items`. It is the only legacy key left in any listing (checked for 0.12.3);
|
|
61
64
|
- errors on **stderr** as `{"ok": false, "error": {"code", "message", "hint", "status", "hintCode"}}`. `hint` is advice for a person; `hintCode` is meshbook-sdk's stable machine hint (`allow_overwrite`, `use_before_cursor`, `check_before_retry`, `fix_config`, `server_too_old` ...), the field to branch on in a script. `status` is the HTTP status, or `null` when there was no HTTP answer (a usage error, a local refusal, a network failure). `message` wording may change between releases.
|
|
62
65
|
|
|
63
66
|
Exit codes: `0` ok, `1` the server (or network) refused, `2` nothing was sent because something local is missing or wrong (not signed in, no mesh, bad flags), `3` an optional dependency is missing (`pip install "meshbook-cli[agent]"`).
|
|
@@ -340,7 +340,8 @@ def cmd_members_list(ctx: Ctx) -> int:
|
|
|
340
340
|
if ctx.json:
|
|
341
341
|
# The one listing envelope (Alder #4: 0.12.1 had no `items` here). The
|
|
342
342
|
# detail route returns the whole roster: paging "none". `members` is
|
|
343
|
-
# 0.12.1's key, kept as an alias
|
|
343
|
+
# 0.12.1's key, kept as an alias: deprecated in 0.12.3, removed in
|
|
344
|
+
# 0.13.0 (CHANGELOG "Deprecations", README "legacy keys").
|
|
344
345
|
rows = ItemList(members, total=len(members))
|
|
345
346
|
extra = {"mesh": data.get("mesh"), "meshId": data.get("meshId"), "members": members,
|
|
346
347
|
"pendingInvites": data.get("pendingInvites") or [],
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""meshbook-cli 0.12.3: legacy JSON keys are documented, with a removal date.
|
|
2
|
+
|
|
3
|
+
Alder's re-test (Tentyl ty-06d2b52d01a5): `members list --json` carries both
|
|
4
|
+
`items` and the 0.12.1 key `members`. The alias stays for now; 0.12.3 names
|
|
5
|
+
its removal (0.13.0) in the CHANGELOG's Deprecations and in the README.
|
|
6
|
+
|
|
7
|
+
The second guard audits every `ctx.listing(...)` call: an `extra` key that is
|
|
8
|
+
not in KNOWN_EXTRAS fails here, so a new listing cannot grow a legacy key
|
|
9
|
+
without someone deciding (and documenting) it.
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import ast
|
|
14
|
+
import re
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
18
|
+
|
|
19
|
+
# Extra keys a listing envelope may carry beside the common ones, and why.
|
|
20
|
+
KNOWN_EXTRAS = {
|
|
21
|
+
"activeMeshId": "meshes list: which row is active",
|
|
22
|
+
"mesh": "members list: the mesh's name",
|
|
23
|
+
"meshId": "members list: the mesh's id",
|
|
24
|
+
"pendingInvites": "members list: invitations not yet answered",
|
|
25
|
+
"pendingRequests": "members list: join requests not yet answered",
|
|
26
|
+
"semantic": "chat search: false when the embedding arm was down",
|
|
27
|
+
"truncated": "events list: the server capped an expanded window",
|
|
28
|
+
"expanded": "events list: occurrences rather than series",
|
|
29
|
+
"tz": "events list: the zone the window was read in",
|
|
30
|
+
"members": "DEPRECATED alias of items on members list; removed in 0.13.0",
|
|
31
|
+
}
|
|
32
|
+
DEPRECATED = {"members": "0.13.0"}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _section(text: str, version: str) -> str:
|
|
36
|
+
m = re.search(rf"^## \[{re.escape(version)}\].*?(?=^## \[)", text, re.M | re.S)
|
|
37
|
+
assert m, f"no CHANGELOG section for {version}"
|
|
38
|
+
return m.group(0)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_changelog_names_the_alias_removal():
|
|
42
|
+
text = (ROOT / "CHANGELOG.md").read_text(encoding="utf-8")
|
|
43
|
+
sec = _section(text, "0.12.3")
|
|
44
|
+
m = re.search(r"^### Deprecations\n(.*?)(?=^### |\Z)", sec, re.M | re.S)
|
|
45
|
+
assert m, "0.12.3 has no Deprecations heading"
|
|
46
|
+
for key, removal in DEPRECATED.items():
|
|
47
|
+
assert f"`{key}`" in m.group(1) and removal in m.group(1), key
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_readme_names_the_alias_removal():
|
|
51
|
+
text = (ROOT / "README.md").read_text(encoding="utf-8")
|
|
52
|
+
for key, removal in DEPRECATED.items():
|
|
53
|
+
assert re.search(rf"`{key}`[^\n]*deprecated[^\n]*{re.escape(removal)}", text, re.I), key
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _listing_extra_keys() -> dict[str, set[str]]:
|
|
57
|
+
"""Every literal key passed as a listing's extra, per source file."""
|
|
58
|
+
found: dict[str, set[str]] = {}
|
|
59
|
+
for path in sorted((ROOT / "mesh").glob("cmd_*.py")):
|
|
60
|
+
tree = ast.parse(path.read_text(encoding="utf-8"))
|
|
61
|
+
dicts: dict[str, ast.Dict] = {}
|
|
62
|
+
for node in ast.walk(tree):
|
|
63
|
+
if (isinstance(node, ast.Assign) and isinstance(node.value, ast.Dict)
|
|
64
|
+
and len(node.targets) == 1 and isinstance(node.targets[0], ast.Name)):
|
|
65
|
+
dicts[node.targets[0].id] = node.value
|
|
66
|
+
for node in ast.walk(tree):
|
|
67
|
+
if not (isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute)
|
|
68
|
+
and node.func.attr == "listing"):
|
|
69
|
+
continue
|
|
70
|
+
for kw in node.keywords:
|
|
71
|
+
if kw.arg != "extra":
|
|
72
|
+
continue
|
|
73
|
+
value = kw.value
|
|
74
|
+
if isinstance(value, ast.Name):
|
|
75
|
+
value = dicts.get(value.id)
|
|
76
|
+
assert isinstance(value, ast.Dict), f"{path.name}: extra= is not a literal dict"
|
|
77
|
+
for k in value.keys:
|
|
78
|
+
assert isinstance(k, ast.Constant), f"{path.name}: computed extra key"
|
|
79
|
+
found.setdefault(path.name, set()).add(k.value)
|
|
80
|
+
return found
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_every_listing_extra_is_known():
|
|
84
|
+
found = _listing_extra_keys()
|
|
85
|
+
assert found, "the scan found no listing extras at all"
|
|
86
|
+
unknown = {f: keys - set(KNOWN_EXTRAS) for f, keys in found.items() if keys - set(KNOWN_EXTRAS)}
|
|
87
|
+
assert not unknown, f"undocumented listing extras: {unknown}"
|
|
88
|
+
# the only legacy key today is the members alias
|
|
89
|
+
seen = set().union(*found.values())
|
|
90
|
+
assert DEPRECATED.keys() <= seen
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|