memor-cli 0.1.1__tar.gz → 0.2.0__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 (89) hide show
  1. {memor_cli-0.1.1 → memor_cli-0.2.0}/PKG-INFO +1 -1
  2. memor_cli-0.2.0/memor/__init__.py +1 -0
  3. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/cli.py +63 -10
  4. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/daemon.py +9 -0
  5. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/dashboard/server.py +20 -0
  6. memor_cli-0.2.0/memor/dashboard/static/index.html +821 -0
  7. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/ingest/claude_code.py +55 -1
  8. memor_cli-0.2.0/memor/service.py +187 -0
  9. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/store/sqlite_store.py +106 -1
  10. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/types.py +15 -0
  11. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor_cli.egg-info/PKG-INFO +1 -1
  12. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor_cli.egg-info/SOURCES.txt +2 -0
  13. {memor_cli-0.1.1 → memor_cli-0.2.0}/pyproject.toml +1 -1
  14. memor_cli-0.2.0/tests/test_service.py +25 -0
  15. memor_cli-0.1.1/memor/dashboard/static/index.html +0 -688
  16. memor_cli-0.1.1/memor/store/__init__.py +0 -0
  17. {memor_cli-0.1.1 → memor_cli-0.2.0}/LICENSE +0 -0
  18. {memor_cli-0.1.1 → memor_cli-0.2.0}/README.md +0 -0
  19. {memor_cli-0.1.1/memor → memor_cli-0.2.0/memor/dashboard}/__init__.py +0 -0
  20. {memor_cli-0.1.1/memor/dashboard → memor_cli-0.2.0/memor/distill}/__init__.py +0 -0
  21. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/distill/distiller.py +0 -0
  22. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/distill/extractive.py +0 -0
  23. {memor_cli-0.1.1/memor/distill → memor_cli-0.2.0/memor/embed}/__init__.py +0 -0
  24. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/embed/api.py +0 -0
  25. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/embed/fake.py +0 -0
  26. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/embed/local.py +0 -0
  27. {memor_cli-0.1.1/memor/embed → memor_cli-0.2.0/memor/eval}/__init__.py +0 -0
  28. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/eval/baselines/__init__.py +0 -0
  29. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/eval/baselines/base.py +0 -0
  30. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/eval/baselines/claude_mem.py +0 -0
  31. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/eval/baselines/graphiti.py +0 -0
  32. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/eval/dataset.py +0 -0
  33. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/eval/embed_benchmark.py +0 -0
  34. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/eval/judge.py +0 -0
  35. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/eval/metrics.py +0 -0
  36. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/eval/runner.py +0 -0
  37. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/feedback.py +0 -0
  38. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/hook_cli.py +0 -0
  39. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/hook_server.py +0 -0
  40. {memor_cli-0.1.1/memor/eval → memor_cli-0.2.0/memor/ingest}/__init__.py +0 -0
  41. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/ingest/documents.py +0 -0
  42. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/interfaces.py +0 -0
  43. {memor_cli-0.1.1/memor/ingest → memor_cli-0.2.0/memor/llm}/__init__.py +0 -0
  44. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/llm/anthropic.py +0 -0
  45. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/llm/base.py +0 -0
  46. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/llm/openai_compat.py +0 -0
  47. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/project.py +0 -0
  48. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/recall.py +0 -0
  49. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/redact.py +0 -0
  50. {memor_cli-0.1.1/memor/llm → memor_cli-0.2.0/memor/retrieve}/__init__.py +0 -0
  51. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/retrieve/retriever.py +0 -0
  52. {memor_cli-0.1.1/memor/retrieve → memor_cli-0.2.0/memor/store}/__init__.py +0 -0
  53. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor/tokencount.py +0 -0
  54. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor_cli.egg-info/dependency_links.txt +0 -0
  55. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor_cli.egg-info/entry_points.txt +0 -0
  56. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor_cli.egg-info/requires.txt +0 -0
  57. {memor_cli-0.1.1 → memor_cli-0.2.0}/memor_cli.egg-info/top_level.txt +0 -0
  58. {memor_cli-0.1.1 → memor_cli-0.2.0}/setup.cfg +0 -0
  59. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_cli_smoke.py +0 -0
  60. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_daemon.py +0 -0
  61. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_dashboard.py +0 -0
  62. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_dataset_builder.py +0 -0
  63. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_dimension_safety.py +0 -0
  64. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_distiller.py +0 -0
  65. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_embed.py +0 -0
  66. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_embed_benchmark.py +0 -0
  67. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_eval_ablation.py +0 -0
  68. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_eval_runner.py +0 -0
  69. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_external_baselines.py +0 -0
  70. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_extractive.py +0 -0
  71. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_feedback.py +0 -0
  72. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_hook.py +0 -0
  73. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_hook_server.py +0 -0
  74. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_ingest_claude_code.py +0 -0
  75. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_ingest_documents.py +0 -0
  76. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_install_hook.py +0 -0
  77. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_interfaces.py +0 -0
  78. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_judge.py +0 -0
  79. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_metrics.py +0 -0
  80. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_noise_filter.py +0 -0
  81. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_project_resolver.py +0 -0
  82. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_recall_core.py +0 -0
  83. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_redact.py +0 -0
  84. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_retriever.py +0 -0
  85. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_skill_recall.py +0 -0
  86. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_store.py +0 -0
  87. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_supersession.py +0 -0
  88. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_tokencount.py +0 -0
  89. {memor_cli-0.1.1 → memor_cli-0.2.0}/tests/test_types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memor-cli
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: Measured memory for coding agents. Fire and forget — no API keys needed.
5
5
  Author-email: Nimit Bhandari <nimitbhandari17@gmail.com>
