neoagent 2.5.2-beta.9 → 3.0.1-beta.0

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 (52) hide show
  1. package/README.md +5 -1
  2. package/docs/integrations.md +11 -7
  3. package/flutter_app/lib/main_controller.dart +34 -0
  4. package/flutter_app/lib/main_security.dart +19 -0
  5. package/lib/schema_migrations.js +224 -0
  6. package/package.json +2 -2
  7. package/server/admin/admin.css +29 -0
  8. package/server/admin/admin.js +81 -1
  9. package/server/admin/index.html +97 -9
  10. package/server/db/database.js +57 -1
  11. package/server/public/.last_build_id +1 -1
  12. package/server/public/flutter_bootstrap.js +1 -1
  13. package/server/public/main.dart.js +32788 -32752
  14. package/server/routes/security.js +19 -0
  15. package/server/routes/settings.js +1 -0
  16. package/server/routes/skills.js +9 -5
  17. package/server/services/ai/deliverables/artifact_helpers.js +92 -9
  18. package/server/services/ai/deliverables/selector.js +17 -0
  19. package/server/services/ai/hooks.js +3 -2
  20. package/server/services/ai/learning.js +8 -3
  21. package/server/services/ai/loop/agent_engine_core.js +67 -0
  22. package/server/services/ai/loop/blank_recovery.js +37 -0
  23. package/server/services/ai/loop/conversation_loop.js +391 -252
  24. package/server/services/ai/loop/error_recovery.js +38 -0
  25. package/server/services/ai/loop/messaging_delivery.js +52 -6
  26. package/server/services/ai/loop/progress_classification.js +178 -0
  27. package/server/services/ai/loop/progress_monitor.js +6 -5
  28. package/server/services/ai/loop/tool_dispatch.js +1 -0
  29. package/server/services/ai/loopPolicy.js +15 -6
  30. package/server/services/ai/messagingFallback.js +23 -1
  31. package/server/services/ai/preModelCompaction.js +31 -0
  32. package/server/services/ai/repetitionGuard.js +47 -2
  33. package/server/services/ai/settings.js +8 -0
  34. package/server/services/ai/systemPrompt.js +24 -0
  35. package/server/services/ai/taskAnalysis.js +10 -0
  36. package/server/services/ai/toolEvidence.js +39 -3
  37. package/server/services/ai/toolResult.js +29 -0
  38. package/server/services/ai/toolRunner.js +262 -55
  39. package/server/services/ai/toolSelector.js +20 -3
  40. package/server/services/ai/tools.js +201 -31
  41. package/server/services/cli/shell_worker_pool.js +87 -5
  42. package/server/services/integrations/github/common.js +2 -2
  43. package/server/services/integrations/github/repos.js +123 -55
  44. package/server/services/manager.js +16 -0
  45. package/server/services/memory/manager.js +39 -24
  46. package/server/services/runtime/docker-vm-manager.js +21 -1
  47. package/server/services/runtime/manager.js +6 -2
  48. package/server/services/security/approval_gate_service.js +108 -5
  49. package/server/services/security/tool_categories.js +113 -4
  50. package/server/services/security/tool_security_hook.js +7 -2
  51. package/server/services/skills/runtime.js +2 -0
  52. package/server/services/workspace/manager.js +56 -0
@@ -6,6 +6,12 @@
6
6
  <title>NeoAgent Admin</title>
7
7
  <link rel="icon" href="/admin/logo.svg" type="image/svg+xml">
8
8
  <link rel="stylesheet" href="/admin/admin.css">
9
+ <script>
10
+ // Set theme before first paint to avoid a flash of the wrong palette.
11
+ try {
12
+ document.documentElement.setAttribute('data-theme', localStorage.getItem('admin-theme') || 'dark');
13
+ } catch (_) { document.documentElement.setAttribute('data-theme', 'dark'); }
14
+ </script>
9
15
  <style>
10
16
  /* ── Layout ────────────────────────────────────────────────────── */
11
17
  body {
@@ -62,7 +68,7 @@
62
68
  text-decoration: none;
63
69
  }
64
70
 
