neoagent 2.3.1-beta.89 → 2.3.1-beta.91
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 +4 -0
- package/README.md +16 -7
- package/flutter_app/lib/features/location/location_service.dart +2 -4
- package/flutter_app/lib/main.dart +1 -0
- package/flutter_app/lib/main_app_shell.dart +17 -15
- package/flutter_app/lib/main_chat.dart +46 -42
- package/flutter_app/lib/main_controller.dart +6 -1
- package/flutter_app/lib/main_devices.dart +86 -742
- package/flutter_app/lib/main_integrations.dart +3 -3
- package/flutter_app/lib/main_settings.dart +50 -0
- package/flutter_app/lib/main_spacing.dart +18 -0
- package/flutter_app/lib/main_theme.dart +9 -0
- package/flutter_app/lib/main_unified.dart +3 -3
- package/lib/manager.js +33 -0
- package/package.json +1 -1
- package/server/db/database.js +74 -16
- package/server/guest_agent.js +1 -0
- package/server/public/.last_build_id +1 -1
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/flutter_bootstrap.js +1 -1
- package/server/public/main.dart.js +50396 -50271
- package/server/services/ai/capabilityHealth.js +2 -3
- package/server/services/android/android_bootstrap_worker.js +18 -3
- package/server/services/android/controller.js +460 -2753
- package/server/services/runtime/backends/local-vm.js +33 -145
- package/server/services/runtime/docker-vm-manager.js +392 -0
- package/server/services/runtime/manager.js +53 -38
- package/server/services/runtime/settings.js +12 -10
- package/server/services/runtime/validation.js +4 -1
- package/server/utils/deployment.js +8 -2
- package/server/services/runtime/qemu.js +0 -1118
|
@@ -1,31 +1,51 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
1
3
|
const { LocalVmExecutionBackend } = require('./backends/local-vm');
|
|
2
|
-
const {
|
|
4
|
+
const { DockerVMManager } = require('./docker-vm-manager');
|
|
3
5
|
const { getRuntimeSettings } = require('./settings');
|
|
4
6
|
const { ExtensionBrowserProvider } = require('../browser/extension/provider');
|
|
5
7
|
const { AndroidController } = require('../android/controller');
|
|
8
|
+
const { DesktopProvider } = require('../desktop/provider');
|
|
9
|
+
|
|
10
|
+
// Resource defaults for Docker VMs (overridable via env).
|
|
11
|
+
const DEFAULT_VM_MEMORY_MB = Number(process.env.NEOAGENT_VM_MEMORY_MB ?? 2048);
|
|
12
|
+
const DEFAULT_VM_CPUS = Number(process.env.NEOAGENT_VM_CPUS ?? 2);
|
|
6
13
|
|
|
7
14
|
class RuntimeManager {
|
|
8
15
|
constructor(options = {}) {
|
|
9
16
|
this.browserExtensionRegistry = options.browserExtensionRegistry || null;
|
|
10
|
-
|
|
17
|
+
this.desktopCompanionRegistry = options.desktopCompanionRegistry || null;
|
|
18
|
+
|
|
19
|
+
const browserVmManager = options.browserVmManager || new DockerVMManager({
|
|
11
20
|
runtimeProfile: 'browser_cli',
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
21
|
+
image: 'mcr.microsoft.com/playwright:v1.44.0-focal',
|
|
22
|
+
memoryMb: DEFAULT_VM_MEMORY_MB,
|
|
23
|
+
cpus: DEFAULT_VM_CPUS,
|
|
15
24
|
});
|
|
16
25
|
this.browserBackend = new LocalVmExecutionBackend({
|
|
17
26
|
runtimeProfile: 'browser_cli',
|
|
18
27
|
vmManager: browserVmManager,
|
|
19
28
|
artifactStore: options.artifactStore,
|
|
20
29
|
});
|
|
21
|
-
|
|
22
|
-
this.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
userId
|
|
26
|
-
|
|
30
|
+
|
|
31
|
+
this.artifactStore = options.artifactStore || null;
|
|
32
|
+
|
|
33
|
+
this.getExtensionBrowserProvider = options.getExtensionBrowserProvider
|
|
34
|
+
|| ((userId) => new ExtensionBrowserProvider({
|
|
35
|
+
registry: options.browserExtensionRegistry,
|
|
36
|
+
artifactStore: options.artifactStore,
|
|
37
|
+
userId,
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
this.getDesktopCliProvider = options.getDesktopCliProvider
|
|
41
|
+
|| ((userId) => new DesktopProvider({
|
|
42
|
+
registry: options.desktopCompanionRegistry,
|
|
43
|
+
artifactStore: options.artifactStore,
|
|
44
|
+
userId,
|
|
45
|
+
}));
|
|
27
46
|
}
|
|
28
47
|
|
|
48
|
+
|
|
29
49
|
getSettings(userId) {
|
|
30
50
|
return getRuntimeSettings(userId);
|
|
31
51
|
}
|
|
@@ -38,8 +58,17 @@ class RuntimeManager {
|
|
|
38
58
|
);
|
|
39
59
|
}
|
|
40
60
|
|
|
61
|
+
hasActiveDesktopCompanion(userId) {
|
|
62
|
+
return Boolean(
|
|
63
|
+
this.desktopCompanionRegistry
|
|
64
|
+
&& typeof this.desktopCompanionRegistry.isConnected === 'function'
|
|
65
|
+
&& this.desktopCompanionRegistry.isConnected(userId)
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
41
69
|
resolveBackend(userId, requested) {
|
|
42
70
|
void userId;
|
|
71
|
+
void requested;
|
|
43
72
|
return this.browserBackend;
|
|
44
73
|
}
|
|
45
74
|
|
|
@@ -49,9 +78,6 @@ class RuntimeManager {
|
|
|
49
78
|
}
|
|
50
79
|
|
|
51
80
|
hasVmForUser(userId, capability = 'browser') {
|
|
52
|
-
if (capability === 'android') {
|
|
53
|
-
return Boolean(this.androidControllers.get(String(userId || '').trim()));
|
|
54
|
-
}
|
|
55
81
|
return Boolean(this.browserBackend?.vmManager?.hasVm?.(userId));
|
|
56
82
|
}
|
|
57
83
|
|
|
@@ -71,34 +97,25 @@ class RuntimeManager {
|
|
|
71
97
|
return this.browserBackend.getBrowserProviderForUser(userId);
|
|
72
98
|
}
|
|
73
99
|
|
|
100
|
+
async getCliProviderForUser(userId) {
|
|
101
|
+
const settings = this.getSettings(userId);
|
|
102
|
+
if (settings.cli_backend === 'desktop' && this.hasActiveDesktopCompanion(userId)) {
|
|
103
|
+
return this.getDesktopCliProvider(userId);
|
|
104
|
+
}
|
|
105
|
+
return this.browserBackend.getCommandExecutorForUser(userId);
|
|
106
|
+
}
|
|
107
|
+
|
|
74
108
|
async getAndroidProviderForUser(userId) {
|
|
75
|
-
|
|
76
|
-
if (!key) {
|
|
109
|
+
if (userId == null || String(userId).trim() === '') {
|
|
77
110
|
throw new Error('Android provider requires a user ID.');
|
|
78
111
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
artifactStore: null,
|
|
84
|
-
}));
|
|
85
|
-
}
|
|
86
|
-
return this.androidControllers.get(key);
|
|
112
|
+
return new AndroidController({
|
|
113
|
+
userId: String(userId).trim(),
|
|
114
|
+
artifactStore: this.artifactStore,
|
|
115
|
+
});
|
|
87
116
|
}
|
|
88
117
|
|
|
89
118
|
async isGuestAgentReadyForUser(userId, timeoutMs = 1000, capability = 'browser') {
|
|
90
|
-
if (capability === 'android') {
|
|
91
|
-
const controller = this.androidControllers.get(String(userId || '').trim());
|
|
92
|
-
if (!controller || typeof controller.getStatus !== 'function') {
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
try {
|
|
96
|
-
const status = await controller.getStatus();
|
|
97
|
-
return Boolean(status?.bootstrapped || status?.serial || status?.starting);
|
|
98
|
-
} catch {
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
119
|
if (typeof this.browserBackend?.isGuestAgentReadyForUser !== 'function') {
|
|
103
120
|
return false;
|
|
104
121
|
}
|
|
@@ -108,9 +125,7 @@ class RuntimeManager {
|
|
|
108
125
|
async shutdown() {
|
|
109
126
|
await Promise.allSettled([
|
|
110
127
|
this.browserBackend?.shutdown?.(),
|
|
111
|
-
...[...this.androidControllers.values()].map((controller) => controller?.stopEmulator?.().catch?.(() => {})),
|
|
112
128
|
]);
|
|
113
|
-
this.androidControllers.clear();
|
|
114
129
|
}
|
|
115
130
|
}
|
|
116
131
|
|
|
@@ -9,6 +9,7 @@ function createDefaultRuntimeSettings() {
|
|
|
9
9
|
browser_backend: policy.runtimeDefaults.browser_backend,
|
|
10
10
|
android_backend: policy.runtimeDefaults.android_backend,
|
|
11
11
|
mcp_backend: policy.runtimeDefaults.mcp_backend,
|
|
12
|
+
cli_backend: policy.runtimeDefaults.cli_backend ?? 'vm',
|
|
12
13
|
};
|
|
13
14
|
}
|
|
14
15
|
|
|
@@ -24,6 +25,7 @@ const BASE_FALLBACK_SETTINGS = Object.freeze({
|
|
|
24
25
|
browser_backend: 'vm',
|
|
25
26
|
android_backend: 'host',
|
|
26
27
|
mcp_backend: 'host-remote',
|
|
28
|
+
cli_backend: 'vm',
|
|
27
29
|
});
|
|
28
30
|
|
|
29
31
|
const RUNTIME_SETTING_KEYS = Object.freeze(Object.keys(DEFAULT_RUNTIME_SETTINGS));
|
|
@@ -42,6 +44,7 @@ function deriveDefaultsForProfile(profile) {
|
|
|
42
44
|
runtime_backend: 'vm',
|
|
43
45
|
browser_backend: 'vm',
|
|
44
46
|
android_backend: 'host',
|
|
47
|
+
cli_backend: 'vm',
|
|
45
48
|
};
|
|
46
49
|
}
|
|
47
50
|
}
|
|
@@ -53,21 +56,18 @@ function normalizeRuntimeSettings(raw = {}) {
|
|
|
53
56
|
const derived = deriveDefaultsForProfile(profile);
|
|
54
57
|
const runtimeBackend = normalizeChoice(raw.runtime_backend, ['vm'], derived.runtime_backend);
|
|
55
58
|
const browserBackend = normalizeChoice(raw.browser_backend, ['vm', 'extension'], derived.browser_backend);
|
|
56
|
-
const
|
|
59
|
+
const cliBackend = normalizeChoice(raw.cli_backend, ['vm', 'desktop'], derived.cli_backend ?? 'vm');
|
|
60
|
+
const androidBackend = 'host';
|
|
57
61
|
return {
|
|
58
62
|
runtime_profile: profile === 'trusted-host' ? 'secure-vm' : profile,
|
|
59
63
|
runtime_backend: runtimeBackend,
|
|
60
64
|
browser_backend: browserBackend === 'extension' ? 'extension' : 'vm',
|
|
61
|
-
android_backend: androidBackend
|
|
65
|
+
android_backend: androidBackend,
|
|
62
66
|
mcp_backend: 'host-remote',
|
|
67
|
+
cli_backend: cliBackend === 'desktop' ? 'desktop' : 'vm',
|
|
63
68
|
};
|
|
64
69
|
}
|
|
65
70
|
|
|
66
|
-
function deriveCloudBrowserBackend(raw = {}) {
|
|
67
|
-
normalizeRuntimeSettings(raw);
|
|
68
|
-
return 'vm';
|
|
69
|
-
}
|
|
70
|
-
|
|
71
71
|
function parseStoredRuntimeValue(key, value) {
|
|
72
72
|
if (typeof value !== 'string') {
|
|
73
73
|
return value;
|
|
@@ -102,8 +102,11 @@ function validateRuntimeSettings(raw = {}) {
|
|
|
102
102
|
if (settings.browser_backend !== 'vm' && settings.browser_backend !== 'extension') {
|
|
103
103
|
issues.push('This deployment requires the VM browser backend or a paired browser extension backend.');
|
|
104
104
|
}
|
|
105
|
-
if (settings.android_backend !== 'host') {
|
|
106
|
-
issues.push('This deployment requires
|
|
105
|
+
if (settings.android_backend !== 'host' && settings.android_backend !== 'vm') {
|
|
106
|
+
issues.push('This deployment requires a supported Android backend.');
|
|
107
|
+
}
|
|
108
|
+
if (settings.cli_backend !== 'vm' && settings.cli_backend !== 'desktop') {
|
|
109
|
+
issues.push('This deployment requires a supported CLI backend.');
|
|
107
110
|
}
|
|
108
111
|
}
|
|
109
112
|
|
|
@@ -154,7 +157,6 @@ function getRuntimeSettings(userId) {
|
|
|
154
157
|
module.exports = {
|
|
155
158
|
DEFAULT_RUNTIME_SETTINGS,
|
|
156
159
|
RUNTIME_SETTING_KEYS,
|
|
157
|
-
deriveCloudBrowserBackend,
|
|
158
160
|
ensureDefaultRuntimeSettings,
|
|
159
161
|
getRuntimeSettings,
|
|
160
162
|
normalizeRuntimeSettings,
|
|
@@ -54,22 +54,28 @@ function getDeploymentProfile(env = process.env) {
|
|
|
54
54
|
return parseDeploymentProfile(env.NEOAGENT_PROFILE);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
function getAllowSignup(env = process.env) {
|
|
58
|
+
const raw = String(env.NEOAGENT_ALLOW_SIGNUP ?? '').trim().toLowerCase();
|
|
59
|
+
if (raw === 'false' || raw === '0' || raw === 'no') return false;
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
57
63
|
function getDeploymentPolicy(env = process.env) {
|
|
58
64
|
const profile = getDeploymentProfile(env);
|
|
59
65
|
const mode = getDeploymentMode(env);
|
|
60
|
-
const isProdProfile = profile === DEPLOYMENT_PROFILE_PROD;
|
|
61
66
|
return {
|
|
62
67
|
mode,
|
|
63
68
|
profile,
|
|
64
69
|
managed: mode === DEPLOYMENT_MODE_MANAGED,
|
|
65
70
|
allowSelfUpdate: mode !== DEPLOYMENT_MODE_MANAGED,
|
|
66
|
-
registrationOpen:
|
|
71
|
+
registrationOpen: getAllowSignup(env),
|
|
67
72
|
runtimeDefaults: {
|
|
68
73
|
runtime_profile: 'secure-vm',
|
|
69
74
|
runtime_backend: 'vm',
|
|
70
75
|
browser_backend: 'vm',
|
|
71
76
|
android_backend: 'host',
|
|
72
77
|
mcp_backend: 'host-remote',
|
|
78
|
+
cli_backend: 'vm',
|
|
73
79
|
},
|
|
74
80
|
allowHostRuntime: false,
|
|
75
81
|
};
|