neoagent 2.3.1-beta.25 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neoagent",
3
- "version": "2.3.1-beta.25",
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",
@@ -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: "1747451041" /* 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');