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.
Files changed (62) hide show
  1. package/README.md +18 -4
  2. package/docs/configuration.md +2 -2
  3. package/docs/skills.md +1 -1
  4. package/lib/manager.js +64 -2
  5. package/package.json +9 -2
  6. package/server/config/origins.js +34 -0
  7. package/server/db/database.js +0 -13
  8. package/server/http/errors.js +17 -0
  9. package/server/http/middleware.js +81 -0
  10. package/server/http/routes.js +45 -0
  11. package/server/http/socket.js +23 -0
  12. package/server/http/static.js +50 -0
  13. package/server/index.js +50 -188
  14. package/server/public/.last_build_id +1 -0
  15. package/server/public/assets/AssetManifest.bin +1 -0
  16. package/server/public/assets/AssetManifest.bin.json +1 -0
  17. package/server/public/assets/AssetManifest.json +1 -0
  18. package/server/public/assets/FontManifest.json +1 -0
  19. package/server/public/assets/NOTICES +33454 -0
  20. package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
  21. package/server/public/assets/packages/cupertino_icons/assets/CupertinoIcons.ttf +0 -0
  22. package/server/public/assets/shaders/ink_sparkle.frag +126 -0
  23. package/server/public/assets/web/icons/Icon-192.png +0 -0
  24. package/server/public/canvaskit/canvaskit.js +192 -0
  25. package/server/public/canvaskit/canvaskit.js.symbols +12142 -0
  26. package/server/public/canvaskit/canvaskit.wasm +0 -0
  27. package/server/public/canvaskit/chromium/canvaskit.js +192 -0
  28. package/server/public/canvaskit/chromium/canvaskit.js.symbols +11106 -0
  29. package/server/public/canvaskit/chromium/canvaskit.wasm +0 -0
  30. package/server/public/canvaskit/skwasm.js +140 -0
  31. package/server/public/canvaskit/skwasm.js.symbols +12164 -0
  32. package/server/public/canvaskit/skwasm.wasm +0 -0
  33. package/server/public/canvaskit/skwasm_heavy.js +140 -0
  34. package/server/public/canvaskit/skwasm_heavy.js.symbols +13766 -0
  35. package/server/public/canvaskit/skwasm_heavy.wasm +0 -0
  36. package/server/public/favicon.png +0 -0
  37. package/server/public/flutter.js +32 -0
  38. package/server/public/flutter_bootstrap.js +43 -0
  39. package/server/public/flutter_service_worker.js +208 -0
  40. package/server/public/icons/Icon-192.png +0 -0
  41. package/server/public/icons/Icon-512.png +0 -0
  42. package/server/public/icons/Icon-maskable-192.png +0 -0
  43. package/server/public/icons/Icon-maskable-512.png +0 -0
  44. package/server/public/index.html +38 -0
  45. package/server/public/main.dart.js +103124 -0
  46. package/server/public/manifest.json +35 -0
  47. package/server/public/version.json +1 -0
  48. package/server/services/ai/models.js +2 -8
  49. package/server/services/ai/tools.js +0 -47
  50. package/server/services/browser/controller.js +34 -0
  51. package/server/services/manager.js +49 -118
  52. package/server/services/messaging/automation.js +210 -0
  53. package/server/utils/version.js +37 -0
  54. package/server/public/app.html +0 -682
  55. package/server/public/assets/world-office-dark.png +0 -0
  56. package/server/public/assets/world-office-light.png +0 -0
  57. package/server/public/css/app.css +0 -941
  58. package/server/public/css/styles.css +0 -963
  59. package/server/public/favicon.svg +0 -17
  60. package/server/public/js/app.js +0 -4105
  61. package/server/public/login.html +0 -313
  62. package/server/routes/protocols.js +0 -87
package/server/index.js CHANGED
@@ -1,220 +1,82 @@
1
- const { ENV_FILE, DATA_DIR, APP_DIR, migrateLegacyRuntime, ensureRuntimeDirs } = require('../runtime/paths');
1
+ 'use strict';
2
+
3
+ const {
4
+ ENV_FILE,
5
+ migrateLegacyRuntime,
6
+ ensureRuntimeDirs
7
+ } = require('../runtime/paths');
8
+
2
9
  require('dotenv').config({ path: ENV_FILE });
