claude-memory-hub 0.5.1 → 0.5.2

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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ Format follows [Keep a Changelog](https://keepachangelog.com/).
5
5
 
6
6
  ---
7
7
 
8
+ ## [0.5.2] - 2026-04-01
9
+
10
+ ### Fixed
11
+ - **Viewer JS broken after bundle** — inline `onclick` handlers lost reference when Bun bundled template literal into `cli.js`. Rewrote all JS to IIFE + `addEventListener` pattern
12
+ - **Escaped quotes in template literal** — `this.classList.toggle('expanded')` caused `SyntaxError: Unexpected identifier` after bundle. Switched to double quotes and event delegation
13
+ - **push-private.sh deletes source** — `git checkout main` removed untracked `src/` directory. Added backup/restore of source dirs around branch switch
14
+
15
+ ### Changed
16
+ - **push-public.sh** — fixed version extraction in commit message (`node -p` with proper quoting)
17
+
18
+ ---
19
+
8
20
  ## [0.5.1] - 2026-04-01
9
21
 
10
22
  ### Fixed
package/README.md CHANGED
@@ -235,6 +235,21 @@ One command. Registers MCP server + 5 hooks globally. Works on CLI, VS Code, Jet
235
235
 
236
236
  **Coming from claude-mem?** The installer auto-detects `~/.claude-mem/claude-mem.db` and migrates your data automatically. No manual steps needed.
237
237
 
238
+ ### Update
239
+
240
+ ```bash
241
+ bunx claude-memory-hub@latest install
242
+ ```
243
+
244
+ Or if installed globally:
245
+
246
+ ```bash
247
+ bun install -g claude-memory-hub@latest
248
+ claude-memory-hub install
249
+ ```
250
+
251
+ Your data at `~/.claude-memory-hub/` is preserved across updates. Schema migrations run automatically.
252
+
238
253
  ### From source
239
254
 
240
255
  ```bash
package/dist/cli.js CHANGED
@@ -944,130 +944,132 @@ body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', syst
944
944
  </div>
945
945
 
946
946
  <div class="tabs" id="tabsContainer">
947
- <button class="tab active" onclick="switchTab('summaries',this)">Summaries <span class="count" id="cnt-summaries"></span></button>
948
- <button class="tab" onclick="switchTab('sessions',this)">Sessions <span class="count" id="cnt-sessions"></span></button>
949
- <button class="tab" onclick="switchTab('entities',this)">Entities <span class="count" id="cnt-entities"></span></button>
947
+ <button class="tab active" data-tab="summaries">Summaries <span class="count" id="cnt-summaries"></span></button>
948
+ <button class="tab" data-tab="sessions">Sessions <span class="count" id="cnt-sessions"></span></button>
949
+ <button class="tab" data-tab="entities">Entities <span class="count" id="cnt-entities"></span></button>
950
950
  </div>
951
951
 
952
952
  <div id="results"></div>
953
953
 
954
954
  <div class="pagination">
955
- <button class="pg-btn" id="prevBtn" onclick="paginate(-1)" disabled>Previous</button>
955
+ <button class="pg-btn" id="prevBtn" disabled>Previous</button>
956
956
  <span class="pg-info" id="pageInfo"></span>
957
- <button class="pg-btn" id="nextBtn" onclick="paginate(1)">Next</button>
957
+ <button class="pg-btn" id="nextBtn">Next</button>
958
958
  </div>
959
959
  </div>
960
960
 
961
961
  <script>
962
- let currentTab = 'summaries', currentOffset = 0;
963
- const PAGE_SIZE = 15;
962
+ (function(){
963
+ var currentTab = "summaries";
964
+ var currentOffset = 0;
965
+ var PAGE_SIZE = 15;
964
966
 
965
- async function api(path) {
966
- try {
967
- const res = await fetch(path);
968
- if (!res.ok) return [];
969
- return res.json();
970
- } catch { return []; }
971
- }
972
-
973
- async function init() {
974
- const [stats, health] = await Promise.all([api('/api/stats'), api('/api/health')]);
975
-
976
- document.getElementById('stats').innerHTML = [
977
- {k:'sessions',icon:'S'}, {k:'entities',icon:'E'}, {k:'summaries',icon:'M'}, {k:'notes',icon:'N'}
978
- ].map(({k}) =>
979
- '<div class="stat-card"><div class="stat-value">'+(stats[k]||0)+'</div><div class="stat-label">'+k+'</div></div>'
980
- ).join('');
981
-
982
- document.getElementById('cnt-summaries').textContent = stats.summaries || '';
983
- document.getElementById('cnt-sessions').textContent = stats.sessions || '';
984
- document.getElementById('cnt-entities').textContent = stats.entities || '';
985
-
986
- if (health.checks) {
987
- document.getElementById('health').innerHTML = health.checks.map(function(c) {
988
- return '<span class="badge badge-'+c.status+'">'+c.component+'</span>';
989
- }).join('');
967
+ function api(path) {
968
+ return fetch(path).then(function(r){ return r.ok ? r.json() : []; }).catch(function(){ return []; });
990
969
  }
991
970
 
992
- loadTab();
993
- }
971
+ function fmtDate(epoch) {
972
+ if (!epoch) return "N/A";
973
+ var d = new Date(epoch);
974
+ return d.toLocaleDateString("en-US", {month:"short",day:"numeric"}) + " " + d.toLocaleTimeString("en-US", {hour:"2-digit",minute:"2-digit"});
975
+ }
994
976
 
995
- function switchTab(tab, btn) {
996
- currentTab = tab;
997
- currentOffset = 0;
998
- document.querySelectorAll('.tab').forEach(function(b){b.classList.remove('active')});
999
- btn.classList.add('active');
1000
- loadTab();
1001
- }
977
+ function esc(s) { var d = document.createElement("div"); d.textContent = s || ""; return d.innerHTML; }
1002
978
 
1003
- async function loadTab() {
1004
- var results = document.getElementById('results');
1005
- results.innerHTML = '<div class="empty"><div class="empty-icon">...</div><div class="empty-text">Loading</div></div>';
979
+ function updatePagination(count) {
980
+ document.getElementById("prevBtn").disabled = currentOffset === 0;
981
+ document.getElementById("nextBtn").disabled = count < PAGE_SIZE;
982
+ document.getElementById("pageInfo").textContent = "Page " + (Math.floor(currentOffset / PAGE_SIZE) + 1);
983
+ }
1006
984
 
1007
- var data = await api('/api/' + currentTab + '?limit=' + PAGE_SIZE + '&offset=' + currentOffset);
985
+ function renderCards(data) {
986
+ if (currentTab === "summaries") {
987
+ return data.map(function(s) {
988
+ var preview = (s.summary || "").slice(0, 400);
989
+ return '<div class="card"><div class="card-header"><span class="card-type type-summary">summary</span><div class="card-meta"><span>' + fmtDate(s.created_at) + '</span><span>' + esc(s.project) + '</span><span>' + esc(s.session_id || "").slice(0,8) + '</span></div></div><div class="card-content">' + esc(preview) + '</div></div>';
990
+ }).join("");
991
+ }
992
+ if (currentTab === "sessions") {
993
+ return data.map(function(s) {
994
+ var cls = s.status === "completed" ? "type-summary" : s.status === "failed" ? "type-error" : "type-session";
995
+ return '<div class="card"><div class="card-header"><span class="card-type ' + cls + '">' + esc(s.status) + '</span><div class="card-meta"><span>' + fmtDate(s.started_at) + '</span><span>' + esc(s.project) + '</span><span>' + esc(s.id || "").slice(0,12) + '</span></div></div><div class="card-content">' + esc(s.user_prompt || "(no prompt)") + '</div></div>';
996
+ }).join("");
997
+ }
998
+ return data.map(function(e) {
999
+ return '<div class="card"><div class="card-header"><span class="card-type type-' + (e.entity_type || "entity") + '">' + esc(e.entity_type) + '</span><div class="card-meta"><span>' + fmtDate(e.created_at) + '</span><span>' + esc(e.tool_name) + '</span><span>imp: ' + e.importance + '</span></div></div><div class="card-content">' + esc(e.entity_value) + (e.context ? "\\n" + esc(e.context) : "") + '</div></div>';
1000
+ }).join("");
1001
+ }
1008
1002
 
1009
- if (!data || data.length === 0 || data.error) {
1010
- results.innerHTML = '<div class="empty"><div class="empty-icon">O</div><div class="empty-text">'+(data&&data.error ? esc(data.error) : 'No data yet')+'</div></div>';
1011
- updatePagination(0);
1012
- return;
1003
+ function loadTab() {
1004
+ var el = document.getElementById("results");
1005
+ el.innerHTML = '<div class="empty"><div class="empty-text">Loading...</div></div>';
1006
+ api("/api/" + currentTab + "?limit=" + PAGE_SIZE + "&offset=" + currentOffset).then(function(data) {
1007
+ if (!data || data.length === 0 || data.error) {
1008
+ el.innerHTML = '<div class="empty"><div class="empty-text">' + (data && data.error ? esc(data.error) : "No data yet.") + '</div></div>';
1009
+ updatePagination(0);
1010
+ return;
1011
+ }
1012
+ el.innerHTML = renderCards(data);
1013
+ updatePagination(data.length);
1014
+ el.querySelectorAll(".card-content").forEach(function(c){ c.addEventListener("click", function(){ this.classList.toggle("expanded"); }); });
1015
+ });
1013
1016
  }
1014
1017
 
1015
- if (currentTab === 'summaries') {
1016
- results.innerHTML = data.map(function(s) {
1017
- var preview = (s.summary||'').slice(0, 300);
1018
- return '<div class="card"><div class="card-header"><span class="card-type type-summary">summary</span><div class="card-meta"><span>'+fmtDate(s.created_at)+'</span><span>'+esc(s.project)+'</span><span>'+esc(s.session_id||'').slice(0,8)+'</span></div></div><div class="card-content" onclick="this.classList.toggle('expanded')">'+esc(preview)+'</div>'+(s.summary&&s.summary.length>300?'<button class="card-expand" onclick="this.previousElementSibling.classList.toggle('expanded')">Show more</button>':'')+'</div>';
1019
- }).join('');
1020
- } else if (currentTab === 'sessions') {
1021
- results.innerHTML = data.map(function(s) {
1022
- var statusCls = s.status==='completed'?'type-summary':s.status==='failed'?'type-error':'type-session';
1023
- return '<div class="card"><div class="card-header"><span class="card-type '+statusCls+'">'+esc(s.status)+'</span><div class="card-meta"><span>'+fmtDate(s.started_at)+'</span><span>'+esc(s.project)+'</span><span>'+esc(s.id||'').slice(0,12)+'</span></div></div><div class="card-content">'+esc(s.user_prompt||'(no prompt recorded)')+'</div></div>';
1024
- }).join('');
1025
- } else {
1026
- results.innerHTML = data.map(function(e) {
1027
- var typeCls = 'type-'+(e.entity_type||'entity');
1028
- return '<div class="card"><div class="card-header"><span class="card-type '+typeCls+'">'+esc(e.entity_type)+'</span><div class="card-meta"><span>'+fmtDate(e.created_at)+'</span><span>'+esc(e.tool_name)+'</span><span>imp: '+e.importance+'</span></div></div><div class="card-content">'+esc(e.entity_value)+(e.context?'\\n'+esc(e.context):'')+'</div></div>';
1029
- }).join('');
1018
+ function doSearch() {
1019
+ var q = document.getElementById("searchInput").value.trim();
1020
+ if (!q) { currentOffset = 0; loadTab(); return; }
1021
+ var el = document.getElementById("results");
1022
+ el.innerHTML = '<div class="empty"><div class="empty-text">Searching...</div></div>';
1023
+ api("/api/search?q=" + encodeURIComponent(q) + "&limit=" + PAGE_SIZE).then(function(data) {
1024
+ if (!data || data.length === 0) {
1025
+ el.innerHTML = '<div class="empty"><div class="empty-text">No results for "' + esc(q) + '"</div></div>';
1026
+ return;
1027
+ }
1028
+ el.innerHTML = data.map(function(r) {
1029
+ return '<div class="card"><div class="card-header"><span class="card-type type-' + r.type + '">' + esc(r.type) + "#" + r.id + '</span><div class="card-meta"><span>' + fmtDate(r.created_at) + '</span><span>' + esc(r.project) + '</span><span>score: ' + (r.score || 0).toFixed(2) + '</span></div></div><div class="card-content">' + esc(r.title) + '</div></div>';
1030
+ }).join("");
1031
+ });
1030
1032
  }
1031
- updatePagination(data.length);
1032
- }
1033
1033
 
1034
- async function doSearch() {
1035
- var q = document.getElementById('searchInput').value.trim();
1036
- if (!q) { currentOffset=0; loadTab(); return; }
1034
+ // Tab click handlers
1035
+ document.querySelectorAll("[data-tab]").forEach(function(btn) {
1036
+ btn.addEventListener("click", function() {
1037
+ currentTab = this.getAttribute("data-tab");
1038
+ currentOffset = 0;
1039
+ document.querySelectorAll(".tab").forEach(function(b){ b.classList.remove("active"); });
1040
+ this.classList.add("active");
1041
+ loadTab();
1042
+ });
1043
+ });
1037
1044
 
1038
- var results = document.getElementById('results');
1039
- results.innerHTML = '<div class="empty"><div class="empty-icon">...</div><div class="empty-text">Searching</div></div>';
1045
+ // Pagination
1046
+ document.getElementById("prevBtn").addEventListener("click", function(){ currentOffset = Math.max(0, currentOffset - PAGE_SIZE); loadTab(); });
1047
+ document.getElementById("nextBtn").addEventListener("click", function(){ currentOffset += PAGE_SIZE; loadTab(); });
1040
1048
 
1041
- var data = await api('/api/search?q=' + encodeURIComponent(q) + '&limit=' + PAGE_SIZE);
1042
- if (!data || data.length === 0) {
1043
- results.innerHTML = '<div class="empty"><div class="empty-icon">?</div><div class="empty-text">No results for "'+esc(q)+'"</div></div>';
1044
- return;
1045
- }
1046
- results.innerHTML = data.map(function(r) {
1047
- return '<div class="card"><div class="card-header"><span class="card-type type-'+r.type+'">'+esc(r.type)+'#'+r.id+'</span><div class="card-meta"><span>'+fmtDate(r.created_at)+'</span><span>'+esc(r.project)+'</span><span>score: '+(r.score||0).toFixed(2)+'</span></div></div><div class="card-content">'+esc(r.title)+'</div></div>';
1048
- }).join('');
1049
- }
1049
+ // Search
1050
+ document.getElementById("searchInput").addEventListener("keydown", function(e){ if (e.key === "Enter") doSearch(); });
1050
1051
 
1051
- function paginate(dir) {
1052
- currentOffset = Math.max(0, currentOffset + dir * PAGE_SIZE);
1053
- loadTab();
1054
- }
1052
+ // Init
1053
+ Promise.all([api("/api/stats"), api("/api/health")]).then(function(res) {
1054
+ var stats = res[0], health = res[1];
1055
1055
 
1056
- function updatePagination(count) {
1057
- document.getElementById('prevBtn').disabled = currentOffset === 0;
1058
- document.getElementById('nextBtn').disabled = count < PAGE_SIZE;
1059
- document.getElementById('pageInfo').textContent = 'Page ' + (Math.floor(currentOffset / PAGE_SIZE) + 1);
1060
- }
1056
+ document.getElementById("stats").innerHTML = ["sessions","entities","summaries","notes"].map(function(k) {
1057
+ return '<div class="stat-card"><div class="stat-value">' + (stats[k] || 0) + '</div><div class="stat-label">' + k + '</div></div>';
1058
+ }).join("");
1061
1059
 
1062
- function fmtDate(epoch) {
1063
- if (!epoch) return 'N/A';
1064
- var d = new Date(epoch);
1065
- return d.toLocaleDateString('en-US', {month:'short',day:'numeric'}) + ' ' + d.toLocaleTimeString('en-US', {hour:'2-digit',minute:'2-digit'});
1066
- }
1067
- function esc(s) { var d = document.createElement('div'); d.textContent = s || ''; return d.innerHTML; }
1060
+ var cntS = document.getElementById("cnt-summaries"); if(cntS) cntS.textContent = stats.summaries || "";
1061
+ var cntSe = document.getElementById("cnt-sessions"); if(cntSe) cntSe.textContent = stats.sessions || "";
1062
+ var cntE = document.getElementById("cnt-entities"); if(cntE) cntE.textContent = stats.entities || "";
1068
1063
 
1069
- document.getElementById('searchInput').addEventListener('keydown', function(e) { if (e.key === 'Enter') doSearch(); });
1070
- init();
1064
+ if (health && health.checks) {
1065
+ document.getElementById("health").innerHTML = health.checks.map(function(c) {
1066
+ return '<span class="badge badge-' + c.status + '">' + c.component + '</span>';
1067
+ }).join("");
1068
+ }
1069
+
1070
+ loadTab();
1071
+ });
1072
+ })();
1071
1073
  </script>
1072
1074
  </body>
1073
1075
  </html>`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-memory-hub",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Persistent memory system for Claude Code. Zero API key. Zero Python. 5 hooks + MCP server + SQLite FTS5.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",