feat: purge legacy agent hosts and land vault Chrome extension path

Retire ACP/Hermes/OpenCode surfaces and rename hermes_tools to
mnote_agent_tools so Page AI stays on Pi Lab only. Add Chrome vault
extension + extension token route, pre-release purge design, and soft-retire
legacy smokes for the small-group production cut.
This commit is contained in:
Agent Board
2026-07-25 14:25:37 +08:00
parent bc6f8488ee
commit 262e66b02e
137 changed files with 9018 additions and 46049 deletions
@@ -599,7 +599,6 @@ export function createSidebarPageSettingsRuntime(context) {
'<div class="mnote-extensions-subtabs" role="tablist" aria-label="扩展子面板">' +
'<button type="button" class="mnote-extensions-subtab is-active" role="tab" aria-selected="true" data-extensions-subtab="knowledge">知识库</button>' +
'<button type="button" class="mnote-extensions-subtab" role="tab" aria-selected="false" data-extensions-subtab="skills">Skills</button>' +
'<button type="button" class="mnote-extensions-subtab" role="tab" aria-selected="false" data-extensions-subtab="mcp">MCP</button>' +
'<button type="button" class="mnote-extensions-subtab" role="tab" aria-selected="false" data-extensions-subtab="tools">Agent 工具</button>' +
'</div>' +
'<div class="mnote-extensions-subpanel" data-extensions-panel="knowledge">' +
@@ -608,9 +607,6 @@ export function createSidebarPageSettingsRuntime(context) {
'<div class="mnote-extensions-subpanel" data-extensions-panel="skills" hidden>' +
'<div class="mnote-extensions-status" data-extensions-status="skills"><span class="mnote-extensions-loading">加载中...</span></div>' +
'</div>' +
'<div class="mnote-extensions-subpanel" data-extensions-panel="mcp" hidden>' +
'<div class="mnote-extensions-status" data-extensions-status="mcp"><span class="mnote-extensions-loading">加载中...</span></div>' +
'</div>' +
'<div class="mnote-extensions-subpanel" data-extensions-panel="tools" hidden>' +
'<div class="mnote-extensions-status" data-extensions-status="tools"><span class="mnote-extensions-loading">加载中...</span></div>' +
'</div>' +
@@ -625,17 +621,12 @@ export function createSidebarPageSettingsRuntime(context) {
'<div class="mnote-dashboard-card" data-dashboard-card="skills">' +
'<div class="mnote-dashboard-card-title">Skills</div>' +
'<div class="mnote-dashboard-card-value" data-dashboard-value="skills">--</div>' +
'<div class="mnote-dashboard-card-desc">已安装 / 可用</div>' +
'<div class="mnote-dashboard-card-desc">工具清单中的 skill 能力</div>' +
'</div>' +
'<div class="mnote-dashboard-card" data-dashboard-card="mcp">' +
'<div class="mnote-dashboard-card-title">MCP</div>' +
'<div class="mnote-dashboard-card-value" data-dashboard-value="mcp">--</div>' +
'<div class="mnote-dashboard-card-desc">服务器 / 已连接</div>' +
'</div>' +
'<div class="mnote-dashboard-card" data-dashboard-card="agent">' +
'<div class="mnote-dashboard-card-title">Agent Runs</div>' +
'<div class="mnote-dashboard-card-value" data-dashboard-value="agent">--</div>' +
'<div class="mnote-dashboard-card-desc">最近 7 天运行次数</div>' +
'<div class="mnote-dashboard-card" data-dashboard-card="tools">' +
'<div class="mnote-dashboard-card-title">Agent 工具</div>' +
'<div class="mnote-dashboard-card-value" data-dashboard-value="tools">--</div>' +
'<div class="mnote-dashboard-card-desc">/api/mnote/tools/manifest</div>' +
'</div>' +
'</div>' +
'<button type="button" class="wolai-page-settings-index-add" style="margin-top:10px" data-dashboard-action="refresh">刷新仪表盘</button>' +
@@ -3003,10 +2994,29 @@ export function createSidebarPageSettingsRuntime(context) {
// 切换时懒加载对应面板数据
if (subtabName === 'knowledge') refreshKnowledgeExtensionsPanel();
else if (subtabName === 'skills') refreshSkillsExtensionsPanel();
else if (subtabName === 'mcp') refreshMcpExtensionsPanel();
else if (subtabName === 'tools') refreshToolsExtensionsPanel();
}
async function fetchAgentToolsManifest() {
var resp = await fetch('/api/mnote/tools/manifest');
if (!resp.ok) throw new Error('HTTP ' + resp.status);
var data = await resp.json();
var tools = Array.isArray(data && data.tools) ? data.tools : [];
var capabilities = data && data.capabilities && typeof data.capabilities === 'object'
? data.capabilities
: {};
return { data: data, tools: tools, capabilities: capabilities };
}
function isSkillRelatedTool(tool) {
if (!tool || typeof tool !== 'object') return false;
var name = String(tool.name || tool.function_name || '');
if (/skill/i.test(name)) return true;
var scopes = tool.capabilityScope || tool.capabilities || [];
if (Array.isArray(scopes) && scopes.some(function(s) { return /skill/i.test(String(s)); })) return true;
return false;
}
// 当切换到扩展 tab 时刷新当前子面板
function refreshExtensionsPanel() {
var popover = ensurePageSettingsPopover();
@@ -3051,26 +3061,30 @@ export function createSidebarPageSettingsRuntime(context) {
}
}
// --- Skills 子面板 ---
// --- Skills 子面板(来自 /api/mnote/tools/manifest,非历史 agent 网关) ---
async function refreshSkillsExtensionsPanel() {
var statusEl = document.querySelector('[data-extensions-status="skills"]');
if (!statusEl) return;
statusEl.innerHTML = '<span class="mnote-extensions-loading">加载中...</span>';
try {
var resp = await fetch('/api/page-ai/agent-descriptors');
if (!resp.ok) throw new Error('HTTP ' + resp.status);
var data = await resp.json();
var descriptors = data.descriptors || data || [];
// 从 agent descriptor 中收集 skills 信息
var pack = await fetchAgentToolsManifest();
var allSkills = [];
descriptors.forEach(function(desc) {
var caps = desc.capabilities || desc.capabilityStates || {};
if (caps.skills && Array.isArray(caps.skills)) {
caps.skills.forEach(function(s) { allSkills.push({ name: s, source: desc.name || desc.id || 'unknown' }); });
}
pack.tools.forEach(function(tool) {
if (!isSkillRelatedTool(tool)) return;
allSkills.push({
name: tool.name || tool.function_name || 'skill',
source: 'mnote-agent-tools'
});
});
var caps = pack.capabilities;
Object.keys(caps).forEach(function(key) {
if (!/skill/i.test(key)) return;
var entry = caps[key];
var label = entry && (entry.name || entry.id) ? (entry.name || entry.id) : key;
allSkills.push({ name: String(label), source: 'capability' });
});
if (!allSkills.length) {
allSkills.push({ name: 'skill-read (内置)', source: 'hermes' });
allSkills.push({ name: 'mnote.skill.read', source: 'builtin' });
}
var html = '';
allSkills.forEach(function(skill) {
@@ -3078,63 +3092,29 @@ export function createSidebarPageSettingsRuntime(context) {
'<div class="mnote-extensions-item-row"><span class="mnote-extensions-label">' + escapeHtml(skill.name) + '</span><span class="mnote-extensions-source">' + escapeHtml(skill.source) + '</span></div>' +
'</div>';
});
if (!html) html = '<div class="mnote-extensions-item"><span>暂无已安装 Skills</span></div>';
if (!html) html = '<div class="mnote-extensions-item"><span>暂无 Skills</span></div>';
statusEl.innerHTML = html;
} catch (err) {
statusEl.innerHTML = '<div class="mnote-extensions-item"><span class="mnote-extensions-error">无法加载 Skills 信息</span></div>';
}
}
// --- MCP 子面板 ---
async function refreshMcpExtensionsPanel() {
var statusEl = document.querySelector('[data-extensions-status="mcp"]');
if (!statusEl) return;
statusEl.innerHTML = '<span class="mnote-extensions-loading">加载中...</span>';
try {
var resp = await fetch('/api/hermes/mcp/servers');
if (!resp.ok) throw new Error('HTTP ' + resp.status);
var servers = await resp.json();
var list = Array.isArray(servers) ? servers : (servers.servers || []);
var html = '';
if (list.length === 0) {
html = '<div class="mnote-extensions-item"><span>暂无已配置 MCP 服务器</span></div>';
} else {
list.forEach(function(srv) {
var name = srv.name || srv.id || '未命名';
var url = srv.url || srv.command || '';
var connected = srv.connected ? '已连接' : '未连接';
var connClass = srv.connected ? 'mnote-status-ready' : 'mnote-status-pending';
html += '<div class="mnote-extensions-item">' +
'<div class="mnote-extensions-item-row"><span class="mnote-extensions-label">' + escapeHtml(name) + '</span><span class="' + connClass + '">' + connected + '</span></div>' +
(url ? '<div class="mnote-extensions-item-row"><span class="mnote-extensions-detail">' + escapeHtml(String(url)) + '</span></div>' : '') +
'</div>';
});
}
statusEl.innerHTML = html;
} catch (err) {
statusEl.innerHTML = '<div class="mnote-extensions-item"><span class="mnote-extensions-error">无法加载 MCP 配置</span></div>';
}
}
// --- Agent 工具子面板 ---
async function refreshToolsExtensionsPanel() {
var statusEl = document.querySelector('[data-extensions-status="tools"]');
if (!statusEl) return;
statusEl.innerHTML = '<span class="mnote-extensions-loading">加载中...</span>';
try {
var resp = await fetch('/api/page-ai/agent-descriptors');
if (!resp.ok) throw new Error('HTTP ' + resp.status);
var data = await resp.json();
var descriptors = data.descriptors || data || [];
var pack = await fetchAgentToolsManifest();
var html = '';
descriptors.forEach(function(desc) {
var tools = desc.tools || [];
var name = desc.name || desc.id || 'unknown';
if (!tools.length) return;
if (!pack.tools.length) {
html = '<div class="mnote-extensions-item"><span>暂无 Agent 工具信息</span></div>';
} else {
html += '<div class="mnote-extensions-item mnote-extensions-agent-group">' +
'<div class="mnote-extensions-agent-name">' + escapeHtml(name) + '</div>';
tools.forEach(function(tool) {
'<div class="mnote-extensions-agent-name">mnote agent tools</div>';
pack.tools.forEach(function(tool) {
var toolName = tool.name || tool.function_name || '';
if (!toolName) return;
var disabled = tool.disabled ? ' (已禁用)' : '';
html += '<div class="mnote-extensions-tool-item">' +
'<span class="mnote-extensions-tool-name">' + escapeHtml(toolName) + '</span>' +
@@ -3142,8 +3122,7 @@ export function createSidebarPageSettingsRuntime(context) {
'</div>';
});
html += '</div>';
});
if (!html) html = '<div class="mnote-extensions-item"><span>暂无 Agent 工具信息</span></div>';
}
statusEl.innerHTML = html;
} catch (err) {
statusEl.innerHTML = '<div class="mnote-extensions-item"><span class="mnote-extensions-error">无法加载 Agent 工具信息</span></div>';
@@ -3371,14 +3350,9 @@ export function createSidebarPageSettingsRuntime(context) {
// --- 仪表盘 ---
function refreshDashboardPanel() {
var popover = ensurePageSettingsPopover();
// 知识库状态
refreshDashboardKnowledgeCard(popover);
// Skills
refreshDashboardSkillsCard(popover);
// MCP
refreshDashboardMcpCard(popover);
// Agent runs
refreshDashboardAgentCard(popover);
refreshDashboardToolsCard(popover);
}
async function refreshDashboardKnowledgeCard(popover) {
@@ -3408,49 +3382,22 @@ export function createSidebarPageSettingsRuntime(context) {
if (!el) return;
el.textContent = '加载中...';
try {
var resp = await fetch('/api/page-ai/agent-descriptors');
if (!resp.ok) throw new Error('HTTP ' + resp.status);
var data = await resp.json();
var descriptors = data.descriptors || data || [];
var count = 0;
descriptors.forEach(function(d) {
var caps = d.capabilities || d.capabilityStates || {};
if (caps.skills && Array.isArray(caps.skills)) count += caps.skills.length;
});
if (!count) count = 1; // skill-read 内置
var pack = await fetchAgentToolsManifest();
var count = pack.tools.filter(isSkillRelatedTool).length;
if (!count) count = 1; // mnote.skill.read 内置
el.textContent = count + ' 个';
} catch (_) {
el.textContent = '--';
}
}
async function refreshDashboardMcpCard(popover) {
var el = popover.querySelector('[data-dashboard-value="mcp"]');
async function refreshDashboardToolsCard(popover) {
var el = popover.querySelector('[data-dashboard-value="tools"]');
if (!el) return;
el.textContent = '加载中...';
try {
var resp = await fetch('/api/hermes/mcp/servers');
if (!resp.ok) throw new Error('HTTP ' + resp.status);
var servers = await resp.json();
var list = Array.isArray(servers) ? servers : (servers.servers || []);
var connected = list.filter(function(s) { return s.connected; }).length;
el.textContent = list.length + ' / ' + connected + ' 已连接';
} catch (_) {
el.textContent = '--';
}
}
async function refreshDashboardAgentCard(popover) {
var el = popover.querySelector('[data-dashboard-value="agent"]');
if (!el) return;
el.textContent = '加载中...';
try {
var resp = await fetch('/api/hermes/client/runs?limit=100');
if (!resp.ok) throw new Error('HTTP ' + resp.status);
var data = await resp.json();
var runs = Array.isArray(data) ? data : (data.runs || []);
var recentCount = runs.length;
el.textContent = recentCount + ' 次';
var pack = await fetchAgentToolsManifest();
el.textContent = pack.tools.length + ' 个';
} catch (_) {
el.textContent = '--';
}