neoagent 1.6.0 → 2.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.
- package/README.md +18 -4
- package/docs/configuration.md +2 -2
- package/docs/skills.md +1 -1
- package/lib/manager.js +64 -2
- package/package.json +9 -2
- package/server/config/origins.js +34 -0
- package/server/db/database.js +0 -13
- package/server/http/errors.js +17 -0
- package/server/http/middleware.js +81 -0
- package/server/http/routes.js +45 -0
- package/server/http/socket.js +23 -0
- package/server/http/static.js +50 -0
- package/server/index.js +50 -188
- package/server/public/.last_build_id +1 -0
- package/server/public/assets/AssetManifest.bin +1 -0
- package/server/public/assets/AssetManifest.bin.json +1 -0
- package/server/public/assets/AssetManifest.json +1 -0
- package/server/public/assets/FontManifest.json +1 -0
- package/server/public/assets/NOTICES +33454 -0
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/assets/packages/cupertino_icons/assets/CupertinoIcons.ttf +0 -0
- package/server/public/assets/shaders/ink_sparkle.frag +126 -0
- package/server/public/assets/web/icons/Icon-192.png +0 -0
- package/server/public/canvaskit/canvaskit.js +192 -0
- package/server/public/canvaskit/canvaskit.js.symbols +12142 -0
- package/server/public/canvaskit/canvaskit.wasm +0 -0
- package/server/public/canvaskit/chromium/canvaskit.js +192 -0
- package/server/public/canvaskit/chromium/canvaskit.js.symbols +11106 -0
- package/server/public/canvaskit/chromium/canvaskit.wasm +0 -0
- package/server/public/canvaskit/skwasm.js +140 -0
- package/server/public/canvaskit/skwasm.js.symbols +12164 -0
- package/server/public/canvaskit/skwasm.wasm +0 -0
- package/server/public/canvaskit/skwasm_heavy.js +140 -0
- package/server/public/canvaskit/skwasm_heavy.js.symbols +13766 -0
- package/server/public/canvaskit/skwasm_heavy.wasm +0 -0
- package/server/public/favicon.png +0 -0
- package/server/public/flutter.js +32 -0
- package/server/public/flutter_bootstrap.js +43 -0
- package/server/public/flutter_service_worker.js +208 -0
- package/server/public/icons/Icon-192.png +0 -0
- package/server/public/icons/Icon-512.png +0 -0
- package/server/public/icons/Icon-maskable-192.png +0 -0
- package/server/public/icons/Icon-maskable-512.png +0 -0
- package/server/public/index.html +38 -0
- package/server/public/main.dart.js +103124 -0
- package/server/public/manifest.json +35 -0
- package/server/public/version.json +1 -0
- package/server/services/ai/models.js +2 -8
- package/server/services/ai/tools.js +0 -47
- package/server/services/browser/controller.js +34 -0
- package/server/services/manager.js +49 -118
- package/server/services/messaging/automation.js +210 -0
- package/server/utils/version.js +37 -0
- package/server/public/app.html +0 -682
- package/server/public/assets/world-office-dark.png +0 -0
- package/server/public/assets/world-office-light.png +0 -0
- package/server/public/css/app.css +0 -941
- package/server/public/css/styles.css +0 -963
- package/server/public/favicon.svg +0 -17
- package/server/public/js/app.js +0 -4105
- package/server/public/login.html +0 -313
- package/server/routes/protocols.js +0 -87
package/server/public/login.html
DELETED
|
@@ -1,313 +0,0 @@
|
|
|
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.0">
|
|
6
|
-
<title>NeoAgent — Login</title>
|
|
7
|
-
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
8
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
10
|
-
<link rel="stylesheet" href="/css/styles.css">
|
|
11
|
-
<style>
|
|
12
|
-
body {
|
|
13
|
-
display: flex;
|
|
14
|
-
align-items: center;
|
|
15
|
-
justify-content: center;
|
|
16
|
-
min-height: 100vh;
|
|
17
|
-
background: var(--bg-primary);
|
|
18
|
-
overflow: hidden;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.login-bg {
|
|
22
|
-
position: fixed;
|
|
23
|
-
inset: 0;
|
|
24
|
-
overflow: hidden;
|
|
25
|
-
z-index: 0;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
.login-bg .orb {
|
|
29
|
-
position: absolute;
|
|
30
|
-
border-radius: 50%;
|
|
31
|
-
filter: blur(120px);
|
|
32
|
-
opacity: 0.15;
|
|
33
|
-
animation: float 20s ease-in-out infinite;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
.login-bg .orb-1 {
|
|
37
|
-
width: 500px; height: 500px;
|
|
38
|
-
background: var(--accent);
|
|
39
|
-
top: -100px; left: -100px;
|
|
40
|
-
animation-delay: 0s;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.login-bg .orb-2 {
|
|
44
|
-
width: 400px; height: 400px;
|
|
45
|
-
background: #8b5cf6;
|
|
46
|
-
bottom: -80px; right: -80px;
|
|
47
|
-
animation-delay: -7s;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.login-bg .orb-3 {
|
|
51
|
-
width: 300px; height: 300px;
|
|
52
|
-
background: #06b6d4;
|
|
53
|
-
top: 50%; left: 60%;
|
|
54
|
-
animation-delay: -14s;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
@keyframes float {
|
|
58
|
-
0%, 100% { transform: translate(0, 0) scale(1); }
|
|
59
|
-
33% { transform: translate(30px, -30px) scale(1.05); }
|
|
60
|
-
66% { transform: translate(-20px, 20px) scale(0.95); }
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.login-card {
|
|
64
|
-
position: relative; z-index: 1;
|
|
65
|
-
width: 100%; max-width: 400px;
|
|
66
|
-
background: rgba(12,12,24,.92);
|
|
67
|
-
backdrop-filter: blur(24px) saturate(1.4);
|
|
68
|
-
-webkit-backdrop-filter: blur(24px) saturate(1.4);
|
|
69
|
-
border: 1px solid rgba(255,255,255,.1);
|
|
70
|
-
border-radius: 20px; padding: 40px;
|
|
71
|
-
box-shadow: 0 20px 60px rgba(0,0,0,.6);
|
|
72
|
-
animation: cardIn 400ms cubic-bezier(.16,1,.3,1) both;
|
|
73
|
-
}
|
|
74
|
-
@keyframes cardIn {
|
|
75
|
-
from { opacity: 0; transform: translateY(20px) scale(.97); }
|
|
76
|
-
to { opacity: 1; transform: translateY(0) scale(1); }
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.login-logo {
|
|
80
|
-
text-align: center;
|
|
81
|
-
margin-bottom: 32px;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
.login-logo .logo-icon {
|
|
85
|
-
width: 52px; height: 52px;
|
|
86
|
-
background: linear-gradient(135deg, var(--accent), #8b5cf6);
|
|
87
|
-
border-radius: 14px;
|
|
88
|
-
display: inline-flex; align-items: center; justify-content: center;
|
|
89
|
-
margin-bottom: 16px;
|
|
90
|
-
box-shadow: 0 4px 24px rgba(99,102,241,.45);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.login-logo .logo-icon svg {
|
|
94
|
-
width: 28px;
|
|
95
|
-
height: 28px;
|
|
96
|
-
stroke: white;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
.login-logo h1 {
|
|
100
|
-
font-size: 24px;
|
|
101
|
-
font-weight: 700;
|
|
102
|
-
margin-bottom: 4px;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
.login-logo p {
|
|
106
|
-
color: var(--text-secondary);
|
|
107
|
-
font-size: 14px;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
.login-tabs {
|
|
111
|
-
display: flex;
|
|
112
|
-
margin-bottom: 24px;
|
|
113
|
-
background: var(--bg-primary);
|
|
114
|
-
border-radius: var(--radius);
|
|
115
|
-
padding: 3px;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
.login-tab {
|
|
119
|
-
flex: 1;
|
|
120
|
-
text-align: center;
|
|
121
|
-
padding: 8px;
|
|
122
|
-
cursor: pointer;
|
|
123
|
-
border-radius: 6px;
|
|
124
|
-
font-weight: 500;
|
|
125
|
-
font-size: 13px;
|
|
126
|
-
color: var(--text-secondary);
|
|
127
|
-
transition: all var(--transition);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.login-tab.active {
|
|
131
|
-
background: var(--accent);
|
|
132
|
-
color: white;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
.login-form { display: none; }
|
|
136
|
-
.login-form.active { display: block; }
|
|
137
|
-
|
|
138
|
-
.login-form .btn {
|
|
139
|
-
width: 100%;
|
|
140
|
-
justify-content: center;
|
|
141
|
-
padding: 12px;
|
|
142
|
-
margin-top: 8px;
|
|
143
|
-
font-size: 14px;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
.login-error {
|
|
147
|
-
background: rgba(239, 68, 68, 0.1);
|
|
148
|
-
border: 1px solid rgba(239, 68, 68, 0.3);
|
|
149
|
-
color: var(--error);
|
|
150
|
-
padding: 10px 14px;
|
|
151
|
-
border-radius: var(--radius);
|
|
152
|
-
font-size: 13px;
|
|
153
|
-
margin-bottom: 16px;
|
|
154
|
-
display: none;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
.login-error.show { display: block; }
|
|
158
|
-
</style>
|
|
159
|
-
</head>
|
|
160
|
-
<body>
|
|
161
|
-
<div class="login-bg">
|
|
162
|
-
<div class="orb orb-1"></div>
|
|
163
|
-
<div class="orb orb-2"></div>
|
|
164
|
-
<div class="orb orb-3"></div>
|
|
165
|
-
</div>
|
|
166
|
-
|
|
167
|
-
<div class="login-card">
|
|
168
|
-
<div class="login-logo">
|
|
169
|
-
<div class="logo-icon">
|
|
170
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
|
171
|
-
<polygon points="12,2 2,7 12,12 22,7" fill="white" stroke="none"/>
|
|
172
|
-
<polyline points="2,17 12,22 22,17" fill="none" stroke="white" stroke-width="2"/>
|
|
173
|
-
<polyline points="2,12 12,17 22,12" fill="none" stroke="white" stroke-width="2"/>
|
|
174
|
-
</svg>
|
|
175
|
-
</div>
|
|
176
|
-
<h1>NeoAgent</h1>
|
|
177
|
-
<p>Your proactive AI agent</p>
|
|
178
|
-
</div>
|
|
179
|
-
|
|
180
|
-
<div class="login-tabs" id="tabBar" style="display:none">
|
|
181
|
-
<div class="login-tab active" data-tab="login">Sign In</div>
|
|
182
|
-
<div class="login-tab" data-tab="register" id="registerTab" style="display:none">Setup</div>
|
|
183
|
-
</div>
|
|
184
|
-
|
|
185
|
-
<div class="login-error" id="error"></div>
|
|
186
|
-
|
|
187
|
-
<form class="login-form active" id="loginForm" data-tab="login">
|
|
188
|
-
<div class="form-group">
|
|
189
|
-
<label class="form-label">Username</label>
|
|
190
|
-
<input type="text" class="input" name="username" autocomplete="username" required autofocus>
|
|
191
|
-
</div>
|
|
192
|
-
<div class="form-group">
|
|
193
|
-
<label class="form-label">Password</label>
|
|
194
|
-
<input type="password" class="input" name="password" autocomplete="current-password" required>
|
|
195
|
-
</div>
|
|
196
|
-
<button type="submit" class="btn btn-primary">Sign In</button>
|
|
197
|
-
</form>
|
|
198
|
-
|
|
199
|
-
<form class="login-form" id="registerForm" data-tab="register">
|
|
200
|
-
<div class="form-group">
|
|
201
|
-
<label class="form-label">Username</label>
|
|
202
|
-
<input type="text" class="input" name="username" autocomplete="username" required minlength="3">
|
|
203
|
-
</div>
|
|
204
|
-
<div class="form-group">
|
|
205
|
-
<label class="form-label">Password</label>
|
|
206
|
-
<input type="password" class="input" name="password" autocomplete="new-password" required minlength="8">
|
|
207
|
-
</div>
|
|
208
|
-
<div class="form-group">
|
|
209
|
-
<label class="form-label">Confirm Password</label>
|
|
210
|
-
<input type="password" class="input" name="confirmPassword" autocomplete="new-password" required>
|
|
211
|
-
</div>
|
|
212
|
-
<button type="submit" class="btn btn-primary">Create Account</button>
|
|
213
|
-
</form>
|
|
214
|
-
</div>
|
|
215
|
-
|
|
216
|
-
<script>
|
|
217
|
-
const tabs = document.querySelectorAll('.login-tab');
|
|
218
|
-
const forms = document.querySelectorAll('.login-form');
|
|
219
|
-
const errorEl = document.getElementById('error');
|
|
220
|
-
|
|
221
|
-
function switchTab(target) {
|
|
222
|
-
tabs.forEach(t => t.classList.toggle('active', t.dataset.tab === target));
|
|
223
|
-
forms.forEach(f => f.classList.toggle('active', f.dataset.tab === target));
|
|
224
|
-
errorEl.classList.remove('show');
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
tabs.forEach(tab => tab.addEventListener('click', () => switchTab(tab.dataset.tab)));
|
|
228
|
-
|
|
229
|
-
// Show tab bar + setup tab only if no user exists yet; otherwise hide the whole bar
|
|
230
|
-
fetch('/api/auth/status', { credentials: 'include' }).then(r => r.json()).then(data => {
|
|
231
|
-
if (!data.hasUser) {
|
|
232
|
-
document.getElementById('registerTab').style.display = '';
|
|
233
|
-
document.getElementById('tabBar').style.display = '';
|
|
234
|
-
switchTab('register');
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
function showError(msg) {
|
|
239
|
-
errorEl.textContent = msg;
|
|
240
|
-
errorEl.classList.add('show');
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
document.getElementById('loginForm').addEventListener('submit', async (e) => {
|
|
244
|
-
e.preventDefault();
|
|
245
|
-
const form = e.target;
|
|
246
|
-
const btn = form.querySelector('button');
|
|
247
|
-
btn.disabled = true;
|
|
248
|
-
btn.textContent = 'Signing in...';
|
|
249
|
-
errorEl.classList.remove('show');
|
|
250
|
-
|
|
251
|
-
try {
|
|
252
|
-
const res = await fetch('/api/auth/login', {
|
|
253
|
-
method: 'POST',
|
|
254
|
-
headers: { 'Content-Type': 'application/json' },
|
|
255
|
-
credentials: 'include',
|
|
256
|
-
body: JSON.stringify({
|
|
257
|
-
username: form.username.value,
|
|
258
|
-
password: form.password.value
|
|
259
|
-
})
|
|
260
|
-
});
|
|
261
|
-
const data = await res.json();
|
|
262
|
-
if (res.ok) {
|
|
263
|
-
window.location.href = data.redirect || '/app';
|
|
264
|
-
} else {
|
|
265
|
-
showError(data.error || 'Login failed');
|
|
266
|
-
}
|
|
267
|
-
} catch (err) {
|
|
268
|
-
showError('Connection error');
|
|
269
|
-
} finally {
|
|
270
|
-
btn.disabled = false;
|
|
271
|
-
btn.textContent = 'Sign In';
|
|
272
|
-
}
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
document.getElementById('registerForm').addEventListener('submit', async (e) => {
|
|
276
|
-
e.preventDefault();
|
|
277
|
-
const form = e.target;
|
|
278
|
-
const btn = form.querySelector('button');
|
|
279
|
-
|
|
280
|
-
if (form.password.value !== form.confirmPassword.value) {
|
|
281
|
-
return showError('Passwords do not match');
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
btn.disabled = true;
|
|
285
|
-
btn.textContent = 'Creating account...';
|
|
286
|
-
errorEl.classList.remove('show');
|
|
287
|
-
|
|
288
|
-
try {
|
|
289
|
-
const res = await fetch('/api/auth/register', {
|
|
290
|
-
method: 'POST',
|
|
291
|
-
headers: { 'Content-Type': 'application/json' },
|
|
292
|
-
credentials: 'include',
|
|
293
|
-
body: JSON.stringify({
|
|
294
|
-
username: form.username.value,
|
|
295
|
-
password: form.password.value
|
|
296
|
-
})
|
|
297
|
-
});
|
|
298
|
-
const data = await res.json();
|
|
299
|
-
if (res.ok) {
|
|
300
|
-
window.location.href = data.redirect || '/app';
|
|
301
|
-
} else {
|
|
302
|
-
showError(data.error || 'Setup failed');
|
|
303
|
-
}
|
|
304
|
-
} catch (err) {
|
|
305
|
-
showError('Connection error');
|
|
306
|
-
} finally {
|
|
307
|
-
btn.disabled = false;
|
|
308
|
-
btn.textContent = 'Create Account';
|
|
309
|
-
}
|
|
310
|
-
});
|
|
311
|
-
</script>
|
|
312
|
-
</body>
|
|
313
|
-
</html>
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
const express = require('express');
|
|
2
|
-
const router = express.Router();
|
|
3
|
-
const db = require('../db/database');
|
|
4
|
-
const { requireAuth } = require('../middleware/auth');
|
|
5
|
-
|
|
6
|
-
router.use(requireAuth);
|
|
7
|
-
|
|
8
|
-
// List protocols
|
|
9
|
-
router.get('/', (req, res) => {
|
|
10
|
-
try {
|
|
11
|
-
const protocols = db.prepare('SELECT id, name, description, content, updated_at FROM protocols WHERE user_id = ? ORDER BY name ASC').all(req.session.userId);
|
|
12
|
-
res.json(protocols);
|
|
13
|
-
} catch (err) {
|
|
14
|
-
res.status(500).json({ error: err.message });
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
// Get single protocol
|
|
19
|
-
router.get('/:id', (req, res) => {
|
|
20
|
-
try {
|
|
21
|
-
const p = db.prepare('SELECT * FROM protocols WHERE id = ? AND user_id = ?').get(req.params.id, req.session.userId);
|
|
22
|
-
if (!p) return res.status(404).json({ error: 'Not found' });
|
|
23
|
-
res.json(p);
|
|
24
|
-
} catch (err) {
|
|
25
|
-
res.status(500).json({ error: err.message });
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
// Create protocol
|
|
30
|
-
router.post('/', (req, res) => {
|
|
31
|
-
try {
|
|
32
|
-
const { name, description, content } = req.body;
|
|
33
|
-
if (!name || !content) return res.status(400).json({ error: 'Name and content are required' });
|
|
34
|
-
|
|
35
|
-
const stmt = db.prepare('INSERT INTO protocols (user_id, name, description, content) VALUES (?, ?, ?, ?)');
|
|
36
|
-
const info = stmt.run(req.session.userId, name, description || '', content);
|
|
37
|
-
|
|
38
|
-
const p = db.prepare('SELECT * FROM protocols WHERE id = ?').get(info.lastInsertRowid);
|
|
39
|
-
res.status(201).json(p);
|
|
40
|
-
} catch (err) {
|
|
41
|
-
if (err.code === 'SQLITE_CONSTRAINT_UNIQUE') {
|
|
42
|
-
return res.status(400).json({ error: 'Protocol with this name already exists' });
|
|
43
|
-
}
|
|
44
|
-
res.status(500).json({ error: err.message });
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
// Update protocol
|
|
49
|
-
router.put('/:id', (req, res) => {
|
|
50
|
-
try {
|
|
51
|
-
const { name, description, content } = req.body;
|
|
52
|
-
|
|
53
|
-
// check existence
|
|
54
|
-
const existing = db.prepare('SELECT id FROM protocols WHERE id = ? AND user_id = ?').get(req.params.id, req.session.userId);
|
|
55
|
-
if (!existing) return res.status(404).json({ error: 'Not found' });
|
|
56
|
-
|
|
57
|
-
const stmt = db.prepare(`
|
|
58
|
-
UPDATE protocols
|
|
59
|
-
SET name = ?, description = ?, content = ?, updated_at = datetime('now')
|
|
60
|
-
WHERE id = ? AND user_id = ?
|
|
61
|
-
`);
|
|
62
|
-
|
|
63
|
-
stmt.run(name, description || '', content, req.params.id, req.session.userId);
|
|
64
|
-
const p = db.prepare('SELECT * FROM protocols WHERE id = ?').get(req.params.id);
|
|
65
|
-
res.json(p);
|
|
66
|
-
} catch (err) {
|
|
67
|
-
if (err.code === 'SQLITE_CONSTRAINT_UNIQUE') {
|
|
68
|
-
return res.status(400).json({ error: 'Protocol with this name already exists' });
|
|
69
|
-
}
|
|
70
|
-
res.status(500).json({ error: err.message });
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
// Delete protocol
|
|
75
|
-
router.delete('/:id', (req, res) => {
|
|
76
|
-
try {
|
|
77
|
-
const stmt = db.prepare('DELETE FROM protocols WHERE id = ? AND user_id = ?');
|
|
78
|
-
const info = stmt.run(req.params.id, req.session.userId);
|
|
79
|
-
|
|
80
|
-
if (info.changes === 0) return res.status(404).json({ error: 'Not found' });
|
|
81
|
-
res.json({ success: true });
|
|
82
|
-
} catch (err) {
|
|
83
|
-
res.status(500).json({ error: err.message });
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
module.exports = router;
|