compartment 3.1__tar.gz → 3.2__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.
Files changed (72) hide show
  1. {compartment-3.1 → compartment-3.2}/PKG-INFO +1 -1
  2. {compartment-3.1 → compartment-3.2}/pyproject.toml +1 -1
  3. {compartment-3.1 → compartment-3.2}/src/compartment/__init__.py +1 -1
  4. {compartment-3.1 → compartment-3.2}/src/compartment/cli.py +114 -0
  5. {compartment-3.1 → compartment-3.2}/src/compartment/menubar.py +22 -0
  6. {compartment-3.1 → compartment-3.2}/src/compartment/systray.py +13 -1
  7. {compartment-3.1 → compartment-3.2}/src/compartment.egg-info/PKG-INFO +1 -1
  8. {compartment-3.1 → compartment-3.2}/README.md +0 -0
  9. {compartment-3.1 → compartment-3.2}/setup.cfg +0 -0
  10. {compartment-3.1 → compartment-3.2}/src/compartment/acl.py +0 -0
  11. {compartment-3.1 → compartment-3.2}/src/compartment/audit.py +0 -0
  12. {compartment-3.1 → compartment-3.2}/src/compartment/bench.py +0 -0
  13. {compartment-3.1 → compartment-3.2}/src/compartment/claude_hooks.py +0 -0
  14. {compartment-3.1 → compartment-3.2}/src/compartment/claude_memory.py +0 -0
  15. {compartment-3.1 → compartment-3.2}/src/compartment/crypto.py +0 -0
  16. {compartment-3.1 → compartment-3.2}/src/compartment/dash.py +0 -0
  17. {compartment-3.1 → compartment-3.2}/src/compartment/data/hermes-plugin/__init__.py +0 -0
  18. {compartment-3.1 → compartment-3.2}/src/compartment/data/hermes-plugin/plugin.yaml +0 -0
  19. {compartment-3.1 → compartment-3.2}/src/compartment/data/menubar.png +0 -0
  20. {compartment-3.1 → compartment-3.2}/src/compartment/data/menubar@2x.png +0 -0
  21. {compartment-3.1 → compartment-3.2}/src/compartment/data/starter.mpack +0 -0
  22. {compartment-3.1 → compartment-3.2}/src/compartment/data/tray.ico +0 -0
  23. {compartment-3.1 → compartment-3.2}/src/compartment/embed.py +0 -0
  24. {compartment-3.1 → compartment-3.2}/src/compartment/home.py +0 -0
  25. {compartment-3.1 → compartment-3.2}/src/compartment/longmemeval.py +0 -0
  26. {compartment-3.1 → compartment-3.2}/src/compartment/models/bge-small-en-v1.5-int8/model_quantized.onnx +0 -0
  27. {compartment-3.1 → compartment-3.2}/src/compartment/models/bge-small-en-v1.5-int8/tokenizer.json +0 -0
  28. {compartment-3.1 → compartment-3.2}/src/compartment/offline_guard.py +0 -0
  29. {compartment-3.1 → compartment-3.2}/src/compartment/packs.py +0 -0
  30. {compartment-3.1 → compartment-3.2}/src/compartment/platforms.py +0 -0
  31. {compartment-3.1 → compartment-3.2}/src/compartment/salience.py +0 -0
  32. {compartment-3.1 → compartment-3.2}/src/compartment/selftest.py +0 -0
  33. {compartment-3.1 → compartment-3.2}/src/compartment/server.py +0 -0
  34. {compartment-3.1 → compartment-3.2}/src/compartment/session.py +0 -0
  35. {compartment-3.1 → compartment-3.2}/src/compartment/store.py +0 -0
  36. {compartment-3.1 → compartment-3.2}/src/compartment/vault.py +0 -0
  37. {compartment-3.1 → compartment-3.2}/src/compartment/vaultfile.py +0 -0
  38. {compartment-3.1 → compartment-3.2}/src/compartment/vindex.py +0 -0
  39. {compartment-3.1 → compartment-3.2}/src/compartment/wire.py +0 -0
  40. {compartment-3.1 → compartment-3.2}/src/compartment.egg-info/SOURCES.txt +0 -0
  41. {compartment-3.1 → compartment-3.2}/src/compartment.egg-info/dependency_links.txt +0 -0
  42. {compartment-3.1 → compartment-3.2}/src/compartment.egg-info/entry_points.txt +0 -0
  43. {compartment-3.1 → compartment-3.2}/src/compartment.egg-info/requires.txt +0 -0
  44. {compartment-3.1 → compartment-3.2}/src/compartment.egg-info/top_level.txt +0 -0
  45. {compartment-3.1 → compartment-3.2}/tests/test_acl_audit_packs.py +0 -0
  46. {compartment-3.1 → compartment-3.2}/tests/test_acl_precedence.py +0 -0
  47. {compartment-3.1 → compartment-3.2}/tests/test_attempt_pacing.py +0 -0
  48. {compartment-3.1 → compartment-3.2}/tests/test_audit_chain.py +0 -0
  49. {compartment-3.1 → compartment-3.2}/tests/test_claude_hooks_and_integrate.py +0 -0
  50. {compartment-3.1 → compartment-3.2}/tests/test_claude_memory_and_recent.py +0 -0
  51. {compartment-3.1 → compartment-3.2}/tests/test_crypto.py +0 -0
  52. {compartment-3.1 → compartment-3.2}/tests/test_dash.py +0 -0
  53. {compartment-3.1 → compartment-3.2}/tests/test_instructions.py +0 -0
  54. {compartment-3.1 → compartment-3.2}/tests/test_journal_framing.py +0 -0
  55. {compartment-3.1 → compartment-3.2}/tests/test_macos_bundle.py +0 -0
  56. {compartment-3.1 → compartment-3.2}/tests/test_menubar.py +0 -0
  57. {compartment-3.1 → compartment-3.2}/tests/test_offline_guard_paths.py +0 -0
  58. {compartment-3.1 → compartment-3.2}/tests/test_offline_selftest_bench.py +0 -0
  59. {compartment-3.1 → compartment-3.2}/tests/test_ondisk_format.py +0 -0
  60. {compartment-3.1 → compartment-3.2}/tests/test_pack_trust.py +0 -0
  61. {compartment-3.1 → compartment-3.2}/tests/test_platforms.py +0 -0
  62. {compartment-3.1 → compartment-3.2}/tests/test_relations.py +0 -0
  63. {compartment-3.1 → compartment-3.2}/tests/test_salience.py +0 -0
  64. {compartment-3.1 → compartment-3.2}/tests/test_session_entropy.py +0 -0
  65. {compartment-3.1 → compartment-3.2}/tests/test_session_lock.py +0 -0
  66. {compartment-3.1 → compartment-3.2}/tests/test_starter_data_quality.py +0 -0
  67. {compartment-3.1 → compartment-3.2}/tests/test_starter_packs.py +0 -0
  68. {compartment-3.1 → compartment-3.2}/tests/test_status_bar_install.py +0 -0
  69. {compartment-3.1 → compartment-3.2}/tests/test_systray.py +0 -0
  70. {compartment-3.1 → compartment-3.2}/tests/test_tamper.py +0 -0
  71. {compartment-3.1 → compartment-3.2}/tests/test_twofa.py +0 -0
  72. {compartment-3.1 → compartment-3.2}/tests/test_vault_ops.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: compartment
