claude-code-memory-explorer 0.1.0 → 0.2.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/package.json +27 -2
- package/public/app.js +69 -29
- package/public/index.html +3 -0
- package/public/style.css +28 -13
- package/server.js +34 -0
- package/.claude/commands/release.md +0 -54
- package/.github/workflows/pages.yml +0 -36
- package/CLAUDE.md +0 -49
- package/assets/main-dark.png +0 -0
- package/assets/main-light.png +0 -0
- package/biome.json +0 -33
- package/docs/assets/main-dark.png +0 -0
- package/docs/assets/main-light.png +0 -0
- package/docs/index.html +0 -988
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-memory-explorer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Memory explorer dashboard for Claude Code",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"bin": {
|
|
@@ -22,5 +22,30 @@
|
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"husky": "^9.0.0"
|
|
24
24
|
},
|
|
25
|
-
"
|
|
25
|
+
"keywords": [
|
|
26
|
+
"claude",
|
|
27
|
+
"claude-code",
|
|
28
|
+
"memory",
|
|
29
|
+
"dashboard",
|
|
30
|
+
"anthropic",
|
|
31
|
+
"ai",
|
|
32
|
+
"cli",
|
|
33
|
+
"explorer"
|
|
34
|
+
],
|
|
35
|
+
"homepage": "https://github.com/NikiforovAll/claude-code-memory",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/NikiforovAll/claude-code-memory.git"
|
|
39
|
+
},
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/NikiforovAll/claude-code-memory/issues"
|
|
42
|
+
},
|
|
43
|
+
"author": "NikiforovAll",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"files": [
|
|
46
|
+
"server.js",
|
|
47
|
+
"public/",
|
|
48
|
+
"README.md",
|
|
49
|
+
"LICENSE"
|
|
50
|
+
]
|
|
26
51
|
}
|
package/public/app.js
CHANGED
|
@@ -59,11 +59,13 @@ function highlightSource(text, fileName) {
|
|
|
59
59
|
|
|
60
60
|
function linkifyImports(text, sourceId) {
|
|
61
61
|
if (!stackData.length) return { text, placeholders: [] };
|
|
62
|
-
const byName = Object.fromEntries(stackData.map(c => [c.name, c]));
|
|
62
|
+
const byName = Object.fromEntries(stackData.map((c) => [c.name, c]));
|
|
63
63
|
const placeholders = [];
|
|
64
64
|
const ph = (child, display) => {
|
|
65
65
|
const token = `\x00LINK${placeholders.length}\x00`;
|
|
66
|
-
placeholders.push(
|
|
66
|
+
placeholders.push(
|
|
67
|
+
`<a class="inline-import" href="#" onclick="selectFile('${escJs(child.id)}');return false" title="${esc(child.path)}">${esc(display)}</a>`,
|
|
68
|
+
);
|
|
67
69
|
return token;
|
|
68
70
|
};
|
|
69
71
|
// Replace @path refs with placeholders
|
|
@@ -293,7 +295,9 @@ function getTreeIndex() {
|
|
|
293
295
|
return treeIndex;
|
|
294
296
|
}
|
|
295
297
|
|
|
296
|
-
function invalidateTreeIndex() {
|
|
298
|
+
function invalidateTreeIndex() {
|
|
299
|
+
treeIndex = null;
|
|
300
|
+
}
|
|
297
301
|
|
|
298
302
|
function renderTree() {
|
|
299
303
|
const container = document.getElementById('treeContent');
|
|
@@ -376,9 +380,7 @@ function navigateGroup(direction) {
|
|
|
376
380
|
if (!activeScopes.length) return;
|
|
377
381
|
|
|
378
382
|
const current = stackData.find((s) => s.id === selectedFileId);
|
|
379
|
-
const currentScope = current?.parentId
|
|
380
|
-
? stackData.find((s) => s.id === current.parentId)?.scope
|
|
381
|
-
: current?.scope;
|
|
383
|
+
const currentScope = current?.parentId ? stackData.find((s) => s.id === current.parentId)?.scope : current?.scope;
|
|
382
384
|
let scopeIdx = activeScopes.indexOf(currentScope);
|
|
383
385
|
if (scopeIdx === -1) {
|
|
384
386
|
scopeIdx = direction > 0 ? 0 : activeScopes.length - 1;
|
|
@@ -435,7 +437,7 @@ async function renderPreview() {
|
|
|
435
437
|
html += '</div>';
|
|
436
438
|
|
|
437
439
|
// Imports — only show children (files that have this source as parent)
|
|
438
|
-
const children = stackData.filter(s => s.parentId === source.id);
|
|
440
|
+
const children = stackData.filter((s) => s.parentId === source.id);
|
|
439
441
|
const unresolved = source.unresolvedImports || [];
|
|
440
442
|
if (children.length || unresolved.length) {
|
|
441
443
|
html += '<div class="preview-imports">';
|
|
@@ -516,11 +518,15 @@ function renderBudget() {
|
|
|
516
518
|
document.getElementById('statAlways').textContent = summaryData.alwaysLoaded;
|
|
517
519
|
|
|
518
520
|
// Budget text
|
|
519
|
-
document.getElementById('budgetText').textContent =
|
|
521
|
+
document.getElementById('budgetText').textContent =
|
|
522
|
+
`${summaryData.totalLines.toLocaleString()} lines / ${formatBytes(summaryData.totalBytes)}`;
|
|
520
523
|
|
|
521
524
|
// Budget segments — proportional by lines per scope
|
|
522
525
|
const segContainer = document.getElementById('budgetSegments');
|
|
523
|
-
if (!stackData.length) {
|
|
526
|
+
if (!stackData.length) {
|
|
527
|
+
segContainer.innerHTML = '';
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
524
530
|
|
|
525
531
|
const scopeTotals = {};
|
|
526
532
|
for (const s of stackData) {
|
|
@@ -543,10 +549,7 @@ function renderBudget() {
|
|
|
543
549
|
|
|
544
550
|
async function loadData() {
|
|
545
551
|
try {
|
|
546
|
-
[stackData, summaryData] = await Promise.all([
|
|
547
|
-
fetchJSON('/api/stack'),
|
|
548
|
-
fetchJSON('/api/summary'),
|
|
549
|
-
]);
|
|
552
|
+
[stackData, summaryData] = await Promise.all([fetchJSON('/api/stack'), fetchJSON('/api/summary')]);
|
|
550
553
|
invalidateTreeIndex();
|
|
551
554
|
renderTree();
|
|
552
555
|
renderBudget();
|
|
@@ -556,7 +559,10 @@ async function loadData() {
|
|
|
556
559
|
const auto = proj || user;
|
|
557
560
|
if (auto) selectedFileId = auto.id;
|
|
558
561
|
}
|
|
559
|
-
if (selectedFileId) {
|
|
562
|
+
if (selectedFileId) {
|
|
563
|
+
renderTree();
|
|
564
|
+
renderPreview();
|
|
565
|
+
}
|
|
560
566
|
} catch (err) {
|
|
561
567
|
showToast('Failed to load: ' + err.message, 'error');
|
|
562
568
|
}
|
|
@@ -609,10 +615,22 @@ document.addEventListener('keydown', (e) => {
|
|
|
609
615
|
e.preventDefault();
|
|
610
616
|
changeProject();
|
|
611
617
|
}
|
|
612
|
-
if (e.key === 'j' || e.key === 'ArrowDown') {
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
618
|
+
if (e.key === 'j' || e.key === 'ArrowDown') {
|
|
619
|
+
e.preventDefault();
|
|
620
|
+
navigateTree(1);
|
|
621
|
+
}
|
|
622
|
+
if (e.key === 'k' || e.key === 'ArrowUp') {
|
|
623
|
+
e.preventDefault();
|
|
624
|
+
navigateTree(-1);
|
|
625
|
+
}
|
|
626
|
+
if (e.key === 'h' || e.key === 'ArrowLeft') {
|
|
627
|
+
e.preventDefault();
|
|
628
|
+
navigateGroup(-1);
|
|
629
|
+
}
|
|
630
|
+
if (e.key === 'l' || e.key === 'ArrowRight') {
|
|
631
|
+
e.preventDefault();
|
|
632
|
+
navigateGroup(1);
|
|
633
|
+
}
|
|
616
634
|
if (e.key === 'Enter' && selectedFileId) renderPreview();
|
|
617
635
|
if (e.key === 'e' && selectedFileId) {
|
|
618
636
|
const s = stackData.find((x) => x.id === selectedFileId);
|
|
@@ -624,13 +642,27 @@ document.addEventListener('keydown', (e) => {
|
|
|
624
642
|
|
|
625
643
|
// #region HUB_INTEGRATION
|
|
626
644
|
|
|
627
|
-
async function
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
645
|
+
(async function initHub() {
|
|
646
|
+
const cfg = await fetch('/hub-config')
|
|
647
|
+
.then((r) => r.json())
|
|
648
|
+
.catch(() => ({}));
|
|
649
|
+
if (!cfg.enabled) return;
|
|
650
|
+
window.__HUB__ = cfg;
|
|
651
|
+
document.addEventListener('keydown', (e) => {
|
|
652
|
+
if (e.ctrlKey && e.altKey && (e.key === 'ArrowLeft' || e.key === 'ArrowRight')) {
|
|
653
|
+
e.preventDefault();
|
|
654
|
+
window.parent?.postMessage({ type: 'hub:keydown', key: e.key }, '*');
|
|
655
|
+
}
|
|
656
|
+
if (e.altKey && !e.ctrlKey && !e.shiftKey && !e.metaKey && /^[1-9]$/.test(e.key)) {
|
|
657
|
+
e.preventDefault();
|
|
658
|
+
window.parent?.postMessage({ type: 'hub:keydown', key: e.key }, '*');
|
|
659
|
+
}
|
|
660
|
+
});
|
|
661
|
+
})();
|
|
662
|
+
|
|
663
|
+
function hubNavigate(app, url) {
|
|
664
|
+
if (!window.__HUB__?.enabled) return;
|
|
665
|
+
window.parent?.postMessage({ type: 'hub:navigate', app, url }, '*');
|
|
634
666
|
}
|
|
635
667
|
|
|
636
668
|
// #endregion HUB_INTEGRATION
|
|
@@ -688,7 +720,6 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|
|
688
720
|
loadTheme();
|
|
689
721
|
initResize();
|
|
690
722
|
bindModalKeys('projectPathInput', 'projectPickerModal', submitProjectPicker);
|
|
691
|
-
await detectHub();
|
|
692
723
|
// Handle ?project= query param
|
|
693
724
|
const params = new URLSearchParams(location.search);
|
|
694
725
|
if (params.has('project')) {
|
|
@@ -705,12 +736,21 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|
|
705
736
|
const qs = params.toString();
|
|
706
737
|
history.replaceState(null, '', qs ? `?${qs}` : location.pathname + location.hash);
|
|
707
738
|
}
|
|
708
|
-
|
|
709
|
-
|
|
739
|
+
// Retry initial load — server may not be ready yet (e.g. Hub iframe race)
|
|
740
|
+
for (let attempt = 0; attempt < 5; attempt++) {
|
|
741
|
+
try {
|
|
742
|
+
await loadProject();
|
|
743
|
+
break;
|
|
744
|
+
} catch {
|
|
745
|
+
if (attempt < 4) await new Promise((r) => setTimeout(r, 500));
|
|
746
|
+
else showToast('Failed to connect to server', 'error');
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
if (projectData) addRecentProject(projectData.path);
|
|
710
750
|
await loadData();
|
|
711
751
|
// Restore file selection from hash
|
|
712
752
|
const hash = decodeURIComponent(location.hash.slice(1));
|
|
713
|
-
if (hash && stackData.find(s => s.id === hash)) {
|
|
753
|
+
if (hash && stackData.find((s) => s.id === hash)) {
|
|
714
754
|
selectedFileId = hash;
|
|
715
755
|
renderTree();
|
|
716
756
|
renderPreview();
|
package/public/index.html
CHANGED
|
@@ -40,6 +40,9 @@
|
|
|
40
40
|
<button class="topbar-btn" id="themeBtn" title="Toggle theme (t)" onclick="toggleTheme()">
|
|
41
41
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
|
|
42
42
|
</button>
|
|
43
|
+
<a class="topbar-btn" href="https://github.com/NikiforovAll/claude-code-memory" target="_blank" rel="noopener" title="GitHub">
|
|
44
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
|
|
45
|
+
</a>
|
|
43
46
|
</div>
|
|
44
47
|
|
|
45
48
|
<!-- Size bar -->
|
package/public/style.css
CHANGED
|
@@ -120,7 +120,7 @@ body {
|
|
|
120
120
|
cursor: pointer;
|
|
121
121
|
font-size: 11px;
|
|
122
122
|
font-family: var(--font-mono);
|
|
123
|
-
|
|
123
|
+
white-space: nowrap;
|
|
124
124
|
}
|
|
125
125
|
.topbar-project:hover {
|
|
126
126
|
border-color: var(--accent);
|
|
@@ -130,25 +130,34 @@ body {
|
|
|
130
130
|
flex: 1;
|
|
131
131
|
}
|
|
132
132
|
.topbar-btn {
|
|
133
|
+
display: flex;
|
|
134
|
+
align-items: center;
|
|
135
|
+
gap: 5px;
|
|
133
136
|
padding: 6px 10px;
|
|
134
137
|
border-radius: 6px;
|
|
135
138
|
font-size: 11px;
|
|
136
139
|
font-weight: 500;
|
|
140
|
+
cursor: pointer;
|
|
137
141
|
border: 1px solid var(--border);
|
|
138
142
|
background: var(--bg-elevated);
|
|
139
143
|
color: var(--text-tertiary);
|
|
140
144
|
font-family: var(--font-mono);
|
|
145
|
+
transition: all 0.15s ease;
|
|
146
|
+
white-space: nowrap;
|
|
141
147
|
text-transform: uppercase;
|
|
142
148
|
letter-spacing: 0.03em;
|
|
143
|
-
|
|
144
|
-
display: flex;
|
|
145
|
-
align-items: center;
|
|
146
|
-
gap: 6px;
|
|
149
|
+
text-decoration: none;
|
|
147
150
|
}
|
|
148
151
|
.topbar-btn:hover {
|
|
149
152
|
border-color: var(--accent);
|
|
150
153
|
color: var(--text-secondary);
|
|
151
154
|
}
|
|
155
|
+
.topbar-btn svg {
|
|
156
|
+
color: var(--text-muted);
|
|
157
|
+
}
|
|
158
|
+
.topbar-btn.loading svg {
|
|
159
|
+
animation: spin 1s linear infinite;
|
|
160
|
+
}
|
|
152
161
|
/* #endregion TOPBAR */
|
|
153
162
|
|
|
154
163
|
/* #region BUDGET_BAR */
|
|
@@ -288,9 +297,15 @@ body {
|
|
|
288
297
|
font-family: var(--font-mono);
|
|
289
298
|
flex-shrink: 0;
|
|
290
299
|
}
|
|
291
|
-
.tree-child .file-name {
|
|
292
|
-
|
|
293
|
-
|
|
300
|
+
.tree-child .file-name {
|
|
301
|
+
opacity: 0.75;
|
|
302
|
+
}
|
|
303
|
+
.tree-conditional .file-name {
|
|
304
|
+
opacity: 0.55;
|
|
305
|
+
}
|
|
306
|
+
body.light .tree-conditional .file-name {
|
|
307
|
+
opacity: 0.75;
|
|
308
|
+
}
|
|
294
309
|
/* #endregion TREE */
|
|
295
310
|
|
|
296
311
|
/* #region PREVIEW */
|
|
@@ -752,13 +767,13 @@ kbd {
|
|
|
752
767
|
body.light {
|
|
753
768
|
--bg-deep: #e8e6e3;
|
|
754
769
|
--bg-surface: #f4f3f1;
|
|
755
|
-
--bg-elevated: #
|
|
756
|
-
--bg-hover: #
|
|
757
|
-
--border: #
|
|
770
|
+
--bg-elevated: #dddbd8;
|
|
771
|
+
--bg-hover: #d2d0cc;
|
|
772
|
+
--border: #a09b94;
|
|
758
773
|
--text-primary: #0a0a0a;
|
|
759
|
-
--text-secondary: #
|
|
774
|
+
--text-secondary: #444444;
|
|
760
775
|
--text-tertiary: #666666;
|
|
761
|
-
--text-muted: #
|
|
776
|
+
--text-muted: #888888;
|
|
762
777
|
--accent-text: #b85a20;
|
|
763
778
|
}
|
|
764
779
|
/* #endregion LIGHT_THEME */
|
package/server.js
CHANGED
|
@@ -250,6 +250,38 @@ function discoverMemorySources(projectPath) {
|
|
|
250
250
|
}
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
+
// 4b. Scan subdirectories of projectPath for CLAUDE.md (tree-scoped)
|
|
254
|
+
const SKIP_DIRS = new Set(['node_modules', '.git', '.hg', '.svn', 'dist', 'build', 'out', '.next', '.nuxt', 'vendor', '__pycache__', '.venv', 'venv']);
|
|
255
|
+
function walkForClaudeMd(dir, depth) {
|
|
256
|
+
if (depth > 5) return;
|
|
257
|
+
let entries;
|
|
258
|
+
try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
|
|
259
|
+
for (const entry of entries) {
|
|
260
|
+
if (!entry.isDirectory() || SKIP_DIRS.has(entry.name) || entry.name.startsWith('.')) continue;
|
|
261
|
+
const subdir = path.join(dir, entry.name);
|
|
262
|
+
for (const name of ['CLAUDE.md', '.claude/CLAUDE.md']) {
|
|
263
|
+
const filePath = path.join(subdir, name);
|
|
264
|
+
if (seenPaths.has(filePath)) continue;
|
|
265
|
+
const info = fileInfo(filePath);
|
|
266
|
+
if (!info) continue;
|
|
267
|
+
seenPaths.add(filePath);
|
|
268
|
+
const rel = path.relative(projectPath, subdir).replace(/\\/g, '/');
|
|
269
|
+
sources.push({
|
|
270
|
+
id: `project-claude-md-${subdir.replace(/[^a-zA-Z0-9]/g, '-')}`,
|
|
271
|
+
name: `${rel}/${name.includes('/') ? '.claude/CLAUDE.md' : 'CLAUDE.md'}`,
|
|
272
|
+
scope: 'project',
|
|
273
|
+
load: 'tree',
|
|
274
|
+
...info,
|
|
275
|
+
dir: subdir,
|
|
276
|
+
isProjectRoot: false,
|
|
277
|
+
...spreadImports(info.path, info.content),
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
walkForClaudeMd(subdir, depth + 1);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
walkForClaudeMd(projectPath, 0);
|
|
284
|
+
|
|
253
285
|
// 5. Project rules (.claude/rules/*.md)
|
|
254
286
|
const projectRulesDir = path.join(projectPath, '.claude', 'rules');
|
|
255
287
|
if (fs.existsSync(projectRulesDir)) {
|
|
@@ -439,6 +471,8 @@ app.get('/hub-config', (_req, res) => {
|
|
|
439
471
|
name: 'Claude Code Memory',
|
|
440
472
|
icon: 'brain',
|
|
441
473
|
description: 'Explore Claude Code memory sources',
|
|
474
|
+
enabled: !!process.env.CLAUDE_HUB,
|
|
475
|
+
url: process.env.HUB_URL || null,
|
|
442
476
|
});
|
|
443
477
|
});
|
|
444
478
|
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Bump version, tag, push, and create a GitHub release with auto-generated notes
|
|
3
|
-
argument-hint: "[version e.g. 1.13.0 or rc4]"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Release
|
|
7
|
-
|
|
8
|
-
Create a new release for this project.
|
|
9
|
-
|
|
10
|
-
## Inputs
|
|
11
|
-
|
|
12
|
-
- `$ARGUMENTS` — target version or shorthand. Examples:
|
|
13
|
-
- `1.13.0` — full version
|
|
14
|
-
- `rc4` — shorthand for next RC (e.g. if current is `1.19.0-rc.3`, becomes `1.19.0-rc.4`)
|
|
15
|
-
- If not provided, ask the user.
|
|
16
|
-
|
|
17
|
-
## Steps
|
|
18
|
-
|
|
19
|
-
1. **Determine version**: Use `$ARGUMENTS` or ask user. Handle `rc<N>` shorthand by reading current version from `package.json` and replacing/appending the RC suffix. Validate it's different from the current version.
|
|
20
|
-
|
|
21
|
-
2. **Detect prerelease**: If version contains `-rc.`, `-alpha.`, `-beta.`, treat as prerelease.
|
|
22
|
-
|
|
23
|
-
3. **Check working tree**: Run `git status`. If there are uncommitted changes, warn the user and stop.
|
|
24
|
-
|
|
25
|
-
4. **Bump version**:
|
|
26
|
-
```
|
|
27
|
-
npm version <version> --no-git-tag-version
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
5. **Commit & push** (push to current branch, not hardcoded `main`):
|
|
31
|
-
```
|
|
32
|
-
git add package.json package-lock.json
|
|
33
|
-
git commit -m "🔖 chore: Bump version to <version>"
|
|
34
|
-
git push origin HEAD
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
6. **Tag & push tag**:
|
|
38
|
-
```
|
|
39
|
-
git tag v<version>
|
|
40
|
-
git push origin v<version>
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
7. **Generate release notes**: Collect commits since the previous tag using `git log --oneline <prev-tag>..HEAD`. Write a **user-facing summary** grouped by:
|
|
44
|
-
- Features (✨) — describe what was added, not raw commit messages
|
|
45
|
-
- Fixes (🐛)
|
|
46
|
-
- Other notable changes
|
|
47
|
-
Include a "Full Changelog" compare link at the bottom.
|
|
48
|
-
|
|
49
|
-
8. **Create GitHub release** (add `--prerelease` flag for RC/alpha/beta):
|
|
50
|
-
```
|
|
51
|
-
gh release create v<version> --title "v<version>" --notes "<notes>" [--prerelease]
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
9. **Report**: Show the release URL to the user.
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
name: Deploy static site to Pages
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: ["main", "master"]
|
|
6
|
-
paths:
|
|
7
|
-
- "docs/**"
|
|
8
|
-
workflow_dispatch:
|
|
9
|
-
|
|
10
|
-
permissions:
|
|
11
|
-
contents: read
|
|
12
|
-
pages: write
|
|
13
|
-
id-token: write
|
|
14
|
-
|
|
15
|
-
concurrency:
|
|
16
|
-
group: "pages"
|
|
17
|
-
cancel-in-progress: false
|
|
18
|
-
|
|
19
|
-
jobs:
|
|
20
|
-
deploy:
|
|
21
|
-
environment:
|
|
22
|
-
name: github-pages
|
|
23
|
-
url: ${{ steps.deployment.outputs.page_url }}
|
|
24
|
-
runs-on: ubuntu-latest
|
|
25
|
-
steps:
|
|
26
|
-
- name: Checkout
|
|
27
|
-
uses: actions/checkout@v4
|
|
28
|
-
- name: Setup Pages
|
|
29
|
-
uses: actions/configure-pages@v5
|
|
30
|
-
- name: Upload artifact
|
|
31
|
-
uses: actions/upload-pages-artifact@v3
|
|
32
|
-
with:
|
|
33
|
-
path: "docs"
|
|
34
|
-
- name: Deploy to GitHub Pages
|
|
35
|
-
id: deployment
|
|
36
|
-
uses: actions/deploy-pages@v4
|
package/CLAUDE.md
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# CLAUDE.md
|
|
2
|
-
|
|
3
|
-
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
-
|
|
5
|
-
## What This Is
|
|
6
|
-
|
|
7
|
-
Dashboard for visualizing all memory sources that influence Claude Code behavior. Shows the full memory stack: CLAUDE.md files (user/project/local), rules (`.claude/rules/*.md` with optional path-scoped frontmatter), auto memory (`~/.claude/projects/<encoded>/memory/`), and `@import` chains.
|
|
8
|
-
|
|
9
|
-
## Commands
|
|
10
|
-
|
|
11
|
-
- `npm start` — run server (port 3459)
|
|
12
|
-
- `npm run dev` — run with auto-open browser
|
|
13
|
-
- `npx @biomejs/biome check public/app.js public/style.css` — lint
|
|
14
|
-
- `npx @biomejs/biome format --write public/app.js public/style.css` — format
|
|
15
|
-
|
|
16
|
-
## Architecture
|
|
17
|
-
|
|
18
|
-
Single-file Express backend + vanilla JS frontend. No build step, no framework.
|
|
19
|
-
|
|
20
|
-
- **`server.js`** — Express server with two main responsibilities:
|
|
21
|
-
1. **Filesystem scanning** (`discoverMemorySources`) — walks `~/.claude/`, ancestor directories, project `.claude/rules/`, and auto memory dirs to build the full memory source stack
|
|
22
|
-
2. **API endpoints** — `/api/stack`, `/api/summary`, `/api/file`, `/api/rules/match`, `/api/imports` etc.
|
|
23
|
-
- **`public/app.js`** — SPA with tree panel (left) + preview panel (right) split layout. Fetches from API, renders tree grouped by scope, shows syntax-highlighted preview with frontmatter badges and clickable `@import` links.
|
|
24
|
-
- **`public/style.css`** — CSS variables on `:root` (dark default), `body.light` overrides. Scope colors: user=blue, project=green, local=yellow, rule=purple, memory=orange, policy=red.
|
|
25
|
-
|
|
26
|
-
Both JS files use `// #region` / `// #endregion` markers for code organization.
|
|
27
|
-
|
|
28
|
-
## Key Server Concepts
|
|
29
|
-
|
|
30
|
-
- **Project path encoding**: Claude Code stores auto memory in `~/.claude/projects/<encoded-path>/memory/`. The encoding replaces `/` with `-` and strips `:` from drive letters. `findMemoryDir()` tries exact match first, falls back to substring matching.
|
|
31
|
-
- **Import resolution**: `@path/to/file.md` references are parsed from content. `resolveExistingImports()` resolves paths and filters out non-existent files. Imported files are recursively added to the stack (max 5 levels).
|
|
32
|
-
- **Frontmatter parsing**: YAML frontmatter in rules files (`paths`, `type`, `name`, `description`) determines conditional loading. `parseFrontmatter()` handles both inline values and YAML array syntax.
|
|
33
|
-
- **Rules matching**: `micromatch` glob matching against rule `paths` frontmatter via `/api/rules/match?file=`.
|
|
34
|
-
- **Cache**: 30-second TTL on `discoverMemorySources` results, cleared on project switch or manual refresh.
|
|
35
|
-
|
|
36
|
-
## Conventions
|
|
37
|
-
|
|
38
|
-
- Dark theme default, light theme via `body.light` class
|
|
39
|
-
- Accent color: `#e86f33`
|
|
40
|
-
- Fonts: IBM Plex Mono (data/code), Playfair Display (headings)
|
|
41
|
-
- Keyboard-driven: j/k navigation, t=theme, r=refresh, e=open in editor, ?=help
|
|
42
|
-
- Port 3459 (cost=3458, marketplace=3460)
|
|
43
|
-
- `zoom: 1.25` on body for proportional scaling
|
|
44
|
-
- No token/context budget estimation — only line/byte counts (deliberate decision)
|
|
45
|
-
|
|
46
|
-
## Prior Art
|
|
47
|
-
|
|
48
|
-
- `../claude-code-cost` — same stack, data visualization patterns
|
|
49
|
-
- `../claude-code-marketplace` — file tree, markdown preview, project picker, Highlight.js usage
|
package/assets/main-dark.png
DELETED
|
Binary file
|
package/assets/main-light.png
DELETED
|
Binary file
|
package/biome.json
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://biomejs.dev/schemas/2.4.10/schema.json",
|
|
3
|
-
"formatter": {
|
|
4
|
-
"enabled": true,
|
|
5
|
-
"indentStyle": "space",
|
|
6
|
-
"indentWidth": 2,
|
|
7
|
-
"lineWidth": 120
|
|
8
|
-
},
|
|
9
|
-
"linter": {
|
|
10
|
-
"enabled": true,
|
|
11
|
-
"rules": {
|
|
12
|
-
"style": {
|
|
13
|
-
"noDescendingSpecificity": "off"
|
|
14
|
-
},
|
|
15
|
-
"suspicious": {
|
|
16
|
-
"useIterableCallbackReturn": "off"
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
"javascript": {
|
|
21
|
-
"formatter": {
|
|
22
|
-
"quoteStyle": "single"
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
"css": {
|
|
26
|
-
"formatter": {
|
|
27
|
-
"quoteStyle": "single"
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
"files": {
|
|
31
|
-
"includes": ["public/app.js", "public/style.css"]
|
|
32
|
-
}
|
|
33
|
-
}
|
|
Binary file
|
|
Binary file
|