repomemory 1.0.4 → 1.1.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.
- package/.claude-plugin/plugin.json +2 -2
- package/README.md +93 -34
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +20 -0
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/dashboard.d.ts.map +1 -1
- package/dist/commands/dashboard.js +282 -36
- package/dist/commands/dashboard.js.map +1 -1
- package/dist/commands/go.d.ts +6 -0
- package/dist/commands/go.d.ts.map +1 -0
- package/dist/commands/go.js +165 -0
- package/dist/commands/go.js.map +1 -0
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +18 -9
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/setup.js +7 -1
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +3 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/wizard.d.ts.map +1 -1
- package/dist/commands/wizard.js +2 -0
- package/dist/commands/wizard.js.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts +9 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +8 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/context-store.d.ts.map +1 -1
- package/dist/lib/context-store.js +2 -1
- package/dist/lib/context-store.js.map +1 -1
- package/dist/lib/embeddings.d.ts +27 -0
- package/dist/lib/embeddings.d.ts.map +1 -0
- package/dist/lib/embeddings.js +100 -0
- package/dist/lib/embeddings.js.map +1 -0
- package/dist/lib/search.d.ts +9 -1
- package/dist/lib/search.d.ts.map +1 -1
- package/dist/lib/search.js +208 -16
- package/dist/lib/search.js.map +1 -1
- package/dist/mcp/server.d.ts +26 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +322 -43
- package/dist/mcp/server.js.map +1 -1
- package/package.json +1 -1
- package/server.json +11 -7
- package/skills/repomemory/SKILL.md +7 -4
- package/skills/session-end/SKILL.md +19 -0
- package/skills/session-start/SKILL.md +14 -0
|
@@ -3,6 +3,7 @@ import { createServer } from "http";
|
|
|
3
3
|
import { exec } from "child_process";
|
|
4
4
|
import { loadConfig } from "../lib/config.js";
|
|
5
5
|
import { ContextStore } from "../lib/context-store.js";
|
|
6
|
+
import { SearchIndex } from "../lib/search.js";
|
|
6
7
|
export async function dashboardCommand(options) {
|
|
7
8
|
const repoRoot = options.dir || process.cwd();
|
|
8
9
|
const port = parseInt(options.port || "3333");
|
|
@@ -12,10 +13,71 @@ export async function dashboardCommand(options) {
|
|
|
12
13
|
console.log(chalk.red("\u2717 No .context/ directory found. Run `repomemory init` first."));
|
|
13
14
|
process.exit(1);
|
|
14
15
|
}
|
|
16
|
+
// Initialize search index for server-side search
|
|
17
|
+
let searchIndex = null;
|
|
18
|
+
try {
|
|
19
|
+
searchIndex = new SearchIndex(store.path, store);
|
|
20
|
+
await searchIndex.rebuild();
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// Search will fall back to client-side filtering
|
|
24
|
+
}
|
|
15
25
|
const server = createServer((req, res) => {
|
|
16
26
|
const url = new URL(req.url || "/", `http://localhost:${port}`);
|
|
27
|
+
// CORS preflight
|
|
28
|
+
if (req.method === "OPTIONS") {
|
|
29
|
+
res.writeHead(204, {
|
|
30
|
+
"Access-Control-Allow-Origin": "*",
|
|
31
|
+
"Access-Control-Allow-Methods": "GET, PUT, OPTIONS",
|
|
32
|
+
"Access-Control-Allow-Headers": "Content-Type",
|
|
33
|
+
});
|
|
34
|
+
res.end();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
17
37
|
// API: return JSON data
|
|
18
38
|
if (url.pathname === "/api/entries") {
|
|
39
|
+
if (req.method === "PUT") {
|
|
40
|
+
// Edit an entry
|
|
41
|
+
const MAX_BODY_SIZE = 5 * 1024 * 1024; // 5MB
|
|
42
|
+
let body = "";
|
|
43
|
+
let bodyTooLarge = false;
|
|
44
|
+
req.on("data", (chunk) => {
|
|
45
|
+
body += chunk;
|
|
46
|
+
if (body.length > MAX_BODY_SIZE) {
|
|
47
|
+
bodyTooLarge = true;
|
|
48
|
+
res.writeHead(413, { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" });
|
|
49
|
+
res.end(JSON.stringify({ error: "Request body too large (max 5MB)" }));
|
|
50
|
+
req.destroy();
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
req.on("end", async () => {
|
|
54
|
+
if (bodyTooLarge)
|
|
55
|
+
return;
|
|
56
|
+
try {
|
|
57
|
+
const { category, filename, content } = JSON.parse(body);
|
|
58
|
+
if (!category || !filename || content === undefined || content === null) {
|
|
59
|
+
res.writeHead(400, { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" });
|
|
60
|
+
res.end(JSON.stringify({ error: "Missing required fields: category, filename, and content" }));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const writtenPath = store.writeEntry(category, filename, content);
|
|
64
|
+
// Update search index — match by relativePath since filename gets sanitized
|
|
65
|
+
if (searchIndex) {
|
|
66
|
+
const entries = store.listEntries(category);
|
|
67
|
+
const entry = entries.find((e) => e.relativePath === writtenPath);
|
|
68
|
+
if (entry)
|
|
69
|
+
await searchIndex.indexEntry(entry);
|
|
70
|
+
}
|
|
71
|
+
res.writeHead(200, { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" });
|
|
72
|
+
res.end(JSON.stringify({ success: true }));
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
res.writeHead(400, { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" });
|
|
76
|
+
res.end(JSON.stringify({ error: e.message }));
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
19
81
|
const category = url.searchParams.get("category") || undefined;
|
|
20
82
|
const entries = store.listEntries(category);
|
|
21
83
|
res.writeHead(200, { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" });
|
|
@@ -30,6 +92,31 @@ export async function dashboardCommand(options) {
|
|
|
30
92
|
}))));
|
|
31
93
|
return;
|
|
32
94
|
}
|
|
95
|
+
if (url.pathname === "/api/search") {
|
|
96
|
+
const query = url.searchParams.get("q") || "";
|
|
97
|
+
const category = url.searchParams.get("category") || undefined;
|
|
98
|
+
if (!query || query.length < 2) {
|
|
99
|
+
res.writeHead(200, { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" });
|
|
100
|
+
res.end(JSON.stringify([]));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
(async () => {
|
|
104
|
+
try {
|
|
105
|
+
if (!searchIndex) {
|
|
106
|
+
searchIndex = new SearchIndex(store.path, store);
|
|
107
|
+
await searchIndex.rebuild();
|
|
108
|
+
}
|
|
109
|
+
const results = await searchIndex.search(query, category, 20);
|
|
110
|
+
res.writeHead(200, { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" });
|
|
111
|
+
res.end(JSON.stringify(results));
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
res.writeHead(200, { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" });
|
|
115
|
+
res.end(JSON.stringify([]));
|
|
116
|
+
}
|
|
117
|
+
})();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
33
120
|
if (url.pathname === "/api/stats") {
|
|
34
121
|
const stats = store.getStats();
|
|
35
122
|
res.writeHead(200, { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" });
|
|
@@ -67,6 +154,7 @@ function buildDashboardHTML(provider, model) {
|
|
|
67
154
|
<meta charset="UTF-8">
|
|
68
155
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
69
156
|
<title>repomemory dashboard</title>
|
|
157
|
+
<script src="https://cdn.jsdelivr.net/npm/marked@15/marked.min.js"></script>
|
|
70
158
|
<style>
|
|
71
159
|
:root {
|
|
72
160
|
--bg: #0a0a0f;
|
|
@@ -80,6 +168,7 @@ function buildDashboardHTML(provider, model) {
|
|
|
80
168
|
--warn: #f0b040;
|
|
81
169
|
--danger: #f85149;
|
|
82
170
|
--purple: #bc8cff;
|
|
171
|
+
--pink: #e88fcf;
|
|
83
172
|
--radius: 12px;
|
|
84
173
|
}
|
|
85
174
|
|
|
@@ -122,8 +211,24 @@ function buildDashboardHTML(provider, model) {
|
|
|
122
211
|
.header .meta {
|
|
123
212
|
color: var(--text-dim);
|
|
124
213
|
font-size: 13px;
|
|
214
|
+
display: flex;
|
|
215
|
+
gap: 12px;
|
|
216
|
+
align-items: center;
|
|
125
217
|
}
|
|
126
218
|
|
|
219
|
+
.header .export-btn {
|
|
220
|
+
background: var(--surface2);
|
|
221
|
+
border: 1px solid var(--border);
|
|
222
|
+
color: var(--text-dim);
|
|
223
|
+
padding: 6px 14px;
|
|
224
|
+
border-radius: 8px;
|
|
225
|
+
font-size: 12px;
|
|
226
|
+
cursor: pointer;
|
|
227
|
+
transition: all 0.15s;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.header .export-btn:hover { border-color: var(--accent); color: var(--text); }
|
|
231
|
+
|
|
127
232
|
.search-bar {
|
|
128
233
|
margin: 24px 32px;
|
|
129
234
|
position: relative;
|
|
@@ -141,9 +246,7 @@ function buildDashboardHTML(provider, model) {
|
|
|
141
246
|
transition: border-color 0.2s;
|
|
142
247
|
}
|
|
143
248
|
|
|
144
|
-
.search-bar input:focus {
|
|
145
|
-
border-color: var(--accent);
|
|
146
|
-
}
|
|
249
|
+
.search-bar input:focus { border-color: var(--accent); }
|
|
147
250
|
|
|
148
251
|
.search-bar .icon {
|
|
149
252
|
position: absolute;
|
|
@@ -208,10 +311,7 @@ function buildDashboardHTML(provider, model) {
|
|
|
208
311
|
border-left: 3px solid transparent;
|
|
209
312
|
}
|
|
210
313
|
|
|
211
|
-
.sidebar .cat-btn:hover {
|
|
212
|
-
background: var(--surface);
|
|
213
|
-
color: var(--text);
|
|
214
|
-
}
|
|
314
|
+
.sidebar .cat-btn:hover { background: var(--surface); color: var(--text); }
|
|
215
315
|
|
|
216
316
|
.sidebar .cat-btn.active {
|
|
217
317
|
background: var(--surface);
|
|
@@ -229,14 +329,9 @@ function buildDashboardHTML(provider, model) {
|
|
|
229
329
|
border-radius: 99px;
|
|
230
330
|
}
|
|
231
331
|
|
|
232
|
-
.content {
|
|
233
|
-
padding: 20px 32px;
|
|
234
|
-
}
|
|
332
|
+
.content { padding: 20px 32px; }
|
|
235
333
|
|
|
236
|
-
.entry-grid {
|
|
237
|
-
display: grid;
|
|
238
|
-
gap: 12px;
|
|
239
|
-
}
|
|
334
|
+
.entry-grid { display: grid; gap: 12px; }
|
|
240
335
|
|
|
241
336
|
.entry-card {
|
|
242
337
|
background: var(--surface);
|
|
@@ -247,10 +342,7 @@ function buildDashboardHTML(provider, model) {
|
|
|
247
342
|
transition: all 0.15s;
|
|
248
343
|
}
|
|
249
344
|
|
|
250
|
-
.entry-card:hover {
|
|
251
|
-
border-color: var(--accent);
|
|
252
|
-
transform: translateY(-1px);
|
|
253
|
-
}
|
|
345
|
+
.entry-card:hover { border-color: var(--accent); transform: translateY(-1px); }
|
|
254
346
|
|
|
255
347
|
.entry-card .card-header {
|
|
256
348
|
display: flex;
|
|
@@ -259,10 +351,7 @@ function buildDashboardHTML(provider, model) {
|
|
|
259
351
|
margin-bottom: 8px;
|
|
260
352
|
}
|
|
261
353
|
|
|
262
|
-
.entry-card .card-title {
|
|
263
|
-
font-weight: 600;
|
|
264
|
-
font-size: 15px;
|
|
265
|
-
}
|
|
354
|
+
.entry-card .card-title { font-weight: 600; font-size: 15px; }
|
|
266
355
|
|
|
267
356
|
.entry-card .card-meta {
|
|
268
357
|
color: var(--text-dim);
|
|
@@ -285,6 +374,7 @@ function buildDashboardHTML(provider, model) {
|
|
|
285
374
|
.cat-regressions { background: rgba(248, 81, 73, 0.15); color: var(--danger); }
|
|
286
375
|
.cat-sessions { background: rgba(57, 211, 83, 0.15); color: var(--accent2); }
|
|
287
376
|
.cat-changelog { background: rgba(240, 176, 64, 0.15); color: var(--warn); }
|
|
377
|
+
.cat-preferences { background: rgba(232, 143, 207, 0.15); color: var(--pink); }
|
|
288
378
|
|
|
289
379
|
.entry-card .preview {
|
|
290
380
|
color: var(--text-dim);
|
|
@@ -318,8 +408,26 @@ function buildDashboardHTML(provider, model) {
|
|
|
318
408
|
padding: 32px;
|
|
319
409
|
}
|
|
320
410
|
|
|
321
|
-
.detail-panel .
|
|
411
|
+
.detail-panel .detail-actions {
|
|
322
412
|
float: right;
|
|
413
|
+
display: flex;
|
|
414
|
+
gap: 8px;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
.detail-panel .action-btn {
|
|
418
|
+
background: var(--surface2);
|
|
419
|
+
border: 1px solid var(--border);
|
|
420
|
+
color: var(--text-dim);
|
|
421
|
+
padding: 6px 14px;
|
|
422
|
+
border-radius: 8px;
|
|
423
|
+
font-size: 12px;
|
|
424
|
+
cursor: pointer;
|
|
425
|
+
transition: all 0.15s;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.detail-panel .action-btn:hover { border-color: var(--accent); color: var(--text); }
|
|
429
|
+
|
|
430
|
+
.detail-panel .close-btn {
|
|
323
431
|
background: none;
|
|
324
432
|
border: none;
|
|
325
433
|
color: var(--text-dim);
|
|
@@ -361,6 +469,25 @@ function buildDashboardHTML(provider, model) {
|
|
|
361
469
|
}
|
|
362
470
|
.detail-panel .md-content hr { border: none; border-top: 1px solid var(--border); margin: 16px 0; }
|
|
363
471
|
|
|
472
|
+
.edit-area {
|
|
473
|
+
display: none;
|
|
474
|
+
width: 100%;
|
|
475
|
+
min-height: 400px;
|
|
476
|
+
background: var(--bg);
|
|
477
|
+
border: 1px solid var(--border);
|
|
478
|
+
border-radius: 8px;
|
|
479
|
+
padding: 16px;
|
|
480
|
+
color: var(--text);
|
|
481
|
+
font-family: 'SF Mono', 'Cascadia Code', 'Fira Code', monospace;
|
|
482
|
+
font-size: 13px;
|
|
483
|
+
line-height: 1.5;
|
|
484
|
+
resize: vertical;
|
|
485
|
+
outline: none;
|
|
486
|
+
margin-top: 12px;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.edit-area:focus { border-color: var(--accent); }
|
|
490
|
+
|
|
364
491
|
.empty {
|
|
365
492
|
text-align: center;
|
|
366
493
|
color: var(--text-dim);
|
|
@@ -381,7 +508,10 @@ function buildDashboardHTML(provider, model) {
|
|
|
381
508
|
|
|
382
509
|
<div class="header">
|
|
383
510
|
<h1><span class="logo">\u25c9 repomemory</span> <span style="color:var(--text-dim);font-weight:400;font-size:14px">dashboard</span></h1>
|
|
384
|
-
<div class="meta"
|
|
511
|
+
<div class="meta">
|
|
512
|
+
<span>${provider} \u00b7 ${model}</span>
|
|
513
|
+
<button class="export-btn" onclick="exportAll()">\u2913 Export</button>
|
|
514
|
+
</div>
|
|
385
515
|
</div>
|
|
386
516
|
|
|
387
517
|
<div class="search-bar">
|
|
@@ -398,16 +528,23 @@ function buildDashboardHTML(provider, model) {
|
|
|
398
528
|
|
|
399
529
|
<div class="detail-overlay" id="detailOverlay">
|
|
400
530
|
<div class="detail-panel" id="detailPanel">
|
|
401
|
-
<
|
|
531
|
+
<div class="detail-actions">
|
|
532
|
+
<button class="action-btn" id="editBtn" onclick="toggleEdit()">\u270e Edit</button>
|
|
533
|
+
<button class="action-btn" id="saveBtn" style="display:none;color:var(--accent2)" onclick="saveEdit()">\u2713 Save</button>
|
|
534
|
+
<button class="close-btn" onclick="closeDetail()">\u00d7</button>
|
|
535
|
+
</div>
|
|
402
536
|
<h2 id="detailTitle"></h2>
|
|
403
537
|
<div class="card-meta" id="detailMeta" style="margin-bottom:16px"></div>
|
|
404
538
|
<div class="md-content" id="detailContent"></div>
|
|
539
|
+
<textarea class="edit-area" id="editArea"></textarea>
|
|
405
540
|
</div>
|
|
406
541
|
</div>
|
|
407
542
|
|
|
408
543
|
<script>
|
|
409
544
|
let allEntries = [];
|
|
410
545
|
let currentCategory = null;
|
|
546
|
+
let editingEntry = null;
|
|
547
|
+
let searchDebounce = null;
|
|
411
548
|
|
|
412
549
|
async function init() {
|
|
413
550
|
const [entries, stats] = await Promise.all([
|
|
@@ -481,14 +618,69 @@ function showDetail(index) {
|
|
|
481
618
|
const e = filtered[index];
|
|
482
619
|
if (!e) return;
|
|
483
620
|
|
|
621
|
+
editingEntry = e;
|
|
484
622
|
document.getElementById('detailTitle').textContent = e.category + '/' + e.filename;
|
|
485
623
|
document.getElementById('detailMeta').innerHTML = \`<span>\${e.title}</span> · <span>\${(e.sizeBytes/1024).toFixed(1)}KB</span> · <span>\${timeAgo(Date.now() - new Date(e.lastModified).getTime())}</span>\`;
|
|
486
624
|
document.getElementById('detailContent').innerHTML = renderMarkdown(e.content);
|
|
487
625
|
document.getElementById('detailOverlay').classList.add('visible');
|
|
626
|
+
|
|
627
|
+
// Reset edit state
|
|
628
|
+
document.getElementById('editArea').style.display = 'none';
|
|
629
|
+
document.getElementById('detailContent').style.display = 'block';
|
|
630
|
+
document.getElementById('saveBtn').style.display = 'none';
|
|
631
|
+
document.getElementById('editBtn').textContent = '\u270e Edit';
|
|
488
632
|
}
|
|
489
633
|
|
|
490
634
|
function closeDetail() {
|
|
491
635
|
document.getElementById('detailOverlay').classList.remove('visible');
|
|
636
|
+
editingEntry = null;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
function toggleEdit() {
|
|
640
|
+
const editArea = document.getElementById('editArea');
|
|
641
|
+
const content = document.getElementById('detailContent');
|
|
642
|
+
const saveBtn = document.getElementById('saveBtn');
|
|
643
|
+
const editBtn = document.getElementById('editBtn');
|
|
644
|
+
|
|
645
|
+
if (editArea.style.display === 'none') {
|
|
646
|
+
editArea.value = editingEntry.content;
|
|
647
|
+
editArea.style.display = 'block';
|
|
648
|
+
content.style.display = 'none';
|
|
649
|
+
saveBtn.style.display = 'inline-block';
|
|
650
|
+
editBtn.textContent = '\u2715 Cancel';
|
|
651
|
+
editArea.focus();
|
|
652
|
+
} else {
|
|
653
|
+
editArea.style.display = 'none';
|
|
654
|
+
content.style.display = 'block';
|
|
655
|
+
saveBtn.style.display = 'none';
|
|
656
|
+
editBtn.textContent = '\u270e Edit';
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
async function saveEdit() {
|
|
661
|
+
const content = document.getElementById('editArea').value;
|
|
662
|
+
const fname = editingEntry.filename.replace(/\\.md$/, '');
|
|
663
|
+
|
|
664
|
+
try {
|
|
665
|
+
const resp = await fetch('/api/entries', {
|
|
666
|
+
method: 'PUT',
|
|
667
|
+
headers: { 'Content-Type': 'application/json' },
|
|
668
|
+
body: JSON.stringify({
|
|
669
|
+
category: editingEntry.category,
|
|
670
|
+
filename: fname,
|
|
671
|
+
content,
|
|
672
|
+
}),
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
if (!resp.ok) throw new Error('Save failed');
|
|
676
|
+
|
|
677
|
+
editingEntry.content = content;
|
|
678
|
+
document.getElementById('detailContent').innerHTML = renderMarkdown(content);
|
|
679
|
+
toggleEdit();
|
|
680
|
+
init(); // Refresh all entries
|
|
681
|
+
} catch (e) {
|
|
682
|
+
alert('Failed to save: ' + e.message);
|
|
683
|
+
}
|
|
492
684
|
}
|
|
493
685
|
|
|
494
686
|
function getFilteredEntries() {
|
|
@@ -500,8 +692,32 @@ function getFilteredEntries() {
|
|
|
500
692
|
});
|
|
501
693
|
}
|
|
502
694
|
|
|
695
|
+
// Server-side search with debounce
|
|
503
696
|
document.getElementById('searchInput').addEventListener('input', () => {
|
|
504
|
-
|
|
697
|
+
clearTimeout(searchDebounce);
|
|
698
|
+
const q = document.getElementById('searchInput').value;
|
|
699
|
+
|
|
700
|
+
searchDebounce = setTimeout(async () => {
|
|
701
|
+
if (q.length >= 2) {
|
|
702
|
+
try {
|
|
703
|
+
const results = await fetch('/api/search?q=' + encodeURIComponent(q) + (currentCategory ? '&category=' + currentCategory : '')).then(r => r.json());
|
|
704
|
+
if (results.length > 0) {
|
|
705
|
+
const matchedFilenames = new Set(results.map(r => r.filename));
|
|
706
|
+
const filtered = allEntries.filter(e =>
|
|
707
|
+
matchedFilenames.has(e.filename) &&
|
|
708
|
+
(!currentCategory || e.category === currentCategory)
|
|
709
|
+
);
|
|
710
|
+
renderEntries(filtered.length > 0 ? filtered : getFilteredEntries());
|
|
711
|
+
} else {
|
|
712
|
+
renderEntries(getFilteredEntries());
|
|
713
|
+
}
|
|
714
|
+
} catch {
|
|
715
|
+
filterCategory(currentCategory, document.querySelector('.cat-btn.active'));
|
|
716
|
+
}
|
|
717
|
+
} else {
|
|
718
|
+
filterCategory(currentCategory, document.querySelector('.cat-btn.active'));
|
|
719
|
+
}
|
|
720
|
+
}, 300);
|
|
505
721
|
});
|
|
506
722
|
|
|
507
723
|
document.getElementById('detailOverlay').addEventListener('click', (e) => {
|
|
@@ -517,6 +733,14 @@ function escapeHtml(s) {
|
|
|
517
733
|
}
|
|
518
734
|
|
|
519
735
|
function renderMarkdown(md) {
|
|
736
|
+
// Use marked.js if available (loaded from CDN), else fallback to regex
|
|
737
|
+
if (typeof marked !== 'undefined') {
|
|
738
|
+
try { return marked.parse(md); } catch {}
|
|
739
|
+
}
|
|
740
|
+
return regexRenderMarkdown(md);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
function regexRenderMarkdown(md) {
|
|
520
744
|
var html = escapeHtml(md);
|
|
521
745
|
var BT = String.fromCharCode(96);
|
|
522
746
|
var codeBlockRe = new RegExp(BT+BT+BT+'(\\\\w*)?\\\\n([\\\\s\\\\S]*?)'+BT+BT+BT, 'g');
|
|
@@ -524,22 +748,31 @@ function renderMarkdown(md) {
|
|
|
524
748
|
return '<pre><code>' + code.trim() + '</code></pre>';
|
|
525
749
|
});
|
|
526
750
|
var inlineCodeRe = new RegExp(BT+'([^'+BT+']+)'+BT, 'g');
|
|
527
|
-
html = html.replace(inlineCodeRe, '<code
|
|
528
|
-
html = html.replace(/^### (.+)
|
|
529
|
-
html = html.replace(/^## (.+)
|
|
530
|
-
html = html.replace(/^# (.+)
|
|
531
|
-
html = html.replace(/\\*\\*([^*]+)\\*\\*/g, '<strong
|
|
532
|
-
html = html.replace(/\\*([^*]+)\\*/g, '<em
|
|
533
|
-
html = html.replace(/^> (.+)
|
|
534
|
-
html = html.replace(
|
|
535
|
-
html = html.replace(/^- (.+)
|
|
751
|
+
html = html.replace(inlineCodeRe, '<code>$1</code>');
|
|
752
|
+
html = html.replace(/^### (.+)$/gm, '<h3>$1</h3>');
|
|
753
|
+
html = html.replace(/^## (.+)$/gm, '<h2>$1</h2>');
|
|
754
|
+
html = html.replace(/^# (.+)$/gm, '<h1>$1</h1>');
|
|
755
|
+
html = html.replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>');
|
|
756
|
+
html = html.replace(/\\*([^*]+)\\*/g, '<em>$1</em>');
|
|
757
|
+
html = html.replace(/^> (.+)$/gm, '<blockquote>$1</blockquote>');
|
|
758
|
+
html = html.replace(/^---$/gm, '<hr>');
|
|
759
|
+
html = html.replace(/^- (.+)$/gm, '<li>$1</li>');
|
|
536
760
|
html = html.replace(/((<li>.*<\\/li>)\\n?)+/g, function(m) { return '<ul>' + m + '</ul>'; });
|
|
537
|
-
html = html.replace(/^\\d+\\. (.+)
|
|
761
|
+
html = html.replace(/^\\d+\\. (.+)$/gm, '<li>$1</li>');
|
|
538
762
|
html = html.replace(/\\n\\n(?!<)/g, '</p><p>');
|
|
539
763
|
html = html.replace(/\\n(?!<)/g, '<br>');
|
|
540
764
|
return '<p>' + html + '</p>';
|
|
541
765
|
}
|
|
542
766
|
|
|
767
|
+
function exportAll() {
|
|
768
|
+
const blob = new Blob([JSON.stringify(allEntries, null, 2)], { type: 'application/json' });
|
|
769
|
+
const a = document.createElement('a');
|
|
770
|
+
a.href = URL.createObjectURL(blob);
|
|
771
|
+
a.download = 'repomemory-export.json';
|
|
772
|
+
a.click();
|
|
773
|
+
URL.revokeObjectURL(a.href);
|
|
774
|
+
}
|
|
775
|
+
|
|
543
776
|
function timeAgo(ms) {
|
|
544
777
|
const s = Math.floor(ms / 1000);
|
|
545
778
|
if (s < 60) return 'just now';
|
|
@@ -551,6 +784,19 @@ function timeAgo(ms) {
|
|
|
551
784
|
return Math.floor(d/365) + 'y ago';
|
|
552
785
|
}
|
|
553
786
|
|
|
787
|
+
// Real-time polling for changes
|
|
788
|
+
setInterval(async () => {
|
|
789
|
+
try {
|
|
790
|
+
const entries = await fetch('/api/entries').then(r => r.json());
|
|
791
|
+
if (JSON.stringify(entries.map(e => e.lastModified)) !== JSON.stringify(allEntries.map(e => e.lastModified))) {
|
|
792
|
+
allEntries = entries;
|
|
793
|
+
const stats = await fetch('/api/stats').then(r => r.json());
|
|
794
|
+
renderSidebar(stats.categories);
|
|
795
|
+
filterCategory(currentCategory, document.querySelector('.cat-btn.active'));
|
|
796
|
+
}
|
|
797
|
+
} catch {}
|
|
798
|
+
}, 5000);
|
|
799
|
+
|
|
554
800
|
init();
|
|
555
801
|
</script>
|
|
556
802
|
</body>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/commands/dashboard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/commands/dashboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"go.d.ts","sourceRoot":"","sources":["../../src/commands/go.ts"],"names":[],"mappings":"AAWA,wBAAsB,SAAS,CAAC,OAAO,EAAE;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,iBA+JA"}
|