reepoe 1.1.1
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/scripts/setup.js
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ReePoe Post-Install Setup
|
|
4
|
+
* Automatically configures ReePoe for the current project
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const { spawn } = require('child_process');
|
|
10
|
+
const os = require('os');
|
|
11
|
+
|
|
12
|
+
// Detect project type
|
|
13
|
+
function detectProjectType(projectPath) {
|
|
14
|
+
const markers = {
|
|
15
|
+
'package.json': { language: 'javascript', name: 'Node.js' },
|
|
16
|
+
'requirements.txt': { language: 'python', name: 'Python' },
|
|
17
|
+
'go.mod': { language: 'go', name: 'Go' },
|
|
18
|
+
'Cargo.toml': { language: 'rust', name: 'Rust' },
|
|
19
|
+
'pom.xml': { language: 'java', name: 'Java' }
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
for (const [file, config] of Object.entries(markers)) {
|
|
23
|
+
if (fs.existsSync(path.join(projectPath, file))) {
|
|
24
|
+
// Read project name if possible
|
|
25
|
+
let projectName = path.basename(projectPath);
|
|
26
|
+
|
|
27
|
+
if (file === 'package.json') {
|
|
28
|
+
try {
|
|
29
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(projectPath, file), 'utf8'));
|
|
30
|
+
projectName = pkg.name || projectName;
|
|
31
|
+
|
|
32
|
+
// Detect framework
|
|
33
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
34
|
+
if (deps.express) config.framework = 'Express';
|
|
35
|
+
else if (deps.react) config.framework = 'React';
|
|
36
|
+
else if (deps.vue) config.framework = 'Vue';
|
|
37
|
+
|
|
38
|
+
} catch (e) {
|
|
39
|
+
// Use defaults
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return { ...config, projectName };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return { language: 'unknown', name: 'Generic', projectName: path.basename(projectPath) };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Find available port
|
|
51
|
+
async function findAvailablePort(start = 8000, end = 9000) {
|
|
52
|
+
const net = require('net');
|
|
53
|
+
|
|
54
|
+
for (let port = start; port <= end; port++) {
|
|
55
|
+
const available = await new Promise((resolve) => {
|
|
56
|
+
const server = net.createServer();
|
|
57
|
+
server.once('error', () => resolve(false));
|
|
58
|
+
server.once('listening', () => {
|
|
59
|
+
server.close();
|
|
60
|
+
resolve(true);
|
|
61
|
+
});
|
|
62
|
+
server.listen(port, '127.0.0.1');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (available) {
|
|
66
|
+
return port;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return start; // Fallback to first port
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Create configuration file
|
|
74
|
+
async function createConfiguration(projectInfo, port) {
|
|
75
|
+
const config = {
|
|
76
|
+
project: {
|
|
77
|
+
name: projectInfo.projectName,
|
|
78
|
+
type: projectInfo.language,
|
|
79
|
+
framework: projectInfo.framework || null,
|
|
80
|
+
root: process.cwd()
|
|
81
|
+
},
|
|
82
|
+
api: {
|
|
83
|
+
port: port,
|
|
84
|
+
host: '127.0.0.1'
|
|
85
|
+
},
|
|
86
|
+
mini_rag: {
|
|
87
|
+
enabled: true,
|
|
88
|
+
confidence_threshold: 0.6,
|
|
89
|
+
cta_whitelist: ['run_tests', 'open_file', 'search_symbols', 'get_repo_stats']
|
|
90
|
+
},
|
|
91
|
+
scanner: {
|
|
92
|
+
language: projectInfo.language,
|
|
93
|
+
auto_scan: true
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const configPath = path.join(process.cwd(), 'reepoe.config.json');
|
|
98
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
99
|
+
|
|
100
|
+
return configPath;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Create data directories
|
|
104
|
+
function createDataDirectories() {
|
|
105
|
+
const dirs = ['data', 'logs'];
|
|
106
|
+
|
|
107
|
+
for (const dir of dirs) {
|
|
108
|
+
const dirPath = path.join(process.cwd(), dir);
|
|
109
|
+
if (!fs.existsSync(dirPath)) {
|
|
110
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ========== BYOK (Bring Your Own Key) Setup Wizard ==========
|
|
116
|
+
|
|
117
|
+
async function setupBYOK() {
|
|
118
|
+
// BYOK Setup Wizard for global installations
|
|
119
|
+
const readline = require('readline');
|
|
120
|
+
const crypto = require('crypto');
|
|
121
|
+
|
|
122
|
+
console.log('\n╔══════════════════════════════════════════════════════════════╗');
|
|
123
|
+
console.log('║ ReePoe BYOK Setup - Bring Your Own Key ║');
|
|
124
|
+
console.log('╚══════════════════════════════════════════════════════════════╝\n');
|
|
125
|
+
|
|
126
|
+
console.log('💡 ReePoe can use YOUR OpenRouter API key for intelligent routing.');
|
|
127
|
+
console.log(' Benefits:');
|
|
128
|
+
console.log(' ✅ Use OpenRouter free tier (50 queries/day)');
|
|
129
|
+
console.log(' ✅ Full cost transparency and tracking');
|
|
130
|
+
console.log(' ✅ Uses google/gemma-3-4b-it:free for routing\n');
|
|
131
|
+
|
|
132
|
+
console.log(' ℹ️ Your key is stored locally and NEVER transmitted.');
|
|
133
|
+
console.log(' ℹ️ Get a free key at: https://openrouter.ai/keys\n');
|
|
134
|
+
|
|
135
|
+
// Prompt for API key
|
|
136
|
+
const rl = readline.createInterface({
|
|
137
|
+
input: process.stdin,
|
|
138
|
+
output: process.stdout
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const apiKey = await new Promise((resolve) => {
|
|
142
|
+
rl.question('Enter OpenRouter API key (or press Enter to skip): ', (answer) => {
|
|
143
|
+
rl.close();
|
|
144
|
+
resolve(answer.trim());
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
if (apiKey && apiKey.length > 0) {
|
|
149
|
+
// Validate format
|
|
150
|
+
if (apiKey.startsWith('sk-or-v1-')) {
|
|
151
|
+
try {
|
|
152
|
+
// Store API key in ~/.reepoe/config.json
|
|
153
|
+
const globalConfigDir = path.join(os.homedir(), '.reepoe');
|
|
154
|
+
const globalConfigPath = path.join(globalConfigDir, 'config.json');
|
|
155
|
+
|
|
156
|
+
// Create directory if doesn't exist
|
|
157
|
+
if (!fs.existsSync(globalConfigDir)) {
|
|
158
|
+
fs.mkdirSync(globalConfigDir, { recursive: true, mode: 0o700 });
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Generate anonymous user ID
|
|
162
|
+
const userId = 'anon_' + crypto.createHash('sha256')
|
|
163
|
+
.update(crypto.randomBytes(32))
|
|
164
|
+
.digest('hex')
|
|
165
|
+
.substring(0, 16);
|
|
166
|
+
|
|
167
|
+
// Simple encryption (base64)
|
|
168
|
+
const encryptedKey = Buffer.from(apiKey).toString('base64');
|
|
169
|
+
|
|
170
|
+
const globalConfig = {
|
|
171
|
+
api_keys: {
|
|
172
|
+
openrouter: encryptedKey,
|
|
173
|
+
encrypted: true
|
|
174
|
+
},
|
|
175
|
+
user_id: userId,
|
|
176
|
+
analytics: {
|
|
177
|
+
enabled: true,
|
|
178
|
+
anonymous: true
|
|
179
|
+
},
|
|
180
|
+
created_at: new Date().toISOString()
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
fs.writeFileSync(globalConfigPath, JSON.stringify(globalConfig, null, 2), { mode: 0o600 });
|
|
184
|
+
|
|
185
|
+
console.log('\n✅ API key stored securely in ~/.reepoe/config.json');
|
|
186
|
+
console.log(' Your key is encrypted and only accessible by you.');
|
|
187
|
+
console.log(' Anonymous user ID generated for analytics.');
|
|
188
|
+
console.log('\n💰 Cost tracking enabled - monitor your usage in real-time!');
|
|
189
|
+
|
|
190
|
+
} catch (error) {
|
|
191
|
+
console.error(`\n❌ Failed to store API key: ${error.message}`);
|
|
192
|
+
console.log(' Continuing with limited features...');
|
|
193
|
+
}
|
|
194
|
+
} else {
|
|
195
|
+
console.log('\n⚠️ Invalid API key format (should start with sk-or-v1-)');
|
|
196
|
+
console.log(' Skipping BYOK setup - ReePoe will use default routing.');
|
|
197
|
+
console.log(' You can add your key later in ~/.reepoe/config.json');
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
console.log('\n ℹ️ Skipping BYOK setup - using default routing');
|
|
201
|
+
console.log(' ReePoe will work with limited features.');
|
|
202
|
+
console.log(' To enable BYOK later, run: reepoe-setup-key');
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Main setup function
|
|
207
|
+
async function setup() {
|
|
208
|
+
// For global install, run BYOK wizard
|
|
209
|
+
if (process.env.npm_config_global === 'true') {
|
|
210
|
+
await setupBYOK();
|
|
211
|
+
|
|
212
|
+
console.log('\n✅ ReePoe installed globally');
|
|
213
|
+
console.log('\n📝 To use in a project:');
|
|
214
|
+
console.log(' cd /path/to/your/project');
|
|
215
|
+
console.log(' reepoe-start\n');
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
console.log('\n╔══════════════════════════════════════════════════════════════╗');
|
|
220
|
+
console.log('║ ReePoe Plugin - Auto Setup ║');
|
|
221
|
+
console.log('╚══════════════════════════════════════════════════════════════╝\n');
|
|
222
|
+
|
|
223
|
+
// Detect project
|
|
224
|
+
console.log('🔍 Detecting project type...');
|
|
225
|
+
const projectInfo = detectProjectType(process.cwd());
|
|
226
|
+
console.log(` ✅ ${projectInfo.name} project detected`);
|
|
227
|
+
if (projectInfo.framework) {
|
|
228
|
+
console.log(` Framework: ${projectInfo.framework}`);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Find available port
|
|
232
|
+
console.log('\n⚙️ Finding available port...');
|
|
233
|
+
const port = await findAvailablePort();
|
|
234
|
+
console.log(` ✅ Port ${port} available`);
|
|
235
|
+
|
|
236
|
+
// Create configuration
|
|
237
|
+
console.log('\n📝 Creating configuration...');
|
|
238
|
+
const configPath = await createConfiguration(projectInfo, port);
|
|
239
|
+
console.log(` ✅ Configuration created: ${configPath}`);
|
|
240
|
+
|
|
241
|
+
// Create directories
|
|
242
|
+
console.log('\n📁 Setting up directories...');
|
|
243
|
+
createDataDirectories();
|
|
244
|
+
console.log(` ✅ Data directories created`);
|
|
245
|
+
|
|
246
|
+
// Success message
|
|
247
|
+
console.log('\n╔══════════════════════════════════════════════════════════════╗');
|
|
248
|
+
console.log('║ ✅ ReePoe Setup Complete! ║');
|
|
249
|
+
console.log('╚══════════════════════════════════════════════════════════════╝\n');
|
|
250
|
+
|
|
251
|
+
console.log('🚀 Start ReePoe:');
|
|
252
|
+
console.log(' reepoe-start\n');
|
|
253
|
+
|
|
254
|
+
console.log('💡 Try these commands:');
|
|
255
|
+
console.log(' reepoe query "what does this codebase do?"');
|
|
256
|
+
console.log(' reepoe query "show me all API endpoints"');
|
|
257
|
+
console.log(' reepoe query "find test files"\n');
|
|
258
|
+
|
|
259
|
+
console.log('📊 Management:');
|
|
260
|
+
console.log(' reepoe-status - Check server status');
|
|
261
|
+
console.log(' reepoe-stop - Stop server\n');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
setup().catch(error => {
|
|
265
|
+
console.error(`\n❌ Setup failed: ${error.message}`);
|
|
266
|
+
console.error(' You can run setup manually with: node scripts/setup.js');
|
|
267
|
+
process.exit(1);
|
|
268
|
+
});
|
|
269
|
+
|