6
6
  License-Expression: MIT
@@ -0,0 +1 @@
1
+ __version__ = "0.2.0"
@@ -9,6 +9,8 @@ from memor.types import Scope
9
9
  from memor.ingest.claude_code import parse_transcript
10
10
 
11
11
  app = typer.Typer(no_args_is_help=True)
12
+ service_app = typer.Typer(help="Manage the memor daemon as a background service.")
13
+ app.add_typer(service_app, name="service")
12
14
 
13
15
  def _db_path(db: str) -> str:
14
16
  return str(Path(db).expanduser())
@@ -42,14 +44,21 @@ HELP_TEXT = """\
42
44
  memor — measured memory for coding agents
43
45
 
44
46
  GETTING STARTED
45
- memor install-hook Install the Claude Code recall hook + download model
46
- memor daemon Start the background watcher (ingests + distills)
47
- memor dashboard Open the web dashboard at localhost:8420
47
+ memor install-hook Install the Claude Code recall hook + download model
48
+ memor service install Start the daemon as a background service
49
+ memor dashboard Open the web dashboard at localhost:8420
50
+
51
+ SERVICE MANAGEMENT
52
+ memor service install Install and start as a background service (survives reboots)
53
+ memor service status Check if the daemon is running
54
+ memor service stop Stop the service (restarts on next login)
55
+ memor service uninstall Stop and remove the service completely
56
+ memor daemon Run the daemon in the foreground (alternative to service)
48
57
 
49
58
  QUERYING
50
- memor query <text> Search memories from the command line
51
- --project <name> Scope to a specific project
52
- --k <n> Number of results (default: 8)
59
+ memor query <text> Search memories from the command line
60
+ --project <name> Scope to a specific project
61
+ --k <n> Number of results (default: 8)
53
62
 
54
63
  INGESTION
55
64
  memor ingest-cc <file> Ingest a single transcript
@@ -66,6 +75,7 @@ MAINTENANCE
66
75
  memor scan Audit DB for leaked secrets
67
76
  memor scan --purge Redact secrets in place
68
77
  memor setup-model Download/retry the embedding model (~60MB)
78
+ memor version Print the installed version
69
79
 
70
80
  EVALUATION
71
81
  memor eval <cases.json> Run eval suite
@@ -77,10 +87,10 @@ CONFIGURATION
77
87
  No configuration needed — just install, hook, and run the daemon.
78
88
 
79
89
  EXAMPLES
80
- memor install-hook && memor daemon # one-time setup
90
+ memor install-hook && memor service install # one-time setup
81
91
  memor query "auth flow" --project my-app
82
- memor reingest --project my-app -y # refresh one project
83
- memor dashboard # see stats at localhost:8420
92
+ memor reingest --project my-app -y # refresh one project
93
+ memor dashboard # see stats at localhost:8420
84
94
  """
