@mcptoolshop/registry-stats 3.0.0 → 3.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/README.md CHANGED
@@ -1,7 +1,7 @@
1
- <p align="center">
2
- <a href="README.ja.md">日本語</a> | <a href="README.zh.md">中文</a> | <a href="README.es.md">Español</a> | <a href="README.fr.md">Français</a> | <a href="README.hi.md">हिन्दी</a> | <a href="README.it.md">Italiano</a> | <a href="README.pt-BR.md">Português (BR)</a>
3
- </p>
4
-
1
+ <p align="center">
2
+ <a href="README.ja.md">日本語</a> | <a href="README.zh.md">中文</a> | <a href="README.es.md">Español</a> | <a href="README.fr.md">Français</a> | <a href="README.hi.md">हिन्दी</a> | <a href="README.it.md">Italiano</a> | <a href="README.pt-BR.md">Português (BR)</a>
3
+ </p>
4
+
5
5
  <p align="center">
6
6
  <img src="https://raw.githubusercontent.com/mcp-tool-shop-org/brand/main/logos/registry-stats/readme.png" alt="registry-stats logo" width="400" />
7
7
  </p>
@@ -39,8 +39,8 @@ Zero runtime dependencies. Uses native `fetch()`. Node 18+.
39
39
 
40
40
  | Layer | What it does |
41
41
  |-------|-------------|
42
- | **Engine** | TypeScript library + CLI + REST server. Query five registries with one interface. Published to npm as `@mcptoolshop/registry-stats`. |
43
- | **Dashboard** | Astro-powered web app with Pulse AI co-pilot (streaming voice, web search, fullscreen, GitHub data connectors), six interactive charts, live refresh, export reports (PDF / JSONL / Markdown), and tabbed Help guide. Rebuilt weekly by CI; refreshable on demand. |
42
+ | **Engine** | TypeScript library + CLI + REST server + AI inference. Query five registries with one interface. Published to npm as `@mcptoolshop/registry-stats`. |
43
+ | **Dashboard** | Astro-powered web app with AI inference panel, Pulse AI co-pilot (streaming voice, web search, fullscreen, GitHub data connectors), six interactive charts, live refresh, export reports (PDF / JSONL / Markdown), and tabbed Help guide. Rebuilt daily by CI; refreshable on demand. |
44
44
  | **Desktop** | WinUI 3 + WebView2 native Windows app. Bundles the dashboard offline, fetches live stats on demand. |
45
45
 
46
46
  ## Dashboard
