claude_memory 0.5.0 → 0.5.1
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.
- checksums.yaml +4 -4
- data/.claude/CLAUDE.md +1 -1
- data/.claude/settings.json +6 -6
- data/.claude-plugin/plugin.json +1 -1
- data/.mcp.json +9 -0
- data/CHANGELOG.md +14 -0
- data/lib/claude_memory/store/sqlite_store.rb +78 -28
- data/lib/claude_memory/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f05a4ccf0612b34b72ae1e2001278be3dd6dc569aa11a764589056f1117710cb
|
|
4
|
+
data.tar.gz: 252d4a50878ac81b9b5a1ee337f7524edd7a4562b305927891c69e6de13ec2f8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 412f9099d2fa874c4136c23a01633bbf17bb5ede675d0c36a832e42af0900d80ec12409a82e65f45b8bad3b8d85c7e35d742195beee877db5b0092be6940367e
|
|
7
|
+
data.tar.gz: 200a79697ed133fbd15754845fbefd1f302fedd785487d4f5c4e56606e6cfabcbd3931e28d023561e1a5827b6242c09e3bbc10f2fa8cd9b624fdf6dd0b3f5767
|
data/.claude/CLAUDE.md
CHANGED
data/.claude/settings.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"hooks": [
|
|
6
6
|
{
|
|
7
7
|
"type": "command",
|
|
8
|
-
"command": "claude-memory hook ingest
|
|
8
|
+
"command": "claude-memory hook ingest",
|
|
9
9
|
"timeout": 10
|
|
10
10
|
}
|
|
11
11
|
]
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"hooks": [
|
|
17
17
|
{
|
|
18
18
|
"type": "command",
|
|
19
|
-
"command": "claude-memory hook ingest
|
|
19
|
+
"command": "claude-memory hook ingest",
|
|
20
20
|
"timeout": 10
|
|
21
21
|
}
|
|
22
22
|
]
|
|
@@ -27,12 +27,12 @@
|
|
|
27
27
|
"hooks": [
|
|
28
28
|
{
|
|
29
29
|
"type": "command",
|
|
30
|
-
"command": "claude-memory hook ingest
|
|
30
|
+
"command": "claude-memory hook ingest",
|
|
31
31
|
"timeout": 30
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
"type": "command",
|
|
35
|
-
"command": "claude-memory hook sweep
|
|
35
|
+
"command": "claude-memory hook sweep",
|
|
36
36
|
"timeout": 30
|
|
37
37
|
}
|
|
38
38
|
]
|
|
@@ -43,12 +43,12 @@
|
|
|
43
43
|
"hooks": [
|
|
44
44
|
{
|
|
45
45
|
"type": "command",
|
|
46
|
-
"command": "claude-memory hook ingest
|
|
46
|
+
"command": "claude-memory hook ingest",
|
|
47
47
|
"timeout": 30
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
"type": "command",
|
|
51
|
-
"command": "claude-memory hook sweep
|
|
51
|
+
"command": "claude-memory hook sweep",
|
|
52
52
|
"timeout": 30
|
|
53
53
|
}
|
|
54
54
|
]
|
data/.claude-plugin/plugin.json
CHANGED
data/.mcp.json
ADDED
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.5.1] - 2026-02-04
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **Database Lock Errors**: Fixed "database is locked" and "database is busy" errors when
|
|
12
|
+
multiple Claude Code hooks run concurrently
|
|
13
|
+
- Added application-level retry with exponential backoff (5 retries, 0.1s base delay)
|
|
14
|
+
- Reduced SQLite busy_timeout from 30s to 1s for faster failure detection
|
|
15
|
+
- Added `with_retry` and `transaction_with_retry` methods for concurrent access handling
|
|
16
|
+
- SQLite's busy_timeout doesn't reliably detect lock release; app-level retry compensates
|
|
17
|
+
|
|
18
|
+
- **MCP Server Auto-Registration**: Added `.mcp.json` at plugin root so MCP server is
|
|
19
|
+
automatically registered when plugin is installed (previously only worked in dev directory)
|
|
20
|
+
|
|
7
21
|
## [0.5.0] - 2026-02-04
|
|
8
22
|
|
|
9
23
|
### Added
|
|
@@ -21,17 +21,65 @@ module ClaudeMemory
|
|
|
21
21
|
ensure_schema!
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
# Retry configuration for database operations
|
|
25
|
+
# SQLite's busy_timeout doesn't reliably detect lock release, so we use
|
|
26
|
+
# shorter timeouts with application-level retry for better responsiveness
|
|
27
|
+
MAX_RETRIES = 5
|
|
28
|
+
RETRY_BASE_DELAY = 0.1 # seconds, with exponential backoff
|
|
29
|
+
|
|
30
|
+
# Execute a block with retry logic for busy/locked errors
|
|
31
|
+
# This handles concurrent access from multiple hook processes
|
|
32
|
+
def with_retry(operation_name = "database operation")
|
|
33
|
+
retries = 0
|
|
34
|
+
begin
|
|
35
|
+
yield
|
|
36
|
+
rescue Sequel::DatabaseError, Extralite::Error, Extralite::BusyError => e
|
|
37
|
+
if retryable_error?(e) && retries < MAX_RETRIES
|
|
38
|
+
retries += 1
|
|
39
|
+
delay = RETRY_BASE_DELAY * (2**retries) # Exponential backoff
|
|
40
|
+
sleep(delay)
|
|
41
|
+
retry
|
|
42
|
+
end
|
|
43
|
+
raise
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Execute a transaction with retry logic for concurrent access
|
|
48
|
+
# Use this instead of @db.transaction when concurrent writes are expected
|
|
49
|
+
def transaction_with_retry(&block)
|
|
50
|
+
with_retry("transaction") do
|
|
51
|
+
@db.transaction(&block)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
24
55
|
private
|
|
25
56
|
|
|
57
|
+
def retryable_error?(error)
|
|
58
|
+
message = error.message.downcase
|
|
59
|
+
message.include?("busy") || message.include?("locked")
|
|
60
|
+
end
|
|
61
|
+
|
|
26
62
|
def connect_database(db_path)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
63
|
+
retries = 0
|
|
64
|
+
begin
|
|
65
|
+
Sequel.connect(
|
|
66
|
+
"extralite:#{db_path}",
|
|
67
|
+
# Use shorter busy_timeout since we handle retry at app level
|
|
68
|
+
# This allows faster detection of lock release between retries
|
|
69
|
+
connect_sqls: [
|
|
70
|
+
"PRAGMA busy_timeout = 1000",
|
|
71
|
+
"PRAGMA journal_mode = WAL",
|
|
72
|
+
"PRAGMA synchronous = NORMAL"
|
|
73
|
+
]
|
|
74
|
+
)
|
|
75
|
+
rescue Sequel::DatabaseConnectionError, Extralite::Error => e
|
|
76
|
+
retries += 1
|
|
77
|
+
if retries <= MAX_RETRIES && retryable_error?(e)
|
|
78
|
+
sleep(RETRY_BASE_DELAY * (2**retries))
|
|
79
|
+
retry
|
|
80
|
+
end
|
|
81
|
+
raise
|
|
82
|
+
end
|
|
35
83
|
end
|
|
36
84
|
|
|
37
85
|
public
|
|
@@ -106,27 +154,29 @@ module ClaudeMemory
|
|
|
106
154
|
def upsert_content_item(source:, text_hash:, byte_len:, session_id: nil, transcript_path: nil,
|
|
107
155
|
project_path: nil, occurred_at: nil, raw_text: nil, metadata: nil,
|
|
108
156
|
git_branch: nil, cwd: nil, claude_version: nil, thinking_level: nil, source_mtime: nil)
|
|
109
|
-
|
|
110
|
-
|
|
157
|
+
with_retry("upsert_content_item") do
|
|
158
|
+
existing = content_items.where(text_hash: text_hash, session_id: session_id).get(:id)
|
|
159
|
+
return existing if existing
|
|
111
160
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
161
|
+
now = Time.now.utc.iso8601
|
|
162
|
+
content_items.insert(
|
|
163
|
+
source: source,
|
|
164
|
+
session_id: session_id,
|
|
165
|
+
transcript_path: transcript_path,
|
|
166
|
+
project_path: project_path,
|
|
167
|
+
occurred_at: occurred_at || now,
|
|
168
|
+
ingested_at: now,
|
|
169
|
+
text_hash: text_hash,
|
|
170
|
+
byte_len: byte_len,
|
|
171
|
+
raw_text: raw_text,
|
|
172
|
+
metadata_json: metadata&.to_json,
|
|
173
|
+
git_branch: git_branch,
|
|
174
|
+
cwd: cwd,
|
|
175
|
+
claude_version: claude_version,
|
|
176
|
+
thinking_level: thinking_level,
|
|
177
|
+
source_mtime: source_mtime
|
|
178
|
+
)
|
|
179
|
+
end
|
|
130
180
|
end
|
|
131
181
|
|
|
132
182
|
def content_item_by_transcript_and_mtime(transcript_path, mtime_iso8601)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: claude_memory
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Valentino Stoll
|
|
@@ -70,6 +70,7 @@ files:
|
|
|
70
70
|
- ".claude/skills/study-repo/analysis-template.md"
|
|
71
71
|
- ".claude/skills/study-repo/focus-examples.md"
|
|
72
72
|
- ".lefthook/map_specs.rb"
|
|
73
|
+
- ".mcp.json"
|
|
73
74
|
- ".ruby-version"
|
|
74
75
|
- CHANGELOG.md
|
|
75
76
|
- CLAUDE.md
|
|
@@ -255,7 +256,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
255
256
|
- !ruby/object:Gem::Version
|
|
256
257
|
version: '0'
|
|
257
258
|
requirements: []
|
|
258
|
-
rubygems_version: 4.0.
|
|
259
|
+
rubygems_version: 4.0.3
|
|
259
260
|
specification_version: 4
|
|
260
261
|
summary: Long-term, self-managed memory for Claude Code
|
|
261
262
|
test_files: []
|