claude-memory-agent 2.0.0

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 (100) hide show
  1. package/.env.example +107 -0
  2. package/README.md +200 -0
  3. package/agent_card.py +512 -0
  4. package/bin/cli.js +181 -0
  5. package/bin/postinstall.js +216 -0
  6. package/config.py +104 -0
  7. package/dashboard.html +2689 -0
  8. package/hooks/README.md +196 -0
  9. package/hooks/__pycache__/auto-detect-response.cpython-312.pyc +0 -0
  10. package/hooks/__pycache__/auto_capture.cpython-312.pyc +0 -0
  11. package/hooks/__pycache__/session_end.cpython-312.pyc +0 -0
  12. package/hooks/__pycache__/session_start.cpython-312.pyc +0 -0
  13. package/hooks/auto-detect-response.py +348 -0
  14. package/hooks/auto_capture.py +255 -0
  15. package/hooks/detect-correction.py +173 -0
  16. package/hooks/grounding-hook.py +348 -0
  17. package/hooks/log-tool-use.py +234 -0
  18. package/hooks/log-user-request.py +208 -0
  19. package/hooks/pre-tool-decision.py +218 -0
  20. package/hooks/problem-detector.py +343 -0
  21. package/hooks/session_end.py +192 -0
  22. package/hooks/session_start.py +227 -0
  23. package/install.py +887 -0
  24. package/main.py +2859 -0
  25. package/manager.py +997 -0
  26. package/package.json +55 -0
  27. package/requirements.txt +8 -0
  28. package/run_server.py +136 -0
  29. package/services/__init__.py +50 -0
  30. package/services/__pycache__/__init__.cpython-312.pyc +0 -0
  31. package/services/__pycache__/agent_registry.cpython-312.pyc +0 -0
  32. package/services/__pycache__/auth.cpython-312.pyc +0 -0
  33. package/services/__pycache__/auto_inject.cpython-312.pyc +0 -0
  34. package/services/__pycache__/claude_md_sync.cpython-312.pyc +0 -0
  35. package/services/__pycache__/cleanup.cpython-312.pyc +0 -0
  36. package/services/__pycache__/compaction_flush.cpython-312.pyc +0 -0
  37. package/services/__pycache__/confidence.cpython-312.pyc +0 -0
  38. package/services/__pycache__/daily_log.cpython-312.pyc +0 -0
  39. package/services/__pycache__/database.cpython-312.pyc +0 -0
  40. package/services/__pycache__/embeddings.cpython-312.pyc +0 -0
  41. package/services/__pycache__/insights.cpython-312.pyc +0 -0
  42. package/services/__pycache__/llm_analyzer.cpython-312.pyc +0 -0
  43. package/services/__pycache__/memory_md_sync.cpython-312.pyc +0 -0
  44. package/services/__pycache__/retry_queue.cpython-312.pyc +0 -0
  45. package/services/__pycache__/timeline.cpython-312.pyc +0 -0
  46. package/services/__pycache__/vector_index.cpython-312.pyc +0 -0
  47. package/services/__pycache__/websocket.cpython-312.pyc +0 -0
  48. package/services/agent_registry.py +753 -0
  49. package/services/auth.py +331 -0
  50. package/services/auto_inject.py +250 -0
  51. package/services/claude_md_sync.py +275 -0
  52. package/services/cleanup.py +667 -0
  53. package/services/compaction_flush.py +447 -0
  54. package/services/confidence.py +301 -0
  55. package/services/daily_log.py +333 -0
  56. package/services/database.py +2485 -0
  57. package/services/embeddings.py +358 -0
  58. package/services/insights.py +632 -0
  59. package/services/llm_analyzer.py +595 -0
  60. package/services/memory_md_sync.py +409 -0
  61. package/services/retry_queue.py +453 -0
  62. package/services/timeline.py +579 -0
  63. package/services/vector_index.py +398 -0
  64. package/services/websocket.py +257 -0
  65. package/skills/__init__.py +6 -0
  66. package/skills/__pycache__/__init__.cpython-312.pyc +0 -0
  67. package/skills/__pycache__/admin.cpython-312.pyc +0 -0
  68. package/skills/__pycache__/checkpoint.cpython-312.pyc +0 -0
  69. package/skills/__pycache__/claude_md.cpython-312.pyc +0 -0
  70. package/skills/__pycache__/cleanup.cpython-312.pyc +0 -0
  71. package/skills/__pycache__/grounding.cpython-312.pyc +0 -0
  72. package/skills/__pycache__/insights.cpython-312.pyc +0 -0
  73. package/skills/__pycache__/natural_language.cpython-312.pyc +0 -0
  74. package/skills/__pycache__/retrieve.cpython-312.pyc +0 -0
  75. package/skills/__pycache__/search.cpython-312.pyc +0 -0
  76. package/skills/__pycache__/state.cpython-312.pyc +0 -0
  77. package/skills/__pycache__/store.cpython-312.pyc +0 -0
  78. package/skills/__pycache__/summarize.cpython-312.pyc +0 -0
  79. package/skills/__pycache__/timeline.cpython-312.pyc +0 -0
  80. package/skills/__pycache__/verification.cpython-312.pyc +0 -0
  81. package/skills/admin.py +469 -0
  82. package/skills/checkpoint.py +198 -0
  83. package/skills/claude_md.py +363 -0
  84. package/skills/cleanup.py +241 -0
  85. package/skills/grounding.py +801 -0
  86. package/skills/insights.py +231 -0
  87. package/skills/natural_language.py +277 -0
  88. package/skills/retrieve.py +67 -0
  89. package/skills/search.py +213 -0
  90. package/skills/state.py +182 -0
  91. package/skills/store.py +179 -0
  92. package/skills/summarize.py +588 -0
  93. package/skills/timeline.py +387 -0
  94. package/skills/verification.py +391 -0
  95. package/start_daemon.py +155 -0
  96. package/test_automation.py +221 -0
  97. package/test_complete.py +338 -0
  98. package/test_full.py +322 -0
  99. package/update_system.py +817 -0
  100. package/verify_db.py +134 -0
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "claude-memory-agent",
3
+ "version": "2.0.0",
4
+ "description": "Persistent semantic memory system for Claude Code sessions with anti-hallucination grounding",
5
+ "keywords": [
6
+ "claude",
7
+ "claude-code",
8
+ "memory",
9
+ "ai",
10
+ "mcp",
11
+ "semantic-search",
12
+ "embeddings",
13
+ "ollama"
14
+ ],
15
+ "author": "Your Name",
16
+ "license": "MIT",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/yourusername/claude-memory-agent.git"
20
+ },
21
+ "homepage": "https://github.com/yourusername/claude-memory-agent#readme",
22
+ "bugs": {
23
+ "url": "https://github.com/yourusername/claude-memory-agent/issues"
24
+ },
25
+ "bin": {
26
+ "claude-memory-agent": "./bin/cli.js",
27
+ "claude-memory": "./bin/cli.js"
28
+ },
29
+ "files": [
30
+ "bin/",
31
+ "services/",
32
+ "skills/",
33
+ "hooks/",
34
+ "*.py",
35
+ "*.md",
36
+ "*.txt",
37
+ "*.html",
38
+ ".env.example"
39
+ ],
40
+ "scripts": {
41
+ "postinstall": "node bin/postinstall.js",
42
+ "start": "python main.py",
43
+ "install-agent": "python install.py --auto",
44
+ "test": "python -m pytest"
45
+ },
46
+ "engines": {
47
+ "node": ">=16.0.0"
48
+ },
49
+ "os": [
50
+ "win32",
51
+ "darwin",
52
+ "linux"
53
+ ],
54
+ "preferGlobal": true
55
+ }
@@ -0,0 +1,8 @@
1
+ fastapi>=0.109.0
2
+ uvicorn>=0.27.0
3
+ ollama>=0.4.0
4
+ python-dotenv>=1.0.0
5
+ pydantic>=2.0.0
6
+ httpx>=0.27.0
7
+ numpy>=1.26.0
8
+ faiss-cpu>=1.7.4
package/run_server.py ADDED
@@ -0,0 +1,136 @@
1
+ """Run the memory agent server (for background/production use).
2
+
3
+ Uses Windows file locking (msvcrt.locking) for a true process mutex.
4
+ The lock is held for the entire lifetime of the server, ensuring only
5
+ one instance can run at a time.
6
+ """
7
+ import os
8
+ import sys
9
+ import time
10
+ import atexit
11
+ import signal
12
+ import uvicorn
13
+ from dotenv import load_dotenv
14
+
15
+ load_dotenv()
16
+
17
+ AGENT_DIR = os.path.dirname(os.path.abspath(__file__))
18
+ LOCK_FILE = os.path.join(AGENT_DIR, "memory-agent.lock")
19
+ PID_FILE = os.path.join(AGENT_DIR, "memory-agent.pid")
20
+ PORT = int(os.getenv("PORT", 8102))
21
+
22
+ # Global lock file handle - must stay open for lock to persist
23
+ _lock_handle = None
24
+
25
+
26
+ def is_port_in_use(port: int) -> bool:
27
+ """Check if the port is already in use."""
28
+ import socket
29
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
30
+ return s.connect_ex(('localhost', port)) == 0
31
+
32
+
33
+ def acquire_server_lock() -> bool:
34
+ """Acquire exclusive server lock using Windows file locking.
35
+
36
+ This uses msvcrt.locking() which provides mandatory file locking on Windows.
37
+ The lock is held as long as the file handle remains open.
38
+ """
39
+ global _lock_handle
40
+ import msvcrt
41
+
42
+ my_pid = os.getpid()
43
+
44
+ try:
45
+ # Open file for read/write, create if doesn't exist
46
+ # Using os.open to get a file descriptor for msvcrt.locking
47
+ _lock_handle = open(LOCK_FILE, 'w+')
48
+
49
+ # Try to acquire exclusive lock (non-blocking)
50
+ # msvcrt.LK_NBLCK = non-blocking exclusive lock
51
+ try:
52
+ msvcrt.locking(_lock_handle.fileno(), msvcrt.LK_NBLCK, 1)
53
+ except (IOError, OSError) as e:
54
+ # Lock is held by another process
55
+ print(f"[MUTEX] Cannot acquire lock - another instance is running")
56
+ _lock_handle.close()
57
+ _lock_handle = None
58
+ return False
59
+
60
+ # We have the lock - write our PID
61
+ _lock_handle.seek(0)
62
+ _lock_handle.truncate()
63
+ _lock_handle.write(str(my_pid))
64
+ _lock_handle.flush()
65
+
66
+ # Double-check the port isn't somehow in use
67
+ if is_port_in_use(PORT):
68
+ print(f"[MUTEX] Port {PORT} is already in use!")
69
+ release_server_lock()
70
+ return False
71
+
72
+ print(f"[MUTEX] Acquired server lock (PID: {my_pid})")
73
+ return True
74
+
75
+ except Exception as e:
76
+ print(f"[MUTEX] Failed to acquire lock: {e}")
77
+ if _lock_handle:
78
+ try:
79
+ _lock_handle.close()
80
+ except:
81
+ pass
82
+ _lock_handle = None
83
+ return False
84
+
85
+
86
+ def release_server_lock():
87
+ """Release the server lock on exit."""
88
+ global _lock_handle
89
+ import msvcrt
90
+
91
+ try:
92
+ if _lock_handle:
93
+ try:
94
+ # Unlock the file
95
+ msvcrt.locking(_lock_handle.fileno(), msvcrt.LK_UNLCK, 1)
96
+ except:
97
+ pass
98
+ _lock_handle.close()
99
+ _lock_handle = None
100
+ print("[MUTEX] Released server lock")
101
+ except Exception as e:
102
+ print(f"[MUTEX] Error releasing lock: {e}")
103
+
104
+
105
+ def cleanup_and_exit(signum=None, frame=None):
106
+ """Clean up lock and exit."""
107
+ release_server_lock()
108
+ if signum:
109
+ sys.exit(0)
110
+
111
+
112
+ if __name__ == "__main__":
113
+ # Register cleanup handlers FIRST
114
+ atexit.register(release_server_lock)
115
+ signal.signal(signal.SIGTERM, cleanup_and_exit)
116
+ signal.signal(signal.SIGINT, cleanup_and_exit)
117
+
118
+ # Try to acquire the mutex - this blocks other instances
119
+ if not acquire_server_lock():
120
+ print("[MUTEX] Cannot start: another instance is running")
121
+ sys.exit(1)
122
+
123
+ # Write PID file (for convenience, the lock is the real mutex)
124
+ with open(PID_FILE, 'w') as f:
125
+ f.write(str(os.getpid()))
126
+
127
+ print(f"[SERVER] Starting memory agent on port {PORT}...")
128
+
129
+ # Note: The lock is held because _lock_handle stays open
130
+ uvicorn.run(
131
+ "main:app",
132
+ host=os.getenv("HOST", "0.0.0.0"),
133
+ port=PORT,
134
+ reload=False,
135
+ log_level="warning"
136
+ )
@@ -0,0 +1,50 @@
1
+ from .database import DatabaseService
2
+ from .embeddings import EmbeddingService
3
+
4
+ # Moltbot-inspired transparency services
5
+ from .daily_log import (
6
+ append_entry as daily_log_append,
7
+ append_session_summary as daily_log_append_session,
8
+ load_recent_logs as daily_log_read,
9
+ get_today_highlights as daily_log_highlights,
10
+ list_logs as daily_log_list,
11
+ get_log_path
12
+ )
13
+ from .memory_md_sync import (
14
+ sync_to_memory_md,
15
+ read_memory_md,
16
+ add_fact as add_memory_md_fact,
17
+ get_memory_md_summary,
18
+ get_memory_md_path
19
+ )
20
+ from .compaction_flush import (
21
+ check_flush_needed,
22
+ execute_flush as pre_compaction_flush,
23
+ list_flushes,
24
+ read_flush,
25
+ get_flush_path
26
+ )
27
+
28
+ __all__ = [
29
+ "DatabaseService",
30
+ "EmbeddingService",
31
+ # Daily log
32
+ "daily_log_append",
33
+ "daily_log_append_session",
34
+ "daily_log_read",
35
+ "daily_log_highlights",
36
+ "daily_log_list",
37
+ "get_log_path",
38
+ # MEMORY.md
39
+ "sync_to_memory_md",
40
+ "read_memory_md",
41
+ "add_memory_md_fact",
42
+ "get_memory_md_summary",
43
+ "get_memory_md_path",
44
+ # Compaction flush
45
+ "check_flush_needed",
46
+ "pre_compaction_flush",
47
+ "list_flushes",
48
+ "read_flush",
49
+ "get_flush_path",
50
+ ]