3
- Version: 3.1
3
+ Version: 3.2
4
4
  Summary: Compartment - high-security, fully offline, encrypted vector memory for AI agents (MCP)
5
5
  Project-URL: Homepage, https://github.com/MaxFreedomPollard/Compartment
6
6
  Project-URL: Source, https://github.com/MaxFreedomPollard/Compartment
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "compartment"
7
- version = "3.1"
7
+ version = "3.2"
8
8
  description = "Compartment - high-security, fully offline, encrypted vector memory for AI agents (MCP)"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -1,6 +1,6 @@
1
1
  """Compartment - high-security, fully offline, encrypted vector memory for AI agents."""
2
2
 
3
- __version__ = "3.1"
3
+ __version__ = "3.2"
4
4
 
5
5
  from . import offline_guard as _og
6
6
 
@@ -249,6 +249,106 @@ def _start_status_bar_app(vault: str) -> None:
249
249
  "`compartment menubar` yourself")
250
250
 
251
251
 
252
+ def _install_kind() -> tuple[str, list[str]]:
253
+ """How this copy was installed, and the command that upgrades it."""
254
+ exe = Path(sys.argv[0]).resolve()
255
+ if "uv/tools" in str(exe) or shutil.which("uv") and "uv/tools" in str(
256
+ Path(shutil.which("compartment") or "").resolve()):
257
+ return "uv", ["uv", "tool", "upgrade", "compartment"]
258
+ return "pip", [sys.executable, "-m", "pip", "install", "--upgrade",
259
+ "compartment"]
260
+
261
+
262
+ def cmd_update(args) -> None:
263
+ """Upgrade Compartment in place, then put the app back up."""
264
+ kind, cmd = _install_kind()
265
+ if args.source:
266
+ target = "git+https://github.com/MaxFreedomPollard/Compartment@main"
267
+ cmd = (["uv", "tool", "install", "--force", target] if kind == "uv"
268
+ else [sys.executable, "-m", "pip", "install", "--upgrade",
269
+ "--force-reinstall", target])
270
+ print(f"Compartment {__version__} - updating ({kind} install)")
271
+ print(" " + " ".join(cmd))
272
+ try:
273
+ res = subprocess.run(cmd, timeout=1800)
274
+ except (OSError, subprocess.SubprocessError) as exc:
275
+ _die(f"update failed to run: {exc}")
276
+ if res.returncode != 0:
277
+ _die(f"update failed (exit {res.returncode})")
278
+ ver = "?"
279
+ try:
280
+ out = subprocess.run([shutil.which("compartment") or "compartment",
281
+ "--version"], capture_output=True, text=True,
282
+ timeout=120)
283
+ ver = (out.stdout or "").strip() or "?"
284
+ except (OSError, subprocess.SubprocessError):
285
+ pass
286
+ print(f" updated: now {ver}")
287
+ print(" your vault and settings are untouched")
288
+ if not args.no_app and sys.platform in ("darwin", "win32"):
289
+ _restart_status_bar_app(args.vault)
290
+
291
+
292
+ def _restart_status_bar_app(vault: str) -> None:
293
+ """Stop the running status bar app and start the new build."""
294
+ try:
295
+ app = _tray_app()
296
+ app.quit_running()
297
+ except Exception: # noqa: BLE001
298
+ pass
299
+ _start_status_bar_app(vault)
300
+
301
+
302
+ def cmd_uninstall(args) -> None:
303
+ """Remove Compartment from this machine. The vault is KEPT unless asked."""
304
+ print(f"Compartment {__version__} - uninstalling")
305
+ if sys.platform in ("darwin", "win32"):
306
+ try:
307
+ app = _tray_app()
308
+ try:
309
+ app.quit_running()
310
+ print(" status bar app stopped")
311
+ except Exception: # noqa: BLE001
312
+ pass
313
+ print(f" start at login: {app.set_login(False)}")
314
+ except Exception as exc: # noqa: BLE001
315
+ print(f" status bar app: nothing to remove ({exc})")
316
+ try:
317
+ if claude_hooks.is_installed():
318
+ claude_hooks.uninstall()
319
+ print(" Claude Code capture hook removed")
320
+ except Exception as exc: # noqa: BLE001
321
+ print(f" capture hook: {exc}")
322
+ from .home import LEGACY_NAME, NAME
323
+ for name in (NAME, LEGACY_NAME):
324
+ try:
325
+ r = subprocess.run(["claude", "mcp", "remove", name],
326
+ capture_output=True, text=True, timeout=120)
327
+ if r.returncode == 0:
328
+ print(f" MCP registration removed: {name}")
329
+ except (OSError, subprocess.SubprocessError):
330
+ pass
331
+ if args.purge:
332
+ # only on an explicit --purge: this is the only copy of everything
333
+ # the agent has ever learned, and it is not recoverable.
334
+ for f in (args.vault, args.vault + ".config.json",
335
+ args.vault + ".flock"):
336
+ try:
337
+ os.remove(f)
338
+ print(f" deleted {f}")
339
+ except OSError:
340
+ pass
341
+ print(" vault deleted (--purge)")
342
+ else:
343
+ print(f" vault KEPT at {args.vault}")
344
+ print(" delete it yourself, or re-run with --purge, once you are sure")
345
+ kind, _ = _install_kind()
346
+ final = ("uv tool uninstall compartment" if kind == "uv"
347
+ else f"{sys.executable} -m pip uninstall compartment")
348
+ print("\nOne step left, which cannot remove itself while it is running:")
349
+ print(f" {final}")
350
+
351
+
252
352
  def _ask_yn(q: str) -> bool:
