neoagent 3.1.1-beta.3 → 3.1.1-beta.4

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.
Files changed (40) hide show
  1. package/extensions/chrome-browser/manifest.json +1 -1
  2. package/extensions/chrome-browser/protocol.mjs +36 -0
  3. package/flutter_app/lib/main_app_shell.dart +9 -3
  4. package/flutter_app/lib/main_controller.dart +32 -0
  5. package/flutter_app/lib/main_settings.dart +301 -1
  6. package/flutter_app/lib/main_shared.dart +7 -2
  7. package/flutter_app/lib/main_timeline.dart +82 -11
  8. package/flutter_app/lib/src/backend_client.dart +30 -0
  9. package/landing/index.html +3 -0
  10. package/landing/status.html +178 -0
  11. package/package.json +1 -1
  12. package/server/http/routes.js +2 -0
  13. package/server/http/static.js +1 -0
  14. package/server/public/.last_build_id +1 -1
  15. package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
  16. package/server/public/flutter_bootstrap.js +1 -1
  17. package/server/public/main.dart.js +69698 -69237
  18. package/server/routes/public_status.js +12 -0
  19. package/server/routes/settings.js +14 -0
  20. package/server/routes/social_reach.js +88 -0
  21. package/server/services/ai/tools.js +59 -0
  22. package/server/services/browser/extension/protocol.js +1 -0
  23. package/server/services/manager.js +14 -0
  24. package/server/services/public_status.js +103 -0
  25. package/server/services/runtime/settings.js +6 -0
  26. package/server/services/social_reach/channels/base.js +56 -0
  27. package/server/services/social_reach/channels/github.js +75 -0
  28. package/server/services/social_reach/channels/index.js +34 -0
  29. package/server/services/social_reach/channels/linkedin.js +34 -0
  30. package/server/services/social_reach/channels/rss.js +58 -0
  31. package/server/services/social_reach/channels/unsupported.js +49 -0
  32. package/server/services/social_reach/channels/v2ex.js +85 -0
  33. package/server/services/social_reach/channels/web.js +40 -0
  34. package/server/services/social_reach/channels/xueqiu.js +101 -0
  35. package/server/services/social_reach/channels/youtube.js +42 -0
  36. package/server/services/social_reach/index.js +7 -0
  37. package/server/services/social_reach/platforms.js +162 -0
  38. package/server/services/social_reach/service.js +163 -0
  39. package/server/services/social_reach/store.js +89 -0
  40. package/server/services/social_reach/utils.js +95 -0
@@ -524,6 +524,36 @@ class BackendClient {
524
524
  );
525
525
  }
526
526
 
527
+ Future<Map<String, dynamic>> fetchSocialReachStatus(String baseUrl) async {
528
+ return getMap(baseUrl, '/api/social-reach/status');
529
+ }
530
+
531
+ Future<Map<String, dynamic>> importSocialReachCookies(
532
+ String baseUrl,
533
+ String platform, {
534
+ String? tokenId,
535
+ }) async {
536
+ return postMap(
537
+ baseUrl,
538
+ '/api/social-reach/cookies/import',
539
+ <String, dynamic>{
540
+ 'platform': platform,
541
+ if (tokenId != null && tokenId.trim().isNotEmpty)
542
+ 'tokenId': tokenId.trim(),
543
+ },
544
+ );
545
+ }
546
+
547
+ Future<Map<String, dynamic>> clearSocialReachCookies(
548
+ String baseUrl,
549
+ String platform,
550
+ ) async {
551
+ return deleteMap(
552
+ baseUrl,
553
+ '/api/social-reach/cookies/${Uri.encodeComponent(platform)}',
554
+ );
555
+ }
556
+
527
557
  Future<Map<String, dynamic>> fetchUpdateStatus(String baseUrl) async {
528
558
  return getMap(baseUrl, '/api/settings/update/status');
529
559
  }
@@ -887,6 +887,7 @@ p { margin: 0; text-wrap: pretty; }
887
887
  <a href="#features">Features</a>
888
888
  <a href="#channels">Channels</a>
889
889
  <a href="#how">How it works</a>
890
+ <a href="/status">Status</a>
890
891
  </nav>
891
892
  <div class="nav-right">
