neoagent 2.3.1-beta.24 → 2.3.1-beta.26

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/.env.example CHANGED
@@ -174,6 +174,11 @@ SPOTIFY_OAUTH_CLIENT_ID=your-spotify-oauth-client-id
174
174
  SPOTIFY_OAUTH_CLIENT_SECRET=your-spotify-oauth-client-secret
175
175
  SPOTIFY_OAUTH_REDIRECT_URI=
176
176
 
177
+ # Trello official integration API key.
178
+ # This is used for Trello account connections in Official Integrations.
179
+ # Users still connect their own Trello account token per agent in the UI.
180
+ TRELLO_API_KEY=your-trello-api-key
181
+
177
182
  ########################################
178
183
  # Tools and media services
179
184
  ########################################
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neoagent",
3
- "version": "2.3.1-beta.24",
3
+ "version": "2.3.1-beta.26",
4
4
  "description": "Proactive personal AI agent with no limits",
5
5
  "license": "MIT",
6
6
  "main": "server/index.js",
@@ -1337,18 +1337,6 @@ function migrateIntegrationProviderConfigsTable() {
1337
1337
  .prepare('SELECT * FROM integration_provider_configs ORDER BY id ASC')
1338
1338
  .all();
1339
1339
 
1340
- const insert = db.prepare(`
1341
- INSERT OR REPLACE INTO integration_provider_configs (
1342
- id,
1343
- user_id,
1344
- agent_id,
1345
- provider_key,
1346
- config_json,
1347
- created_at,
1348
- updated_at
1349
- ) VALUES (?, ?, ?, ?, ?, ?, ?)
1350
- `);
1351
-
1352
1340
  db.exec('BEGIN');
1353
1341
  try {
1354
1342
  db.exec(`
@@ -1367,6 +1355,17 @@ function migrateIntegrationProviderConfigsTable() {
1367
1355
  UNIQUE(user_id, agent_id, provider_key)
1368
1356
  );
1369
1357
  `);
1358
+ const insert = db.prepare(`
1359
+ INSERT OR REPLACE INTO integration_provider_configs (
1360
+ id,
1361
+ user_id,
1362
+ agent_id,
1363
+ provider_key,
1364
+ config_json,
1365
+ created_at,
1366
+ updated_at
1367
+ ) VALUES (?, ?, ?, ?, ?, ?, ?)
1368
+ `);
1370
1369
 
1371
1370
  for (const row of rows) {
1372
1371
  insert.run(
@@ -69,9 +69,11 @@ ensureSessionStoreSchema(sessionsDb);
69
69
  function buildHelmetOptions({ secureCookies }) {
70
70
  const wsConnectSrc = secureCookies ? ['wss:'] : ['ws:', 'wss:'];
71
71
  const isDevelopment = String(process.env.NODE_ENV || '').trim() === 'development';
72
- const allowUnsafeEval = boolEnv('NEOAGENT_CSP_ALLOW_UNSAFE_EVAL', isDevelopment);
73
- const allowExternalScriptCdn = boolEnv('NEOAGENT_CSP_ALLOW_EXTERNAL_SCRIPT_CDN', isDevelopment);
74
- const allowExternalConnect = boolEnv('NEOAGENT_CSP_ALLOW_EXTERNAL_CONNECT', false);
72
+ // Flutter web (CanvasKit) requires external script/connect sources and wasm eval.
73
+ // Keep strict overrides available via env for hardened deployments.
74
+ const allowUnsafeEval = boolEnv('NEOAGENT_CSP_ALLOW_UNSAFE_EVAL', true);
75
+ const allowExternalScriptCdn = boolEnv('NEOAGENT_CSP_ALLOW_EXTERNAL_SCRIPT_CDN', true);
76
+ const allowExternalConnect = boolEnv('NEOAGENT_CSP_ALLOW_EXTERNAL_CONNECT', true);
75
77
 
76
78
  const scriptSrc = ["'self'", "'unsafe-inline'", 'blob:'];
77
79
  if (allowUnsafeEval) {
@@ -83,7 +85,7 @@ function buildHelmetOptions({ secureCookies }) {
83
85
 
84
86
  const connectSrc = ["'self'", ...wsConnectSrc];
85
87
  if (allowExternalConnect) {
86
- connectSrc.push('https://fonts.googleapis.com', 'https://fonts.gstatic.com', 'https://www.gstatic.com');
88
+ connectSrc.push('https://fonts.googleapis.com', 'https://fonts.gstatic.com', 'https://www.gstatic.com', 'https://cdn.jsdelivr.net');
87
89
  }
88
90
 
89
91
  return {
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"59aa584fdf100e6c78c785d8a5b565d1de4b48
37
37
 
38
38
  _flutter.loader.load({
39
39
  serviceWorkerSettings: {
40
- serviceWorkerVersion: "3095431667" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
40
+ serviceWorkerVersion: "753731712" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
41
41
  }
42
42
  });
@@ -12,7 +12,7 @@ const { getErrorMessage } = require('../bootstrap_helpers');
12
12
  const execAsync = promisify(exec);
13
13
 
14
14
  class ScreenRecorder {
15
- constructor() {
15
+ constructor(options = {}) {
16
16
  this.intervalMs = 10000; // 10 seconds
17
17
  this.intervalId = null;
18
18
  this.cleanupIntervalId = null;
@@ -20,6 +20,9 @@ class ScreenRecorder {
20
20
  this.isProcessing = false;
21
21
  this.tempFilePath = path.join(os.tmpdir(), `neoagent-screen-${Date.now()}.png`);
22
22
  this.lastBenignSkipAt = 0;
23
+ this.hasActiveRemoteCaptureSession = typeof options.hasActiveRemoteCaptureSession === 'function'
24
+ ? options.hasActiveRemoteCaptureSession
25
+ : () => false;
23
26
  }
24
27
 
25
28
  _isCaptureInactiveApp(appName) {
@@ -94,6 +97,13 @@ class ScreenRecorder {
94
97
  this.isProcessing = true;
95
98
 
96
99
  try {
100
+ // Only capture while at least one external device/session is actively connected.
101
+ // This prevents host-level screenshots when no user-side capture source is live.
102
+ if (!this.hasActiveRemoteCaptureSession()) {
103
+ this._logBenignSkip('no active external capture session');
104
+ return;
105
+ }
106
+
97
107
  // Skip capture when the desktop session is inactive (e.g. locked screen).
98
108
  let frontmostApp = '';
99
109
  try {
@@ -430,10 +430,35 @@ function createWidgetService(app) {
430
430
  }
431
431
 
432
432
  function createScreenRecorder(app) {
433
+ const hasActiveRemoteCaptureSession = () => {
434
+ const desktopRegistry = app.locals.desktopCompanionRegistry;
435
+ if (desktopRegistry?.connectionsByUser instanceof Map) {
436
+ for (const userMap of desktopRegistry.connectionsByUser.values()) {
437
+ if (!(userMap instanceof Map)) continue;
438
+ for (const connection of userMap.values()) {
439
+ if (typeof connection?.isOpen === 'function' && connection.isOpen()) {
440
+ return true;
441
+ }
442
+ }
443
+ }
444
+ }
445
+
446
+ const extensionRegistry = app.locals.browserExtensionRegistry;
447
+ if (extensionRegistry?.connectionsByUser instanceof Map) {
448
+ for (const connection of extensionRegistry.connectionsByUser.values()) {
449
+ if (typeof connection?.isOpen === 'function' && connection.isOpen()) {
450
+ return true;
451
+ }
452
+ }
453
+ }
454
+
455
+ return false;
456
+ };
457
+
433
458
  const screenRecorder = registerLocal(
434
459
  app,
435
460
  'screenRecorder',
436
- new ScreenRecorder(),
461
+ new ScreenRecorder({ hasActiveRemoteCaptureSession }),
437
462
  );
438
463
  screenRecorder.start();
439
464
  logServiceReady('Screen recorder started');