agentdev-webui 1.0.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.
Files changed (39) hide show
  1. package/lib/agent-api.js +530 -0
  2. package/lib/auth.js +127 -0
  3. package/lib/config.js +53 -0
  4. package/lib/database.js +762 -0
  5. package/lib/device-flow.js +257 -0
  6. package/lib/email.js +420 -0
  7. package/lib/encryption.js +112 -0
  8. package/lib/github.js +339 -0
  9. package/lib/history.js +143 -0
  10. package/lib/pwa.js +107 -0
  11. package/lib/redis-logs.js +226 -0
  12. package/lib/routes.js +680 -0
  13. package/migrations/000_create_database.sql +33 -0
  14. package/migrations/001_create_agentdev_schema.sql +135 -0
  15. package/migrations/001_create_agentdev_schema.sql.old +100 -0
  16. package/migrations/001_create_agentdev_schema_fixed.sql +135 -0
  17. package/migrations/002_add_github_token.sql +17 -0
  18. package/migrations/003_add_agent_logs_table.sql +23 -0
  19. package/migrations/004_remove_oauth_columns.sql +11 -0
  20. package/migrations/005_add_projects.sql +44 -0
  21. package/migrations/006_project_github_token.sql +7 -0
  22. package/migrations/007_project_repositories.sql +12 -0
  23. package/migrations/008_add_notifications.sql +20 -0
  24. package/migrations/009_unified_oauth.sql +153 -0
  25. package/migrations/README.md +97 -0
  26. package/package.json +37 -0
  27. package/public/css/styles.css +1140 -0
  28. package/public/device.html +384 -0
  29. package/public/docs.html +862 -0
  30. package/public/docs.md +697 -0
  31. package/public/favicon.svg +5 -0
  32. package/public/index.html +271 -0
  33. package/public/js/app.js +2379 -0
  34. package/public/login.html +224 -0
  35. package/public/profile.html +394 -0
  36. package/public/register.html +392 -0
  37. package/public/reset-password.html +349 -0
  38. package/public/verify-email.html +177 -0
  39. package/server.js +1450 -0