@@ -50,18 +50,73 @@ A self-updating stats dashboard lives at [`/dashboard/`](https://mcp-tool-shop-o
50
50
  - **Tabbed interface** — Home, Analytics, Leaderboard, and Help tabs
51
51
  - **Pulse AI co-pilot** — Ollama-powered conversational assistant with streaming voice synthesis (speaks as the LLM streams, 4 voices via [mcp-voice-soundboard](https://github.com/mcp-tool-shop-org/mcp-voice-soundboard)), web search (Wikipedia + optional SearXNG), auto-speak, fullscreen mode, GitHub org data connector, model selector, and conversation memory
52
52
  - **Executive snapshot** — health score (0–100), diversity index, weekly change, total downloads across all registries
53
- - **Six interactive charts** — 30-day trend (aggregate / per-registry / top-5 toggles), registry share (polar area), portfolio risk (histogram + Gini & P90), top-10 momentum, velocity tracker with sparklines, and 30-day heatmap with spike detection (>2σ)
53
+ - **Seven interactive charts** — 30-day trend (aggregate / per-registry / top-5 toggles + click-to-drill-down + scroll zoom/pan), registry share (polar area), portfolio risk (histogram + Gini & P90), top-10 momentum, velocity tracker with sparklines, 30-day heatmap with spike detection (>2σ), and portfolio trend (stacked area, yearly)
54
54
  - **Smart growth engine** — handles small-denominator distortion with baseline threshold, percentage cap, and damped velocity formula
55
- - **Actionable insights** — auto-generated recommendations and attention alerts for declining packages
55
+ - **AI Inference Panel** — portfolio momentum (-100 to +100), risk score, 7-day forecast with confidence intervals, automated recommendations, actionable advice with severity/urgency levels, and package health scoreboard (A–F grades)
56
+ - **Actionable advice** — severity-tagged advice cards (critical/warning/info/success) with urgency levels, specific action steps, and affected package lists
57
+ - **Package health scores** — 0–100 composite score (activity + consistency + growth + stability) with letter grades per package
58
+ - **Yearly progress tracking** — persistent history layer accumulates monthly per-package and weekly portfolio aggregates; portfolio trend chart with per-registry stacking
56
59
  - **Pulse panel** — split view of Established Movers (≥ 50 downloads/wk) and Emerging & New packages, with inline 7-day sparklines, absolute + percentage deltas, baseline context, and a one-line executive summary
57
60
  - **Live refresh** — on-demand client-side fetch from npm and PyPI APIs with progress indicator; results cached in sessionStorage (5 min TTL) so tab switches are instant
58
61
  - **Export reports** — dropdown next to the Refresh button offering three formats: **Exec PDF** (via jsPDF), **LLM JSONL** (typed records for AI ingestion), and **Dev Markdown** (GFM tables)
59
62
  - **Leaderboard** — 132 packages ranked by weekly downloads with inline 30-day sparklines and smart trend badges
60
63
  - **Setup page** — portfolio editor with validation, registry-sync companion section, and pipeline overview
61
- - **Help tab** — human-friendly guide covering every tab, key concepts, AI assistant tips, data pipeline, and useful links
64
+ - **Leaderboard search** — instant text filter for finding packages by name or registry
65
+ - **Keyboard navigation** — arrow keys to cycle between tabs
66
+ - **Help tab** — human-friendly guide covering every tab, key concepts, AI inference engine, data pipeline, and useful links
62
67
  - **Dark / light theme** — follows system preference
68
+ - **Mobile responsive** — hamburger menu for small screens
69
+
70
+ Data is fetched at build time and rebuilt daily by CI (06:00 UTC). Live refresh pulls the latest numbers directly from registry APIs. Configure tracked packages in `site/src/data/packages.json`.
71
+
72
+ ## AI Inference Engine
73
+
74
+ Zero-dependency, pure-math inference that runs at build time — no ML runtime, no external APIs.
75
+
76
+ ```typescript
77
+ import {
78
+ forecast, detectAnomalies, segmentTrends,
79
+ detectSeasonality, computeMomentum,
80
+ generateRecommendations, computeHealthScore,
81
+ generateActionableAdvice, computeYearlyProgress,
82
+ inferPortfolio,
83
+ } from '@mcptoolshop/registry-stats';
84
+
85
+ // 7-day forecast with 80% confidence intervals
86
+ const predictions = forecast(dailySeries, 7);
87
+ // → [{ day: 1, predicted: 142, lower: 98, upper: 186 }, ...]
88
+
89
+ // Anomaly detection (adaptive rolling z-score, 14-day window)
90
+ const anomalies = detectAnomalies(dailySeries);
91
+ // → [{ day: 20, value: 1500, expected: 120, zscore: 4.2, type: 'spike' }]
92
+
93
+ // Composite momentum score (-100 to +100)
94
+ const momentum = computeMomentum(dailySeries);
95
+
96
+ // Package health score (0-100 with A-F grade)
97
+ const health = computeHealthScore('my-pkg', 'npm', dailySeries, momentum);
98
+ // → { score: 72, grade: 'B', components: { activity: 20, consistency: 18, growth: 16, stability: 18 } }
99
+
100
+ // Yearly progress from monthly history
101
+ const progress = computeYearlyProgress('my-pkg', 'npm', monthlyHistory);
102
+ // → { currentYearTotal, yoyGrowthPct, projectedYearEnd, milestones, ... }
103
+
104
+ // Full portfolio analysis (now includes health scores + actionable advice)
105
+ const result = inferPortfolio(leaderboard, { gini: 0.6, npmPct: 85 });
106
+ // → { packages, forecastTotal7, riskScore, portfolioMomentum, recommendations, healthScores, actionableAdvice }
107
+ ```
63
108
 
64
- Data is fetched at build time and rebuilt weekly by CI (Mondays 06:00 UTC). Live refresh pulls the latest numbers directly from registry APIs. Configure tracked packages in `site/src/data/packages.json` (132 packages across 5 registries).
109
+ | Capability | Method | What it does |
110
+ |-----------|--------|-------------|
111
+ | **Forecast** | Weighted linear regression | Exponential recency bias, 80% CI that widens over time |
112
+ | **Anomaly detection** | Adaptive rolling z-score | 14-day baseline window, detects spikes and drops |
113
+ | **Trend segmentation** | Piecewise linear | Identifies up/down/flat segments in time series |
114
+ | **Seasonality** | Day-of-week decomposition | Detects weekly patterns, reports peak day |
115
+ | **Momentum** | Composite score | Direction + acceleration + consistency + volume |
116
+ | **Health score** | Multi-factor composite | Activity + consistency + growth + stability (0–100, A–F grade) |
117
+ | **Yearly progress** | Monthly accumulation | YoY growth, projected year-end, milestone tracking |
118
+ | **Actionable advice** | Severity rule engine | Critical/warning/info/success with urgency and specific actions |
119
+ | **Recommendations** | Rule engine | Growth, risk, opportunity, and attention categories |
65
120
 
66
121
  ## Desktop App
67
122
 
@@ -212,8 +267,10 @@ await stats('npm', 'express', { cache }); // cache hit
212
267
 
213
268
  - Automatic retry with exponential backoff on 429/5xx errors
214
269
  - Respects `Retry-After` headers
270
+ - 30-second request timeouts via `AbortSignal.timeout`
215
271
  - Concurrency limiting for bulk requests
216
272
  - Optional TTL cache (pluggable — bring your own Redis/file backend via `StatsCache` interface)
273
+ - SHA-pinned GitHub Actions for supply chain security
217
274
 
218
275
  ## REST API Server
219
276
 
package/dist/cli.js CHANGED
@@ -40,7 +40,7 @@ async function fetchWithRetry(url, registry, init) {
40
40
  let lastError;
41
41
  for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
42
42
  await acquireSlot(registry);
43
- const res = await fetch(url, init);
43
+ const res = await fetch(url, { signal: AbortSignal.timeout(3e4), ...init });
44
44
  if (res.status === 404) return null;
45
45
  if (res.ok) return res.json();
46
46
  const retryAfter = res.headers.get("retry-after");
@@ -62,7 +62,7 @@ async function fetchWithRetry(url, registry, init) {
62
62
  async function fetchDirect(url, registry, init) {
63
63
  let lastError;
64
64
  for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
65
- const res = await fetch(url, init);
65
+ const res = await fetch(url, { signal: AbortSignal.timeout(3e4), ...init });
66
66
  if (res.status === 404) return null;
67
67
  if (res.ok) return res.json();
68
68
  const retryAfter = res.headers.get("retry-after");
@@ -284,7 +284,8 @@ var docker = {
284
284
  if (options?.dockerToken) {
285
285
  headers["Authorization"] = `Bearer ${options.dockerToken}`;
286
286
  }
287
- const json2 = await fetchWithRetry(`${API4}/${pkg}`, "docker", { headers });
287
+ const safePkg = pkg.split("/").map((s) => encodeURIComponent(s)).join("/");
288
+ const json2 = await fetchWithRetry(`${API4}/${safePkg}`, "docker", { headers });
288
289
  if (!json2 || !json2.name || !json2.namespace) return null;
289
290
  return {
290
291
  registry: "docker",