neoagent 2.1.5 → 2.1.7

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.1.5",
3
+ "version": "2.1.7",
4
4
  "description": "Proactive personal AI agent with no limits",
5
5
  "license": "MIT",
6
6
  "main": "server/index.js",
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"052f31d115eceda8cbff1b3481fcde4330c4ae
37
37
 
38
38
  _flutter.loader.load({
39
39
  serviceWorkerSettings: {
40
- serviceWorkerVersion: "315305623" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
40
+ serviceWorkerVersion: "204310170" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
41
41
  }
42
42
  });
@@ -47,6 +47,18 @@ function sleep(ms) {
47
47
  return new Promise((resolve) => setTimeout(resolve, ms));
48
48
  }
49
49
 
50
+ function tailFile(filePath, maxLines = 40) {
51
+ try {
52
+ const lines = fs.readFileSync(filePath, 'utf8')
53
+ .split('\n')
54
+ .map((line) => line.trim())
55
+ .filter(Boolean);
56
+ return lines.slice(-maxLines);
57
+ } catch {
58
+ return [];
59
+ }
60
+ }
61
+
50
62
  function commandExists(command) {
51
63
  const probe = spawnSync('bash', ['-lc', `command -v "${command}"`], { encoding: 'utf8' });
52
64
  return probe.status === 0;
@@ -270,25 +282,75 @@ function systemImageTagScore(tag) {
270
282
  return 0;
271
283
  }
272
284
 
285
+ function parseSystemImageCandidates(entries = []) {
286
+ return entries.map((entry) => {
287
+ const platform = parseSystemImagePlatform(entry.platformId);
288
+ return {
289
+ packageName: entry.packageName,
290
+ platformId: entry.platformId,
291
+ tag: entry.tag,
292
+ arch: entry.arch,
293
+ apiLevel: platform.apiLevel,
294
+ stable: platform.stable,
295
+ tagScore: systemImageTagScore(entry.tag),
296
+ };
297
+ });
298
+ }
299
+
273
300
  function parseSystemImages(listOutput) {
274
301
  const matches = [];
275
302
  const regex = /system-images;(android-[^;\s]+);([^;\s]+);([^;\s]+)/g;
276
303
  let match = regex.exec(listOutput);
277
304
  while (match) {
278
- const platform = parseSystemImagePlatform(match[1]);
279
305
  matches.push({
280
306
  packageName: match[0],
281
307
  platformId: match[1],
282
308
  tag: match[2],
283
309
  arch: match[3],
284
- apiLevel: platform.apiLevel,
285
- stable: platform.stable,
286
- tagScore: systemImageTagScore(match[2]),
287
310
  });
288
311
  match = regex.exec(listOutput);
289
312
  }
290
313
 
291
- return matches;
314
+ return parseSystemImageCandidates(matches);
315
+ }
316
+
317
+ function parseInstalledSystemImages() {
318
+ const root = path.join(SDK_ROOT, 'system-images');
319
+ if (!fs.existsSync(root)) {
320
+ return [];
321
+ }
322
+
323
+ const matches = [];
324
+ const platforms = fs.readdirSync(root, { withFileTypes: true })
325
+ .filter((entry) => entry.isDirectory())
326
+ .map((entry) => entry.name);
327
+
328
+ for (const platformId of platforms) {
329
+ const platformDir = path.join(root, platformId);
330
+ const tags = fs.readdirSync(platformDir, { withFileTypes: true })
331
+ .filter((entry) => entry.isDirectory())
332
+ .map((entry) => entry.name);
333
+ for (const tag of tags) {
334
+ const tagDir = path.join(platformDir, tag);
335
+ const archs = fs.readdirSync(tagDir, { withFileTypes: true })
336
+ .filter((entry) => entry.isDirectory())
337
+ .map((entry) => entry.name);
338
+ for (const arch of archs) {
339
+ const packageXml = path.join(tagDir, arch, 'package.xml');
340
+ if (!fs.existsSync(packageXml)) {
341
+ continue;
342
+ }
343
+ matches.push({
344
+ packageName: `system-images;${platformId};${tag};${arch}`,
345
+ platformId,
346
+ tag,
347
+ arch,
348
+ });
349
+ }
350
+ }
351
+ }
352
+
353
+ return parseSystemImageCandidates(matches);
292
354
  }
293
355
 
294
356
  function rankSystemImagePool(pool) {
@@ -297,8 +359,8 @@ function rankSystemImagePool(pool) {
297
359
 
298
360
  rankedPool.sort((a, b) =>
299
361
  Number(b.stable) - Number(a.stable) ||
300
- b.apiLevel - a.apiLevel ||
301
362
  b.tagScore - a.tagScore ||
363
+ b.apiLevel - a.apiLevel ||
302
364
  a.packageName.localeCompare(b.packageName)
303
365
  );
304
366
 
@@ -306,7 +368,9 @@ function rankSystemImagePool(pool) {
306
368
  }
307
369
 
308
370
  function chooseConfiguredSystemImage(listOutput) {
309
- const matches = parseSystemImages(listOutput);
371
+ const matches = Array.isArray(listOutput)
372
+ ? parseSystemImageCandidates(listOutput)
373
+ : parseSystemImages(listOutput);
310
374
  const packageName = configuredSystemImagePackage();
311
375
  if (packageName) {
312
376
  return matches.find((candidate) => candidate.packageName === packageName) || null;
@@ -328,7 +392,9 @@ function chooseConfiguredSystemImage(listOutput) {
328
392
  }
329
393
 
330
394
  function chooseLatestSystemImage(listOutput, preferredArchs = systemImageArchCandidates()) {
331
- const matches = parseSystemImages(listOutput);
395
+ const matches = Array.isArray(listOutput)
396
+ ? parseSystemImageCandidates(listOutput)
397
+ : parseSystemImages(listOutput);
332
398
  const archPool = Array.isArray(preferredArchs) && preferredArchs.length > 0
333
399
  ? preferredArchs
334
400
  : systemImageArchCandidates();
@@ -347,7 +413,10 @@ function chooseLatestSystemImage(listOutput, preferredArchs = systemImageArchCan
347
413
  }
348
414
 
349
415
  function formatSystemImageError(listOutput) {
350
- const availableArchs = [...new Set(parseSystemImages(listOutput).map((candidate) => candidate.arch))].sort();
416
+ const candidates = Array.isArray(listOutput)
417
+ ? parseSystemImageCandidates(listOutput)
418
+ : parseSystemImages(listOutput);
419
+ const availableArchs = [...new Set(candidates.map((candidate) => candidate.arch))].sort();
351
420
  const wantedArchs = systemImageArchCandidates().join(', ');
352
421
  const packageName = configuredSystemImagePackage();
353
422
  const platformId = configuredSystemImagePlatform();
@@ -489,12 +558,27 @@ class AndroidController {
489
558
  }
490
559
 
491
560
  const state = readState();
492
- if (
493
- state.bootstrapped === true &&
494
- state.systemImage &&
495
- !shouldForceSdkRefresh()
496
- ) {
497
- return;
561
+ if (!shouldForceSdkRefresh()) {
562
+ const installedImages = parseInstalledSystemImages();
563
+ if (installedImages.length > 0) {
564
+ const preferredInstalled =
565
+ chooseConfiguredSystemImage(installedImages) ||
566
+ chooseLatestSystemImage(installedImages);
567
+ if (
568
+ preferredInstalled &&
569
+ preferredInstalled.packageName !== state.systemImage
570
+ ) {
571
+ appendState({
572
+ bootstrapped: true,
573
+ systemImage: preferredInstalled.packageName,
574
+ apiLevel: preferredInstalled.apiLevel,
575
+ systemImageArch: preferredInstalled.arch,
576
+ });
577
+ }
578
+ return;
579
+ } else if (state.bootstrapped === true && state.systemImage) {
580
+ return;
581
+ }
498
582
  }
499
583
 
500
584
  appendState({ bootstrapped: true });
@@ -693,7 +777,6 @@ class AndroidController {
693
777
  stdio: ['ignore', out, out],
694
778
  env: sdkEnv(),
695
779
  });
696
- child.unref();
697
780
 
698
781
  console.log(`[Android] Emulator process started (pid ${child.pid})`);
699
782
  appendState({
@@ -706,7 +789,38 @@ class AndroidController {
706
789
  lastLogLine: 'Android emulator process started. Waiting for boot completion...',
707
790
  });
708
791
 
709
- const onlineSerial = await this.waitForDevice({ timeoutMs: options.timeoutMs || 240000 });
792
+ const processExit = new Promise((resolve) => {
793
+ child.once('exit', (code, signal) => {
794
+ resolve({ code, signal });
795
+ });
796
+ child.once('error', (error) => {
797
+ resolve({ code: null, signal: null, error });
798
+ });
799
+ });
800
+
801
+ child.unref();
802
+
803
+ const bootResult = await Promise.race([
804
+ this.waitForDevice({ timeoutMs: options.timeoutMs || 240000 }).then((serial) => ({
805
+ serial,
806
+ exited: false,
807
+ })),
808
+ processExit.then((result) => ({
809
+ exited: true,
810
+ ...result,
811
+ })),
812
+ ]);
813
+
814
+ if (bootResult.exited) {
815
+ const recentLogLines = tailFile(logPath, 12);
816
+ const lastLine =
817
+ bootResult.error?.message ||
818
+ recentLogLines[recentLogLines.length - 1] ||
819
+ `Emulator process exited before boot completed (code ${bootResult.code ?? 'unknown'}, signal ${bootResult.signal ?? 'none'}).`;
820
+ throw new Error(lastLine);
821
+ }
822
+
823
+ const onlineSerial = bootResult.serial;
710
824
  appendState({
711
825
  serial: onlineSerial,
712
826
  emulatorPid: child.pid,
@@ -772,14 +886,17 @@ class AndroidController {
772
886
  lastLogLine: 'Android start requested.',
773
887
  });
774
888
  const startPromise = this.#startEmulatorBlocking(options).catch((err) => {
889
+ const state = readState();
890
+ const recentLogLines = state.logPath ? tailFile(state.logPath, 12) : [];
891
+ const detailedMessage = recentLogLines[recentLogLines.length - 1] || err.message;
775
892
  appendState({
776
893
  starting: false,
777
894
  startupPhase: 'Start failed',
778
- lastStartError: err.message,
779
- lastLogLine: err.message,
895
+ lastStartError: detailedMessage,
896
+ lastLogLine: detailedMessage,
780
897
  });
781
- console.error('[Android] Emulator start failed:', err.message);
782
- throw err;
898
+ console.error('[Android] Emulator start failed:', detailedMessage);
899
+ throw new Error(detailedMessage);
783
900
  }).finally(() => {
784
901
  if (this.startPromise === startPromise) {
785
902
  this.startPromise = null;