neoagent 2.1.14 → 2.1.15
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/README.md +1 -1
- package/lib/manager.js +109 -13
- package/package.json +1 -1
- package/runtime/release_channel.js +123 -0
- package/server/index.js +9 -4
- package/server/public/flutter_bootstrap.js +1 -1
- package/server/public/main.dart.js +32583 -32469
- package/server/routes/settings.js +32 -1
- package/server/services/bootstrap_helpers.js +54 -0
- package/server/services/manager.js +290 -154
- package/server/utils/version.js +17 -1
|
@@ -7,6 +7,12 @@ const { requireAuth } = require('../middleware/auth');
|
|
|
7
7
|
const { normalizeWhatsAppWhitelist } = require('../utils/whatsapp');
|
|
8
8
|
const { getVersionInfo } = require('../utils/version');
|
|
9
9
|
const { UPDATE_STATUS_FILE, APP_DIR } = require('../../runtime/paths');
|
|
10
|
+
const {
|
|
11
|
+
parseReleaseChannel,
|
|
12
|
+
getReleaseChannelBranch,
|
|
13
|
+
getReleaseChannelDistTag,
|
|
14
|
+
writeReleaseChannelToEnvFile,
|
|
15
|
+
} = require('../../runtime/release_channel');
|
|
10
16
|
const {
|
|
11
17
|
createDefaultAiSettings,
|
|
12
18
|
ensureDefaultAiSettings,
|
|
@@ -316,6 +322,27 @@ router.post('/update', (req, res) => {
|
|
|
316
322
|
res.json({ success: true, message: 'Update triggered', pid: child.pid });
|
|
317
323
|
});
|
|
318
324
|
|
|
325
|
+
router.put('/update/channel', (req, res) => {
|
|
326
|
+
const requested = req.body?.channel;
|
|
327
|
+
const releaseChannel = parseReleaseChannel(requested);
|
|
328
|
+
if (!releaseChannel) {
|
|
329
|
+
return res.status(400).json({
|
|
330
|
+
success: false,
|
|
331
|
+
error: 'Release channel must be "stable" or "beta".',
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
writeReleaseChannelToEnvFile(releaseChannel);
|
|
336
|
+
process.env.NEOAGENT_RELEASE_CHANNEL = releaseChannel;
|
|
337
|
+
|
|
338
|
+
res.json({
|
|
339
|
+
success: true,
|
|
340
|
+
releaseChannel,
|
|
341
|
+
targetBranch: getReleaseChannelBranch(releaseChannel),
|
|
342
|
+
npmDistTag: getReleaseChannelDistTag(releaseChannel),
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
|
|
319
346
|
router.get('/update/status', (req, res) => {
|
|
320
347
|
const status = readUpdateStatus();
|
|
321
348
|
const version = getVersionInfo();
|
|
@@ -325,7 +352,11 @@ router.get('/update/status', (req, res) => {
|
|
|
325
352
|
installedVersion: version.installedVersion,
|
|
326
353
|
packageVersion: version.packageVersion,
|
|
327
354
|
gitVersion: version.gitVersion,
|
|
328
|
-
gitSha: version.gitSha
|
|
355
|
+
gitSha: version.gitSha,
|
|
356
|
+
gitBranch: version.gitBranch,
|
|
357
|
+
releaseChannel: version.releaseChannel,
|
|
358
|
+
targetBranch: version.targetBranch,
|
|
359
|
+
npmDistTag: version.npmDistTag,
|
|
329
360
|
});
|
|
330
361
|
});
|
|
331
362
|
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const HEADLESS_BROWSER_SETTING_KEY = 'headless_browser';
|
|
4
|
+
|
|
5
|
+
function getErrorMessage(error) {
|
|
6
|
+
if (error instanceof Error && error.message) {
|
|
7
|
+
return error.message;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return String(error);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function isEnabledSetting(value) {
|
|
14
|
+
return value !== 'false' && value !== false && value !== '0';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function restoreBrowserHeadlessPreference(browserController, database) {
|
|
18
|
+
const userCount =
|
|
19
|
+
database.prepare('SELECT COUNT(*) AS count FROM users').get()?.count || 0;
|
|
20
|
+
const headlessSetting =
|
|
21
|
+
userCount === 1
|
|
22
|
+
? database
|
|
23
|
+
.prepare(
|
|
24
|
+
'SELECT value FROM user_settings WHERE user_id = (SELECT id FROM users LIMIT 1) AND key = ?',
|
|
25
|
+
)
|
|
26
|
+
.get(HEADLESS_BROWSER_SETTING_KEY)
|
|
27
|
+
: null;
|
|
28
|
+
|
|
29
|
+
if (!headlessSetting) {
|
|
30
|
+
return { restored: false, userCount };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
browserController.headless = isEnabledSetting(headlessSetting.value);
|
|
34
|
+
return {
|
|
35
|
+
restored: true,
|
|
36
|
+
userCount,
|
|
37
|
+
headless: browserController.headless,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function runBackgroundTask(errorPrefix, task, logger = console.error) {
|
|
42
|
+
return Promise.resolve()
|
|
43
|
+
.then(task)
|
|
44
|
+
.catch((error) => {
|
|
45
|
+
logger(errorPrefix, getErrorMessage(error));
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = {
|
|
50
|
+
getErrorMessage,
|
|
51
|
+
isEnabledSetting,
|
|
52
|
+
restoreBrowserHeadlessPreference,
|
|
53
|
+
runBackgroundTask,
|
|
54
|
+
};
|
|
@@ -15,173 +15,309 @@ const { setupWebSocket } = require('./websocket');
|
|
|
15
15
|
const { registerMessagingAutomation } = require('./messaging/automation');
|
|
16
16
|
const { RecordingManager } = require('./recordings/manager');
|
|
17
17
|
const { CLIExecutor } = require('./cli/executor');
|
|
18
|
+
const {
|
|
19
|
+
getErrorMessage,
|
|
20
|
+
restoreBrowserHeadlessPreference,
|
|
21
|
+
runBackgroundTask,
|
|
22
|
+
} = require('./bootstrap_helpers');
|
|
23
|
+
|
|
24
|
+
function registerLocal(app, key, value) {
|
|
25
|
+
app.locals[key] = value;
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function logServiceReady(message) {
|
|
30
|
+
console.log(`[Services] ${message}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function createCliExecutor(app) {
|
|
34
|
+
const cliExecutor = registerLocal(app, 'cliExecutor', new CLIExecutor());
|
|
35
|
+
logServiceReady('CLI executor ready');
|
|
36
|
+
return cliExecutor;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function createMemoryManager(app) {
|
|
40
|
+
const memoryManager = registerLocal(app, 'memoryManager', new MemoryManager());
|
|
41
|
+
logServiceReady('Memory manager ready');
|
|
42
|
+
return memoryManager;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function createMcpClient(app) {
|
|
46
|
+
const mcpClient = registerLocal(app, 'mcpClient', new MCPClient());
|
|
47
|
+
logServiceReady('MCP client ready');
|
|
48
|
+
return mcpClient;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function createBrowserController(app) {
|
|
52
|
+
const browserController = registerLocal(
|
|
53
|
+
app,
|
|
54
|
+
'browserController',
|
|
55
|
+
new BrowserController(),
|
|
56
|
+
);
|
|
57
|
+
const { restored, userCount, headless } = restoreBrowserHeadlessPreference(
|
|
58
|
+
browserController,
|
|
59
|
+
db,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
if (restored) {
|
|
63
|
+
logServiceReady(`Browser headless setting restored to ${headless}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
logServiceReady(`Browser controller ready for ${userCount} user(s)`);
|
|
67
|
+
return browserController;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function createAndroidController(app) {
|
|
71
|
+
const androidController = registerLocal(
|
|
72
|
+
app,
|
|
73
|
+
'androidController',
|
|
74
|
+
new AndroidController(),
|
|
75
|
+
);
|
|
76
|
+
logServiceReady('Android controller ready');
|
|
77
|
+
return androidController;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function createSkillRunner(app, cliExecutor) {
|
|
81
|
+
const skillRunner = registerLocal(
|
|
82
|
+
app,
|
|
83
|
+
'skillRunner',
|
|
84
|
+
new SkillRunner({ executor: cliExecutor }),
|
|
85
|
+
);
|
|
86
|
+
await skillRunner.loadSkills();
|
|
87
|
+
logServiceReady('Skills loaded');
|
|
88
|
+
return skillRunner;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function createLearningManager(app, skillRunner, io) {
|
|
92
|
+
const learningManager = registerLocal(
|
|
93
|
+
app,
|
|
94
|
+
'learningManager',
|
|
95
|
+
new LearningManager(skillRunner, io),
|
|
96
|
+
);
|
|
97
|
+
logServiceReady('Learning manager ready');
|
|
98
|
+
return learningManager;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function createAgentEngine(
|
|
102
|
+
app,
|
|
103
|
+
io,
|
|
104
|
+
{
|
|
105
|
+
cliExecutor,
|
|
106
|
+
memoryManager,
|
|
107
|
+
mcpClient,
|
|
108
|
+
browserController,
|
|
109
|
+
androidController,
|
|
110
|
+
skillRunner,
|
|
111
|
+
learningManager,
|
|
112
|
+
},
|
|
113
|
+
) {
|
|
114
|
+
const agentEngine = registerLocal(
|
|
115
|
+
app,
|
|
116
|
+
'agentEngine',
|
|
117
|
+
new AgentEngine(io, {
|
|
118
|
+
cliExecutor,
|
|
119
|
+
memoryManager,
|
|
120
|
+
mcpClient,
|
|
121
|
+
browserController,
|
|
122
|
+
androidController,
|
|
123
|
+
messagingManager: null,
|
|
124
|
+
skillRunner,
|
|
125
|
+
learningManager,
|
|
126
|
+
}),
|
|
127
|
+
);
|
|
128
|
+
logServiceReady('Agent engine ready');
|
|
129
|
+
return agentEngine;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function createMultiStep(app, agentEngine, io) {
|
|
133
|
+
const multiStep = registerLocal(
|
|
134
|
+
app,
|
|
135
|
+
'multiStep',
|
|
136
|
+
new MultiStepOrchestrator(agentEngine, io),
|
|
137
|
+
);
|
|
138
|
+
logServiceReady('Multi-step orchestrator ready');
|
|
139
|
+
return multiStep;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function createMessagingManager(app, io, agentEngine) {
|
|
143
|
+
const messagingManager = registerLocal(
|
|
144
|
+
app,
|
|
145
|
+
'messagingManager',
|
|
146
|
+
new MessagingManager(io),
|
|
147
|
+
);
|
|
148
|
+
agentEngine.messagingManager = messagingManager;
|
|
149
|
+
logServiceReady('Messaging manager ready');
|
|
150
|
+
return messagingManager;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function createRecordingManager(app, io) {
|
|
154
|
+
const recordingManager = registerLocal(
|
|
155
|
+
app,
|
|
156
|
+
'recordingManager',
|
|
157
|
+
new RecordingManager(io),
|
|
158
|
+
);
|
|
159
|
+
logServiceReady('Recording manager ready');
|
|
160
|
+
return recordingManager;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function restoreMessagingConnections(messagingManager) {
|
|
164
|
+
void runBackgroundTask('[Messaging] Restore error:', () =>
|
|
165
|
+
messagingManager.restoreConnections(),
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function restoreMcpClients(mcpClient) {
|
|
170
|
+
const users = db.prepare('SELECT id FROM users').all();
|
|
171
|
+
logServiceReady(`Restoring MCP clients for ${users.length} user(s)`);
|
|
172
|
+
|
|
173
|
+
for (const user of users) {
|
|
174
|
+
void runBackgroundTask('[MCP] Auto-start error:', () =>
|
|
175
|
+
mcpClient.loadFromDB(user.id),
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function startScheduler(app, io, agentEngine) {
|
|
181
|
+
const scheduler = registerLocal(app, 'scheduler', new Scheduler(io, agentEngine, app));
|
|
182
|
+
agentEngine.scheduler = scheduler;
|
|
183
|
+
scheduler.start();
|
|
184
|
+
logServiceReady('Scheduler started');
|
|
185
|
+
return scheduler;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function configureRealtime(app, io, services) {
|
|
189
|
+
setupWebSocket(io, {
|
|
190
|
+
agentEngine: services.agentEngine,
|
|
191
|
+
messagingManager: services.messagingManager,
|
|
192
|
+
mcpClient: services.mcpClient,
|
|
193
|
+
scheduler: services.scheduler,
|
|
194
|
+
recordingManager: services.recordingManager,
|
|
195
|
+
memoryManager: services.memoryManager,
|
|
196
|
+
app,
|
|
197
|
+
});
|
|
198
|
+
app.locals.io = io;
|
|
199
|
+
logServiceReady('WebSocket handlers registered');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function resumePendingRecordingSessions(recordingManager) {
|
|
203
|
+
void runBackgroundTask('[Recordings] Resume error:', () =>
|
|
204
|
+
recordingManager.resumePendingSessions(),
|
|
205
|
+
);
|
|
206
|
+
}
|
|
18
207
|
|
|
19
208
|
async function startServices(app, io) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
app.locals.multiStep = multiStep;
|
|
75
|
-
console.log('[Services] Multi-step orchestrator ready');
|
|
76
|
-
|
|
77
|
-
const messagingManager = new MessagingManager(io);
|
|
78
|
-
app.locals.messagingManager = messagingManager;
|
|
79
|
-
agentEngine.messagingManager = messagingManager;
|
|
80
|
-
console.log('[Services] Messaging manager ready');
|
|
81
|
-
|
|
82
|
-
messagingManager.restoreConnections().catch(err => console.error('[Messaging] Restore error:', err.message));
|
|
83
|
-
|
|
84
|
-
const recordingManager = new RecordingManager(io);
|
|
85
|
-
app.locals.recordingManager = recordingManager;
|
|
86
|
-
console.log('[Services] Recording manager ready');
|
|
87
|
-
|
|
88
|
-
const users = db.prepare('SELECT id FROM users').all();
|
|
89
|
-
console.log(`[Services] Restoring MCP clients for ${users.length} user(s)`);
|
|
90
|
-
for (const u of users) {
|
|
91
|
-
mcpClient.loadFromDB(u.id).catch(err => console.error('[MCP] Auto-start error:', err.message));
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
registerMessagingAutomation({
|
|
95
|
-
app,
|
|
96
|
-
io,
|
|
97
|
-
messagingManager,
|
|
98
|
-
agentEngine,
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
const scheduler = new Scheduler(io, agentEngine, app);
|
|
102
|
-
app.locals.scheduler = scheduler;
|
|
103
|
-
agentEngine.scheduler = scheduler;
|
|
104
|
-
scheduler.start();
|
|
105
|
-
console.log('[Services] Scheduler started');
|
|
106
|
-
|
|
107
|
-
setupWebSocket(io, {
|
|
108
|
-
agentEngine,
|
|
109
|
-
messagingManager,
|
|
110
|
-
mcpClient,
|
|
111
|
-
scheduler,
|
|
112
|
-
recordingManager,
|
|
113
|
-
memoryManager,
|
|
114
|
-
app
|
|
115
|
-
});
|
|
116
|
-
app.locals.io = io;
|
|
117
|
-
console.log('[Services] WebSocket handlers registered');
|
|
118
|
-
|
|
119
|
-
recordingManager.resumePendingSessions().catch((err) => {
|
|
120
|
-
console.error('[Recordings] Resume error:', err.message);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
console.log('All services initialized');
|
|
124
|
-
} catch (err) {
|
|
125
|
-
console.error('Service init error:', err);
|
|
126
|
-
}
|
|
209
|
+
console.log('[Services] Starting service initialization');
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
const cliExecutor = createCliExecutor(app);
|
|
213
|
+
const memoryManager = createMemoryManager(app);
|
|
214
|
+
const mcpClient = createMcpClient(app);
|
|
215
|
+
const browserController = createBrowserController(app);
|
|
216
|
+
const androidController = createAndroidController(app);
|
|
217
|
+
const skillRunner = await createSkillRunner(app, cliExecutor);
|
|
218
|
+
const learningManager = createLearningManager(app, skillRunner, io);
|
|
219
|
+
const agentEngine = createAgentEngine(app, io, {
|
|
220
|
+
cliExecutor,
|
|
221
|
+
memoryManager,
|
|
222
|
+
mcpClient,
|
|
223
|
+
browserController,
|
|
224
|
+
androidController,
|
|
225
|
+
skillRunner,
|
|
226
|
+
learningManager,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
createMultiStep(app, agentEngine, io);
|
|
230
|
+
|
|
231
|
+
const messagingManager = createMessagingManager(app, io, agentEngine);
|
|
232
|
+
const recordingManager = createRecordingManager(app, io);
|
|
233
|
+
|
|
234
|
+
restoreMessagingConnections(messagingManager);
|
|
235
|
+
restoreMcpClients(mcpClient);
|
|
236
|
+
|
|
237
|
+
registerMessagingAutomation({
|
|
238
|
+
app,
|
|
239
|
+
io,
|
|
240
|
+
messagingManager,
|
|
241
|
+
agentEngine,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
const scheduler = startScheduler(app, io, agentEngine);
|
|
245
|
+
|
|
246
|
+
configureRealtime(app, io, {
|
|
247
|
+
agentEngine,
|
|
248
|
+
messagingManager,
|
|
249
|
+
mcpClient,
|
|
250
|
+
scheduler,
|
|
251
|
+
recordingManager,
|
|
252
|
+
memoryManager,
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
resumePendingRecordingSessions(recordingManager);
|
|
256
|
+
|
|
257
|
+
console.log('All services initialized');
|
|
258
|
+
} catch (err) {
|
|
259
|
+
console.error('Service init error:', err);
|
|
260
|
+
await stopServices(app);
|
|
261
|
+
throw err;
|
|
262
|
+
}
|
|
127
263
|
}
|
|
128
264
|
|
|
129
265
|
async function stopServices(app) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (app.locals.scheduler) {
|
|
134
|
-
try {
|
|
135
|
-
app.locals.scheduler.stop();
|
|
136
|
-
console.log('[Services] Scheduler stopped');
|
|
137
|
-
} catch (err) {
|
|
138
|
-
console.error('[Scheduler] Stop error:', err.message);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
266
|
+
const tasks = [];
|
|
267
|
+
console.log('[Services] Stopping services');
|
|
141
268
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
269
|
+
if (app.locals.scheduler) {
|
|
270
|
+
try {
|
|
271
|
+
app.locals.scheduler.stop();
|
|
272
|
+
logServiceReady('Scheduler stopped');
|
|
273
|
+
} catch (err) {
|
|
274
|
+
console.error('[Scheduler] Stop error:', getErrorMessage(err));
|
|
148
275
|
}
|
|
276
|
+
}
|
|
149
277
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
278
|
+
if (app.locals.mcpClient) {
|
|
279
|
+
tasks.push(
|
|
280
|
+
app.locals.mcpClient.shutdown().catch((err) => {
|
|
281
|
+
console.error('[MCP] Shutdown error:', getErrorMessage(err));
|
|
282
|
+
}),
|
|
283
|
+
);
|
|
284
|
+
}
|
|
157
285
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
286
|
+
if (app.locals.browserController) {
|
|
287
|
+
tasks.push(
|
|
288
|
+
app.locals.browserController.closeBrowser().catch((err) => {
|
|
289
|
+
console.error('[Browser] Shutdown error:', getErrorMessage(err));
|
|
290
|
+
}),
|
|
291
|
+
);
|
|
292
|
+
}
|
|
165
293
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
294
|
+
if (app.locals.androidController) {
|
|
295
|
+
tasks.push(
|
|
296
|
+
app.locals.androidController.close().catch((err) => {
|
|
297
|
+
console.error('[Android] Shutdown error:', getErrorMessage(err));
|
|
298
|
+
}),
|
|
299
|
+
);
|
|
300
|
+
}
|
|
173
301
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
302
|
+
if (app.locals.messagingManager) {
|
|
303
|
+
tasks.push(
|
|
304
|
+
app.locals.messagingManager.shutdown().catch((err) => {
|
|
305
|
+
console.error('[Messaging] Shutdown error:', getErrorMessage(err));
|
|
306
|
+
}),
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (app.locals.cliExecutor) {
|
|
311
|
+
try {
|
|
312
|
+
app.locals.cliExecutor.killAll('shutdown');
|
|
313
|
+
logServiceReady('CLI executor processes terminated');
|
|
314
|
+
} catch (err) {
|
|
315
|
+
console.error('[CLI] Shutdown error:', getErrorMessage(err));
|
|
181
316
|
}
|
|
317
|
+
}
|
|
182
318
|
|
|
183
|
-
|
|
184
|
-
|
|
319
|
+
await Promise.allSettled(tasks);
|
|
320
|
+
logServiceReady('Shutdown tasks settled');
|
|
185
321
|
}
|
|
186
322
|
|
|
187
323
|
module.exports = { startServices, stopServices };
|
package/server/utils/version.js
CHANGED
|
@@ -4,6 +4,11 @@ const fs = require('fs');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const { execSync } = require('child_process');
|
|
6
6
|
const { APP_DIR } = require('../../runtime/paths');
|
|
7
|
+
const {
|
|
8
|
+
getReleaseChannelBranch,
|
|
9
|
+
getReleaseChannelDistTag,
|
|
10
|
+
readConfiguredReleaseChannel,
|
|
11
|
+
} = require('../../runtime/release_channel');
|
|
7
12
|
|
|
8
13
|
const PACKAGE_JSON_PATH = path.join(APP_DIR, 'package.json');
|
|
9
14
|
|
|
@@ -18,9 +23,11 @@ function readPackageVersion() {
|
|
|
18
23
|
|
|
19
24
|
function getVersionInfo() {
|
|
20
25
|
const packageVersion = readPackageVersion() || '0.0.0';
|
|
26
|
+
const releaseChannel = readConfiguredReleaseChannel();
|
|
21
27
|
let version = packageVersion;
|
|
22
28
|
let gitSha = null;
|
|
23
29
|
let gitVersion = null;
|
|
30
|
+
let gitBranch = null;
|
|
24
31
|
|
|
25
32
|
try {
|
|
26
33
|
gitVersion =
|
|
@@ -36,6 +43,11 @@ function getVersionInfo() {
|
|
|
36
43
|
encoding: 'utf8',
|
|
37
44
|
stdio: ['ignore', 'pipe', 'ignore']
|
|
38
45
|
}).trim();
|
|
46
|
+
gitBranch = execSync('git rev-parse --abbrev-ref HEAD', {
|
|
47
|
+
cwd: APP_DIR,
|
|
48
|
+
encoding: 'utf8',
|
|
49
|
+
stdio: ['ignore', 'pipe', 'ignore']
|
|
50
|
+
}).trim();
|
|
39
51
|
} catch {
|
|
40
52
|
gitSha = process.env.GIT_SHA || null;
|
|
41
53
|
}
|
|
@@ -51,8 +63,12 @@ function getVersionInfo() {
|
|
|
51
63
|
version,
|
|
52
64
|
packageVersion,
|
|
53
65
|
gitVersion,
|
|
66
|
+
gitBranch,
|
|
54
67
|
gitSha,
|
|
55
|
-
installedVersion: packageVersion
|
|
68
|
+
installedVersion: packageVersion,
|
|
69
|
+
releaseChannel,
|
|
70
|
+
targetBranch: getReleaseChannelBranch(releaseChannel),
|
|
71
|
+
npmDistTag: getReleaseChannelDistTag(releaseChannel),
|
|
56
72
|
};
|
|
57
73
|
}
|
|
58
74
|
|