nexo-brain 5.3.18 → 5.3.19

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "5.3.18",
3
+ "version": "5.3.19",
4
4
  "description": "Local cognitive runtime for Claude Code \u2014 persistent memory, overnight learning, doctor diagnostics, personal scripts, recovery-aware jobs, startup preflight, and optional dashboard/power helper.",
5
5
  "author": {
6
6
  "name": "NEXO Brain",
package/bin/nexo-brain.js CHANGED
@@ -2511,6 +2511,9 @@ I am ${operatorName}, a cognitive co-operator. Not an assistant — an operation
2511
2511
  calendar: {},
2512
2512
  contacts: [],
2513
2513
  documents: {},
2514
+ notes: { count: 0, folders: [] },
2515
+ reminders: { count: 0, lists: [] },
2516
+ photos: { count: 0 },
2514
2517
  messaging: [],
2515
2518
  interests: [],
2516
2519
  summary: {},
@@ -2747,16 +2750,27 @@ I am ${operatorName}, a cognitive co-operator. Not an assistant — an operation
2747
2750
  // --- Email accounts ---
2748
2751
  process.stdout.write(" \u280B Email accounts...\r");
2749
2752
  if (platform === "darwin") {
2750
- // macOS Mail.app accounts
2751
- const mailAccounts = run("defaults read com.apple.mail MailAccounts 2>/dev/null | grep AccountName | head -20");
2753
+ // macOS Mail.app accounts — try multiple detection methods
2754
+ // Method 1: sandboxed container (modern macOS)
2755
+ let mailAccounts = run("defaults read ~/Library/Containers/com.apple.mail/Data/Library/Preferences/com.apple.mail MailAccounts 2>/dev/null | grep -E 'AccountName|EmailAddresses' | head -30");
2756
+ // Method 2: legacy plist (older macOS)
2757
+ if (!mailAccounts) mailAccounts = run("defaults read com.apple.mail MailAccounts 2>/dev/null | grep -E 'AccountName|EmailAddresses' | head -30");
2758
+ // Method 3: Internet Accounts (covers Mail, Calendar, Contacts, etc.)
2759
+ if (!mailAccounts) mailAccounts = run("defaults read com.apple.internetaccounts Accounts 2>/dev/null | grep -E 'AccountDescription|Username' | head -30");
2760
+ // Method 4: scan Mail directory for account folders
2761
+ if (!mailAccounts) {
2762
+ const mailDir = run("ls -1 ~/Library/Mail/V*/ 2>/dev/null | grep -v '^$' | head -20");
2763
+ if (mailDir) mailAccounts = mailDir;
2764
+ }
2752
2765
  if (mailAccounts) {
2753
2766
  profileData.email = mailAccounts.split("\n")
2754
- .map(l => l.replace(/.*=\s*"?/, "").replace(/"?\s*;?\s*$/, "").trim())
2755
- .filter(Boolean);
2767
+ .map(l => l.replace(/.*=\s*"?/, "").replace(/"?\s*;?\s*$/, "").replace(/\/$/, "").trim())
2768
+ .filter(l => l && l.length > 1 && !l.startsWith("(") && !l.startsWith(")") && !l.includes("{") && !l.includes("}"))
2769
+ .filter((v, i, a) => a.indexOf(v) === i); // dedupe
2756
2770
  }
2757
2771
  }
2758
2772
  if (profileData.email.length > 0) {
2759
- log(`\u2713 ${profileData.email.length} email accounts configured`);
2773
+ log(`\u2713 ${profileData.email.length} email accounts detected`);
2760
2774
  }
2761
2775
 
2762
2776
  // --- Calendar (macOS) ---
@@ -2815,6 +2829,76 @@ I am ${operatorName}, a cognitive co-operator. Not an assistant — an operation
2815
2829
  log(`\u2713 ${totalDocs} recent documents (${typesSummary})`);
2816
2830
  }
2817
2831
 