892
893
  <a class="signin" href="/app">Sign in</a>
@@ -899,6 +900,7 @@ p { margin: 0; text-wrap: pretty; }
899
900
  <a href="#features">Features</a>
900
901
  <a href="#channels">Channels</a>
901
902
  <a href="#how">How it works</a>
903
+ <a href="/status">Status</a>
902
904
  </div>
903
905
  </header>
904
906
 
@@ -1230,6 +1232,7 @@ p { margin: 0; text-wrap: pretty; }
1230
1232
  <a href="#features">Features</a>
1231
1233
  <a href="#channels">Channels</a>
1232
1234
  <a href="#how">How it works</a>
1235
+ <a href="/status">Status</a>
1233
1236
  <a href="https://neolabs-systems.github.io/NeoAgent/">Documentation</a>
1234
1237
  </nav>
1235
1238
  <nav class="footer-legal">
@@ -0,0 +1,178 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>NeoAgent Status</title>
7
+ <meta name="description" content="Public status for NeoAgent systems.">
8
+ <link rel="icon" type="image/png" href="images/favicon.png">
9
+ <style>
10
+ :root {
11
+ color-scheme: light dark;
12
+ --bg: #f7f3ea;
13
+ --ink: #171512;
14
+ --muted: #6f675a;
15
+ --line: rgba(33, 28, 20, 0.14);
16
+ --panel: rgba(255, 252, 245, 0.82);
17
+ --good: #14874d;
18
+ --warn: #b56a09;
19
+ --bad: #b3261e;
20
+ --accent: #9d7635;
21
+ --shadow: 0 22px 70px rgba(52, 38, 17, 0.14);
22
+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
23
+ }
24
+
25
+ @media (prefers-color-scheme: dark) {
26
+ :root {
27
+ --bg: #11100e;
28
+ --ink: #f5efe5;
29
+ --muted: #b8ac9b;
30
+ --line: rgba(245, 239, 229, 0.14);
31
+ --panel: rgba(31, 29, 25, 0.82);
32
+ --good: #49d18b;
33
+ --warn: #efb35d;
34
+ --bad: #ff827a;
35
+ --accent: #e5c58d;
36
+ --shadow: 0 22px 70px rgba(0, 0, 0, 0.28);
37
+ }
38
+ }
39
+
40
+ * { box-sizing: border-box; }
41
+ body {
42
+ margin: 0;
43
+ min-height: 100vh;
44
+ background:
45
+ radial-gradient(circle at 18% 8%, rgba(229, 197, 141, 0.24), transparent 34rem),
46
+ radial-gradient(circle at 88% 20%, rgba(74, 118, 158, 0.12), transparent 32rem),
47
+ var(--bg);
48
+ color: var(--ink);
49
+ }
50
+
51
+ a { color: inherit; text-decoration: none; }
52
+ .shell { width: min(1120px, calc(100% - 32px)); margin: 0 auto; }
53
+ .nav { display: flex; align-items: center; justify-content: space-between; padding: 24px 0; }
54
+ .brand { display: inline-flex; align-items: center; gap: 12px; font-weight: 750; }
55
+ .mark { width: 34px; height: 34px; border-radius: 10px; background: linear-gradient(135deg, #171512, var(--accent)); box-shadow: inset 0 0 0 1px rgba(255,255,255,.18); }
56
+ .nav a:last-child { color: var(--muted); font-size: 14px; font-weight: 650; }
57
+
58
+ .hero { padding: clamp(54px, 8vw, 104px) 0 34px; }
59
+ .eyebrow { color: var(--accent); font-size: 13px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; }
60
+ h1 { max-width: 850px; margin: 14px 0 18px; font-size: clamp(42px, 8vw, 84px); line-height: .96; letter-spacing: 0; font-weight: 520; }
61
+ .lede { max-width: 680px; margin: 0; color: var(--muted); font-size: clamp(17px, 2vw, 21px); line-height: 1.55; }
62
+
63
+ .summary {
64
+ display: grid;
65
+ grid-template-columns: 1fr auto;
66
+ gap: 24px;
67
+ align-items: center;
68
+ margin: 34px 0 22px;
69
+ padding: clamp(20px, 4vw, 32px);
70
+ border: 1px solid var(--line);
71
+ border-radius: 8px;
72
+ background: var(--panel);
73
+ box-shadow: var(--shadow);
74
+ backdrop-filter: blur(18px);
75
+ }
76
+
77
+ .status { display: inline-flex; align-items: center; gap: 10px; font-weight: 800; font-size: clamp(24px, 4vw, 42px); }
78
+ .dot { width: .72em; height: .72em; border-radius: 50%; background: var(--good); box-shadow: 0 0 0 6px color-mix(in srgb, var(--good) 16%, transparent); }
79
+ .status.degraded .dot { background: var(--warn); box-shadow: 0 0 0 6px color-mix(in srgb, var(--warn) 18%, transparent); }
80
+ .status.unavailable .dot { background: var(--bad); box-shadow: 0 0 0 6px color-mix(in srgb, var(--bad) 18%, transparent); }
81
+ .meta { color: var(--muted); font-size: 14px; line-height: 1.7; }
82
+ .note { margin-top: 12px; color: var(--muted); }
83
+
84
+ .grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; padding: 18px 0 64px; }
85
+ .card { border: 1px solid var(--line); border-radius: 8px; padding: 18px; background: color-mix(in srgb, var(--panel) 86%, transparent); }
86
+ .card-top { display: flex; align-items: start; justify-content: space-between; gap: 14px; }
87
+ .group { margin-bottom: 8px; color: var(--accent); font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: .08em; }
88
+ h2 { margin: 0; font-size: 18px; letter-spacing: 0; }
89
+ .pill { flex: 0 0 auto; border: 1px solid var(--line); border-radius: 999px; padding: 5px 10px; color: var(--good); font-size: 12px; font-weight: 800; }
90
+ .pill.degraded { color: var(--warn); }
91
+ .pill.unavailable { color: var(--bad); }
92
+ .description { margin: 12px 0 0; color: var(--muted); line-height: 1.55; }
93
+ .footer { border-top: 1px solid var(--line); color: var(--muted); padding: 24px 0 36px; font-size: 14px; }
94
+
95
+ @media (max-width: 720px) {
96
+ .summary, .grid { grid-template-columns: 1fr; }
97
+ .nav { align-items: flex-start; }
98
+ .card-top { flex-direction: column; }
99
+ }
100
+ </style>
101
+ </head>
102
+ <body>
103
+ <div class="shell">
104
+ <header class="nav">
105
+ <a class="brand" href="/"><span class="mark" aria-hidden="true"></span><span>NeoAgent</span></a>
106
+ <a href="/app">Sign in</a>
107
+ </header>
108
+
109
+ <main>
110
+ <section class="hero">
111
+ <div class="eyebrow">Public status</div>
112
+ <h1>All the important systems, minus the secret knobs.</h1>
113
+ <p class="lede">A live, public overview of NeoAgent platform health. We show broad system posture here, not private account, device, or workspace details.</p>
114
+ </section>
115
+
116
+ <section class="summary" aria-live="polite">
117
+ <div>
118
+ <div id="overall" class="status"><span class="dot" aria-hidden="true"></span><span>Checking systems</span></div>
119
+ <div id="note" class="note">The robots are tapping gauges with tiny clipboards.</div>
120
+ </div>
121
+ <div id="meta" class="meta">Last checked: loading</div>
122
+ </section>
123
+
124
+ <section id="components" class="grid" aria-label="System components"></section>
125
+ </main>
126
+
127
+ <footer class="footer">Status data refreshes automatically. No incident confetti is deployed on this page.</footer>
128
+ </div>
129
+
130
+ <script>
131
+ (function () {
132
+ 'use strict';
133
+ const labels = {
134
+ operational: 'Operational',
135
+ degraded: 'Degraded',
136
+ unavailable: 'Unavailable',
137
+ maintenance: 'Maintenance'
138
+ };
139
+ const fallback = {
140
+ product: 'NeoAgent',
141
+ status: 'degraded',
142
+ updatedAt: new Date().toISOString(),
143
+ note: 'Live status is taking the scenic route.',
144
+ components: [
145
+ { group: 'Core', name: 'Web App & API', status: 'degraded', description: 'The public page loaded, but live component data is unavailable.' }
146
+ ]
147
+ };
148
+
149
+ function esc(value) {
150
+ return String(value == null ? '' : value).replace(/[&<>"']/g, function (char) {
151
+ return ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[char];
152
+ });
153
+ }
154
+
155
+ function render(data) {
156
+ const status = data.status || 'degraded';
157
+ const overall = document.getElementById('overall');
158
+ overall.className = 'status ' + status;
159
+ overall.querySelector('span:last-child').textContent = labels[status] || 'Status unknown';
160
+ document.getElementById('note').textContent = data.note || '';
161
+ document.getElementById('meta').textContent = 'Last checked: ' + new Date(data.updatedAt || Date.now()).toLocaleString();
162
+ document.getElementById('components').innerHTML = (data.components || []).map(function (item) {
163
+ const itemStatus = item.status || 'degraded';
164
+ return '<article class="card">' +
165
+ '<div class="card-top"><div><div class="group">' + esc(item.group) + '</div><h2>' + esc(item.name) + '</h2></div>' +
166
+ '<div class="pill ' + esc(itemStatus) + '">' + esc(labels[itemStatus] || itemStatus) + '</div></div>' +
167
+ '<p class="description">' + esc(item.description) + '</p></article>';
168
+ }).join('');
169
+ }
170
+
171
+ fetch('/api/public/status', { headers: { accept: 'application/json' } })
172
+ .then(function (res) { return res.ok ? res.json() : Promise.reject(new Error('Status unavailable')); })
173
+ .then(render)
174
+ .catch(function () { render(fallback); });
175
+ })();
176
+ </script>
177
+ </body>
178
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neoagent",
3
- "version": "3.1.1-beta.3",
3
+ "version": "3.1.1-beta.4",
4
4
  "description": "Self-hosted AI agent for long-running tasks, automation, messaging, device control, and local memory",
5
5
  "license": "AGPL-3.0-only",
6
6
  "main": "server/index.js",
@@ -6,6 +6,7 @@ const { getVersionInfo } = require('../utils/version');
6
6
  const { getRuntimeValidation } = require('../services/runtime/validation');
7
7
 
8
8
  const routeRegistry = [
9
+ { basePath: '/api/public', modulePath: '../routes/public_status' },
9
10
  { basePath: '/api/runtime', modulePath: '../routes/runtime' },
10
11
  { basePath: null, modulePath: '../routes/auth' },
11
12
  { basePath: '/api/account', modulePath: '../routes/account' },
@@ -30,6 +31,7 @@ const routeRegistry = [
30
31
  { basePath: '/api/stream', modulePath: '../routes/stream' },
31
32
  { basePath: '/api/recordings', modulePath: '../routes/recordings' },
32
33
  { basePath: '/api/social-video', modulePath: '../routes/social_video' },
34
+ { basePath: '/api/social-reach', modulePath: '../routes/social_reach' },
33
35
  { basePath: '/api/voice-assistant', modulePath: '../routes/voice_assistant' },
34
36
  { basePath: '/api/wearable', modulePath: '../routes/wearable' },
35
37
  { basePath: '/api/mobile/health', modulePath: '../routes/mobile-health' },
@@ -80,6 +80,7 @@ function registerStaticRoutes(app) {
80
80
  // Landing page at /
81
81
  if (fs.existsSync(path.join(LANDING_DIR, 'index.html'))) {
82
82
  app.use(express.static(LANDING_DIR));
83
+ app.get('/status', (req, res) => res.sendFile(path.join(LANDING_DIR, 'status.html')));
83
84
  app.get('/', (req, res) => res.sendFile(path.join(LANDING_DIR, 'index.html')));
84
85
  }
85
86
  }
@@ -1 +1 @@
1
- e27e3bdd735d729b1e7255a48e8c9936
1
+ 290aea80d4ae81e5a61607695f613845
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"a10d8ac38de835021c8d2f920dbf50a920ccc0
37
37
 
38
38
  _flutter.loader.load({
39
39
  serviceWorkerSettings: {
40
- serviceWorkerVersion: "3226185212" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
40
+ serviceWorkerVersion: "3576241244" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
41
41
  }
42
42
  });