65
- .nav-item:hover { background: rgba(224,240,224,0.05); color: var(--text); }
71
+ .nav-item:hover { background: var(--row-hover); color: var(--text); }
66
72
 
67
73
  .nav-item.active {
68
74
  background: rgba(225, 176, 82, 0.12);
@@ -78,6 +84,51 @@
78
84
 
79
85
  .nav-item.active svg { opacity: 1; }
80
86
 
87
+ .nav-badge {
88
+ margin-left: auto;
89
+ min-width: 18px;
90
+ padding: 1px 6px;
91
+ border-radius: 999px;
92
+ background: var(--danger);
93
+ color: #fff;
94
+ font-size: 11px;
95
+ font-weight: 600;
96
+ line-height: 1.4;
97
+ text-align: center;
98
+ }
99
+
100
+ .issue-row {
101
+ display: grid;
102
+ grid-template-columns: 1fr auto;
103
+ gap: 12px;
104
+ align-items: start;
105
+ padding: 10px 14px;
106
+ border-bottom: 1px solid var(--border);
107
+ }
108
+ .issue-row:last-child { border-bottom: none; }
109
+ .issue-msg {
110
+ font-family: var(--font-mono);
111
+ font-size: 12.5px;
112
+ color: var(--danger);
113
+ white-space: pre-wrap;
114
+ word-break: break-word;
115
+ }
116
+ .issue-meta {
117
+ font-size: 11px;
118
+ color: var(--text-muted);
119
+ text-align: right;
120
+ white-space: nowrap;
121
+ }
122
+ .issue-count {
123
+ display: inline-block;
124
+ margin-bottom: 3px;
125
+ padding: 1px 7px;
126
+ border-radius: 999px;
127
+ background: var(--accent-muted);
128
+ color: var(--accent);
129
+ font-weight: 600;
130
+ }
131
+
81
132
  .sidebar-footer {
82
133
  padding: 10px;
83
134
  border-top: 1px solid var(--border);
@@ -202,12 +253,12 @@
202
253
  .log-row {
203
254
  display: grid;
204
255
  grid-template-columns: 80px 46px 1fr;
205
- border-bottom: 1px solid rgba(224,240,224,0.04);
256
+ border-bottom: 1px solid var(--border);
206
257
  }
207
258
 
208
259
  .log-row:last-child { border-bottom: none; }
209
260
 
210
- .log-row:hover { background: rgba(224,240,224,0.03); }
261
+ .log-row:hover { background: var(--row-hover); }
211
262
 
212
263
  .log-cell {
213
264
  padding: 6px 10px;
@@ -426,12 +477,12 @@
426
477
 
427
478
  .analytics-table td {
428
479
  padding: 9px 8px;
429
- border-bottom: 1px solid rgba(224,240,224,0.04);
480
+ border-bottom: 1px solid var(--border);
430
481
  color: var(--text-secondary);
431
482
  }
432
483
 
433
484
  .analytics-table tr:last-child td { border-bottom: none; }
434
- .analytics-table tr:hover td { background: rgba(224,240,224,0.025); }
485
+ .analytics-table tr:hover td { background: var(--row-hover); }
435
486
 
436
487
  .cell-truncate {
437
488
  max-width: 280px;
@@ -504,12 +555,12 @@
504
555
 
505
556
  .users-table td {
506
557
  padding: 10px 8px;
507
- border-bottom: 1px solid rgba(224,240,224,0.04);
558
+ border-bottom: 1px solid var(--border);
508
559
  vertical-align: middle;
509
560
  }
510
561
 
511
562
  .users-table tr:last-child td { border-bottom: none; }
512
- .users-table tr:hover td { background: rgba(224,240,224,0.025); }
563
+ .users-table tr:hover td { background: var(--row-hover); }
513
564
 
514
565
  .gdpr-note {
515
566
  font-size: 11px;
@@ -593,7 +644,7 @@
593
644
 
594
645
  .sql-result-table td {
595
646
  padding: 6px 12px;
596
- border-bottom: 1px solid rgba(224,240,224,0.04);
647
+ border-bottom: 1px solid var(--border);
597
648
  color: var(--text-secondary);
598
649
  white-space: nowrap;
599
650
  max-width: 320px;
@@ -602,7 +653,7 @@
602
653
  }
603
654
 
604
655
  .sql-result-table tr:last-child td { border-bottom: none; }
605
- .sql-result-table tr:hover td { background: rgba(224,240,224,0.03); }
656
+ .sql-result-table tr:hover td { background: var(--row-hover); }
606
657
 
607
658
  .sql-error {
608
659
  padding: 12px 14px;
@@ -821,6 +872,14 @@
821
872
  Logs
822
873
  </button>
823
874
 
875
+ <button class="nav-item" data-page="issues" onclick="showPage('issues',this)">
876
+ <svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
877
+ <path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/>
878
+ </svg>
879
+ Issues
880
+ <span class="nav-badge" id="issues-badge" hidden>0</span>
881
+ </button>
882
+
824
883
  <button class="nav-item" data-page="updates" onclick="showPage('updates',this)">
825
884
  <svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
826
885
  <path fill-rule="evenodd" d="M4 2a1 1 0 011 1v2.101a7.002 7.002 0 0111.601 2.566 1 1 0 11-1.885.666A5.002 5.002 0 005.999 7H9a1 1 0 010 2H4a1 1 0 01-1-1V3a1 1 0 011-1zm.008 9.057a1 1 0 011.276.61A5.002 5.002 0 0014.001 13H11a1 1 0 110-2h5a1 1 0 011 1v5a1 1 0 11-2 0v-2.101a7.002 7.002 0 01-11.601-2.566 1 1 0 01.61-1.276z" clip-rule="evenodd"/>
@@ -883,6 +942,12 @@
883
942
  </nav>
884
943
 
885
944
  <div class="sidebar-footer">
945
+ <button class="nav-item" id="theme-toggle" onclick="toggleTheme()" aria-label="Toggle light and dark theme">
946
+ <svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
947
+ <path d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"/>
948
+ </svg>
949
+ <span id="theme-toggle-label">Light mode</span>
950
+ </button>
886
951
  <button class="nav-item btn-danger" onclick="signOut()">
887
952
  <svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
888
953
  <path fill-rule="evenodd" d="M3 3a1 1 0 00-1 1v12a1 1 0 102 0V4a1 1 0 00-1-1zm10.293 9.293a1 1 0 001.414 1.414l3-3a1 1 0 000-1.414l-3-3a1 1 0 10-1.414 1.414L14.586 9H7a1 1 0 100 2h7.586l-1.293 1.293z" clip-rule="evenodd"/>
@@ -938,6 +1003,29 @@
938
1003
  </div>
939
1004
  </section>
940
1005
 
1006
+ <!-- Issues -->
1007
+ <section id="page-issues" class="page" aria-label="Issues">
1008
+ <div class="page-header">
1009
+ <div>
1010
+ <h1 class="page-title">Issues</h1>
1011
+ <p class="page-subtitle">Critical errors from the log stream that should be addressed, grouped by message</p>
1012
+ </div>
1013
+ <span class="refresh-hint" id="issues-ts" aria-live="polite"></span>
1014
+ </div>
1015
+ <div class="content">
1016
+ <div class="card">
1017
+ <div class="toolbar">
1018
+ <span class="toolbar-count" id="issue-count" aria-live="polite">0 issues</span>
1019
+ <span class="spacer"></span>
1020
+ <button class="btn btn-ghost" onclick="loadIssues()">Refresh</button>
1021
+ </div>
1022
+ <div class="log-table" id="issue-table" role="log" aria-label="Critical issues">
1023
+ <div class="empty">No critical issues</div>
1024
+ </div>
1025
+ </div>
1026
+ </div>
1027
+ </section>
1028
+
941
1029
  <!-- Updates -->
942
1030
  <section id="page-updates" class="page" aria-label="Updates">
943
1031
  <div class="page-header">
@@ -91,6 +91,8 @@ function runWithBusyRetry(action, { attempts = 5, delayMs = 50, label = 'SQLite
91
91
  let db = new Database(DB_PATH);
92
92
  db = initializeDatabase(db, DB_PATH);
93
93
 
94
+ const STALE_RUN_INTERRUPTED_ERROR = 'Server restarted while run was in progress.';
95
+
94
96
  db.exec(`
95
97
  CREATE TABLE IF NOT EXISTS users (
96
98
  id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -441,7 +443,8 @@ db.exec(`
441
443
 
442
444
  CREATE TABLE IF NOT EXISTS skills (
443
445
  id INTEGER PRIMARY KEY AUTOINCREMENT,
444
- name TEXT UNIQUE NOT NULL,
446
+ user_id INTEGER NOT NULL DEFAULT 0,
447
+ name TEXT NOT NULL,
445
448
  description TEXT,
446
449
  file_path TEXT NOT NULL,
447
450
  metadata TEXT DEFAULT '{}',
@@ -1078,6 +1081,57 @@ db.exec(`
1078
1081
 
1079
1082
  runSchemaMigrations(db);
1080
1083
 
1084
+ function interruptStaleAgentRuns(reason = STALE_RUN_INTERRUPTED_ERROR) {
1085
+ const normalizedReason = String(reason || STALE_RUN_INTERRUPTED_ERROR).trim()
1086
+ || STALE_RUN_INTERRUPTED_ERROR;
1087
+ const staleRunIds = db.prepare(
1088
+ `SELECT id
1089
+ FROM agent_runs
1090
+ WHERE status = 'running'`
1091
+ ).all().map((row) => row.id);
1092
+ const runsResult = db.prepare(
1093
+ `UPDATE agent_runs
1094
+ SET status = 'interrupted',
1095
+ error = COALESCE(NULLIF(error, ''), ?),
1096
+ updated_at = datetime('now'),
1097
+ completed_at = COALESCE(completed_at, datetime('now'))
1098
+ WHERE status = 'running'`
1099
+ ).run(normalizedReason);
1100
+
1101
+ db.prepare(
1102
+ `UPDATE agent_steps
1103
+ SET status = 'interrupted',
1104
+ error = COALESCE(NULLIF(error, ''), ?),
1105
+ completed_at = COALESCE(completed_at, datetime('now'))
1106
+ WHERE status = 'running'`
1107
+ ).run(normalizedReason);
1108
+
1109
+ db.prepare(
1110
+ `UPDATE agent_delegations
1111
+ SET status = 'interrupted',
1112
+ error = COALESCE(NULLIF(error, ''), ?),
1113
+ updated_at = datetime('now'),
1114
+ completed_at = COALESCE(completed_at, datetime('now'))
1115
+ WHERE status = 'running'`
1116
+ ).run(normalizedReason);
1117
+
1118
+ if (staleRunIds.length) {
1119
+ const placeholders = staleRunIds.map(() => '?').join(', ');
1120
+ db.prepare(
1121
+ `UPDATE pending_approvals
1122
+ SET status = 'expired',
1123
+ decided_at = COALESCE(decided_at, datetime('now')),
1124
+ updated_at = datetime('now')
1125
+ WHERE status = 'pending'
1126
+ AND run_id IN (${placeholders})`
1127
+ ).run(...staleRunIds);
1128
+ }
1129
+
1130
+ return runsResult.changes || 0;
1131
+ }
1132
+
1133
+ interruptStaleAgentRuns();
1134
+
1081
1135
  try {
1082
1136
  db.exec(`
1083
1137
  CREATE VIRTUAL TABLE IF NOT EXISTS screen_history_fts USING fts5(
@@ -2022,3 +2076,5 @@ try {
2022
2076
  }
2023
2077
 
2024
2078
  module.exports = db;
2079
+ module.exports.STALE_RUN_INTERRUPTED_ERROR = STALE_RUN_INTERRUPTED_ERROR;
2080
+ module.exports.interruptStaleAgentRuns = interruptStaleAgentRuns;
@@ -1 +1 @@
1
- 241a9aee71aa1081e7b09f220208b1ae
1
+ 07f0fa2418c3bb652d9c285ad6a55b0f
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"77e2e94772b6eb43759e34ed1ad7da4674e19c
37
37
 
38
38
  _flutter.loader.load({
39
39
  serviceWorkerSettings: {
40
- serviceWorkerVersion: "3097884085" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
40
+ serviceWorkerVersion: "1807031898" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
41
41
  }
42
42
  });