@@ -0,0 +1,392 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
6
+ <meta name="theme-color" content="#1a1a2e">
7
+ <meta name="apple-mobile-web-app-capable" content="yes">
8
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
9
+ <meta name="description" content="Create an Agent Dev account">
10
+ <meta property="og:title" content="Register - Agent Dev">
11
+ <meta property="og:description" content="Create an Agent Dev account">
12
+ <meta property="og:type" content="website">
13
+ <meta property="og:image" content="/og-image.svg">
14
+ <meta name="twitter:card" content="summary_large_image">
15
+ <meta name="twitter:title" content="Register - Agent Dev">
16
+ <meta name="twitter:description" content="Create an Agent Dev account">
17
+ <meta name="twitter:image" content="/og-image.svg">
18
+ <title>Register - Agent Dev</title>
19
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg">
20
+ <link rel="apple-touch-icon" href="/icon-192.png">
21
+ <link rel="manifest" href="/manifest.json">
22
+ <link rel="stylesheet" href="/css/styles.css">
23
+ <style>
24
+ .register-container {
25
+ min-height: 100vh;
26
+ display: flex;
27
+ align-items: center;
28
+ justify-content: center;
29
+ padding: 20px;
30
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
31
+ }
32
+
33
+ .register-box {
34
+ background: rgba(255, 255, 255, 0.05);
35
+ backdrop-filter: blur(10px);
36
+ border: 1px solid rgba(255, 255, 255, 0.1);
37
+ border-radius: 16px;
38
+ padding: 40px;
39
+ width: 100%;
40
+ max-width: 450px;
41
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
42
+ }
43
+
44
+ .register-header {
45
+ text-align: center;
46
+ margin-bottom: 32px;
47
+ }
48
+
49
+ .register-header h1 {
50
+ color: #ffffff;
51
+ font-size: 28px;
52
+ margin-bottom: 8px;
53
+ font-weight: 600;
54
+ }
55
+
56
+ .register-header p {
57
+ color: rgba(255, 255, 255, 0.6);
58
+ font-size: 14px;
59
+ margin: 0;
60
+ }
61
+
62
+ .form-group {
63
+ margin-bottom: 20px;
64
+ }
65
+
66
+ .form-group label {
67
+ display: block;
68
+ color: rgba(255, 255, 255, 0.8);
69
+ font-size: 14px;
70
+ margin-bottom: 8px;
71
+ font-weight: 500;
72
+ }
73
+
74
+ .form-group input {
75
+ width: 100%;
76
+ padding: 12px 16px;
77
+ background: rgba(255, 255, 255, 0.05);
78
+ border: 1px solid rgba(255, 255, 255, 0.1);
79
+ border-radius: 8px;
80
+ color: #ffffff;
81
+ font-size: 15px;
82
+ transition: all 0.3s ease;
83
+ box-sizing: border-box;
84
+ }
85
+
86
+ .form-group input:focus {
87
+ outline: none;
88
+ border-color: rgba(255, 107, 107, 0.5);
89
+ background: rgba(255, 255, 255, 0.08);
90
+ }
91
+
92
+ .form-group input::placeholder {
93
+ color: rgba(255, 255, 255, 0.3);
94
+ }
95
+
96
+ .form-help {
97
+ color: rgba(255, 255, 255, 0.4);
98
+ font-size: 12px;
99
+ margin-top: 4px;
100
+ }
101
+
102
+ .register-button {
103
+ width: 100%;
104
+ padding: 14px;
105
+ background: linear-gradient(135deg, #ff6b6b 0%, #ee5a6f 100%);
106
+ border: none;
107
+ border-radius: 8px;
108
+ color: white;
109
+ font-size: 16px;
110
+ font-weight: 600;
111
+ cursor: pointer;
112
+ transition: all 0.3s ease;
113
+ margin-top: 24px;
114
+ }
115
+
116
+ .register-button:hover {
117
+ transform: translateY(-2px);
118
+ box-shadow: 0 8px 20px rgba(255, 107, 107, 0.3);
119
+ }
120
+
121
+ .register-button:active {
122
+ transform: translateY(0);
123
+ }
124
+
125
+ .register-button:disabled {
126
+ opacity: 0.5;
127
+ cursor: not-allowed;
128
+ transform: none;
129
+ }
130
+
131
+ .error-message {
132
+ background: rgba(255, 107, 107, 0.1);
133
+ border: 1px solid rgba(255, 107, 107, 0.3);
134
+ border-radius: 8px;
135
+ padding: 12px 16px;
136
+ color: #ff6b6b;
137
+ font-size: 14px;
138
+ margin-bottom: 20px;
139
+ display: none;
140
+ }
141
+
142
+ .success-message {
143
+ background: rgba(76, 209, 55, 0.1);
144
+ border: 1px solid rgba(76, 209, 55, 0.3);
145
+ border-radius: 8px;
146
+ padding: 12px 16px;
147
+ color: #4cd137;
148
+ font-size: 14px;
149
+ margin-bottom: 20px;
150
+ display: none;
151
+ }
152
+
153
+ .login-link {
154
+ text-align: center;
155
+ margin-top: 24px;
156
+ padding-top: 24px;
157
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
158
+ }
159
+
160
+ .login-link p {
161
+ color: rgba(255, 255, 255, 0.6);
162
+ font-size: 14px;
163
+ margin: 0;
164
+ }
165
+
166
+ .login-link a {
167
+ color: #ff6b6b;
168
+ text-decoration: none;
169
+ font-weight: 500;
170
+ transition: color 0.3s ease;
171
+ }
172
+
173
+ .login-link a:hover {
174
+ color: #ee5a6f;
175
+ }
176
+
177
+ .password-requirements {
178
+ background: rgba(255, 255, 255, 0.03);
179
+ border: 1px solid rgba(255, 255, 255, 0.1);
180
+ border-radius: 8px;
181
+ padding: 12px 16px;
182
+ margin-top: 8px;
183
+ }
184
+
185
+ .password-requirements ul {
186
+ margin: 8px 0 0 0;
187
+ padding-left: 20px;
188
+ color: rgba(255, 255, 255, 0.5);
189
+ font-size: 12px;
190
+ }
191
+
192
+ .password-requirements li {
193
+ margin: 4px 0;
194
+ }
195
+
196
+ .password-requirements li.valid {
197
+ color: #4cd137;
198
+ }
199
+ </style>
200
+ </head>
201
+ <body>
202
+ <div class="register-container">
203
+ <div class="register-box">
204
+ <div class="register-header">
205
+ <img src="/favicon.svg" width="48" height="48" alt="Agent Dev" style="margin-bottom: 12px;">
206
+ <h1>Create Account</h1>
207
+ <p>Join AgentDev to manage distributed agents</p>
208
+ </div>
209
+
210
+ <div id="error" class="error-message"></div>
211
+ <div id="success" class="success-message"></div>
212
+
213
+ <form id="registerForm">
214
+ <div class="form-group">
215
+ <label for="email">Email Address</label>
216
+ <input
217
+ type="email"
218
+ id="email"
219
+ name="email"
220
+ placeholder="you@example.com"
221
+ required
222
+ autocomplete="email"
223
+ >
224
+ </div>
225
+
226
+ <div class="form-group">
227
+ <label for="password">Password</label>
228
+ <input
229
+ type="password"
230
+ id="password"
231
+ name="password"
232
+ placeholder="Enter a strong password"
233
+ required
234
+ autocomplete="new-password"
235
+ >
236
+ <div class="password-requirements">
237
+ <strong style="color: rgba(255, 255, 255, 0.7); font-size: 12px;">Password must contain:</strong>
238
+ <ul id="requirements">
239
+ <li id="req-length">At least 8 characters</li>
240
+ <li id="req-uppercase">One uppercase letter</li>
241
+ <li id="req-lowercase">One lowercase letter</li>
242
+ <li id="req-number">One number</li>
243
+ </ul>
244
+ </div>
245
+ </div>
246
+
247
+ <div class="form-group">
248
+ <label for="confirmPassword">Confirm Password</label>
249
+ <input
250
+ type="password"
251
+ id="confirmPassword"
252
+ name="confirmPassword"
253
+ placeholder="Re-enter your password"
254
+ required
255
+ autocomplete="new-password"
256
+ >
257
+ </div>
258
+
259
+ <div class="form-group">
260
+ <label for="maxAgents">Maximum Agents (Optional)</label>
261
+ <input
262
+ type="number"
263
+ id="maxAgents"
264
+ name="maxAgents"
265
+ placeholder="3"
266
+ min="1"
267
+ max="10"
268
+ value="3"
269
+ >
270
+ <div class="form-help">Number of agents you can register (1-10, default: 3)</div>
271
+ </div>
272
+
273
+ <button type="submit" class="register-button" id="registerBtn">
274
+ Create Account
275
+ </button>
276
+ </form>
277
+
278
+ <div class="login-link">
279
+ <p>Already have an account? <a href="/login">Sign in</a></p>
280
+ </div>
281
+ </div>
282
+ </div>
283
+
284
+ <script>
285
+ const form = document.getElementById('registerForm');
286
+ const errorDiv = document.getElementById('error');
287
+ const successDiv = document.getElementById('success');
288
+ const registerBtn = document.getElementById('registerBtn');
289
+ const passwordInput = document.getElementById('password');
290
+ const confirmPasswordInput = document.getElementById('confirmPassword');
291
+
292
+ // Password validation
293
+ const requirements = {
294
+ length: (pass) => pass.length >= 8,
295
+ uppercase: (pass) => /[A-Z]/.test(pass),
296
+ lowercase: (pass) => /[a-z]/.test(pass),
297
+ number: (pass) => /[0-9]/.test(pass)
298
+ };
299
+
300
+ passwordInput.addEventListener('input', () => {
301
+ const password = passwordInput.value;
302
+
303
+ Object.keys(requirements).forEach(key => {
304
+ const element = document.getElementById(`req-${key}`);
305
+ if (requirements[key](password)) {
306
+ element.classList.add('valid');
307
+ } else {
308
+ element.classList.remove('valid');
309
+ }
310
+ });
311
+ });
312
+
313
+ function showError(message) {
314
+ errorDiv.textContent = message;
315
+ errorDiv.style.display = 'block';
316
+ successDiv.style.display = 'none';
317
+ }
318
+
319
+ function showSuccess(message) {
320
+ successDiv.textContent = message;
321
+ successDiv.style.display = 'block';
322
+ errorDiv.style.display = 'none';
323
+ }
324
+
325
+ function hideMessages() {
326
+ errorDiv.style.display = 'none';
327
+ successDiv.style.display = 'none';
328
+ }
329
+
330
+ form.addEventListener('submit', async (e) => {
331
+ e.preventDefault();
332
+ hideMessages();
333
+
334
+ const email = document.getElementById('email').value.trim();
335
+ const password = document.getElementById('password').value;
336
+ const confirmPassword = document.getElementById('confirmPassword').value;
337
+ const maxAgents = parseInt(document.getElementById('maxAgents').value) || 3;
338
+
339
+ // Validation
340
+ if (!email || !password) {
341
+ showError('Please fill in all required fields');
342
+ return;
343
+ }
344
+
345
+ if (password !== confirmPassword) {
346
+ showError('Passwords do not match');
347
+ return;
348
+ }
349
+
350
+ // Check password requirements
351
+ const allValid = Object.values(requirements).every(fn => fn(password));
352
+ if (!allValid) {
353
+ showError('Password does not meet requirements');
354
+ return;
355
+ }
356
+
357
+ if (maxAgents < 1 || maxAgents > 10) {
358
+ showError('Max agents must be between 1 and 10');
359
+ return;
360
+ }
361
+
362
+ registerBtn.disabled = true;
363
+ registerBtn.textContent = 'Creating account...';
364
+
365
+ try {
366
+ const response = await fetch('/api/register', {
367
+ method: 'POST',
368
+ headers: { 'Content-Type': 'application/json' },
369
+ body: JSON.stringify({ email, password, maxAgents })
370
+ });
371
+
372
+ const data = await response.json();
373
+
374
+ if (response.ok) {
375
+ showSuccess('Account created successfully! Redirecting to login...');
376
+ setTimeout(() => {
377
+ window.location.href = '/login';
378
+ }, 2000);
379
+ } else {
380
+ showError(data.error || 'Registration failed');
381
+ registerBtn.disabled = false;
382
+ registerBtn.textContent = 'Create Account';
383
+ }
384
+ } catch (error) {
385
+ showError('Network error. Please try again.');
386
+ registerBtn.disabled = false;
387
+ registerBtn.textContent = 'Create Account';
388
+ }
389
+ });
390
+ </script>
391
+ </body>
392
+ </html>