85
95
 
86
96
 
@@ -438,7 +448,8 @@ def install_hook():
438
448
  typer.echo(" retry later with: memor setup-model")
439
449
  typer.echo()
440
450
  typer.echo("Next steps:")
441
- typer.echo(" 1. Start the daemon: memor daemon")
451
+ typer.echo(" 1. Start the daemon: memor service install")
452
+ typer.echo(" (or foreground: memor daemon)")
442
453
  typer.echo(" 2. Open the dashboard: memor dashboard")
443
454
  typer.echo(" Everything works locally — no API keys needed.")
444
455
 
@@ -464,5 +475,47 @@ def dashboard(port: int = typer.Option(8420, help="Port to serve on"),
464
475
  uvicorn.run(app_instance, host="127.0.0.1", port=port, log_level="warning")
465
476
 
466
477
 
478
+ @app.command("version")
479
+ def version():
480
+ """Print the memor version."""
481
+ from memor import __version__
482
+ typer.echo(f"memor {__version__}")
483
+
484
+
485
+ @service_app.command("install")
486
+ def service_install():
487
+ """Install and start the daemon as a background service (survives reboots)."""
488
+ from memor.service import install
489
+ try:
490
+ typer.echo(install())
491
+ except FileNotFoundError as e:
492
+ typer.echo(str(e), err=True)
493
+ raise typer.Exit(1)
494
+ except Exception as e:
495
+ typer.echo(f"Failed to install service: {e}", err=True)
496
+ raise typer.Exit(1)
497
+
498
+
499
+ @service_app.command("uninstall")
500
+ def service_uninstall():
501
+ """Stop and remove the background service."""
502
+ from memor.service import uninstall
503
+ typer.echo(uninstall())
504
+
505
+
506
+ @service_app.command("stop")
507
+ def service_stop():
508
+ """Stop the background service (will restart on next login)."""
509
+ from memor.service import stop
510
+ typer.echo(stop())
511
+
512
+
513
+ @service_app.command("status")
514
+ def service_status():
515
+ """Show whether the daemon service is running."""
516
+ from memor.service import status
517
+ typer.echo(status())
518
+
519
+
467
520
  if __name__ == "__main__":
468
521
  app()
@@ -93,6 +93,15 @@ def ingest_file(path: Path, project: str, store: SqliteStore, embedder) -> int:
93
93
  return 0
94
94
  vecs = embedder.embed([a.text for a in arts])
95
95
  store.add_artifacts(arts, vecs)
96
+
97
+ from memor.ingest.claude_code import parse_session_usage
98
+ try:
99
+ usage = parse_session_usage(path, project)
100
+ if usage:
101
+ store.upsert_session_stats(usage)
102
+ except Exception:
103
+ pass
104
+
96
105
  return len(arts)
97
106
 
98
107
 
@@ -114,6 +114,26 @@ def create_app(db_path: str | None = None) -> FastAPI:
114
114
  })
115
115
  return result
116
116
 
117
+ @app.get("/api/session-efficiency")
118
+ def session_efficiency():
119
+ store = _store()
120
+ return store.get_session_efficiency()
121
+
122
+ @app.get("/api/recall-trend")
123
+ def recall_trend(days: int = Query(30, ge=7, le=90)):
124
+ store = _store()
125
+ rows = store.db.execute("""
126
+ SELECT date(timestamp, 'unixepoch', 'localtime') as day,
127
+ COUNT(*) as recalls,
128
+ SUM(CASE WHEN hits_count > 0 THEN 1 ELSE 0 END) as hits,
129
+ SUM(tokens_injected) as tokens,
130
+ AVG(CASE WHEN hits_count > 0 THEN top_score END) as avg_score
131
+ FROM recall_log
132
+ WHERE timestamp >= unixepoch('now', ? || ' days')
133
+ GROUP BY day ORDER BY day
134
+ """, (f"-{days}",)).fetchall()
135
+ return [dict(r) for r in rows]
136
+
117
137
  @app.get("/api/health")
118
138
  def health():
119
139
  store = _store()