@qiaolei81/copilot-session-viewer 0.1.8 → 0.2.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/.nyc_output/coverage-core-functionality-spec-js-Core-Functionality-Tests-should-be-responsive-on-mobile-viewport-1771605454041.json +435 -0
- package/.nyc_output/coverage-core-functionality-spec-js-Core-Functionality-Tests-should-display-sessions-if-available-1771605462872.json +435 -0
- package/.nyc_output/coverage-core-functionality-spec-js-Core-Functionality-Tests-should-handle-JavaScript-errors-gracefully-1771605463381.json +435 -0
- package/.nyc_output/coverage-core-functionality-spec-js-Core-Functionality-Tests-should-handle-session-import-dialog-1771605466264.json +435 -0
- package/.nyc_output/coverage-core-functionality-spec-js-Core-Functionality-Tests-should-have-working-infinite-scroll-elements-1771605454038.json +435 -0
- package/.nyc_output/coverage-core-functionality-spec-js-Core-Functionality-Tests-should-load-homepage-with-basic-elements-1771605454001.json +435 -0
- package/.nyc_output/coverage-core-functionality-spec-js-Core-Functionality-Tests-should-load-time-analysis-page-1771605464990.json +1236 -0
- package/.nyc_output/coverage-core-functionality-spec-js-Core-Functionality-Tests-should-navigate-to-session-detail-page-1771605472595.json +1177 -0
- package/.nyc_output/coverage-e2e-merged.json +1 -0
- package/.nyc_output/coverage-homepage-spec-js-Homepage-should-display-session-list-1771605453565.json +435 -0
- package/.nyc_output/coverage-homepage-spec-js-Homepage-should-load-homepage-successfully-1771605453552.json +435 -0
- package/.nyc_output/coverage-homepage-spec-js-Homepage-should-navigate-to-session-detail-on-click-1771605469317.json +1134 -0
- package/.nyc_output/coverage-homepage-spec-js-Homepage-should-show-session-metadata-1771605460581.json +435 -0
- package/.nyc_output/coverage-infinite-scroll-spec-js-Infinite-Scroll-should-display-Load-More-Sessions-button-when-there-are-more-sessions-1771605468486.json +435 -0
- package/.nyc_output/coverage-infinite-scroll-spec-js-Infinite-Scroll-should-handle-API-errors-gracefully-during-infinite-scroll-1771605482161.json +471 -0
- package/.nyc_output/coverage-infinite-scroll-spec-js-Infinite-Scroll-should-hide-Load-More-button-when-no-more-sessions-available-1771605478370.json +471 -0
- package/.nyc_output/coverage-infinite-scroll-spec-js-Infinite-Scroll-should-load-additional-sessions-when-Load-More-button-is-clicked-1771605475059.json +471 -0
- package/.nyc_output/coverage-infinite-scroll-spec-js-Infinite-Scroll-should-preserve-session-list-state-during-navigation-1771605494575.json +1633 -0
- package/.nyc_output/coverage-infinite-scroll-spec-js-Infinite-Scroll-should-show-loading-state-when-Load-More-button-is-clicked-1771605475401.json +471 -0
- package/.nyc_output/coverage-infinite-scroll-spec-js-Infinite-Scroll-should-trigger-infinite-scroll-when-scrolling-near-bottom-1771605476949.json +471 -0
- package/.nyc_output/coverage-session-detail-spec-js-Session-Detail-Page-should-clear-search-filter-1771605508542.json +1255 -0
- package/.nyc_output/coverage-session-detail-spec-js-Session-Detail-Page-should-display-event-list-1771605505572.json +1156 -0
- package/.nyc_output/coverage-session-detail-spec-js-Session-Detail-Page-should-display-session-metadata-1771605504552.json +701 -0
- package/.nyc_output/coverage-session-detail-spec-js-Session-Detail-Page-should-expand-and-collapse-tool-details-1771605515809.json +1182 -0
- package/.nyc_output/coverage-session-detail-spec-js-Session-Detail-Page-should-filter-events-by-search-1771605513421.json +1245 -0
- package/.nyc_output/coverage-session-detail-spec-js-Session-Detail-Page-should-load-session-detail-page-1771605494974.json +701 -0
- package/.nyc_output/coverage-session-detail-spec-js-Session-Detail-Page-should-toggle-content-visibility-1771605550729.json +1177 -0
- package/.nyc_output/coverage-unit.json +21 -0
- package/.nycrc +29 -0
- package/CHANGELOG.md +36 -0
- package/README.md +154 -15
- package/examples/parser-usage.js +114 -0
- package/lib/parsers/README.md +239 -0
- package/lib/parsers/base-parser.js +53 -0
- package/lib/parsers/claude-parser.js +181 -0
- package/lib/parsers/copilot-parser.js +143 -0
- package/lib/parsers/index.js +13 -0
- package/lib/parsers/parser-factory.js +77 -0
- package/lib/parsers/pi-mono-parser.js +119 -0
- package/package.json +12 -4
- package/server.js +17 -2
- package/src/app.js +45 -20
- package/src/controllers/insightController.js +44 -8
- package/src/controllers/sessionController.js +217 -3
- package/src/controllers/uploadController.js +447 -7
- package/src/middleware/rateLimiting.js +7 -1
- package/src/models/Session.js +26 -0
- package/src/schemas/event.schema.js +73 -0
- package/src/services/eventNormalizer.js +291 -0
- package/src/services/insightService.js +140 -48
- package/src/services/sessionRepository.js +584 -49
- package/src/services/sessionService.js +1594 -27
- package/src/utils/helpers.js +6 -1
- package/views/index.ejs +111 -4
- package/views/session-vue.ejs +425 -71
- package/views/time-analyze.ejs +140 -57
package/src/utils/helpers.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
function buildMetadata(session) {
|
|
11
11
|
return {
|
|
12
12
|
type: session.type,
|
|
13
|
+
source: session.source, // 'copilot' or 'claude'
|
|
13
14
|
summary: session.summary,
|
|
14
15
|
model: session.model,
|
|
15
16
|
repo: session.workspace?.repository,
|
|
@@ -28,7 +29,11 @@ function buildMetadata(session) {
|
|
|
28
29
|
* @returns {boolean} True if valid
|
|
29
30
|
*/
|
|
30
31
|
function isValidSessionId(sessionId) {
|
|
31
|
-
|
|
32
|
+
// Allow alphanumeric, underscore, and hyphen (common in UUIDs and session IDs)
|
|
33
|
+
// Length limit prevents abuse
|
|
34
|
+
return typeof sessionId === 'string' &&
|
|
35
|
+
/^[a-zA-Z0-9_-]+$/.test(sessionId) &&
|
|
36
|
+
sessionId.length < 256;
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
module.exports = {
|
package/views/index.ejs
CHANGED
|
@@ -280,6 +280,64 @@
|
|
|
280
280
|
border-color: #e8b634;
|
|
281
281
|
border-left-color: #e8b634;
|
|
282
282
|
}
|
|
283
|
+
/* Source badges */
|
|
284
|
+
.status-badge.source-copilot {
|
|
285
|
+
padding: 2px 8px;
|
|
286
|
+
background: rgba(88, 166, 255, 0.15);
|
|
287
|
+
color: #58a6ff;
|
|
288
|
+
border-radius: 12px;
|
|
289
|
+
font-size: 11px;
|
|
290
|
+
font-weight: 600;
|
|
291
|
+
font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
|
|
292
|
+
}
|
|
293
|
+
.status-badge.source-claude {
|
|
294
|
+
padding: 2px 8px;
|
|
295
|
+
background: rgba(204, 120, 92, 0.15);
|
|
296
|
+
color: #e8956f;
|
|
297
|
+
border-radius: 12px;
|
|
298
|
+
font-size: 11px;
|
|
299
|
+
font-weight: 600;
|
|
300
|
+
font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
|
|
301
|
+
}
|
|
302
|
+
.status-badge.source-pi-mono {
|
|
303
|
+
padding: 2px 8px;
|
|
304
|
+
background: rgba(138, 102, 204, 0.15);
|
|
305
|
+
color: #a78bdb;
|
|
306
|
+
border-radius: 12px;
|
|
307
|
+
font-size: 11px;
|
|
308
|
+
font-weight: 600;
|
|
309
|
+
font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/* Filter pills */
|
|
313
|
+
.filter-pills {
|
|
314
|
+
display: flex;
|
|
315
|
+
gap: 8px;
|
|
316
|
+
margin-bottom: 16px;
|
|
317
|
+
flex-wrap: wrap;
|
|
318
|
+
}
|
|
319
|
+
.filter-pill {
|
|
320
|
+
padding: 6px 16px;
|
|
321
|
+
background: #21262d;
|
|
322
|
+
border: 1px solid #30363d;
|
|
323
|
+
border-radius: 20px;
|
|
324
|
+
color: #8b949e;
|
|
325
|
+
font-size: 13px;
|
|
326
|
+
font-weight: 500;
|
|
327
|
+
cursor: pointer;
|
|
328
|
+
transition: all 0.2s;
|
|
329
|
+
min-height: 32px;
|
|
330
|
+
}
|
|
331
|
+
.filter-pill:hover {
|
|
332
|
+
background: #30363d;
|
|
333
|
+
border-color: #58a6ff;
|
|
334
|
+
color: #c9d1d9;
|
|
335
|
+
}
|
|
336
|
+
.filter-pill.active {
|
|
337
|
+
background: #58a6ff;
|
|
338
|
+
border-color: #58a6ff;
|
|
339
|
+
color: #fff;
|
|
340
|
+
}
|
|
283
341
|
|
|
284
342
|
/* Sessions header with import link */
|
|
285
343
|
.sessions-header {
|
|
@@ -384,9 +442,9 @@
|
|
|
384
442
|
<body>
|
|
385
443
|
<div class="container">
|
|
386
444
|
<h1>🤖 Session Viewer</h1>
|
|
387
|
-
<p class="subtitle">View
|
|
445
|
+
<p class="subtitle">View session logs from Copilot, Claude Code, and Pi-Mono</p>
|
|
388
446
|
|
|
389
|
-
<form id="sessionForm"
|
|
447
|
+
<form id="sessionForm">
|
|
390
448
|
<div class="input-group">
|
|
391
449
|
<input
|
|
392
450
|
type="text"
|
|
@@ -412,6 +470,11 @@
|
|
|
412
470
|
</div>
|
|
413
471
|
<a class="import-link" id="importLink">Import session from zip</a>
|
|
414
472
|
</div>
|
|
473
|
+
<div class="filter-pills">
|
|
474
|
+
<button class="filter-pill active" data-source="copilot">Copilot</button>
|
|
475
|
+
<button class="filter-pill" data-source="claude">Claude</button>
|
|
476
|
+
<button class="filter-pill" data-source="pi-mono">Pi</button>
|
|
477
|
+
</div>
|
|
415
478
|
<input
|
|
416
479
|
type="file"
|
|
417
480
|
id="fileInput"
|
|
@@ -449,6 +512,9 @@
|
|
|
449
512
|
let currentOffset = initialSessions.length;
|
|
450
513
|
let hasMore = hasMoreFromServer;
|
|
451
514
|
let isLoading = false;
|
|
515
|
+
|
|
516
|
+
// Filter state
|
|
517
|
+
let currentSourceFilter = 'copilot';
|
|
452
518
|
// Load more sessions
|
|
453
519
|
async function loadMoreSessions() {
|
|
454
520
|
if (isLoading || !hasMore) return;
|
|
@@ -493,14 +559,24 @@
|
|
|
493
559
|
loadMoreSection.style.display = hasMore && !isLoading ? 'block' : 'none';
|
|
494
560
|
}
|
|
495
561
|
|
|
562
|
+
// Get filtered sessions based on current filter
|
|
563
|
+
function getFilteredSessions() {
|
|
564
|
+
return allSessions.filter(session => session.source === currentSourceFilter);
|
|
565
|
+
}
|
|
566
|
+
|
|
496
567
|
// Render all sessions (grouped by date)
|
|
497
568
|
function renderAllSessions() {
|
|
498
569
|
const container = document.getElementById('sessions-container');
|
|
499
570
|
container.innerHTML = ''; // Clear existing
|
|
500
571
|
|
|
501
|
-
|
|
572
|
+
const filteredSessions = getFilteredSessions();
|
|
573
|
+
|
|
574
|
+
if (filteredSessions.length === 0) {
|
|
575
|
+
container.innerHTML = '<div style="text-align: center; color: #6e7681; padding: 40px; font-size: 14px;">No sessions found for this filter.</div>';
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
502
578
|
|
|
503
|
-
const grouped = groupSessionsByDate(
|
|
579
|
+
const grouped = groupSessionsByDate(filteredSessions);
|
|
504
580
|
const sortedDates = Object.keys(grouped).sort((a, b) => b.localeCompare(a)); // Descending
|
|
505
581
|
|
|
506
582
|
sortedDates.forEach(dateKey => {
|
|
@@ -548,6 +624,9 @@
|
|
|
548
624
|
}
|
|
549
625
|
}
|
|
550
626
|
|
|
627
|
+
// Bind form submit event
|
|
628
|
+
document.getElementById('sessionForm').addEventListener('submit', viewSession);
|
|
629
|
+
|
|
551
630
|
// File import handling
|
|
552
631
|
const fileInput = document.getElementById('fileInput');
|
|
553
632
|
const importLink = document.getElementById('importLink');
|
|
@@ -669,6 +748,12 @@
|
|
|
669
748
|
function renderSessionCard(session) {
|
|
670
749
|
// Add status badges
|
|
671
750
|
let badges = '';
|
|
751
|
+
|
|
752
|
+
// Add source badge (use backend-provided metadata - Violation #3 & #5 fix)
|
|
753
|
+
const sourceClass = session.sourceBadgeClass || 'source-copilot';
|
|
754
|
+
const sourceLabel = session.sourceName || 'Copilot';
|
|
755
|
+
badges += `<span class="status-badge ${sourceClass}" title="${sourceLabel} CLI">${sourceLabel}</span>`;
|
|
756
|
+
|
|
672
757
|
if (session.sessionStatus === 'wip') {
|
|
673
758
|
badges += '<span class="status-badge wip" title="Session in progress">🔄 WIP</span>';
|
|
674
759
|
}
|
|
@@ -758,6 +843,25 @@
|
|
|
758
843
|
return div.innerHTML;
|
|
759
844
|
}
|
|
760
845
|
|
|
846
|
+
// Filter pill click handler
|
|
847
|
+
function setupFilterPills() {
|
|
848
|
+
const filterPills = document.querySelectorAll('.filter-pill');
|
|
849
|
+
filterPills.forEach(pill => {
|
|
850
|
+
pill.addEventListener('click', () => {
|
|
851
|
+
// Remove active class from all pills
|
|
852
|
+
filterPills.forEach(p => p.classList.remove('active'));
|
|
853
|
+
// Add active class to clicked pill
|
|
854
|
+
pill.classList.add('active');
|
|
855
|
+
|
|
856
|
+
// Update filter state
|
|
857
|
+
currentSourceFilter = pill.getAttribute('data-source');
|
|
858
|
+
|
|
859
|
+
// Re-render sessions with filter
|
|
860
|
+
renderAllSessions();
|
|
861
|
+
});
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
|
|
761
865
|
// Render grouped sessions
|
|
762
866
|
document.addEventListener('DOMContentLoaded', function() {
|
|
763
867
|
// Initial render
|
|
@@ -769,6 +873,9 @@
|
|
|
769
873
|
|
|
770
874
|
// Add click listener for load more button
|
|
771
875
|
document.getElementById('load-more-btn').addEventListener('click', loadMoreSessions);
|
|
876
|
+
|
|
877
|
+
// Setup filter pills
|
|
878
|
+
setupFilterPills();
|
|
772
879
|
});
|
|
773
880
|
</script>
|
|
774
881
|
|