@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.
Files changed (56) hide show
  1. package/.nyc_output/coverage-core-functionality-spec-js-Core-Functionality-Tests-should-be-responsive-on-mobile-viewport-1771605454041.json +435 -0
  2. package/.nyc_output/coverage-core-functionality-spec-js-Core-Functionality-Tests-should-display-sessions-if-available-1771605462872.json +435 -0
  3. package/.nyc_output/coverage-core-functionality-spec-js-Core-Functionality-Tests-should-handle-JavaScript-errors-gracefully-1771605463381.json +435 -0
  4. package/.nyc_output/coverage-core-functionality-spec-js-Core-Functionality-Tests-should-handle-session-import-dialog-1771605466264.json +435 -0
  5. package/.nyc_output/coverage-core-functionality-spec-js-Core-Functionality-Tests-should-have-working-infinite-scroll-elements-1771605454038.json +435 -0
  6. package/.nyc_output/coverage-core-functionality-spec-js-Core-Functionality-Tests-should-load-homepage-with-basic-elements-1771605454001.json +435 -0
  7. package/.nyc_output/coverage-core-functionality-spec-js-Core-Functionality-Tests-should-load-time-analysis-page-1771605464990.json +1236 -0
  8. package/.nyc_output/coverage-core-functionality-spec-js-Core-Functionality-Tests-should-navigate-to-session-detail-page-1771605472595.json +1177 -0
  9. package/.nyc_output/coverage-e2e-merged.json +1 -0
  10. package/.nyc_output/coverage-homepage-spec-js-Homepage-should-display-session-list-1771605453565.json +435 -0
  11. package/.nyc_output/coverage-homepage-spec-js-Homepage-should-load-homepage-successfully-1771605453552.json +435 -0
  12. package/.nyc_output/coverage-homepage-spec-js-Homepage-should-navigate-to-session-detail-on-click-1771605469317.json +1134 -0
  13. package/.nyc_output/coverage-homepage-spec-js-Homepage-should-show-session-metadata-1771605460581.json +435 -0
  14. 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
  15. package/.nyc_output/coverage-infinite-scroll-spec-js-Infinite-Scroll-should-handle-API-errors-gracefully-during-infinite-scroll-1771605482161.json +471 -0
  16. package/.nyc_output/coverage-infinite-scroll-spec-js-Infinite-Scroll-should-hide-Load-More-button-when-no-more-sessions-available-1771605478370.json +471 -0
  17. package/.nyc_output/coverage-infinite-scroll-spec-js-Infinite-Scroll-should-load-additional-sessions-when-Load-More-button-is-clicked-1771605475059.json +471 -0
  18. package/.nyc_output/coverage-infinite-scroll-spec-js-Infinite-Scroll-should-preserve-session-list-state-during-navigation-1771605494575.json +1633 -0
  19. package/.nyc_output/coverage-infinite-scroll-spec-js-Infinite-Scroll-should-show-loading-state-when-Load-More-button-is-clicked-1771605475401.json +471 -0
  20. package/.nyc_output/coverage-infinite-scroll-spec-js-Infinite-Scroll-should-trigger-infinite-scroll-when-scrolling-near-bottom-1771605476949.json +471 -0
  21. package/.nyc_output/coverage-session-detail-spec-js-Session-Detail-Page-should-clear-search-filter-1771605508542.json +1255 -0
  22. package/.nyc_output/coverage-session-detail-spec-js-Session-Detail-Page-should-display-event-list-1771605505572.json +1156 -0
  23. package/.nyc_output/coverage-session-detail-spec-js-Session-Detail-Page-should-display-session-metadata-1771605504552.json +701 -0
  24. package/.nyc_output/coverage-session-detail-spec-js-Session-Detail-Page-should-expand-and-collapse-tool-details-1771605515809.json +1182 -0
  25. package/.nyc_output/coverage-session-detail-spec-js-Session-Detail-Page-should-filter-events-by-search-1771605513421.json +1245 -0
  26. package/.nyc_output/coverage-session-detail-spec-js-Session-Detail-Page-should-load-session-detail-page-1771605494974.json +701 -0
  27. package/.nyc_output/coverage-session-detail-spec-js-Session-Detail-Page-should-toggle-content-visibility-1771605550729.json +1177 -0
  28. package/.nyc_output/coverage-unit.json +21 -0
  29. package/.nycrc +29 -0
  30. package/CHANGELOG.md +36 -0
  31. package/README.md +154 -15
  32. package/examples/parser-usage.js +114 -0
  33. package/lib/parsers/README.md +239 -0
  34. package/lib/parsers/base-parser.js +53 -0
  35. package/lib/parsers/claude-parser.js +181 -0
  36. package/lib/parsers/copilot-parser.js +143 -0
  37. package/lib/parsers/index.js +13 -0
  38. package/lib/parsers/parser-factory.js +77 -0
  39. package/lib/parsers/pi-mono-parser.js +119 -0
  40. package/package.json +12 -4
  41. package/server.js +17 -2
  42. package/src/app.js +45 -20
  43. package/src/controllers/insightController.js +44 -8
  44. package/src/controllers/sessionController.js +217 -3
  45. package/src/controllers/uploadController.js +447 -7
  46. package/src/middleware/rateLimiting.js +7 -1
  47. package/src/models/Session.js +26 -0
  48. package/src/schemas/event.schema.js +73 -0
  49. package/src/services/eventNormalizer.js +291 -0
  50. package/src/services/insightService.js +140 -48
  51. package/src/services/sessionRepository.js +584 -49
  52. package/src/services/sessionService.js +1594 -27
  53. package/src/utils/helpers.js +6 -1
  54. package/views/index.ejs +111 -4
  55. package/views/session-vue.ejs +425 -71
  56. package/views/time-analyze.ejs +140 -57
@@ -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
- return typeof sessionId === 'string' && /^[a-zA-Z0-9_-]+$/.test(sessionId) && sessionId.length < 256;
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 GitHub Copilot session logs</p>
445
+ <p class="subtitle">View session logs from Copilot, Claude Code, and Pi-Mono</p>
388
446
 
389
- <form id="sessionForm" onsubmit="viewSession(event)">
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
- if (allSessions.length === 0) return;
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(allSessions);
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