3
10
  migrateLegacyRuntime();
4
11
  ensureRuntimeDirs();
5
12
 
6
13
  const express = require('express');
7
- const session = require('express-session');
8
- const SQLiteStore = require('connect-sqlite3')(session);
9
14
  const { createServer } = require('http');
10
- const { Server: SocketIO } = require('socket.io');
11
- const helmet = require('helmet');
12
- const cors = require('cors');
13
- const path = require('path');
14
15
 
15
16
  const db = require('./db/database');
16
- const { requireAuth, requireNoAuth } = require('./middleware/auth');
17
- const { sanitizeError } = require('./utils/security');
18
17
  const { setupConsoleInterceptor } = require('./utils/logger');
19
- const { setupTelnyxWebhook } = require('./routes/telnyx');
20
- const { startServices } = require('./services/manager');
21
- const packageJson = require('../package.json');
22
-
23
- const app = express();
24
- const httpServer = createServer(app);
25
- const io = new SocketIO(httpServer, {
26
- cors: {
27
- origin: process.env.ALLOWED_ORIGINS ? process.env.ALLOWED_ORIGINS.split(',') : false,
28
- credentials: true
29
- }
30
- });
31
-
32
- // ── Console Log Interceptor ──
33
- setupConsoleInterceptor(io);
18
+ const { validateOrigin } = require('./config/origins');
19
+ const {
20
+ applyHttpMiddleware,
21
+ createSessionMiddleware
22
+ } = require('./http/middleware');
23
+ const { createSocketServer, bindSocketSessions } = require('./http/socket');
24
+ const { registerApiRoutes } = require('./http/routes');
25
+ const { registerStaticRoutes } = require('./http/static');
26
+ const { registerErrorHandler } = require('./http/errors');
27
+ const { startServices, stopServices } = require('./services/manager');
28
+
29
+ const PORT = Number(process.env.PORT) || 3333;
30
+ const SECURE_COOKIES = process.env.SECURE_COOKIES === 'true';
34
31
 
35
32
  if (!process.env.SESSION_SECRET) {
36
- console.warn('WARNING: SESSION_SECRET not set — using insecure default. Set it in .env before exposing this server.');
33
+ console.warn(
34
+ 'WARNING: SESSION_SECRET not set — using insecure default. Set it in .env before exposing this server.'
35
+ );
37
36
  }
38
37
 
