0nmcp 1.2.2 → 1.3.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/lib/stats.js ADDED
@@ -0,0 +1,123 @@
1
+ /**
2
+ * ═══════════════════════════════════════════════════════════════
3
+ * 0nMCP — Stats Module
4
+ * ═══════════════════════════════════════════════════════════════
5
+ *
6
+ * Import this anywhere to get live counts:
7
+ *
8
+ * import { getStats } from './lib/stats.js'
9
+ * const { tools, services, actions, triggers } = getStats()
10
+ *
11
+ * Used by:
12
+ * - Homepage (0nmcp.com)
13
+ * - CLI (npx 0nmcp status)
14
+ * - README badges
15
+ * - API (/api/stats endpoint)
16
+ * - Package description
17
+ *
18
+ * ═══════════════════════════════════════════════════════════════
19
+ */
20
+
21
+ import { readFileSync } from 'fs';
22
+ import { resolve, dirname } from 'path';
23
+ import { fileURLToPath } from 'url';
24
+
25
+ const __dirname = dirname(fileURLToPath(import.meta.url));
26
+
27
+ let _cache = null;
28
+
29
+ /**
30
+ * Get current stats from the generated stats.json
31
+ * Falls back to catalog.json if stats.json doesn't exist
32
+ */
33
+ export function getStats() {
34
+ if (_cache) return _cache;
35
+
36
+ try {
37
+ const statsPath = resolve(__dirname, 'stats.json');
38
+ _cache = JSON.parse(readFileSync(statsPath, 'utf-8'));
39
+ return _cache;
40
+ } catch {
41
+ // Fallback: compute from catalog directly
42
+ return computeFromCatalog();
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Compute stats directly from catalog.json (fallback)
48
+ */
49
+ function computeFromCatalog() {
50
+ try {
51
+ const catalogPath = resolve(__dirname, 'catalog.json');
52
+ const catalog = JSON.parse(readFileSync(catalogPath, 'utf-8'));
53
+
54
+ let tools = 0, actions = 0, triggers = 0;
55
+ for (const svc of catalog.services) {
56
+ tools += svc.tools?.length || 0;
57
+ actions += svc.actions?.length || 0;
58
+ triggers += svc.triggers?.length || 0;
59
+ }
60
+
61
+ _cache = {
62
+ services: catalog.services.length,
63
+ tools,
64
+ actions,
65
+ triggers,
66
+ totalCapabilities: tools + actions + triggers,
67
+ categories: Object.keys(catalog.categories).length,
68
+ };
69
+ return _cache;
70
+ } catch {
71
+ // Last resort: return zeros
72
+ return { services: 0, tools: 0, actions: 0, triggers: 0, totalCapabilities: 0, categories: 0 };
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Get the full catalog
78
+ */
79
+ export function getCatalog() {
80
+ const catalogPath = resolve(__dirname, 'catalog.json');
81
+ return JSON.parse(readFileSync(catalogPath, 'utf-8'));
82
+ }
83
+
84
+ /**
85
+ * Get service by ID
86
+ */
87
+ export function getService(id) {
88
+ const catalog = getCatalog();
89
+ return catalog.services.find(s => s.id === id) || null;
90
+ }
91
+
92
+ /**
93
+ * List all service IDs
94
+ */
95
+ export function getServiceIds() {
96
+ const catalog = getCatalog();
97
+ return catalog.services.map(s => s.id);
98
+ }
99
+
100
+ /**
101
+ * Get all tools across all services
102
+ */
103
+ export function getAllTools() {
104
+ const catalog = getCatalog();
105
+ return catalog.services.flatMap(s => s.tools || []);
106
+ }
107
+
108
+ /**
109
+ * Get formatted summary string
110
+ */
111
+ export function getSummary() {
112
+ const s = getStats();
113
+ return `${s.tools} tools, ${s.services} services, ${s.actions} actions, ${s.triggers} triggers`;
114
+ }
115
+
116
+ /**
117
+ * Clear cache (for hot-reload during dev)
118
+ */
119
+ export function clearStatsCache() {
120
+ _cache = null;
121
+ }
122
+
123
+ export default { getStats, getCatalog, getService, getServiceIds, getAllTools, getSummary, clearStatsCache };