sibyl-memory-cli 0.3.13__tar.gz → 0.3.15__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.
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/PKG-INFO +1 -1
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/pyproject.toml +1 -1
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/src/sibyl_memory_cli/cli.py +141 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/src/sibyl_memory_cli.egg-info/PKG-INFO +1 -1
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/src/sibyl_memory_cli.egg-info/SOURCES.txt +2 -0
- sibyl_memory_cli-0.3.15/tests/test_memory_cmd_2026_06_16.py +55 -0
- sibyl_memory_cli-0.3.15/tests/test_status_stores_2026_06_11.py +70 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/README.md +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/setup.cfg +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/src/sibyl_memory_cli/__init__.py +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/src/sibyl_memory_cli/_aesthetic.py +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/src/sibyl_memory_cli/_banner.py +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/src/sibyl_memory_cli/migrate.py +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/src/sibyl_memory_cli/setup.py +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/src/sibyl_memory_cli.egg-info/dependency_links.txt +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/src/sibyl_memory_cli.egg-info/entry_points.txt +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/src/sibyl_memory_cli.egg-info/requires.txt +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/src/sibyl_memory_cli.egg-info/top_level.txt +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/tests/test_hermes_install_args.py +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/tests/test_init_perms_guard.py +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/tests/test_migrate.py +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/tests/test_migrate_adversarial.py +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/tests/test_migrate_force_2026_06_05.py +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/tests/test_orchestrator.py +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/tests/test_setup.py +0 -0
- {sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/tests/test_wiring_fix.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sibyl-memory-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.15
|
|
4
4
|
Summary: Command-line interface for the Sibyl Memory Plugin. `sibyl init` activates, `sibyl upgrade` runs the staker / subscription flow, `sibyl status` shows current tier and DB stats, `sibyl whoami` gives a one-line account summary, `sibyl devices` lists active devices and supports per-device revoke.
|
|
5
5
|
Author-email: "SIBYL, Sibyl Labs LLC" <sibyl@sibyllabs.org>
|
|
6
6
|
License: MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "sibyl-memory-cli"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.15"
|
|
8
8
|
description = "Command-line interface for the Sibyl Memory Plugin. `sibyl init` activates, `sibyl upgrade` runs the staker / subscription flow, `sibyl status` shows current tier and DB stats, `sibyl whoami` gives a one-line account summary, `sibyl devices` lists active devices and supports per-device revoke."
|
|
9
9
|
authors = [{ name = "SIBYL, Sibyl Labs LLC", email = "sibyl@sibyllabs.org" }]
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -516,6 +516,55 @@ def cmd_upgrade(args: argparse.Namespace) -> int:
|
|
|
516
516
|
|
|
517
517
|
# ---- `sibyl status` ----------------------------------------------------
|
|
518
518
|
|
|
519
|
+
def _discover_stores(primary_db: Path) -> list[dict[str, Any]]:
|
|
520
|
+
"""Enumerate every memory.db an agent on this machine might resolve.
|
|
521
|
+
|
|
522
|
+
Beta reports (VRTX 2026-06-11) showed split-brain storage: the SDK / CLI /
|
|
523
|
+
MCP default (``~/.sibyl-memory/memory.db``), the Hermes adapter
|
|
524
|
+
(``$HERMES_HOME/sibyl/memory.db``), per-profile DBs
|
|
525
|
+
(``$HERMES_HOME/sibyl/profiles/<p>/memory.db``), and an MCP
|
|
526
|
+
``SIBYL_MEMORY_DB`` override can each hold a disjoint set of memories, so a
|
|
527
|
+
user switching entry points sees memory "vanish". This surfaces all of
|
|
528
|
+
them in one place. Read-only: it never creates or moves anything (path
|
|
529
|
+
unification is a separate, migration-gated change).
|
|
530
|
+
|
|
531
|
+
Returns one dict per DISTINCT existing store, resolved + deduped:
|
|
532
|
+
``{"label", "path", "size"}``.
|
|
533
|
+
"""
|
|
534
|
+
candidates: list[tuple[str, Path]] = [("default (SDK/CLI/MCP)", primary_db)]
|
|
535
|
+
|
|
536
|
+
hermes_home_env = os.environ.get("HERMES_HOME")
|
|
537
|
+
hermes_home = Path(hermes_home_env).expanduser() if hermes_home_env else (Path.home() / ".hermes")
|
|
538
|
+
candidates.append(("hermes adapter", hermes_home / "sibyl" / "memory.db"))
|
|
539
|
+
profiles_dir = hermes_home / "sibyl" / "profiles"
|
|
540
|
+
if profiles_dir.is_dir():
|
|
541
|
+
for prof in sorted(profiles_dir.iterdir()):
|
|
542
|
+
db = prof / "memory.db"
|
|
543
|
+
if db.exists():
|
|
544
|
+
candidates.append((f"hermes profile · {prof.name}", db))
|
|
545
|
+
|
|
546
|
+
mcp_override = os.environ.get("SIBYL_MEMORY_DB")
|
|
547
|
+
if mcp_override:
|
|
548
|
+
candidates.append(("MCP SIBYL_MEMORY_DB", Path(mcp_override).expanduser()))
|
|
549
|
+
|
|
550
|
+
seen: set[str] = set()
|
|
551
|
+
stores: list[dict[str, Any]] = []
|
|
552
|
+
for label, path in candidates:
|
|
553
|
+
try:
|
|
554
|
+
resolved = str(path.resolve())
|
|
555
|
+
except OSError:
|
|
556
|
+
resolved = str(path)
|
|
557
|
+
if resolved in seen or not path.exists():
|
|
558
|
+
continue
|
|
559
|
+
seen.add(resolved)
|
|
560
|
+
try:
|
|
561
|
+
size = path.stat().st_size
|
|
562
|
+
except OSError:
|
|
563
|
+
size = 0
|
|
564
|
+
stores.append({"label": label, "path": str(path), "size": size})
|
|
565
|
+
return stores
|
|
566
|
+
|
|
567
|
+
|
|
519
568
|
def cmd_status(args: argparse.Namespace) -> int:
|
|
520
569
|
"""Show local + server-side state without modifying anything.
|
|
521
570
|
|
|
@@ -552,6 +601,27 @@ def cmd_status(args: argparse.Namespace) -> int:
|
|
|
552
601
|
else:
|
|
553
602
|
print(a.kv("DB path", f"{db_path} (not created)"))
|
|
554
603
|
|
|
604
|
+
# All resolvable stores on this machine (split-brain visibility floor,
|
|
605
|
+
# VRTX beta report 2026-06-11). Read-only: lists what exists, moves
|
|
606
|
+
# nothing. A divergence warning fires when more than one store holds data,
|
|
607
|
+
# because that is exactly when an agent "loses" memory by switching the
|
|
608
|
+
# entry point it reads from.
|
|
609
|
+
stores = _discover_stores(db_path)
|
|
610
|
+
if len(stores) > 1:
|
|
611
|
+
print()
|
|
612
|
+
print(a.eyebrow("memory stores"))
|
|
613
|
+
for s in stores:
|
|
614
|
+
mb = s["size"] / (1024 * 1024)
|
|
615
|
+
print(a.kv(s["label"], f"{s['path']} ({s['size']:,} bytes · {mb:.2f} MB)"))
|
|
616
|
+
with_data = [s for s in stores if s["size"] > 0]
|
|
617
|
+
if len(with_data) > 1:
|
|
618
|
+
print()
|
|
619
|
+
print(a.warn_line("Multiple memory stores hold data on this machine."))
|
|
620
|
+
print(a.dim(" Memory is NOT shared across these paths. An agent reads only the store"))
|
|
621
|
+
print(a.dim(" for its entry point (SDK/CLI vs Hermes vs profile vs MCP), so memory can"))
|
|
622
|
+
print(a.dim(" look 'missing' when you switch. Point every entry point at one path via"))
|
|
623
|
+
print(a.dim(" --db / SIBYL_MEMORY_DB, or back up and consolidate before relying on recall."))
|
|
624
|
+
|
|
555
625
|
tier_cache = Path(args.tier_cache).expanduser()
|
|
556
626
|
if tier_cache.exists():
|
|
557
627
|
cache = json.loads(tier_cache.read_text(encoding="utf-8"))
|
|
@@ -1144,6 +1214,22 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1144
1214
|
p_h = sub.add_parser("health", help="Run the provider self-check")
|
|
1145
1215
|
p_h.set_defaults(func=cmd_health)
|
|
1146
1216
|
|
|
1217
|
+
p_mem = sub.add_parser("memory", help="Read-only inspection of your memory store (list / search / recall)")
|
|
1218
|
+
mem_sub = p_mem.add_subparsers(dest="mem_cmd")
|
|
1219
|
+
p_ml = mem_sub.add_parser("list", help="List entities (optionally filtered by category)")
|
|
1220
|
+
p_ml.add_argument("category", nargs="?", default=None, help="Optional category to filter by")
|
|
1221
|
+
p_ml.add_argument("--limit", type=int, default=50, help="Max rows (default 50)")
|
|
1222
|
+
p_ml.set_defaults(func=cmd_memory)
|
|
1223
|
+
p_ms = mem_sub.add_parser("search", help="Full-text search across entities + state + reference + journal")
|
|
1224
|
+
p_ms.add_argument("query", help="Search query (matches stored text, not meaning)")
|
|
1225
|
+
p_ms.add_argument("--limit", type=int, default=20, help="Max hits (default 20)")
|
|
1226
|
+
p_ms.set_defaults(func=cmd_memory)
|
|
1227
|
+
p_mr = mem_sub.add_parser("recall", help="Recall one entity by category + name")
|
|
1228
|
+
p_mr.add_argument("category", help="Entity category")
|
|
1229
|
+
p_mr.add_argument("name", help="Entity name")
|
|
1230
|
+
p_mr.set_defaults(func=cmd_memory)
|
|
1231
|
+
p_mem.set_defaults(func=cmd_memory)
|
|
1232
|
+
|
|
1147
1233
|
p_update = sub.add_parser(
|
|
1148
1234
|
"update",
|
|
1149
1235
|
help="Check for newer sibyl-memory-* releases on PyPI (use --apply to upgrade)",
|
|
@@ -1214,6 +1300,61 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1214
1300
|
return p
|
|
1215
1301
|
|
|
1216
1302
|
|
|
1303
|
+
def cmd_memory(args: argparse.Namespace) -> int:
|
|
1304
|
+
"""Read-only inspection of the local memory store (PKG-4, VRTX/deadguy beta).
|
|
1305
|
+
|
|
1306
|
+
sibyl memory list [category] list entities
|
|
1307
|
+
sibyl memory search <query> full-text search across tiers
|
|
1308
|
+
sibyl memory recall <cat> <nm> recall one entity by category + name
|
|
1309
|
+
|
|
1310
|
+
Opens the resolved DB read-only via the SDK; never writes. Respects --db so
|
|
1311
|
+
you can inspect any split-brain store that `sibyl status` surfaces.
|
|
1312
|
+
"""
|
|
1313
|
+
from sibyl_memory_client import MemoryClient
|
|
1314
|
+
|
|
1315
|
+
db_path = Path(args.db).expanduser()
|
|
1316
|
+
print()
|
|
1317
|
+
if not db_path.exists():
|
|
1318
|
+
print(a.warn_line(f"No memory store at {db_path}."))
|
|
1319
|
+
print(a.dim(" Run `sibyl status` to see every store on this machine."))
|
|
1320
|
+
return 1
|
|
1321
|
+
client = MemoryClient.local(path=db_path)
|
|
1322
|
+
op = getattr(args, "mem_cmd", None)
|
|
1323
|
+
if op == "list":
|
|
1324
|
+
rows = client.list_entities(category=args.category, limit=args.limit)
|
|
1325
|
+
if not rows:
|
|
1326
|
+
print(a.dim("(no entities)"))
|
|
1327
|
+
return 0
|
|
1328
|
+
print(a.eyebrow(f"entities ({len(rows)})"))
|
|
1329
|
+
for r in rows:
|
|
1330
|
+
print(a.kv(f"{r['category']}/{r['name']}", r.get("status") or "-"))
|
|
1331
|
+
return 0
|
|
1332
|
+
if op == "search":
|
|
1333
|
+
hits = client.search(args.query, limit=args.limit)
|
|
1334
|
+
if not hits:
|
|
1335
|
+
print(a.dim(f"(no matches for {args.query!r})"))
|
|
1336
|
+
return 0
|
|
1337
|
+
print(a.eyebrow(f"matches ({len(hits)})"))
|
|
1338
|
+
for h in hits:
|
|
1339
|
+
snip = (h.get("snippet") or "").replace("\n", " ")[:100]
|
|
1340
|
+
print(a.kv(f"[{h.get('tier') or '-'}] {h.get('key') or '-'}", snip))
|
|
1341
|
+
return 0
|
|
1342
|
+
if op == "recall":
|
|
1343
|
+
try:
|
|
1344
|
+
ent = client.get_entity(args.category, args.name)
|
|
1345
|
+
except Exception as e:
|
|
1346
|
+
print(a.warn_line(str(e)))
|
|
1347
|
+
return 1
|
|
1348
|
+
print(a.eyebrow(f"{ent['category']}/{ent['name']}"))
|
|
1349
|
+
print(a.kv("status", ent.get("status") or "-"))
|
|
1350
|
+
print(a.kv("updated", ent.get("updated_at") or "-"))
|
|
1351
|
+
body = ent.get("body")
|
|
1352
|
+
print(body if isinstance(body, str) else json.dumps(body, indent=2, ensure_ascii=False))
|
|
1353
|
+
return 0
|
|
1354
|
+
print(a.warn_line("Usage: sibyl memory {list|search|recall} ..."))
|
|
1355
|
+
return 1
|
|
1356
|
+
|
|
1357
|
+
|
|
1217
1358
|
def main(argv: list[str] | None = None) -> int:
|
|
1218
1359
|
parser = build_parser()
|
|
1219
1360
|
args = parser.parse_args(argv)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sibyl-memory-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.15
|
|
4
4
|
Summary: Command-line interface for the Sibyl Memory Plugin. `sibyl init` activates, `sibyl upgrade` runs the staker / subscription flow, `sibyl status` shows current tier and DB stats, `sibyl whoami` gives a one-line account summary, `sibyl devices` lists active devices and supports per-device revoke.
|
|
5
5
|
Author-email: "SIBYL, Sibyl Labs LLC" <sibyl@sibyllabs.org>
|
|
6
6
|
License: MIT
|
{sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/src/sibyl_memory_cli.egg-info/SOURCES.txt
RENAMED
|
@@ -14,9 +14,11 @@ src/sibyl_memory_cli.egg-info/requires.txt
|
|
|
14
14
|
src/sibyl_memory_cli.egg-info/top_level.txt
|
|
15
15
|
tests/test_hermes_install_args.py
|
|
16
16
|
tests/test_init_perms_guard.py
|
|
17
|
+
tests/test_memory_cmd_2026_06_16.py
|
|
17
18
|
tests/test_migrate.py
|
|
18
19
|
tests/test_migrate_adversarial.py
|
|
19
20
|
tests/test_migrate_force_2026_06_05.py
|
|
20
21
|
tests/test_orchestrator.py
|
|
21
22
|
tests/test_setup.py
|
|
23
|
+
tests/test_status_stores_2026_06_11.py
|
|
22
24
|
tests/test_wiring_fix.py
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""PKG-4 (VRTX/deadguy beta): read-only `sibyl memory list/search/recall` CLI.
|
|
2
|
+
Lets a tester inspect what's actually stored without writing through an agent."""
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from sibyl_memory_client import MemoryClient
|
|
8
|
+
from sibyl_memory_cli import cli
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _store(tmp_path: Path) -> Path:
|
|
12
|
+
d = tmp_path / "memory.db"
|
|
13
|
+
c = MemoryClient.local(path=d)
|
|
14
|
+
c.set_entity("partner", "Blocktronics", {"stage": "active", "note": "token forensics suite"})
|
|
15
|
+
c.set_entity("partner", "Reppo", {"stage": "negotiation"})
|
|
16
|
+
return d
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_memory_list(tmp_path, capsys):
|
|
20
|
+
d = _store(tmp_path)
|
|
21
|
+
rc = cli.main(["--db", str(d), "memory", "list"])
|
|
22
|
+
out = capsys.readouterr().out
|
|
23
|
+
assert rc == 0
|
|
24
|
+
assert "Blocktronics" in out and "Reppo" in out
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_memory_list_category_filter(tmp_path, capsys):
|
|
28
|
+
d = _store(tmp_path)
|
|
29
|
+
rc = cli.main(["--db", str(d), "memory", "list", "partner", "--limit", "1"])
|
|
30
|
+
assert rc == 0
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_memory_search(tmp_path, capsys):
|
|
34
|
+
d = _store(tmp_path)
|
|
35
|
+
rc = cli.main(["--db", str(d), "memory", "search", "forensics"])
|
|
36
|
+
out = capsys.readouterr().out
|
|
37
|
+
assert rc == 0 and "Blocktronics" in out
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_memory_recall(tmp_path, capsys):
|
|
41
|
+
d = _store(tmp_path)
|
|
42
|
+
rc = cli.main(["--db", str(d), "memory", "recall", "partner", "Blocktronics"])
|
|
43
|
+
out = capsys.readouterr().out
|
|
44
|
+
assert rc == 0 and "forensics" in out
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_memory_recall_missing_returns_1(tmp_path):
|
|
48
|
+
d = _store(tmp_path)
|
|
49
|
+
rc = cli.main(["--db", str(d), "memory", "recall", "partner", "Nope"])
|
|
50
|
+
assert rc == 1
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_memory_no_store_returns_1(tmp_path):
|
|
54
|
+
rc = cli.main(["--db", str(tmp_path / "absent.db"), "memory", "list"])
|
|
55
|
+
assert rc == 1
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""PKG-2/3 regression: `sibyl status` discovers + lists every memory store and
|
|
2
|
+
warns on split-brain divergence (VRTX beta report 2026-06-11).
|
|
3
|
+
|
|
4
|
+
Read-only: discovery never creates or moves a DB.
|
|
5
|
+
"""
|
|
6
|
+
import os
|
|
7
|
+
import tempfile
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
11
|
+
|
|
12
|
+
from sibyl_memory_cli import cli
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.fixture
|
|
16
|
+
def sandbox(monkeypatch):
|
|
17
|
+
d = Path(tempfile.mkdtemp())
|
|
18
|
+
primary = d / ".sibyl-memory" / "memory.db"
|
|
19
|
+
primary.parent.mkdir(parents=True)
|
|
20
|
+
hermes = d / ".hermes"
|
|
21
|
+
(hermes / "sibyl").mkdir(parents=True)
|
|
22
|
+
monkeypatch.setenv("HERMES_HOME", str(hermes))
|
|
23
|
+
monkeypatch.delenv("SIBYL_MEMORY_DB", raising=False)
|
|
24
|
+
return d, primary, hermes
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_discovers_default_hermes_and_profiles(sandbox):
|
|
28
|
+
d, primary, hermes = sandbox
|
|
29
|
+
primary.write_bytes(b"x" * 100)
|
|
30
|
+
(hermes / "sibyl" / "memory.db").write_bytes(b"y" * 200)
|
|
31
|
+
prof = hermes / "sibyl" / "profiles" / "alpha"
|
|
32
|
+
prof.mkdir(parents=True)
|
|
33
|
+
(prof / "memory.db").write_bytes(b"z" * 50)
|
|
34
|
+
|
|
35
|
+
stores = cli._discover_stores(primary)
|
|
36
|
+
labels = {s["label"] for s in stores}
|
|
37
|
+
assert "default (SDK/CLI/MCP)" in labels
|
|
38
|
+
assert "hermes adapter" in labels
|
|
39
|
+
assert any(l.startswith("hermes profile") for l in labels)
|
|
40
|
+
assert {s["size"] for s in stores} == {100, 200, 50}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_skips_nonexistent_and_dedups(sandbox):
|
|
44
|
+
d, primary, hermes = sandbox
|
|
45
|
+
primary.write_bytes(b"x" * 10)
|
|
46
|
+
# hermes adapter db does not exist → excluded
|
|
47
|
+
stores = cli._discover_stores(primary)
|
|
48
|
+
assert [s["label"] for s in stores] == ["default (SDK/CLI/MCP)"]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_mcp_override_included(sandbox, monkeypatch):
|
|
52
|
+
d, primary, hermes = sandbox
|
|
53
|
+
primary.write_bytes(b"x" * 10)
|
|
54
|
+
shadow = d / "shadow.db"
|
|
55
|
+
shadow.write_bytes(b"s" * 5)
|
|
56
|
+
monkeypatch.setenv("SIBYL_MEMORY_DB", str(shadow))
|
|
57
|
+
stores = cli._discover_stores(primary)
|
|
58
|
+
assert any(s["label"] == "MCP SIBYL_MEMORY_DB" for s in stores)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_status_warns_on_divergence(sandbox, capsys):
|
|
62
|
+
d, primary, hermes = sandbox
|
|
63
|
+
primary.write_bytes(b"x" * 100)
|
|
64
|
+
(hermes / "sibyl" / "memory.db").write_bytes(b"y" * 200)
|
|
65
|
+
|
|
66
|
+
# Build the minimal args cmd_status reads. No credentials → early-return
|
|
67
|
+
# path, so drive discovery directly to assert the warning copy instead.
|
|
68
|
+
stores = cli._discover_stores(primary)
|
|
69
|
+
with_data = [s for s in stores if s["size"] > 0]
|
|
70
|
+
assert len(with_data) > 1 # divergence condition that triggers the warning
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/src/sibyl_memory_cli.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/src/sibyl_memory_cli.egg-info/requires.txt
RENAMED
|
File without changes
|
{sibyl_memory_cli-0.3.13 → sibyl_memory_cli-0.3.15}/src/sibyl_memory_cli.egg-info/top_level.txt
RENAMED
|
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
|