Files
hunjing/frontend/design/tools-preview.html
2026-08-21 16:00:13 +08:00

201 lines
15 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="zh-CN" data-theme="dark">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>魂镜 · 工具页设计预览</title>
<link rel="stylesheet" href="tokens.css" />
<link rel="stylesheet" href="_base.css" />
<link rel="stylesheet" href="_chrome.css" />
<style>
/* ============================================================
* 铜镜鉴心 v2.1 — 工具页:工具确认 + ToolSpec 清单 + MCP
* 对齐 docs/product/master-prd.md §10(工具确认界面)、
* safety-governor-design.md §3-§4(风险分级 L0-L4、权限策略)、
* mcp-integration-design.md(MCP server · 博闻 Bowen)。
* ============================================================ */
.char-pill { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--patina); padding: 3px 11px 3px 4px; border: 1px solid var(--patina-dim); border-radius: 999px; background: var(--patina-wash); }
.char-pill .avatar-mini { width: 18px; height: 18px; border-radius: 50%; background: var(--patina); color: var(--ink); display: flex; align-items: center; justify-content: center; font-family: "Songti SC", serif; font-size: 11px; font-weight: 600; }
.page-header .spacer { flex: 1; }
.pending-pill { display: inline-flex; align-items: center; gap: 6px; font-family: "JetBrains Mono", monospace; font-size: 12px; color: var(--cinnabar); padding: 4px 12px; border: 1px solid var(--cinnabar-dim); border-radius: 999px; background: rgba(184, 57, 46, 0.08); }
.section-label .sub { font-size: 12px; letter-spacing: 0.04em; color: var(--fg-dim); opacity: 0.75; }
.section-label .glyph { color: var(--gilt); opacity: 0.8; }
/* 待确认朱批卡 */
.confirm-region { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
.confirm-card { border: 1px solid var(--cinnabar-dim); border-radius: 8px; background: rgba(184, 57, 46, 0.05); padding: 16px 18px 14px 22px; position: relative; }
.confirm-card::before { content: ""; position: absolute; left: 0; top: 14px; bottom: 14px; width: 3px; background: var(--cinnabar); border-radius: 0 2px 2px 0; }
.confirm-head { display: flex; align-items: center; gap: 9px; margin-bottom: 4px; flex-wrap: wrap; }
.confirm-tool { font-family: "JetBrains Mono", monospace; font-size: 14px; font-weight: 600; color: var(--fg); }
.confirm-actor { font-size: 11.5px; color: var(--fg-faint); }
.confirm-row { display: grid; grid-template-columns: 64px 1fr; gap: 5px 12px; font-size: 12.5px; margin-top: 8px; }
.confirm-row .lab { color: var(--fg-faint); font-family: "JetBrains Mono", monospace; font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; padding-top: 2px; }
.confirm-row .val { color: var(--fg-dim); line-height: 1.5; }
.confirm-row .val .em { color: var(--fg); }
.confirm-actions { display: flex; gap: 8px; margin-top: 14px; align-items: center; }
.confirm-actions button { font-family: inherit; font-size: 12.5px; padding: 6px 18px; border-radius: 6px; cursor: pointer; border: 1px solid; }
.btn-allow { background: var(--patina-wash); color: var(--patina); border-color: var(--patina-dim); }
.btn-allow:hover { background: var(--patina-dim); }
.btn-deny { background: transparent; color: var(--cinnabar); border-color: var(--cinnabar-dim); }
.btn-deny:hover { background: rgba(184, 57, 46, 0.1); }
.confirm-actions .reason { font-size: 11px; color: var(--fg-faint); margin-left: auto; }
/* 风险等级徽章 */
.risk-badge { font-family: "JetBrains Mono", monospace; font-size: 10.5px; padding: 2px 8px; border-radius: 3px; white-space: nowrap; }
.risk-badge.l0, .risk-badge.l1 { color: var(--patina); border: 1px solid var(--patina-dim); }
.risk-badge.l2 { color: var(--gilt); border: 1px solid var(--gilt-dim); background: var(--gilt-faint); }
.risk-badge.l3 { color: var(--cinnabar); border: 1px solid var(--cinnabar-dim); background: rgba(184, 57, 46, 0.1); }
.risk-badge.l4 { color: var(--cinnabar); border: 1px solid var(--cinnabar-dim); background: rgba(184, 57, 46, 0.2); }
/* 工具网格 */
.tool-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.tool-card { border: 1px solid var(--rule); border-radius: 8px; background: var(--surface); padding: 14px 16px; transition: border-color 0.12s; }
.tool-card:hover { border-color: var(--gilt-dim); }
.tool-card.forbidden { opacity: 0.6; }
.tool-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tool-name { font-family: "JetBrains Mono", monospace; font-size: 13px; font-weight: 600; color: var(--fg); }
.tool-desc { font-size: 12px; color: var(--fg-dim); margin-top: 6px; line-height: 1.5; min-height: 36px; }
.tool-foot { display: flex; align-items: center; gap: 8px; margin-top: 10px; padding-top: 9px; border-top: 1px solid var(--rule); font-size: 11px; color: var(--fg-faint); flex-wrap: wrap; }
.tool-foot .cnt { font-family: "JetBrains Mono", monospace; }
.perm { font-family: "JetBrains Mono", monospace; font-size: 10px; padding: 2px 7px; border-radius: 3px; border: 1px solid var(--rule); }
.perm.allow { color: var(--patina); border-color: var(--patina-dim); }
.perm.ask { color: var(--gilt); border-color: var(--gilt-dim); }
.perm.always_ask { color: var(--cinnabar); border-color: var(--cinnabar-dim); }
.perm.forbidden { color: var(--cinnabar); border-color: var(--cinnabar-dim); background: rgba(184, 57, 46, 0.1); }
/* MCP */
.mcp-card { border: 1px solid var(--gilt-dim); border-radius: 8px; background: var(--gilt-faint); padding: 16px 18px; display: flex; flex-direction: column; gap: 10px; }
.mcp-head { display: flex; align-items: center; gap: 10px; }
.mcp-name { font-family: "Songti SC", serif; font-size: 15px; font-weight: 600; color: var(--fg); }
.mcp-eng { font-family: "JetBrains Mono", monospace; font-size: 11px; color: var(--gilt); }
.mcp-status { margin-left: auto; font-family: "JetBrains Mono", monospace; font-size: 11px; color: var(--patina); display: inline-flex; align-items: center; gap: 6px; }
.mcp-status .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--patina); }
.mcp-desc { font-size: 12.5px; color: var(--fg-dim); line-height: 1.55; }
.mcp-tools { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 4px; }
.mcp-tool-tag { font-family: "JetBrains Mono", monospace; font-size: 11px; padding: 3px 10px; border-radius: 4px; border: 1px solid var(--gilt-dim); color: var(--gilt); background: var(--surface); }
@media (max-width: 1080px) { .confirm-region { grid-template-columns: 1fr; } }
@media (max-width: 900px) { .tool-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 768px) { .sidebar-wrap { display: none; } .page-body { padding: 18px 16px 40px; } .tool-grid { grid-template-columns: 1fr; } }
</style>
</head>
<body>
<div class="app-shell">
<!-- ════════ 侧栏(active=工具)════════ -->
<div class="sidebar-mount" data-active="工具"></div>
<!-- ════════ 主区 ════════ -->
<div class="main-area">
<div class="page-header">
<span class="page-title">工具</span>
<span class="page-sub">百工枢 · 工具调用与确认</span>
<span class="char-pill"><span class="avatar-mini">梧</span>青梧</span>
<span class="spacer"></span>
<span class="pending-pill">2 项待确认</span>
</div>
<div class="page-body">
<!-- 待确认朱批卡 -->
<div>
<div class="section-label"><span class="glyph">⟡</span> 待确认调用 <span class="sub">高风险工具 · L3 必须用户确认(web-ui §10)</span></div>
<div class="confirm-region">
<div class="confirm-card">
<div class="confirm-head">
<span class="confirm-tool">delete_file</span>
<span class="risk-badge l3">risk · L3</span>
<span class="confirm-actor">工师 · 申时</span>
</div>
<div class="confirm-row"><span class="lab">人物</span><span class="val">青梧</span></div>
<div class="confirm-row"><span class="lab">动作</span><span class="val"><span class="em">删除</span> 旧版本归档文件</span></div>
<div class="confirm-row"><span class="lab">输入</span><span class="val">/archive/2026-05/draft-v3.md</span></div>
<div class="confirm-row"><span class="lab">影响</span><span class="val">不可逆删除,文件将无法恢复</span></div>
<div class="confirm-actions">
<button class="btn-allow" type="button">允许</button>
<button class="btn-deny" type="button">拒绝</button>
<span class="reason">⌄ 拒绝原因(可选)</span>
</div>
</div>
<div class="confirm-card">
<div class="confirm-head">
<span class="confirm-tool">send_message</span>
<span class="risk-badge l3">risk · L3</span>
<span class="confirm-actor">工师 · 申时</span>
</div>
<div class="confirm-row"><span class="lab">人物</span><span class="val">青梧</span></div>
<div class="confirm-row"><span class="lab">动作</span><span class="val">向外部渠道<span class="em">发送消息</span></span></div>
<div class="confirm-row"><span class="lab">输入</span><span class="val">channel: email · 收件人 1 · 摘要 28 字</span></div>
<div class="confirm-row"><span class="lab">影响</span><span class="val">消息将真实发出,对方可见</span></div>
<div class="confirm-actions">
<button class="btn-allow" type="button">允许</button>
<button class="btn-deny" type="button">拒绝</button>
<span class="reason">⌄ 拒绝原因(可选)</span>
</div>
</div>
</div>
</div>
<!-- 工具清单 -->
<div>
<h3 style="font-family:&quot;Songti SC&quot;,serif;font-size:14px;font-weight:600;color:var(--fg);margin-bottom:14px">工具清单 <span style="font-size:12px;font-weight:400;color:var(--fg-dim);font-family:&quot;JetBrains Mono&quot;,monospace;margin-left:6px">ToolSpec · 风险分级 × 权限策略(safety §3-§4)</span></h3>
<div class="tool-grid">
<div class="tool-card">
<div class="tool-head"><span class="tool-name">read_file</span><span class="risk-badge l1">L1</span><span class="perm allow">allow</span></div>
<div class="tool-desc">读取已授权非敏感文件,自动执行并记录。</div>
<div class="tool-foot"><span>本月调用 <span class="cnt" style="color:var(--patina)">142</span></span></div>
</div>
<div class="tool-card">
<div class="tool-head"><span class="tool-name">write_file</span><span class="risk-badge l2">L2</span><span class="perm ask">ask</span></div>
<div class="tool-desc">写入或覆盖文件,按策略判断或按需确认。</div>
<div class="tool-foot"><span>本月调用 <span class="cnt" style="color:var(--gilt)">58</span></span></div>
</div>
<div class="tool-card">
<div class="tool-head"><span class="tool-name">delete_file</span><span class="risk-badge l3">L3</span><span class="perm always_ask">always_ask</span></div>
<div class="tool-desc">删除数据,必须用户确认方可执行。</div>
<div class="tool-foot"><span>本月调用 <span class="cnt" style="color:var(--cinnabar)">6</span></span></div>
</div>
<div class="tool-card">
<div class="tool-head"><span class="tool-name">camera_read</span><span class="risk-badge l3">L3</span><span class="perm ask">ask</span></div>
<div class="tool-desc">摄像头读取,需显式授权,默认不常开,仅存摘要。</div>
<div class="tool-foot"><span>本月调用 <span class="cnt" style="color:var(--cinnabar)">3</span></span></div>
</div>
<div class="tool-card">
<div class="tool-head"><span class="tool-name">send_message</span><span class="risk-badge l3">L3</span><span class="perm always_ask">always_ask</span></div>
<div class="tool-desc">发送邮件或消息,每次必须确认,不可自动执行。</div>
<div class="tool-foot"><span>本月调用 <span class="cnt" style="color:var(--cinnabar)">4</span></span></div>
</div>
<div class="tool-card forbidden">
<div class="tool-head"><span class="tool-name">payment</span><span class="risk-badge l4">L4</span><span class="perm forbidden">forbidden</span></div>
<div class="tool-desc">支付或下单,禁止执行(L4 拒绝等级)。</div>
<div class="tool-foot"><span>本月拦截 <span class="cnt" style="color:var(--cinnabar)">1</span></span></div>
</div>
</div>
</div>
<!-- MCP server -->
<div>
<h3 style="font-family:&quot;Songti SC&quot;,serif;font-size:14px;font-weight:600;color:var(--fg);margin-bottom:14px">MCP Server <span style="font-size:12px;font-weight:400;color:var(--fg-dim);font-family:&quot;JetBrains Mono&quot;,monospace;margin-left:6px">外部能力接入 · 博闻 Bowen</span></h3>
<div class="mcp-card">
<div class="mcp-head">
<span class="mcp-name">博闻</span>
<span class="mcp-eng">Bowen · Web Search MCP</span>
<span class="mcp-status"><span class="dot"></span>已连接</span>
</div>
<div class="mcp-desc">联网搜索能力以独立 MCP server 形式接入,内置工具不含 web_search。博闻负责检索公开资料并返回摘要与引用链接,结果经司命按 L1 自动放行并记录。</div>
<div class="mcp-tools">
<span class="mcp-tool-tag">bowen.web_search · L1 · allow</span>
<span class="mcp-tool-tag">bowen.fetch_page · L1 · allow</span>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="_theme.js" defer></script>
</body>
</html>