pi-context-map 0.7.1 → 0.7.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
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.7.2] - 2026-06-15
4
+ ### Bug Fixes
5
+ - **Fixed insights context window**: Now uses the actual context window from Pi (e.g., 200k) instead of hardcoded 128k. Critical insight no longer shows wrong percentages.
6
+ - **Fixed file filter**: Changed from direct `addEventListener` to event delegation (`document.addEventListener('change', ...)`). Filter now works after SSE body replacement.
7
+ - **Fixed file search**: Changed to event delegation (`document.addEventListener('input', ...)`). Search now works in real-time and survives SSE body replacement.
8
+ - **Added search icon**: SVG magnifying glass icon inside the search input for better UX.
9
+
3
10
  ## [0.7.1] - 2026-06-15
4
11
  ### Bug Fixes
5
12
  - **Fixed insights dropdown**: Changed from direct `addEventListener` to event delegation (`document.addEventListener('click', ...)` with `e.target.closest('.insight-header')`). The dropdown now works after SSE body replacement.
@@ -312,11 +312,23 @@ h2:first-of-type { margin-top: 48px; }
312
312
  align-items: center;
313
313
  flex-wrap: wrap;
314
314
  }
315
- .file-search {
315
+ .file-search-wrap {
316
316
  flex: 1;
317
317
  min-width: 220px;
318
+ position: relative;
319
+ }
320
+ .file-search-icon {
321
+ position: absolute;
322
+ left: 16px;
323
+ top: 50%;
324
+ transform: translateY(-50%);
325
+ color: var(--ink-quaternary);
326
+ pointer-events: none;
327
+ }
328
+ .file-search {
329
+ width: 100%;
318
330
  height: 44px;
319
- padding: 0 20px;
331
+ padding: 0 20px 0 40px;
320
332
  border: 1px solid rgba(0,0,0,0.08);
321
333
  border-radius: 22px;
322
334
  background: var(--surface);
@@ -579,7 +591,10 @@ h2:first-of-type { margin-top: 48px; }
579
591
  <section>
580
592
  <h2>Files <span style="font-size:14px;font-weight:400;color:var(--ink-tertiary);letter-spacing:0;">(${composition.files_detail.length})</span></h2>
581
593
  <div class="file-controls">
582
- <input type="text" class="file-search" id="fileSearch" placeholder="Search files" aria-label="Search files">
594
+ <div class="file-search-wrap">
595
+ <svg class="file-search-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
596
+ <input type="text" class="file-search" id="fileSearch" placeholder="Search files..." aria-label="Search files">
597
+ </div>
583
598
  <select class="file-filter" id="fileFilter" aria-label="Filter by status">
584
599
  <option value="all">All</option>
585
600
  <option value="active">Active</option>
@@ -598,17 +613,19 @@ h2:first-of-type { margin-top: 48px; }
598
613
 
599
614
  <script>
600
615
  (function() {
601
- var search = document.getElementById('fileSearch');
602
- var filter = document.getElementById('fileFilter');
603
- var grid = document.getElementById('fileGrid');
604
- var count = document.getElementById('fileCount');
605
- var empty = document.getElementById('emptyState');
606
- var cards = grid ? Array.from(grid.querySelectorAll('.file-card')) : [];
607
- var total = cards.length;
616
+ function getCards() {
617
+ var grid = document.getElementById('fileGrid');
618
+ return grid ? Array.from(grid.querySelectorAll('.file-card')) : [];
619
+ }
608
620
 
609
621
  function update() {
610
- var q = (search.value || '').toLowerCase();
611
- var s = filter.value;
622
+ var search = document.getElementById('fileSearch');
623
+ var filter = document.getElementById('fileFilter');
624
+ var count = document.getElementById('fileCount');
625
+ var empty = document.getElementById('emptyState');
626
+ var cards = getCards();
627
+ var q = (search ? search.value : '').toLowerCase();
628
+ var s = filter ? filter.value : 'all';
612
629
  var v = 0;
613
630
  for (var i = 0; i < cards.length; i++) {
614
631
  var c = cards[i];
@@ -619,11 +636,17 @@ h2:first-of-type { margin-top: 48px; }
619
636
  if (mq && ms) { c.classList.remove('hidden'); v++; }
620
637
  else { c.classList.add('hidden'); }
621
638
  }
622
- count.textContent = v === total ? total + ' files' : v + ' of ' + total;
623
- empty.style.display = v === 0 ? '' : 'none';
639
+ if (count) count.textContent = v + ' of ' + cards.length;
640
+ if (empty) empty.style.display = v === 0 ? '' : 'none';
624
641
  }
625
- if (search) search.addEventListener('input', update);
626
- if (filter) filter.addEventListener('change', update);
642
+
643
+ // Event delegation — survives SSE body replacement
644
+ document.addEventListener('input', function(e) {
645
+ if (e.target.id === 'fileSearch') update();
646
+ });
647
+ document.addEventListener('change', function(e) {
648
+ if (e.target.id === 'fileFilter') update();
649
+ });
627
650
  update();
628
651
 
629
652
  // Theme toggle
@@ -680,14 +703,7 @@ h2:first-of-type { margin-top: 48px; }
680
703
  }
681
704
  // Restore theme after body replacement
682
705
  applyTheme(currentTheme);
683
- // Re-bind file search/filter (direct listeners, not delegated)
684
- var ns = document.getElementById('fileSearch');
685
- var nf = document.getElementById('fileFilter');
686
- if (ns) ns.addEventListener('input', update);
687
- if (nf) nf.addEventListener('change', update);
688
- // Re-query cards after body replacement
689
- cards = Array.from(document.getElementById('fileGrid').querySelectorAll('.file-card'));
690
- total = cards.length;
706
+ // Search/filter use event delegation — no re-binding needed
691
707
  update();
692
708
  }
693
709
  } catch(_) {}
@@ -163,7 +163,7 @@ export default async function piContextMap(pi: ExtensionAPI): Promise<void> {
163
163
  }
164
164
  }
