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
package/server/db/database.js
CHANGED
|
@@ -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
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
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: "
|
|
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');
|