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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d32c7aa8093eedade1783eefa7109c996aa134d01dea01b67794612c126cf068
4
- data.tar.gz: 78fe0f2ff602c740b6ab727a0fde88d07fb235f38b1143b644b4e7498f07079f
3
+ metadata.gz: f05a4ccf0612b34b72ae1e2001278be3dd6dc569aa11a764589056f1117710cb
4
+ data.tar.gz: 252d4a50878ac81b9b5a1ee337f7524edd7a4562b305927891c69e6de13ec2f8
5
5
  SHA512:
6
- metadata.gz: be68b153e9e25ef3b8e5ad71ba7fdd89e5ace40f0848125b480bf35c96ad8b0a73b1fd891e59faf5807bc99d8d637f0c6d647e2b1d6c86ad0654b9df69c1ab45
7
- data.tar.gz: 92ee3e92e7967e03f642a5736a84f70563dd6e9f00fc3a7b24714b97294348e35645cdbfdd4b760bc5ee21301bb869bccbc686050cbc95e2bf7399c38508a32e
6
+ metadata.gz: 412f9099d2fa874c4136c23a01633bbf17bb5ede675d0c36a832e42af0900d80ec12409a82e65f45b8bad3b8d85c7e35d742195beee877db5b0092be6940367e
7
+ data.tar.gz: 200a79697ed133fbd15754845fbefd1f302fedd785487d4f5c4e56606e6cfabcbd3931e28d023561e1a5827b6242c09e3bbc10f2fa8cd9b624fdf6dd0b3f5767
data/.claude/CLAUDE.md CHANGED
@@ -1,4 +1,4 @@
1
- <!-- ClaudeMemory v0.5.0 -->
1
+ <!-- ClaudeMemory v0.5.1 -->
2
2
  # Project Memory
3
3
 
4
4
  @.claude/rules/claude_memory.generated.md
@@ -5,7 +5,7 @@
5
5
  "hooks": [
6
6
  {
7
7
  "type": "command",
8
- "command": "claude-memory hook ingest --db /Users/valentinostoll/src/claude_memory/.claude/memory.sqlite3",
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 --db /Users/valentinostoll/src/claude_memory/.claude/memory.sqlite3",
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 --db /Users/valentinostoll/src/claude_memory/.claude/memory.sqlite3",
30
+ "command": "claude-memory hook ingest",
31
31
  "timeout": 30
32
32
  },
33
33
  {
34
34
  "type": "command",
35
- "command": "claude-memory hook sweep --db /Users/valentinostoll/src/claude_memory/.claude/memory.sqlite3",
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 --db /Users/valentinostoll/src/claude_memory/.claude/memory.sqlite3",
46
+ "command": "claude-memory hook ingest",
47
47
  "timeout": 30
48
48
  },
49
49
  {
50
50
  "type": "command",
51
- "command": "claude-memory hook sweep --db /Users/valentinostoll/src/claude_memory/.claude/memory.sqlite3",
51
+ "command": "claude-memory hook sweep",
52
52
  "timeout": 30
53
53
  }
54
54
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-memory",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Long-term self-managed memory for Claude Code with fact extraction, truth maintenance, and provenance tracking",
5
5
  "author": {
6
6
  "name": "Valentino Stoll"
data/.mcp.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "mcpServers": {
3
+ "memory": {
4
+ "type": "stdio",
5
+ "command": "claude-memory",
6
+ "args": ["serve-mcp"]
7
+ }
8
+ }
9
+ }
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
- Sequel.connect(
28
- "extralite:#{db_path}",
29
- connect_sqls: [
30
- "PRAGMA journal_mode = WAL",
31
- "PRAGMA synchronous = NORMAL",
32
- "PRAGMA busy_timeout = 30000"
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
- existing = content_items.where(text_hash: text_hash, session_id: session_id).get(:id)
110
- return existing if existing
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
- now = Time.now.utc.iso8601
113
- content_items.insert(
114
- source: source,
115
- session_id: session_id,
116
- transcript_path: transcript_path,
117
- project_path: project_path,
118
- occurred_at: occurred_at || now,
119
- ingested_at: now,
120
- text_hash: text_hash,
121
- byte_len: byte_len,
122
- raw_text: raw_text,
123
- metadata_json: metadata&.to_json,
124
- git_branch: git_branch,
125
- cwd: cwd,
126
- claude_version: claude_version,
127
- thinking_level: thinking_level,
128
- source_mtime: source_mtime
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)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ClaudeMemory
4
- VERSION = "0.5.0"
4
+ VERSION = "0.5.1"
5
5
  end
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.0
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.4
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: []