165
165
 
166
- const insights = InsightEngine.generate(composition);
166
+ const insights = InsightEngine.generate(composition, contextWindow);
167
167
  const html = ReportGenerator.generateHTML(
168
168
  composition,
169
169
  insights,
@@ -14,15 +14,17 @@ export interface Insight {
14
14
  command?: string; // Suggested slash command
15
15
  }
16
16
 
17
- const TYPICAL_WINDOW = 128_000; // Default context window size (Claude Sonnet/Opus)
18
-
19
17
  export class InsightEngine {
20
18
  /**
21
19
  * Generate a list of insights based on the composition.
22
20
  */
23
- public static generate(composition: ContextComposition): Insight[] {
21
+ public static generate(
22
+ composition: ContextComposition,
23
+ contextWindow?: number,
24
+ ): Insight[] {
24
25
  const insights: Insight[] = [];
25
- const { system, tools, history, files, summaries, total } = composition;
26
+ const { system, tools, files, summaries, total } = composition;
27
+ const windowSize = contextWindow || 128_000;
26
28
 
27
29
  // Rule 1: Tool bloat
28
30
  if (tools.percent > 40) {
@@ -50,7 +52,7 @@ export class InsightEngine {
50
52
  }
51
53
 
52
54
  // Rule 3: High overall usage
53
- const usagePercent = Math.round((total.tokens / TYPICAL_WINDOW) * 100);
55
+ const usagePercent = Math.round((total.tokens / windowSize) * 100);
54
56
  if (usagePercent > 80) {
55
57
  insights.push({
56
58
  id: "high-usage",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-context-map",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "Professional context profiler for Pi that visualizes the session context window, token distribution, and integrates with Nexus packages for actionable insights.",
5
5
  "keywords": [
6
6
  "pi-package",