253
353
  if not sys.stdin.isatty():
254
354
  return False
@@ -1376,6 +1476,20 @@ def main(argv: list[str] | None = None) -> None:
1376
1476
  help="only packs signed by the project are trusted by default. Name an author's 64 hex character public key to trust it deliberately; repeatable")
1377
1477
  p.set_defaults(fn=cmd_pack_export)
1378
1478
 
1479
+ p = sub.add_parser("update", help="upgrade Compartment in place")
1480
+ p.add_argument("--source", action="store_true",
1481
+ help="update from the GitHub main branch instead of PyPI")
1482
+ p.add_argument("--no-app", action="store_true",
1483
+ help="do not restart the status bar app afterwards")
1484
+ p.set_defaults(fn=cmd_update)
1485
+
1486
+ p = sub.add_parser("uninstall",
1487
+ help="remove Compartment from this machine "
1488
+ "(the vault is kept unless --purge)")
1489
+ p.add_argument("--purge", action="store_true",
1490
+ help="ALSO delete the vault and its config, permanently")
1491
+ p.set_defaults(fn=cmd_uninstall)
1492
+
1379
1493
  p = sub.add_parser("integrate",
1380
1494
  help="one-command wiring into claude, hermes, or openclaw")
1381
1495
  p.add_argument("target", choices=["claude", "hermes", "openclaw"])