39
- const PORT = process.env.PORT || 3333;
40
-
41
- // ── Middleware ──
42
-
43
- const SECURE_COOKIES = process.env.SECURE_COOKIES === 'true';
44
- if (SECURE_COOKIES) {
45
- app.set('trust proxy', 1);
46
- }
47
-
48
- const wsConnectSrc = SECURE_COOKIES ? ['wss:'] : ['ws:', 'wss:'];
49
-
50
- app.use(helmet({
51
- strictTransportSecurity: false,
52
- crossOriginOpenerPolicy: false,
53
- originAgentCluster: false,
54
- contentSecurityPolicy: {
55
- directives: {
56
- defaultSrc: ["'self'"],
57
- scriptSrc: ["'self'", "'unsafe-inline'", "https://cdn.jsdelivr.net"],
58
- scriptSrcAttr: ["'unsafe-inline'"],
59
- styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
60
- imgSrc: ["'self'", "data:", "blob:", "https://api.qrserver.com"],
61
- connectSrc: ["'self'", "https://fonts.googleapis.com", "https://fonts.gstatic.com", ...wsConnectSrc],
62
- fontSrc: ["'self'", "data:", "https://fonts.gstatic.com"],
63
- formAction: ["'self'"],
64
- frameAncestors: ["'self'"],
65
- upgradeInsecureRequests: null
66
- }
67
- }
68
- }));
69
-
70
- app.use(cors({
71
- origin: process.env.ALLOWED_ORIGINS ? process.env.ALLOWED_ORIGINS.split(',') : false,
72
- credentials: true
73
- }));
74
- app.use(express.json({ limit: '10mb' }));
75
- app.use(express.urlencoded({ extended: true }));
76
-
77
- const sessionMiddleware = session({
78
- store: new SQLiteStore({ db: 'sessions.db', dir: DATA_DIR }),
79
- secret: process.env.SESSION_SECRET || 'neoagent-dev-secret-change-me',
80
- name: 'neoagent.sid',
81
- resave: false,
82
- saveUninitialized: false,
83
- cookie: {
84
- maxAge: 7 * 24 * 60 * 60 * 1000,
85
- httpOnly: true,
86
- sameSite: 'lax',
87
- secure: SECURE_COOKIES
88
- }
89
- });
90
-
91
- app.use(sessionMiddleware);
92
-
93
- io.use((socket, next) => {
94
- sessionMiddleware(socket.request, {}, next);
95
- });
96
-
97
- // ── Routes ──
98
-
99
- app.use(require('./routes/auth'));
100
- app.use('/api/settings', require('./routes/settings'));
101
- app.use('/api/agents', require('./routes/agents'));
102
- app.use('/api/messaging', require('./routes/messaging'));
103
- app.use('/api/mcp', require('./routes/mcp'));
104
- app.use('/api/skills', require('./routes/skills'));
105
- app.use('/api/protocols', require('./routes/protocols'));
106
- app.use('/api/store', require('./routes/store'));
107
- app.use('/api/memory', require('./routes/memory'));
108
- app.use('/api/scheduler', require('./routes/scheduler'));
109
- app.use('/api/browser', require('./routes/browser'));
110
- app.use('/api/mobile/health', require('./routes/mobile-health'));
111
-
112
- // ── Telnyx voice webhook ──
113
- setupTelnyxWebhook(app);
114
-
115
- app.use('/telnyx-audio', express.static(path.join(DATA_DIR, 'telnyx-audio'), {
116
- index: false,
117
- setHeaders: (res, filePath) => {
118
- if (!filePath.match(/\.(mp3|wav|ogg|aac|m4a)$/i)) {
119
- res.status(403).end();
120
- }
121
- }
122
- }));
123
-
124
- app.use('/screenshots', requireAuth, express.static(path.join(DATA_DIR, 'screenshots')));
125
-
126
- // ── Pages ──
127
-
128
- app.get('/login', requireNoAuth, (req, res) => {
129
- res.sendFile(path.join(__dirname, 'public', 'login.html'));
130
- });
131
-
132
- app.get('/app', requireAuth, (req, res) => {
133
- res.sendFile(path.join(__dirname, 'public', 'app.html'));
134
- });
38
+ const app = express();
39
+ const httpServer = createServer(app);
40
+ const io = createSocketServer(httpServer, { validateOrigin });
41
+ const sessionMiddleware = createSessionMiddleware({ secureCookies: SECURE_COOKIES });
135
42
 
