@reepoe/plugin 1.1.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 +223 -0
- package/bin/admin.js +286 -0
- package/bin/extend-request.js +69 -0
- package/bin/metrics.js +89 -0
- package/bin/reepoe.js +143 -0
- package/bin/start.js +250 -0
- package/bin/status.js +84 -0
- package/bin/stop.js +55 -0
- package/binaries/reepoe-macos-arm64 +0 -0
- package/package.json +58 -0
- package/scripts/setup.js +269 -0
package/README.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# @reepoe/plugin
|
|
2
|
+
|
|
3
|
+
> **ReePoe AI Code Manager** - Install in any codebase for instant AI agent integration
|
|
4
|
+
|
|
5
|
+
Transform your codebase into an AI-optimized workspace in 30 seconds. ReePoe provides intelligent context management, token optimization, and seamless AI agent integration.
|
|
6
|
+
|
|
7
|
+
## š Quick Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Install globally
|
|
11
|
+
npm install -g @reepoe/plugin
|
|
12
|
+
|
|
13
|
+
# Navigate to your project
|
|
14
|
+
cd /path/to/your/project
|
|
15
|
+
|
|
16
|
+
# Start ReePoe
|
|
17
|
+
reepoe-start
|
|
18
|
+
|
|
19
|
+
# Query your codebase
|
|
20
|
+
reepoe query "what does this codebase do?"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
That's it! ReePoe automatically:
|
|
24
|
+
- ā
Detects your project type (Node.js, Python, Go, etc.)
|
|
25
|
+
- ā
Scans your codebase
|
|
26
|
+
- ā
Starts API server
|
|
27
|
+
- ā
Optimizes context for AI agents
|
|
28
|
+
|
|
29
|
+
## š¦ What's Included
|
|
30
|
+
|
|
31
|
+
- **Multi-Language Support** - JavaScript, TypeScript, Python, Go, Rust, Java, and more
|
|
32
|
+
- **Smart Context** - Intelligent code analysis and context optimization
|
|
33
|
+
- **MiniRAG** - Pattern-based instant responses
|
|
34
|
+
- **Token Optimization** - 90%+ token reduction
|
|
35
|
+
- **API Server** - RESTful API for AI agent integration
|
|
36
|
+
- **Dashboard** - Real-time metrics and analytics
|
|
37
|
+
|
|
38
|
+
## š ļø Commands
|
|
39
|
+
|
|
40
|
+
### Server Management
|
|
41
|
+
```bash
|
|
42
|
+
reepoe-start # Start ReePoe server in background
|
|
43
|
+
reepoe-stop # Stop ReePoe server
|
|
44
|
+
reepoe-status # Check server status and health
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Queries
|
|
48
|
+
```bash
|
|
49
|
+
reepoe query "show me all API endpoints"
|
|
50
|
+
reepoe query "find all test files"
|
|
51
|
+
reepoe query "explain the authentication system"
|
|
52
|
+
reepoe query "what's the project structure?"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## š” API Endpoints
|
|
56
|
+
|
|
57
|
+
Once started, ReePoe exposes:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
GET /health - Health check
|
|
61
|
+
GET /describe - Full capability description
|
|
62
|
+
POST /query - Natural language queries
|
|
63
|
+
GET /metrics - Performance analytics
|
|
64
|
+
GET /token-analytics - Token usage details
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## šÆ Use Cases
|
|
68
|
+
|
|
69
|
+
### For AI Agents
|
|
70
|
+
```javascript
|
|
71
|
+
// Claude, ChatGPT, or custom agents can query ReePoe
|
|
72
|
+
const response = await fetch('http://localhost:8000/query', {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
headers: { 'Content-Type': 'application/json' },
|
|
75
|
+
body: JSON.stringify({
|
|
76
|
+
instruction: 'analyze this codebase architecture'
|
|
77
|
+
})
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### For Developers
|
|
82
|
+
```bash
|
|
83
|
+
# Quick codebase insights
|
|
84
|
+
reepoe query "what external APIs are used?"
|
|
85
|
+
reepoe query "show me database models"
|
|
86
|
+
reepoe query "find security-related code"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### For Code Reviews
|
|
90
|
+
```bash
|
|
91
|
+
# Automated analysis
|
|
92
|
+
reepoe query "find all TODO comments"
|
|
93
|
+
reepoe query "show me recent changes to auth system"
|
|
94
|
+
reepoe query "what tests exist for the API?"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## š§ Configuration
|
|
98
|
+
|
|
99
|
+
ReePoe auto-configures on first start, but you can customize:
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
// reepoe.config.json (auto-generated)
|
|
103
|
+
{
|
|
104
|
+
"project": {
|
|
105
|
+
"name": "my-awesome-app",
|
|
106
|
+
"type": "javascript",
|
|
107
|
+
"framework": "Express"
|
|
108
|
+
},
|
|
109
|
+
"api": {
|
|
110
|
+
"port": 8000,
|
|
111
|
+
"host": "127.0.0.1"
|
|
112
|
+
},
|
|
113
|
+
"mini_rag": {
|
|
114
|
+
"enabled": true,
|
|
115
|
+
"cta_whitelist": ["run_tests", "search_symbols"]
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## š Supported Languages
|
|
121
|
+
|
|
122
|
+
| Language | Support Level | Symbol Extraction |
|
|
123
|
+
|----------|---------------|-------------------|
|
|
124
|
+
| JavaScript/TypeScript | ā
Full | Functions, Classes, Interfaces, Types |
|
|
125
|
+
| Python | ā
Full | Functions, Classes, Methods, Decorators |
|
|
126
|
+
| Go | ā
Full | Functions, Structs, Interfaces, Methods |
|
|
127
|
+
| Rust | ā ļø Generic | Functions, Structs, Traits |
|
|
128
|
+
| Java | ā ļø Generic | Classes, Methods, Interfaces |
|
|
129
|
+
| C/C++ | ā ļø Generic | Functions, Classes, Structs |
|
|
130
|
+
|
|
131
|
+
## šļø Architecture
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
āāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāā
|
|
135
|
+
ā AI Agents āāāāāā ReePoe API āāāāāā LLM Providers ā
|
|
136
|
+
ā (Claude, GPT) ā ā ā ā (OpenRouter) ā
|
|
137
|
+
āāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāā
|
|
138
|
+
ā
|
|
139
|
+
āāāāāāāā¼āāāāāāāāā
|
|
140
|
+
ā Your Codebase ā
|
|
141
|
+
ā (Any Language)ā
|
|
142
|
+
āāāāāāāāāāāāāāāāāā
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## š” Features
|
|
146
|
+
|
|
147
|
+
### Intelligent Context Management
|
|
148
|
+
- Automatic codebase indexing
|
|
149
|
+
- Symbol-level navigation
|
|
150
|
+
- Context slicing and optimization
|
|
151
|
+
- Reference-based loading
|
|
152
|
+
|
|
153
|
+
### Token Optimization
|
|
154
|
+
- 90%+ token reduction
|
|
155
|
+
- Smart context compression
|
|
156
|
+
- Pattern-based caching (MiniRAG)
|
|
157
|
+
- Real-time usage tracking
|
|
158
|
+
|
|
159
|
+
### AI Agent Integration
|
|
160
|
+
- Standard REST API
|
|
161
|
+
- MCP (Model Context Protocol) support
|
|
162
|
+
- Auto-discovery via `/describe`
|
|
163
|
+
- Comprehensive onboarding
|
|
164
|
+
|
|
165
|
+
## š Troubleshooting
|
|
166
|
+
|
|
167
|
+
### Server won't start
|
|
168
|
+
```bash
|
|
169
|
+
# Check status
|
|
170
|
+
reepoe-status
|
|
171
|
+
|
|
172
|
+
# Check if port is in use
|
|
173
|
+
lsof -i :8000
|
|
174
|
+
|
|
175
|
+
# Try different port
|
|
176
|
+
# Edit reepoe.config.json and change api.port
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Binary permissions (Unix/Linux)
|
|
180
|
+
```bash
|
|
181
|
+
chmod +x ~/.npm-global/lib/node_modules/@reepoe/plugin/binaries/reepoe-*
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Reset configuration
|
|
185
|
+
```bash
|
|
186
|
+
rm reepoe.config.json
|
|
187
|
+
reepoe-start # Will regenerate
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## š Requirements
|
|
191
|
+
|
|
192
|
+
- **Node.js** 16.0.0 or higher
|
|
193
|
+
- **Operating Systems:** macOS, Linux, Windows
|
|
194
|
+
- **Architecture:** x64, arm64
|
|
195
|
+
|
|
196
|
+
## š Security
|
|
197
|
+
|
|
198
|
+
- Runs locally on your machine
|
|
199
|
+
- No data sent to external servers (except configured LLM APIs)
|
|
200
|
+
- Closed-source binary distribution
|
|
201
|
+
- Whitelist-based CTA execution
|
|
202
|
+
|
|
203
|
+
## š Performance
|
|
204
|
+
|
|
205
|
+
- **Install time:** < 60 seconds
|
|
206
|
+
- **Startup time:** < 3 seconds
|
|
207
|
+
- **Query latency:** < 2 seconds
|
|
208
|
+
- **Memory usage:** < 500MB
|
|
209
|
+
|
|
210
|
+
## š Support
|
|
211
|
+
|
|
212
|
+
- **Documentation:** https://reepoe.com/docs
|
|
213
|
+
- **Issues:** https://github.com/MarcAndre72/ReePoe/issues
|
|
214
|
+
- **API Reference:** http://localhost:8000/describe (after starting)
|
|
215
|
+
|
|
216
|
+
## š License
|
|
217
|
+
|
|
218
|
+
Proprietary - See LICENSE file for details
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
**ReePoe** - Making AI agents smarter, one codebase at a time š
|
|
223
|
+
|
package/bin/admin.js
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ReePoe Admin CLI - Administrative tools
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const ActivationClient = require('../lib/activation-client');
|
|
7
|
+
const readline = require('readline');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
|
|
10
|
+
const client = new ActivationClient();
|
|
11
|
+
|
|
12
|
+
async function promptInput(question) {
|
|
13
|
+
const rl = readline.createInterface({
|
|
14
|
+
input: process.stdin,
|
|
15
|
+
output: process.stdout
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
return new Promise((resolve) => {
|
|
19
|
+
rl.question(question, (answer) => {
|
|
20
|
+
rl.close();
|
|
21
|
+
resolve(answer.trim());
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function adminLogin() {
|
|
27
|
+
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
28
|
+
console.log('ā š ReePoe Admin Login ā');
|
|
29
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
30
|
+
|
|
31
|
+
const email = await promptInput('š§ Admin Email: ');
|
|
32
|
+
const adminCode = await promptInput('š Admin Code: ');
|
|
33
|
+
|
|
34
|
+
console.log('\nā³ Authenticating...\n');
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const result = await client.adminLogin(email, adminCode);
|
|
38
|
+
|
|
39
|
+
if (result.success) {
|
|
40
|
+
console.log('ā
Admin access granted!');
|
|
41
|
+
console.log(` Token valid for: 1 hour`);
|
|
42
|
+
console.log(` Permissions: Full admin access\n`);
|
|
43
|
+
console.log('Commands available:');
|
|
44
|
+
console.log(' reepoe admin users list');
|
|
45
|
+
console.log(' reepoe admin codes generate');
|
|
46
|
+
console.log(' reepoe admin metrics\n');
|
|
47
|
+
} else {
|
|
48
|
+
console.log(`ā Login failed: ${result.message || 'Invalid credentials'}\n`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error(`ā Login error: ${error.message}\n`);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function listUsers(options = {}) {
|
|
58
|
+
try {
|
|
59
|
+
const result = await client.adminListUsers(options.status, options.limit || 50);
|
|
60
|
+
|
|
61
|
+
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
62
|
+
console.log(`ā š„ Users (${result.total} total)${' '.repeat(47 - result.total.toString().length)}ā`);
|
|
63
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
64
|
+
|
|
65
|
+
if (result.users.length === 0) {
|
|
66
|
+
console.log('No users found.\n');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Table header
|
|
71
|
+
console.log('Email Status Queries Tokens Saved Expires');
|
|
72
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
73
|
+
|
|
74
|
+
for (const user of result.users) {
|
|
75
|
+
const email = user.email.substring(0, 25).padEnd(26);
|
|
76
|
+
const status = user.status.padEnd(9);
|
|
77
|
+
const queries = String(user.total_queries || 0).padStart(7);
|
|
78
|
+
const tokens = String(user.total_tokens_saved || 0).padStart(13);
|
|
79
|
+
|
|
80
|
+
let expires = ' - ';
|
|
81
|
+
if (user.expires_at) {
|
|
82
|
+
const expDate = new Date(user.expires_at);
|
|
83
|
+
const days = Math.ceil((expDate - new Date()) / (1000 * 60 * 60 * 24));
|
|
84
|
+
expires = `${days}d`.padStart(8);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log(`${email}${status}${queries} ${tokens}${expires}`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
console.log('\nš” Commands:');
|
|
91
|
+
console.log(' reepoe admin users extend <email> +30d');
|
|
92
|
+
console.log(' reepoe admin users revoke <email>\n');
|
|
93
|
+
|
|
94
|
+
} catch (error) {
|
|
95
|
+
console.error(`\nā Failed to list users: ${error.message}\n`);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function generateCodes(count, options = {}) {
|
|
101
|
+
try {
|
|
102
|
+
const codeType = options.type || 'ALPHA';
|
|
103
|
+
const notes = options.notes;
|
|
104
|
+
const adminEmail = 'admin'; // TODO: Get from admin session
|
|
105
|
+
|
|
106
|
+
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
107
|
+
console.log('ā š Generating Activation Codes ā');
|
|
108
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
109
|
+
|
|
110
|
+
console.log(`Type: ${codeType}`);
|
|
111
|
+
console.log(`Count: ${count}`);
|
|
112
|
+
console.log(`Expires: 30 days from now\n`);
|
|
113
|
+
|
|
114
|
+
console.log('ā³ Generating...\n');
|
|
115
|
+
|
|
116
|
+
const result = await client.adminGenerateCodes(count, codeType, adminEmail, notes);
|
|
117
|
+
|
|
118
|
+
if (result.success) {
|
|
119
|
+
console.log(`ā
Generated ${result.count} codes!\n`);
|
|
120
|
+
|
|
121
|
+
console.log('Codes:');
|
|
122
|
+
result.codes.forEach((code, i) => {
|
|
123
|
+
console.log(` ${i + 1}. ${code}`);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// Save to file
|
|
127
|
+
const filename = `alpha_codes_${Date.now()}.txt`;
|
|
128
|
+
fs.writeFileSync(filename, result.codes.join('\n'));
|
|
129
|
+
|
|
130
|
+
console.log(`\nš Saved to: ${filename}`);
|
|
131
|
+
console.log(`\nš” Share these codes with alpha testers!\n`);
|
|
132
|
+
} else {
|
|
133
|
+
console.log(`ā Failed to generate codes\n`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
} catch (error) {
|
|
137
|
+
console.error(`\nā Code generation failed: ${error.message}\n`);
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function extendUser(email, days) {
|
|
143
|
+
try {
|
|
144
|
+
const adminEmail = 'admin'; // TODO: Get from admin session
|
|
145
|
+
|
|
146
|
+
console.log(`\nā³ Extending ${email} by ${days} days...\n`);
|
|
147
|
+
|
|
148
|
+
const result = await client.adminExtendUser(email, days, adminEmail);
|
|
149
|
+
|
|
150
|
+
if (result.success) {
|
|
151
|
+
console.log(`ā
${result.message}`);
|
|
152
|
+
console.log(` New expiration: ${new Date(result.new_expires_at).toLocaleDateString()}\n`);
|
|
153
|
+
} else {
|
|
154
|
+
console.log(`ā Extension failed: ${result.error}\n`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
} catch (error) {
|
|
158
|
+
console.error(`\nā Extension error: ${error.message}\n`);
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Parse command line arguments
|
|
164
|
+
const args = process.argv.slice(2);
|
|
165
|
+
const command = args[0];
|
|
166
|
+
const subcommand = args[1];
|
|
167
|
+
|
|
168
|
+
async function showUserMetrics(email) {
|
|
169
|
+
const axios = require('axios');
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
console.log(`\nš Loading metrics for ${email}...\n`);
|
|
173
|
+
|
|
174
|
+
// Get aggregate metrics (same as dashboard)
|
|
175
|
+
const API_URL = process.env.REEPOE_API_URL || 'http://localhost:8000';
|
|
176
|
+
const res = await axios.get(`${API_URL}/metrics`);
|
|
177
|
+
const data = res.data;
|
|
178
|
+
|
|
179
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
180
|
+
console.log(`ā š User Metrics - ${email.substring(0, 42).padEnd(42)}ā`);
|
|
181
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
182
|
+
|
|
183
|
+
console.log('ALL TIME (Aggregate):');
|
|
184
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
185
|
+
console.log(` Total Queries: ${data.lifetime?.total_queries || 0}`);
|
|
186
|
+
console.log(` Tokens Saved: ${(data.lifetime?.tokens_saved || 0).toLocaleString()}`);
|
|
187
|
+
console.log(` MiniRAG Hits: ${data.lifetime?.mini_rag_hits || 0}`);
|
|
188
|
+
console.log(` Cache Hit Rate: ${((data.performance?.cache_hit_rate || 0) * 100).toFixed(1)}%`);
|
|
189
|
+
console.log('\nš” Note: Showing aggregate metrics (per-user tracking in Phase 3C)\n');
|
|
190
|
+
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.error(`\nā Failed to load metrics: ${error.message}\n`);
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function showAggregateMetrics() {
|
|
198
|
+
const axios = require('axios');
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
console.log('\nš Loading aggregate metrics...\n');
|
|
202
|
+
|
|
203
|
+
// Get users and metrics
|
|
204
|
+
const users = await client.adminListUsers();
|
|
205
|
+
const API_URL = process.env.REEPOE_API_URL || 'http://localhost:8000';
|
|
206
|
+
const res = await axios.get(`${API_URL}/metrics`);
|
|
207
|
+
const data = res.data;
|
|
208
|
+
|
|
209
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
210
|
+
console.log('ā š ReePoe Admin Dashboard - Aggregate Metrics ā');
|
|
211
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
212
|
+
|
|
213
|
+
console.log('USERS');
|
|
214
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
215
|
+
const activeUsers = users.users.filter(u => u.status === 'active').length;
|
|
216
|
+
const waitlistUsers = users.users.filter(u => u.status === 'waitlist').length;
|
|
217
|
+
console.log(` Total: ${users.total || 0}`);
|
|
218
|
+
console.log(` Active: ${activeUsers}`);
|
|
219
|
+
console.log(` Waitlist: ${waitlistUsers}`);
|
|
220
|
+
|
|
221
|
+
console.log('\nUSAGE (ALL USERS)');
|
|
222
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
223
|
+
console.log(` Total Queries: ${data.lifetime?.total_queries || 0}`);
|
|
224
|
+
console.log(` Tokens Saved: ${(data.lifetime?.tokens_saved || 0).toLocaleString()}`);
|
|
225
|
+
console.log(` MiniRAG Hits: ${data.lifetime?.mini_rag_hits || 0}`);
|
|
226
|
+
console.log(` Cache Hit Rate: ${((data.performance?.cache_hit_rate || 0) * 100).toFixed(1)}%`);
|
|
227
|
+
|
|
228
|
+
console.log('\nPERFORMANCE');
|
|
229
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
230
|
+
console.log(` Token Savings Rate: ${((data.performance?.token_savings_rate || 0) * 100).toFixed(1)}%`);
|
|
231
|
+
console.log(` Avg Response Time: ${(data.performance?.avg_response_time_ms || 0).toFixed(0)}ms`);
|
|
232
|
+
|
|
233
|
+
console.log('\nš Dashboard: https://reepoe.com\n');
|
|
234
|
+
|
|
235
|
+
} catch (error) {
|
|
236
|
+
console.error(`\nā Failed to load metrics: ${error.message}\n`);
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
async function main() {
|
|
242
|
+
if (command === 'login') {
|
|
243
|
+
await adminLogin();
|
|
244
|
+
} else if (command === 'users') {
|
|
245
|
+
if (subcommand === 'list') {
|
|
246
|
+
await listUsers({ status: args[2] });
|
|
247
|
+
} else if (subcommand === 'extend' && args[2]) {
|
|
248
|
+
const email = args[2];
|
|
249
|
+
const days = parseInt(args[3]) || 30;
|
|
250
|
+
await extendUser(email, days);
|
|
251
|
+
} else if (subcommand === 'metrics' && args[2]) {
|
|
252
|
+
const email = args[2];
|
|
253
|
+
await showUserMetrics(email);
|
|
254
|
+
} else {
|
|
255
|
+
console.log('\nUsage:');
|
|
256
|
+
console.log(' reepoe admin users list [status]');
|
|
257
|
+
console.log(' reepoe admin users extend <email> <days>');
|
|
258
|
+
console.log(' reepoe admin users metrics <email>\n');
|
|
259
|
+
}
|
|
260
|
+
} else if (command === 'codes') {
|
|
261
|
+
if (subcommand === 'generate' && args[2]) {
|
|
262
|
+
const count = parseInt(args[2]);
|
|
263
|
+
await generateCodes(count);
|
|
264
|
+
} else {
|
|
265
|
+
console.log('\nUsage:');
|
|
266
|
+
console.log(' reepoe admin codes generate <count>\n');
|
|
267
|
+
}
|
|
268
|
+
} else if (command === 'metrics') {
|
|
269
|
+
await showAggregateMetrics();
|
|
270
|
+
} else {
|
|
271
|
+
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
272
|
+
console.log('ā š ReePoe Admin CLI ā');
|
|
273
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
274
|
+
console.log('Commands:');
|
|
275
|
+
console.log(' reepoe admin login');
|
|
276
|
+
console.log(' reepoe admin users list');
|
|
277
|
+
console.log(' reepoe admin users extend <email> <days>');
|
|
278
|
+
console.log(' reepoe admin codes generate <count>\n');
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
main().catch(error => {
|
|
283
|
+
console.error(`ā Error: ${error.message}`);
|
|
284
|
+
process.exit(1);
|
|
285
|
+
});
|
|
286
|
+
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ReePoe Extension Request - User requests access extension
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const ActivationClient = require('../lib/activation-client');
|
|
7
|
+
const readline = require('readline');
|
|
8
|
+
|
|
9
|
+
async function requestExtension() {
|
|
10
|
+
const client = new ActivationClient();
|
|
11
|
+
|
|
12
|
+
// Load activation
|
|
13
|
+
const activation = client.loadActivation();
|
|
14
|
+
|
|
15
|
+
if (!activation) {
|
|
16
|
+
console.log('\nā No activation found');
|
|
17
|
+
console.log(' Please activate ReePoe first: reepoe-start\n');
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
22
|
+
console.log('ā š§ Request Access Extension ā');
|
|
23
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
24
|
+
|
|
25
|
+
console.log(`Your current access expires:`);
|
|
26
|
+
if (activation.expires_at) {
|
|
27
|
+
const expiresDate = new Date(activation.expires_at);
|
|
28
|
+
const daysRemaining = Math.ceil((expiresDate - new Date()) / (1000 * 60 * 60 * 24));
|
|
29
|
+
console.log(` ${expiresDate.toLocaleDateString()} (${daysRemaining} days remaining)\n`);
|
|
30
|
+
} else {
|
|
31
|
+
console.log(' Lifetime access\n');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const rl = readline.createInterface({
|
|
35
|
+
input: process.stdin,
|
|
36
|
+
output: process.stdout
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const reason = await new Promise((resolve) => {
|
|
40
|
+
rl.question('š¬ Reason for extension (optional): ', (answer) => {
|
|
41
|
+
rl.close();
|
|
42
|
+
resolve(answer.trim());
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
console.log('\nā³ Sending extension request...\n');
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const result = await client.requestExtension(activation.email, reason || 'Standard extension request');
|
|
50
|
+
|
|
51
|
+
if (result.success) {
|
|
52
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
53
|
+
console.log('ā ā
Extension Request Sent! ā');
|
|
54
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
55
|
+
console.log('Your request has been sent to the admin team.');
|
|
56
|
+
console.log('You\'ll be notified when it\'s reviewed.\n');
|
|
57
|
+
console.log('š” Typically reviewed within 24-48 hours.\n');
|
|
58
|
+
} else {
|
|
59
|
+
console.log(`ā Request failed: ${result.message}\n`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error(`\nā Error: ${error.message}\n`);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
requestExtension();
|
|
69
|
+
|
package/bin/metrics.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ReePoe Metrics - Display user's personal statistics
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const ActivationClient = require('../lib/activation-client');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const os = require('os');
|
|
10
|
+
|
|
11
|
+
async function showMetrics() {
|
|
12
|
+
const axios = require('axios');
|
|
13
|
+
const client = new ActivationClient();
|
|
14
|
+
|
|
15
|
+
// Load activation to get email
|
|
16
|
+
const activation = client.loadActivation();
|
|
17
|
+
|
|
18
|
+
if (!activation) {
|
|
19
|
+
console.log('\nā No activation found');
|
|
20
|
+
console.log(' Please activate ReePoe first: reepoe-start\n');
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
console.log('\nš Loading your ReePoe metrics...\n');
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
// Use per-user metrics endpoint (NOT aggregate)
|
|
28
|
+
const API_URL = process.env.REEPOE_API_URL || 'http://localhost:8000';
|
|
29
|
+
const res = await axios.get(`${API_URL}/api/metrics/user/${activation.email}`);
|
|
30
|
+
const data = res.data;
|
|
31
|
+
|
|
32
|
+
// Per-user endpoint returns the correct structure already
|
|
33
|
+
const metrics = {
|
|
34
|
+
metrics: data.metrics, // Already has today, week, alltime
|
|
35
|
+
account: data.account // Already has activated_at, expires_at, status
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
39
|
+
console.log(`ā š ReePoe Metrics - ${activation.email.padEnd(39)}ā`);
|
|
40
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
41
|
+
|
|
42
|
+
console.log('TODAY');
|
|
43
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
44
|
+
console.log(` Queries: ${metrics.metrics.today.queries || 0}`);
|
|
45
|
+
console.log(` Tokens Saved: ${(metrics.metrics.today.tokens_saved || 0).toLocaleString()}`);
|
|
46
|
+
console.log(` Cost Saved: $${(metrics.metrics.today.cost_saved || 0).toFixed(2)}`);
|
|
47
|
+
|
|
48
|
+
console.log('\nTHIS WEEK');
|
|
49
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
50
|
+
console.log(` Queries: ${metrics.metrics.week.queries || 0}`);
|
|
51
|
+
console.log(` Tokens Saved: ${(metrics.metrics.week.tokens_saved || 0).toLocaleString()}`);
|
|
52
|
+
console.log(` Cost Saved: $${(metrics.metrics.week.cost_saved || 0).toFixed(2)}`);
|
|
53
|
+
|
|
54
|
+
console.log('\nALL TIME');
|
|
55
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
56
|
+
console.log(` Queries: ${metrics.metrics.alltime.queries || 0}`);
|
|
57
|
+
console.log(` Tokens Saved: ${(metrics.metrics.alltime.tokens_saved || 0).toLocaleString()}`);
|
|
58
|
+
console.log(` Cost Saved: $${(metrics.metrics.alltime.cost_saved || 0).toFixed(2)}`);
|
|
59
|
+
console.log(` Patterns Learned: ${metrics.metrics.alltime.patterns_learned || 0}`);
|
|
60
|
+
console.log(` Patterns Active: ${metrics.metrics.alltime.patterns_active || 0}`);
|
|
61
|
+
|
|
62
|
+
console.log('\nACCOUNT INFO');
|
|
63
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
64
|
+
console.log(` Status: ā
${metrics.account.status}`);
|
|
65
|
+
|
|
66
|
+
if (metrics.account.expires_at) {
|
|
67
|
+
const expiresDate = new Date(metrics.account.expires_at);
|
|
68
|
+
const daysRemaining = Math.ceil((expiresDate - new Date()) / (1000 * 60 * 60 * 24));
|
|
69
|
+
console.log(` Expires: ${expiresDate.toLocaleDateString()}`);
|
|
70
|
+
console.log(` Days Remaining: ${daysRemaining}`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log('\nš” Your Impact:');
|
|
74
|
+
console.log(` You've saved ${metrics.metrics.alltime.tokens_saved.toLocaleString()} tokens!`);
|
|
75
|
+
if (metrics.metrics.alltime.patterns_active > 0) {
|
|
76
|
+
console.log(` ${metrics.metrics.alltime.patterns_active} query types are now instant (0 tokens)\n`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.error(`\nā Failed to load metrics: ${error.message}\n`);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
showMetrics().catch(error => {
|
|
86
|
+
console.error(`ā Error: ${error.message}`);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
});
|
|
89
|
+
|