@@ -413,6 +413,28 @@ def set_login(enabled: bool) -> str:
413
413
  return login_status()
414
414
 
415
415
 
416
+ def quit_running() -> bool:
417
+ """Stop a running status bar app, so an update or uninstall does not leave
418
+ the old build sitting in the menu bar with its binary already gone."""
419
+ import signal
420
+ killed = False
421
+ try:
422
+ out = subprocess.run(["pgrep", "-f", "compartment.*menubar"],
423
+ capture_output=True, text=True, timeout=15).stdout
424
+ except (OSError, subprocess.SubprocessError):
425
+ return False
426
+ me = os.getpid()
427
+ for pid in [int(x) for x in out.split() if x.isdigit()]:
428
+ if pid == me:
429
+ continue
430
+ try:
431
+ os.kill(pid, signal.SIGTERM)
432
+ killed = True
433
+ except OSError:
434
+ pass
435
+ return killed
436
+
437
+
416
438
  # ----------------------------------------------------------------- self test
417
439
 
418
440
  def self_check(vault: str | None = None) -> int:
@@ -486,5 +486,17 @@ def run(vault: str | None = None, show: bool = False,
486
486
  return 0
487
487
 
488
488
 
489
- __all__ = ["run", "self_check", "login_status", "set_login", "panel_rows",
489
+ def quit_running() -> bool:
490
+ """Stop a running tray app before an update or uninstall replaces it."""
491
+ import subprocess
492
+ try:
493
+ subprocess.run(["taskkill", "/F", "/IM", "compartment.exe"],
494
+ capture_output=True, timeout=30)
495
+ return True
496
+ except (OSError, subprocess.SubprocessError):
497
+ return False
498
+
499
+
500
+ __all__ = ["run", "self_check", "login_status", "set_login", "quit_running",
501
+ "panel_rows",
490
502
  "icon_path"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: compartment
3
- Version: 3.1
3
+ Version: 3.2
4
4
  Summary: Compartment - high-security, fully offline, encrypted vector memory for AI agents (MCP)
5
5
  Project-URL: Homepage, https://github.com/MaxFreedomPollard/Compartment
6
6
  Project-URL: Source, https://github.com/MaxFreedomPollard/Compartment
File without changes
File without changes
File without changes
File without changes