2832
+ // --- Notes ---
2833
+ process.stdout.write(" \u280B Notes...\r");
2834
+ profileData.notes = { count: 0, folders: [] };
2835
+ if (platform === "linux") {
2836
+ // GNOME Notes / Tomboy / Obsidian vaults
2837
+ const obsidianVaults = run(`find "${home}" -maxdepth 3 -name ".obsidian" -type d 2>/dev/null | head -5`);
2838
+ if (obsidianVaults) {
2839
+ const vaults = obsidianVaults.split("\n").filter(Boolean);
2840
+ let totalNotes = 0;
2841
+ for (const v of vaults) {
2842
+ const vaultDir = path.dirname(v);
2843
+ const count = run(`find "${vaultDir}" -name "*.md" -type f 2>/dev/null | wc -l`);
2844
+ totalNotes += parseInt((count || "0").trim());
2845
+ }
2846
+ profileData.notes.count = totalNotes;
2847
+ profileData.notes.folders = vaults.map(v => path.basename(path.dirname(v)));
2848
+ }
2849
+ } else if (platform === "darwin") {
2850
+ const notesDb = path.join(home, "Library", "Group Containers", "group.com.apple.notes", "NoteStore.sqlite");
2851
+ if (fs.existsSync(notesDb)) {
2852
+ const noteCount = run(`sqlite3 "${notesDb}" "SELECT COUNT(*) FROM ZICCLOUDSYNCINGOBJECT WHERE ZTITLE IS NOT NULL AND ZMARKEDFORDELETION != 1" 2>/dev/null`);
2853
+ profileData.notes.count = parseInt((noteCount || "0").trim());
2854
+ const folders = run(`sqlite3 "${notesDb}" "SELECT DISTINCT ZTITLE2 FROM ZICCLOUDSYNCINGOBJECT WHERE ZTITLE2 IS NOT NULL AND ZMARKEDFORDELETION != 1 LIMIT 15" 2>/dev/null`);
2855
+ if (folders) profileData.notes.folders = folders.split("\n").filter(Boolean);
2856
+ }
2857
+ }
2858
+ if (profileData.notes.count > 0) {
2859
+ log(`\u2713 ${profileData.notes.count} notes${profileData.notes.folders.length ? ` in ${profileData.notes.folders.length} folders` : ""}`);
2860
+ }
2861
+
2862
+ // --- Reminders ---
2863
+ process.stdout.write(" \u280B Reminders...\r");
2864
+ profileData.reminders = { count: 0, lists: [] };
2865
+ if (platform === "linux") {
2866
+ // GNOME Reminders / Todoist / task files
2867
+ const todoFiles = run(`find "${home}" -maxdepth 2 -name "todo.txt" -o -name "TODO.md" -o -name "tasks.md" 2>/dev/null | head -5`);
2868
+ if (todoFiles) {
2869
+ let count = 0;
2870
+ todoFiles.split("\n").filter(Boolean).forEach(f => {
2871
+ const lines = run(`wc -l < "${f}" 2>/dev/null`);
2872
+ count += parseInt((lines || "0").trim());
2873
+ });
2874
+ profileData.reminders.count = count;
2875
+ profileData.reminders.lists = todoFiles.split("\n").filter(Boolean).map(f => path.basename(f));
2876
+ }
2877
+ } else if (platform === "darwin") {
2878
+ // Reminders uses EventKit, but we can count via the Calendars directory or osascript
2879
+ const reminderCount = run('osascript -e \'tell application "Reminders" to count of (every reminder whose completed is false)\' 2>/dev/null');
2880
+ if (reminderCount) profileData.reminders.count = parseInt(reminderCount.trim()) || 0;
2881
+ const reminderLists = run('osascript -e \'tell application "Reminders" to get name of every list\' 2>/dev/null');
2882
+ if (reminderLists) profileData.reminders.lists = reminderLists.split(", ").filter(Boolean);
2883
+ }
2884
+ if (profileData.reminders.count > 0) {
2885
+ log(`\u2713 ${profileData.reminders.count} active reminders across ${profileData.reminders.lists.length} lists`);
2886
+ }
2887
+
2888
+ // --- Photos library size (macOS) ---
2889
+ process.stdout.write(" \u280B Photos...\r");
2890
+ profileData.photos = { count: 0 };
2891
+ if (platform === "darwin") {
2892
+ const photosDb = path.join(home, "Pictures", "Photos Library.photoslibrary", "database", "Photos.sqlite");
2893
+ if (fs.existsSync(photosDb)) {
2894
+ const photoCount = run(`sqlite3 "${photosDb}" "SELECT COUNT(*) FROM ZASSET WHERE ZTRASHEDSTATE = 0" 2>/dev/null`);
2895
+ if (photoCount) profileData.photos.count = parseInt(photoCount.trim()) || 0;
2896
+ }
2897
+ }
2898
+ if (profileData.photos.count > 0) {
2899
+ log(`\u2713 ${profileData.photos.count.toLocaleString()} photos in library`);
2900
+ }
2901
+
2818
2902
  // --- Messaging apps ---
2819
2903
  process.stdout.write(" \u280B Messaging...\r");
