@reepoe/plugin 1.1.0 → 1.1.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.
@@ -0,0 +1,318 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Activation API Client (Phase 3B)
4
+ * Handles communication with ReePoe activation API
5
+ */
6
+
7
+ const axios = require('axios');
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const os = require('os');
11
+
12
+ const API_BASE_URL = process.env.REEPOE_API_URL || 'http://localhost:8000';
13
+
14
+ class ActivationClient {
15
+ constructor() {
16
+ this.apiUrl = API_BASE_URL;
17
+ this.activationFile = path.join(os.homedir(), '.reepoe', 'activation.json');
18
+ }
19
+
20
+ /**
21
+ * Check if user is activated
22
+ */
23
+ async checkActivation(email, version) {
24
+ try {
25
+ const response = await axios.post(`${this.apiUrl}/api/activate/check`, {
26
+ email,
27
+ version
28
+ });
29
+ return response.data;
30
+ } catch (error) {
31
+ if (error.response) {
32
+ return error.response.data;
33
+ }
34
+ throw new Error(`Activation check failed: ${error.message}`);
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Redeem activation code
40
+ */
41
+ async redeemCode(email, code, version) {
42
+ try {
43
+ const machineId = this.getMachineId();
44
+
45
+ const response = await axios.post(`${this.apiUrl}/api/activate/redeem`, {
46
+ email,
47
+ code,
48
+ version,
49
+ machine_id: machineId
50
+ });
51
+
52
+ if (response.data.success) {
53
+ // Save activation locally
54
+ this.saveActivation(response.data);
55
+ }
56
+
57
+ return response.data;
58
+ } catch (error) {
59
+ if (error.response) {
60
+ return error.response.data;
61
+ }
62
+ throw new Error(`Code redemption failed: ${error.message}`);
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Join waitlist
68
+ */
69
+ async joinWaitlist(email) {
70
+ try {
71
+ const response = await axios.post(`${this.apiUrl}/api/waitlist/join`, {
72
+ email
73
+ });
74
+ return response.data;
75
+ } catch (error) {
76
+ if (error.response) {
77
+ return error.response.data;
78
+ }
79
+ throw new Error(`Waitlist join failed: ${error.message}`);
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Get user metrics
85
+ */
86
+ async getUserMetrics(email) {
87
+ try {
88
+ const response = await axios.get(`${this.apiUrl}/api/metrics/user/${email}`);
89
+ return response.data;
90
+ } catch (error) {
91
+ if (error.response) {
92
+ return error.response.data;
93
+ }
94
+ throw new Error(`Failed to get metrics: ${error.message}`);
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Request extension
100
+ */
101
+ async requestExtension(email, reason) {
102
+ try {
103
+ const response = await axios.post(`${this.apiUrl}/api/users/extend-request`, {
104
+ email,
105
+ reason
106
+ });
107
+ return response.data;
108
+ } catch (error) {
109
+ if (error.response) {
110
+ return error.response.data;
111
+ }
112
+ throw new Error(`Extension request failed: ${error.message}`);
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Admin: Login
118
+ */
119
+ async adminLogin(email, adminCode) {
120
+ try {
121
+ const response = await axios.post(`${this.apiUrl}/api/admin/auth`, {
122
+ email,
123
+ admin_code: adminCode
124
+ });
125
+
126
+ if (response.data.success) {
127
+ // Save admin token
128
+ this.saveAdminToken(response.data.admin_token);
129
+ }
130
+
131
+ return response.data;
132
+ } catch (error) {
133
+ if (error.response) {
134
+ return error.response.data;
135
+ }
136
+ throw new Error(`Admin login failed: ${error.message}`);
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Admin: List users
142
+ */
143
+ async adminListUsers(status = null, limit = 50) {
144
+ try {
145
+ const token = this.loadAdminToken();
146
+ if (!token) {
147
+ throw new Error('Admin token not found. Run: reepoe admin login');
148
+ }
149
+
150
+ let url = `${this.apiUrl}/api/admin/users?limit=${limit}`;
151
+ if (status) {
152
+ url += `&status=${status}`;
153
+ }
154
+
155
+ const response = await axios.get(url, {
156
+ headers: { 'Authorization': `Bearer ${token}` }
157
+ });
158
+
159
+ return response.data;
160
+ } catch (error) {
161
+ if (error.response) {
162
+ return error.response.data;
163
+ }
164
+ throw new Error(`Failed to list users: ${error.message}`);
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Admin: Generate codes
170
+ */
171
+ async adminGenerateCodes(count, codeType = 'ALPHA', adminEmail, notes) {
172
+ try {
173
+ const token = this.loadAdminToken();
174
+ if (!token) {
175
+ throw new Error('Admin token not found. Run: reepoe admin login');
176
+ }
177
+
178
+ const response = await axios.post(`${this.apiUrl}/api/admin/codes/generate`, {
179
+ count,
180
+ code_type: codeType,
181
+ admin_email: adminEmail,
182
+ notes
183
+ }, {
184
+ headers: { 'Authorization': `Bearer ${token}` }
185
+ });
186
+
187
+ return response.data;
188
+ } catch (error) {
189
+ if (error.response) {
190
+ return error.response.data;
191
+ }
192
+ throw new Error(`Failed to generate codes: ${error.message}`);
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Admin: Extend user
198
+ */
199
+ async adminExtendUser(email, days, adminEmail) {
200
+ try {
201
+ const token = this.loadAdminToken();
202
+ if (!token) {
203
+ throw new Error('Admin token not found. Run: reepoe admin login');
204
+ }
205
+
206
+ const response = await axios.post(`${this.apiUrl}/api/admin/users/extend`, {
207
+ email,
208
+ days,
209
+ admin_email: adminEmail
210
+ }, {
211
+ headers: { 'Authorization': `Bearer ${token}` }
212
+ });
213
+
214
+ return response.data;
215
+ } catch (error) {
216
+ if (error.response) {
217
+ return error.response.data;
218
+ }
219
+ throw new Error(`Failed to extend user: ${error.message}`);
220
+ }
221
+ }
222
+
223
+ // ========== Local Storage ==========
224
+
225
+ /**
226
+ * Save activation data locally
227
+ */
228
+ saveActivation(activationData) {
229
+ const configDir = path.join(os.homedir(), '.reepoe');
230
+ if (!fs.existsSync(configDir)) {
231
+ fs.mkdirSync(configDir, { recursive: true, mode: 0o700 });
232
+ }
233
+
234
+ const data = {
235
+ email: activationData.user?.email || activationData.email,
236
+ token: activationData.token,
237
+ activated_at: activationData.user?.activated_at || new Date().toISOString(),
238
+ expires_at: activationData.user?.expires_at,
239
+ status: activationData.user?.status || 'active'
240
+ };
241
+
242
+ fs.writeFileSync(this.activationFile, JSON.stringify(data, null, 2), { mode: 0o600 });
243
+ }
244
+
245
+ /**
246
+ * Load activation data
247
+ */
248
+ loadActivation() {
249
+ if (!fs.existsSync(this.activationFile)) {
250
+ return null;
251
+ }
252
+
253
+ try {
254
+ const data = JSON.parse(fs.readFileSync(this.activationFile, 'utf8'));
255
+ return data;
256
+ } catch (error) {
257
+ return null;
258
+ }
259
+ }
260
+
261
+ /**
262
+ * Save admin token
263
+ */
264
+ saveAdminToken(token) {
265
+ const configDir = path.join(os.homedir(), '.reepoe');
266
+ const adminFile = path.join(configDir, 'admin_session.json');
267
+
268
+ if (!fs.existsSync(configDir)) {
269
+ fs.mkdirSync(configDir, { recursive: true, mode: 0o700 });
270
+ }
271
+
272
+ const data = {
273
+ token,
274
+ created_at: new Date().toISOString(),
275
+ expires_at: new Date(Date.now() + 3600000).toISOString() // 1 hour
276
+ };
277
+
278
+ fs.writeFileSync(adminFile, JSON.stringify(data, null, 2), { mode: 0o600 });
279
+ }
280
+
281
+ /**
282
+ * Load admin token
283
+ */
284
+ loadAdminToken() {
285
+ const adminFile = path.join(os.homedir(), '.reepoe', 'admin_session.json');
286
+
287
+ if (!fs.existsSync(adminFile)) {
288
+ return null;
289
+ }
290
+
291
+ try {
292
+ const data = JSON.parse(fs.readFileSync(adminFile, 'utf8'));
293
+
294
+ // Check if expired
295
+ const expiresAt = new Date(data.expires_at);
296
+ if (new Date() > expiresAt) {
297
+ fs.unlinkSync(adminFile); // Delete expired token
298
+ return null;
299
+ }
300
+
301
+ return data.token;
302
+ } catch (error) {
303
+ return null;
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Get machine ID (for device tracking)
309
+ */
310
+ getMachineId() {
311
+ const crypto = require('crypto');
312
+ const machineInfo = `${os.hostname()}-${os.platform()}-${os.arch()}`;
313
+ return crypto.createHash('sha256').update(machineInfo).digest('hex').substring(0, 16);
314
+ }
315
+ }
316
+
317
+ module.exports = ActivationClient;
318
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reepoe/plugin",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "ReePoe AI Code Manager - Install in any codebase for instant AI agent integration",
5
5
  "keywords": [
6
6
  "ai",
@@ -51,6 +51,7 @@
51
51
  },
52
52
  "files": [
53
53
  "bin",
54
+ "lib",
54
55
  "scripts",
55
56
  "binaries",
56
57
  "README.md"