Add files via upload

This commit is contained in:
公明
2026-05-04 03:42:24 +08:00
committed by GitHub
parent 62c6f3f191
commit 4fca4a85c2
10 changed files with 4133 additions and 11 deletions
+1875
View File
File diff suppressed because it is too large Load Diff
+59 -2
View File
@@ -103,7 +103,8 @@ async function refreshDashboard() {
recentVulnsRes, rolesRes, agentsRes,
openCriticalRes, openHighRes, openMediumRes, openLowRes, toolsConfigRes,
hitlPendingRes, notificationsRes, externalMcpStatsRes,
webshellRes
webshellRes,
c2ListenersRes, c2SessionsRes, c2TasksRes
] = await Promise.all([
fetchJson('/api/agent-loop/tasks'),
fetchJson('/api/vulnerabilities/stats'),
@@ -129,7 +130,11 @@ async function refreshDashboard() {
// External MCP 健康度
fetchJson('/api/external-mcp/stats'),
// WebShell 已建立的连接(pentest 落地后的 foothold,对运营场景非常关键)
fetchJson('/api/webshell/connections')
fetchJson('/api/webshell/connections'),
// C2 仪表盘条:监听器 / 会话 / 待处理任务(任务接口含 pending_queued_count
fetchJson('/api/c2/listeners'),
fetchJson('/api/c2/sessions?limit=500'),
fetchJson('/api/c2/tasks?page=1&page_size=1')
]);
// 如果在 await 期间 controller 已被 abort,说明又有新刷新启动了,丢弃本次结果
@@ -393,6 +398,9 @@ async function refreshDashboard() {
// 「最近事件」内联展示(来自通知摘要,过滤掉已经被仪表盘其他位置覆盖的类型)
renderRecentEvents(notificationsRes);
// C2 概览条(监听器 / 在线会话 / 待处理任务)
renderDashboardC2Overview(c2ListenersRes, c2SessionsRes, c2TasksRes);
// 关键提醒条:把所有可能的告警源(漏洞/HITL/失败率/MCP健康)合并展示
renderDashboardAlertBanner({
criticalCount: openCriticalCount,
@@ -444,6 +452,8 @@ async function refreshDashboard() {
['tools', 'skills', 'knowledge', 'roles', 'agents', 'webshell'].forEach(function (k) {
setEl('dashboard-resource-' + k, '-');
});
var c2secErr = document.getElementById('dashboard-section-c2');
if (c2secErr) c2secErr.hidden = true;
setRecentVulnsError();
renderDashboardToolsBar(null);
var ph = document.getElementById('dashboard-tools-pie-placeholder');
@@ -458,6 +468,53 @@ async function refreshDashboard() {
}
}
/** C2 概览条:依赖 /api/c2/listeners、sessions、tasks;任一路由失败则整块隐藏 */
function renderDashboardC2Overview(listenersRes, sessionsRes, tasksRes) {
var section = document.getElementById('dashboard-section-c2');
if (!section) return;
if (listenersRes === null && sessionsRes === null && tasksRes === null) {
section.hidden = true;
return;
}
var running = '-';
if (listenersRes && Array.isArray(listenersRes.listeners)) {
running = String(listenersRes.listeners.filter(function (l) {
return (l && (l.status || '').toLowerCase() === 'running');
}).length);
} else if (listenersRes === null) {
running = '-';
} else {
running = '0';
}
var online = '-';
if (sessionsRes && Array.isArray(sessionsRes.sessions)) {
online = String(sessionsRes.sessions.filter(function (s) {
if (!s) return false;
var st = (s.status || '').toLowerCase();
return st === 'active' || st === 'sleeping';
}).length);
} else if (sessionsRes === null) {
online = '-';
} else {
online = '0';
}
var pending = '-';
if (tasksRes && typeof tasksRes.pending_queued_count === 'number') {
pending = String(tasksRes.pending_queued_count);
} else if (tasksRes === null) {
pending = '-';
} else {
pending = '0';
}
setEl('dashboard-c2-listeners-running', running);
setEl('dashboard-c2-sessions-online', online);
setEl('dashboard-c2-tasks-pending', pending);
section.hidden = false;
if (typeof applyTranslations === 'function') {
try { applyTranslations(section); } catch (_e) { /* ignore */ }
}
}
function setEl(id, text) {
const el = document.getElementById(id);
if (el) el.textContent = text;
+18 -5
View File
@@ -142,6 +142,11 @@ function einoMainStreamPlanningTitle(responseData) {
const label = typeof window.t === 'function' ? window.t(key) : '输出';
return prefix + '📝 ' + label;
}
// eino_single / deep / supervisor:主通道是模型流式输出,不是「规划」;模型偶发复述工具 stdout 时,旧文案易被误认为工具结果标题。
if (orch != null && String(orch).trim() !== '' && orch !== 'plan_execute') {
const streamLabel = typeof window.t === 'function' ? window.t('chat.assistantStreamPhase') : '助手输出';
return prefix + '📝 ' + streamLabel;
}
const plan = typeof window.t === 'function' ? window.t('chat.planning') : '规划中';
return prefix + '📝 ' + plan;
}
@@ -1498,7 +1503,7 @@ function handleStreamEvent(event, progressElement, progressId,
const itemId = addTimelineItem(timeline, 'thinking', {
title: title,
message: ' ',
data: responseData
data: Object.assign({}, responseData, { responseStreamPlaceholder: true })
});
responseStreamStateByProgressId.set(progressId, { itemId: itemId, buffer: '', streamMeta: responseData });
break;
@@ -2198,6 +2203,9 @@ function addTimelineItem(timeline, type, options) {
if (options.data && options.data.orchestration != null && String(options.data.orchestration).trim() !== '') {
item.dataset.orchestration = String(options.data.orchestration).trim();
}
if (options.data && options.data.responseStreamPlaceholder === true) {
item.dataset.responseStreamPlaceholder = '1';
}
// 使用传入的createdAt时间,如果没有则使用当前时间(向后兼容)
let eventTime;
@@ -3154,7 +3162,12 @@ function refreshProgressAndTimelineI18n() {
titleSpan.textContent = ap + _t('chat.iterationRound', { n: n });
}
} else if (type === 'thinking') {
if (item.dataset.orchestration === 'plan_execute' && item.dataset.einoAgent && typeof einoMainStreamPlanningTitle === 'function') {
if (item.dataset.responseStreamPlaceholder === '1' && typeof einoMainStreamPlanningTitle === 'function') {
titleSpan.textContent = einoMainStreamPlanningTitle({
orchestration: item.dataset.orchestration || '',
einoAgent: item.dataset.einoAgent || ''
});
} else if (item.dataset.orchestration === 'plan_execute' && item.dataset.einoAgent && typeof einoMainStreamPlanningTitle === 'function') {
titleSpan.textContent = einoMainStreamPlanningTitle({
orchestration: 'plan_execute',
einoAgent: item.dataset.einoAgent
@@ -3163,10 +3176,10 @@ function refreshProgressAndTimelineI18n() {
titleSpan.textContent = ap + '\uD83E\uDD14 ' + _t('chat.aiThinking');
}
} else if (type === 'planning') {
if (item.dataset.orchestration === 'plan_execute' && item.dataset.einoAgent && typeof einoMainStreamPlanningTitle === 'function') {
if (item.dataset.orchestration && typeof einoMainStreamPlanningTitle === 'function') {
titleSpan.textContent = einoMainStreamPlanningTitle({
orchestration: 'plan_execute',
einoAgent: item.dataset.einoAgent
orchestration: item.dataset.orchestration,
einoAgent: item.dataset.einoAgent || ''
});
} else {
titleSpan.textContent = ap + '\uD83D\uDCDD ' + _t('chat.planning');
+19
View File
@@ -129,6 +129,7 @@
if ((item.type === 'task_completed' || item.type === 'long_running_tasks') && item.conversationId) return true;
if (item.type === 'task_failed' && item.executionId) return true;
if (item.type === 'hitl_pending') return true;
if (item.type === 'c2_session_online' && item.sessionId) return true;
return false;
}
@@ -153,6 +154,24 @@
}
if (item.type === 'hitl_pending') {
window.location.hash = 'hitl';
return;
}
if (item.type === 'c2_session_online' && item.sessionId) {
if (typeof window.switchPage === 'function') {
window.switchPage('c2-sessions');
} else {
window.location.hash = 'c2-sessions';
}
const sid = item.sessionId;
window.setTimeout(function () {
if (typeof C2 === 'undefined' || !C2.loadSessions || !C2.selectSession) return;
var p = C2.loadSessions();
if (p && typeof p.then === 'function') {
p.then(function () { C2.selectSession(sid); }).catch(function () {});
} else {
window.setTimeout(function () { try { C2.selectSession(sid); } catch (e) {} }, 500);
}
}, 120);
}
}
+25 -2
View File
@@ -50,7 +50,7 @@ function initRouter() {
if (hash) {
const hashParts = hash.split('?');
const pageId = hashParts[0];
if (pageId && ['dashboard', 'chat', 'hitl', 'info-collect', 'vulnerabilities', 'webshell', 'chat-files', 'mcp-monitor', 'mcp-management', 'knowledge-management', 'knowledge-retrieval-logs', 'roles-management', 'skills-monitor', 'skills-management', 'agents-management', 'settings', 'tasks'].includes(pageId)) {
if (pageId && ['dashboard', 'chat', 'hitl', 'info-collect', 'vulnerabilities', 'webshell', 'chat-files', 'mcp-monitor', 'mcp-management', 'knowledge-management', 'knowledge-retrieval-logs', 'roles-management', 'skills-monitor', 'skills-management', 'agents-management', 'settings', 'tasks', 'c2', 'c2-listeners', 'c2-sessions', 'c2-tasks', 'c2-payloads', 'c2-events', 'c2-profiles'].includes(pageId)) {
switchPage(pageId);
if (pageId === 'chat') {
scheduleChatConversationFromHash(500);
@@ -151,6 +151,17 @@ function updateNavState(pageId) {
if (submenuItem) {
submenuItem.classList.add('active');
}
} else if (pageId.startsWith('c2') || pageId === 'c2-listeners' || pageId === 'c2-sessions' || pageId === 'c2-tasks' || pageId === 'c2-payloads' || pageId === 'c2-events' || pageId === 'c2-profiles') {
// C2 子菜单项
const c2Item = document.querySelector('.nav-item[data-page="c2"]');
if (c2Item) {
c2Item.classList.add('active');
c2Item.classList.add('expanded');
}
const submenuItem = document.querySelector(`.nav-submenu-item[data-page="${pageId}"]`);
if (submenuItem) {
submenuItem.classList.add('active');
}
} else if (pageId === 'roles-management') {
// 角色子菜单项
const rolesItem = document.querySelector('.nav-item[data-page="roles"]');
@@ -405,6 +416,18 @@ async function initPage(pageId) {
loadMarkdownAgents();
}
break;
case 'c2':
case 'c2-listeners':
case 'c2-sessions':
case 'c2-tasks':
case 'c2-payloads':
case 'c2-events':
case 'c2-profiles':
window.currentPageId = pageId;
if (window.C2 && typeof window.C2.init === 'function') {
window.C2.init();
}
break;
}
// 清理其他页面的定时器
@@ -425,7 +448,7 @@ document.addEventListener('DOMContentLoaded', function() {
const hashParts = hash.split('?');
const pageId = hashParts[0];
if (pageId && ['chat', 'hitl', 'info-collect', 'tasks', 'vulnerabilities', 'webshell', 'chat-files', 'mcp-monitor', 'mcp-management', 'knowledge-management', 'knowledge-retrieval-logs', 'roles-management', 'skills-monitor', 'skills-management', 'agents-management', 'settings'].includes(pageId)) {
if (pageId && ['dashboard', 'chat', 'hitl', 'info-collect', 'tasks', 'vulnerabilities', 'webshell', 'chat-files', 'mcp-monitor', 'mcp-management', 'knowledge-management', 'knowledge-retrieval-logs', 'roles-management', 'skills-monitor', 'skills-management', 'agents-management', 'settings', 'c2', 'c2-listeners', 'c2-sessions', 'c2-tasks', 'c2-payloads', 'c2-events', 'c2-profiles'].includes(pageId)) {
switchPage(pageId);
if (pageId === 'chat') {
scheduleChatConversationFromHash(200);