2820
2904
  const msgApps = { "WhatsApp": "WhatsApp.app", "Telegram": "Telegram.app", "Slack": "Slack.app", "Discord": "Discord.app", "Signal": "Signal.app", "Teams": "Microsoft Teams.app", "Zoom": "zoom.us.app" };
@@ -2839,6 +2923,11 @@ I am ${operatorName}, a cognitive co-operator. Not an assistant — an operation
2839
2923
  repos: repos.length,
2840
2924
  servers: profileData.ssh.length,
2841
2925
  email_accounts: profileData.email.length,
2926
+ notes: profileData.notes.count,
2927
+ reminders: profileData.reminders.count,
2928
+ photos: profileData.photos.count,
2929
+ recent_documents: profileData.documents.recent_count || 0,
2930
+ contacts: profileData.contacts.count || 0,
2842
2931
  key_tools: topApps.slice(0, 8),
2843
2932
  work_hours: profileData.terminal.peak_hours || [],
2844
2933
  peak_days: profileData.terminal.peak_days || [],
@@ -2855,12 +2944,24 @@ I am ${operatorName}, a cognitive co-operator. Not an assistant — an operation
2855
2944
  line(`${t.profileTitle}: ${userName || profileData.git.name || "User"}`);
2856
2945
  line("");
2857
2946
  if (topLangs.length) line(`Stack: ${topLangs.join(", ")}`);
2858
- line(`${repos.length} repos \u00B7 ${profileData.ssh.length} servers \u00B7 ${profileData.email.length} email accounts`);
2947
+ // Life data
2948
+ const lifeParts = [];
2949
+ if (profileData.email.length) lifeParts.push(`${profileData.email.length} email`);
2950
+ if (profileData.notes.count) lifeParts.push(`${profileData.notes.count} notes`);
2951
+ if (profileData.reminders.count) lifeParts.push(`${profileData.reminders.count} reminders`);
2952
+ if (profileData.contacts.count) lifeParts.push(`${profileData.contacts.count} contacts`);
2953
+ if (profileData.photos.count) lifeParts.push(`${profileData.photos.count.toLocaleString()} photos`);
2954
+ if (profileData.documents.recent_count) lifeParts.push(`${profileData.documents.recent_count} docs`);
2955
+ if (lifeParts.length) line(lifeParts.join(" \u00B7 "));
2956
+ // Dev data
2957
+ if (repos.length || profileData.ssh.length) {
2958
+ line(`${repos.length} repos \u00B7 ${profileData.ssh.length} servers`);
2959
+ }
2960
+ if (topLangs.length) line(`Stack: ${topLangs.join(", ")}`);
2859
2961
  if (topApps.length) line(`Tools: ${topApps.slice(0, 6).join(", ")}`);
2860
2962
  if (totalCommits) line(`${totalCommits.toLocaleString()} commits/year`);
2861
2963
  if (profileData.terminal.peak_hours) {
2862
2964
  const hours = profileData.terminal.peak_hours;
2863
- // Group consecutive hours into ranges
2864
2965
  const ranges = [];
2865
2966
  let start = hours[0], prev = hours[0];
2866
2967
  for (let i = 1; i <= hours.length; i++) {
@@ -2871,6 +2972,7 @@ I am ${operatorName}, a cognitive co-operator. Not an assistant — an operation
2871
2972
  line(`Hours: ${ranges.join(", ")}${profileData.terminal.peak_days ? ` \u00B7 Peak: ${profileData.terminal.peak_days.join(", ")}` : ""}`);
2872
2973
  }
2873
2974
  if (profileData.messaging.length) line(`Messaging: ${profileData.messaging.join(", ")}`);
2975
+ if (profileData.calendar.events) line(`Calendar: ${profileData.calendar.events} events`);
2874
2976
  line(`Timezone: ${profileData.system.timezone}`);
2875
2977
  line("");
2876
2978
  line(lang === "es" ? "Ya te conozco. Vamos a trabajar." : lang === "fr" ? "Je te connais. Au travail." : lang === "de" ? "Ich kenne dich. Los geht's." : lang === "it" ? "Ti conosco. Al lavoro." : lang === "pt" ? "J\u00E1 te conhe\u00E7o. Ao trabalho." : "I know you now. Let's work.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexo-brain",
3
- "version": "5.3.18",
3
+ "version": "5.3.19",
4
4
  "mcpName": "io.github.wazionapps/nexo",
5
5
  "description": "NEXO Brain — Shared brain for AI agents. Persistent memory, semantic RAG, natural forgetting, metacognitive guard, trust scoring, 150+ MCP tools. Works with Claude Code, Codex, Claude Desktop & any MCP client. 100% local, free.",
6
6
  "homepage": "https://nexo-brain.com",