136
- app.get('/app/*', requireAuth, (req, res) => {
137
- res.sendFile(path.join(__dirname, 'public', 'app.html'));
43
+ setupConsoleInterceptor(io);
44
+ applyHttpMiddleware(app, {
45
+ secureCookies: SECURE_COOKIES,
46
+ sessionMiddleware,
47
+ validateOrigin
138
48
  });
49
+ bindSocketSessions(io, sessionMiddleware);
50
+ registerApiRoutes(app);
51
+ registerStaticRoutes(app);
52
+ registerErrorHandler(app);
139
53
 
140
- app.get('/app.html', requireAuth, (req, res) => {
141
- res.sendFile(path.join(__dirname, 'public', 'app.html'));
142
- });
143
- app.get('/js/app.js', requireAuth, (req, res) => {
144
- res.sendFile(path.join(__dirname, 'public', 'js', 'app.js'));
145
- });
54
+ let shuttingDown = false;
146
55
 
147
- app.use(express.static(path.join(__dirname, 'public')));
56
+ async function shutdown() {
57
+ if (shuttingDown) return;
58
+ shuttingDown = true;
148
59
 
149
- app.get('/', (req, res) => {
150
- if (req.session && req.session.userId) return res.redirect('/app');
151
- res.redirect('/login');
152
- });
60
+ console.log('Shutting down...');
153
61
 
154
- app.get('/api/health', requireAuth, (req, res) => {
155
- res.json({ status: 'ok', timestamp: new Date().toISOString() });
156
- });
62
+ await stopServices(app);
157
63
 
158
- app.get('/api/version', requireAuth, (req, res) => {
159
- let version = packageJson.version;
160
- let gitSha = null;
161
64
  try {
162
- const { execSync } = require('child_process');
163
- version = execSync('git describe --tags --always --dirty', {
164
- cwd: APP_DIR,
165
- encoding: 'utf8',
166
- stdio: ['ignore', 'pipe', 'ignore']
167
- }).trim().replace(/^v/, '') || packageJson.version;
168
- gitSha = execSync('git rev-parse --short HEAD', {
169
- cwd: APP_DIR,
170
- encoding: 'utf8',
171
- stdio: ['ignore', 'pipe', 'ignore']
172
- }).trim();
65
+ await new Promise((resolve) => httpServer.close(resolve));
173
66
  } catch {
174
- gitSha = process.env.GIT_SHA || null;
67
+ // ignore close races during shutdown
175
68
  }
176
69
 
177
- res.json({
178
- name: packageJson.name,
179
- version,
180
- packageVersion: packageJson.version,
181
- gitSha
182
- });
183
- });
184
-
185
- // ── Service Initialization ──
186
- // Handled by services/manager.js
187
-
188
- // ── Global Error Handler ──
189
-
190
- app.use((err, req, res, next) => {
191
- console.error('[Unhandled error]', err);
192
- const status = err.status || err.statusCode || 500;
193
- const message = sanitizeError(err);
194
- if (req.path.startsWith('/api/')) {
195
- return res.status(status).json({ error: message });
196
- }
197
- res.status(status).send('Something went wrong.');
198
- });
70
+ db.close();
71
+ process.exit(0);
72
+ }
199
73
 
200
74
  httpServer.listen(PORT, async () => {
201
75
  console.log(`NeoAgent running on http://localhost:${PORT}`);
202
76
  await startServices(app, io);
203
77
  });
204
78
 
205
- // ── Graceful Shutdown ──
206
-
207
- process.on('SIGINT', async () => {
208
- console.log('Shutting down...');
209
- if (app.locals.scheduler) app.locals.scheduler.stop();
210
- if (app.locals.mcpClient) await app.locals.mcpClient.shutdown().catch(() => { });
211
- if (app.locals.browserController) await app.locals.browserController.closeBrowser().catch(() => { });
212
- db.close();
213
- process.exit(0);
214
- });
215
-
216
- process.on('SIGTERM', () => {
217
- process.emit('SIGINT');
218
- });
79
+ process.on('SIGINT', shutdown);
80
+ process.on('SIGTERM', shutdown);
219
81
 
220
82
  module.exports = { app, io, httpServer };
@@ -0,0 +1 @@
1
+ fe64fce67ac7f05d4575c0fd7302c732
@@ -0,0 +1 @@
1
+ "DQIHMnBhY2thZ2VzL2N1cGVydGlub19pY29ucy9hc3NldHMvQ3VwZXJ0aW5vSWNvbnMudHRmDAENAQcFYXNzZXQHMnBhY2thZ2VzL2N1cGVydGlub19pY29ucy9hc3NldHMvQ3VwZXJ0aW5vSWNvbnMudHRmBxZ3ZWIvaWNvbnMvSWNvbi0xOTIucG5nDAENAQcFYXNzZXQHFndlYi9pY29ucy9JY29uLTE5Mi5wbmc="
@@ -0,0 +1 @@
1
+ {"packages/cupertino_icons/assets/CupertinoIcons.ttf":["packages/cupertino_icons/assets/CupertinoIcons.ttf"],"web/icons/Icon-192.png":["web/icons/Icon-192.png"]}
@@ -0,0 +1 @@
1
+ [{"family":"MaterialIcons","fonts":[{"asset":"fonts/MaterialIcons-Regular.otf"}]},{"family":"packages/cupertino_icons/CupertinoIcons","fonts":[{"asset":"packages/cupertino_icons/assets/CupertinoIcons.ttf"}]}]