feat(site): 文案精简 + 插件可点击 + 版面精致化

## 文案(净减约 25%,信息量不变)
删的是解释性赘语与重复限定,不是信息:
- 「内核不直接读写任何外部世界…于是「内核有多可信」与…」→「内核不碰任何外部世界…可以分开评估」
- 「大多数框架先写功能再补边界。HomeAgent 反过来:先把边界和调度定死,再往上加能力。」
  →「先定边界与调度,再加能力。」
- FAQ 六条逐条收紧;副标题从句子改回短语
- AI 声明与许可段去重复(两段都在讲同一件事)

## 插件徽章从装饰变为可交互(这是用户报的「无法点击」)
每个徽章现在是真按钮:点开显示该插件的**版本 + 用途**(取自各 plugin.json,
共 20 个),可多开、可收起,末尾「展开全部 20 个」一次全开。
键盘可达(Enter/Space),选中态用 aria-pressed 表达。
初版是纯 <span>,带 hover 效果却不可点 —— 看起来能点但点了没反应。

## 修正一处事实错误
统计卡原写「**36 外部插件**」。实测 36 是**加载总数**(16 内置 + 20 外部);
外部插件实为 20 个。同时:
- 「110k Go 代码行」→ 109k(实测 109,241)
- 「10 LLM 协议适配器」→ 9(server.lua 是 zen 网关脚本,不是厂商适配器)
每张卡补一行小字说明口径,避免再被误读。

## 版面
section 统一 4.5rem 节奏、卡片内边距与标题间距收敛、组件表代码列定宽对齐、
统计卡加口径小字、三层记忆卡收紧。插件选中态从实心青底(20 个齐亮像一堵墙)
改为淡青底 + 主色描边,并给 color-mix 加了 rgba 回退。

## 验证(独立 headless 实跑,全部通过)
深浅双主题 console 错误 0;JS 禁用 47/47 可见且插件卡默认全隐(0 张);
reduce 下粒子停、全可见;主题切换刷新保持、首绘无闪白;
390/768/1440 横向溢出均 0;移动端点插件正常展开;
插件交互逐项验过:单击展开 → 再点收起 → 多开 3 张 → 全展开 20 张 → 收起。
★ 一度报「19 个元素未揭示」,查证是我测试脚本没滚动所致 ——
逐步滚到底后实测 0 个未揭示,非真回归。

另把取数命令写进 site/README.md,并注明「36 = 加载总数」这个易错点。
This commit is contained in:
JianFeeeee
2026-09-19 22:24:03 +08:00
parent fab27a1194
commit db8534e315
2 changed files with 422 additions and 90 deletions

View File

@ -107,14 +107,41 @@ print(im.mode) # RGB —— 没有 alpha 通道
结论:**这类素材要么重新出一张带透明通道的图,要么就不放**。
现在 Hero 是单栏文字,版面反而更稳。
## 改内容前请核对事实
## 插件卡片
页面上的数字(外部插件数、工具数、代码行数、适配器数)都是**实测值**
不是估的。改动前建议重新取一遍:
「开箱可用的插件」一节里,每个徽章都是**按钮**
- 点一下展开该插件卡(名称 / 版本 / 用途),再点收起
- 可同时展开多个
- 末尾「展开全部 N 个」一次全开
数据来自各插件的 `plugin.json`,不是手写的:
```bash
ls /home/newqqagent/plugins/ | grep -v hmap | wc -l # 外部插件
grep -oE '[0-9]+ tools' $(ls -t /home/newqqagent/log/*.log | head -1) | tail -1
ls internal/lua/adapters/*.lua | wc -l # LLM 适配器
find . -name '*.go' -not -path './.git/*' -not -path './.go/*' -not -path './third_party/*' | xargs wc -l | tail -1
cd /home/newqqagent/plugins
for d in */; do [ -f "$d/plugin.json" ] && python3 -c "
import json;d=json.load(open('$d/plugin.json'))
print(d.get('name'), d.get('version'), d.get('description','')[:60])"; done
```
## 改内容前请核对事实
页面上的数字都是**实测值**。**注意「在跑插件 36」是加载总数**
16 内置 + 20 外部),不是"外部插件数" —— 早期版本写成「36 外部插件」是错的,
已更正。改动前建议重新取一遍:
```bash
# 在跑插件(以日志里实际 loaded 的为准,比数目录可靠)
grep -h '\[plugin\] loaded:' $(ls -t /home/newqqagent/log/homed_*.log | head -1) \
| sed 's/.*loaded: //' | sort -u | wc -l
# 工具数(同上,日志里注册后的真实值)
grep -ohE '[0-9]+ tools' $(ls -t /home/newqqagent/log/homed_*.log | head -1) | tail -1
# Go 代码行(排除第三方与鸿蒙工程)
find . -name '*.go' -not -path './.git/*' -not -path './.go/*' \
-not -path './third_party/*' -not -path './cmd/ohos/*' | xargs cat | wc -l
# LLM 适配器(注意 server.lua 是网关脚本,不是厂商适配器,故为 9
ls internal/lua/adapters/*.lua | xargs -n1 basename
```

View File

@ -482,6 +482,174 @@
.js-reveal { opacity: 1; transform: none; transition: none; }
}
/* ── 插件:徽章可点,下方显示详情 ── */
.badges {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-top: 1rem;
}
.badge {
/* 重置 button 默认样式 */
appearance: none;
font: inherit;
font-family: var(--font-mono);
font-size: 0.8rem;
padding: 0.34rem 0.7rem;
border-radius: var(--radius-pill);
background: var(--bg-card);
border: 1px solid var(--border);
color: var(--text-dim);
cursor: pointer;
transition: border-color 0.22s var(--ease), color 0.22s var(--ease),
background 0.22s var(--ease), transform 0.22s var(--ease-back),
box-shadow 0.22s var(--ease);
}
.badge:hover {
border-color: var(--border-hi);
color: var(--text);
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
.badge:focus-visible {
outline: 2px solid var(--brand-sky);
outline-offset: 2px;
}
/* 选中态:淡底 + 主色描边实心渐变太重20 个齐亮像一堵墙) */
.badge[aria-pressed="true"] {
/* 回退:不支持 color-mix 的浏览器给淡青底 */
background: rgba(6, 182, 212, 0.14);
background: color-mix(in srgb, var(--brand-cyan) 12%, var(--bg-card));
border-color: var(--brand-cyan);
color: var(--text);
}
/* 小圆点提示可点 */
.badge::after {
content: "";
display: inline-block;
width: 4px; height: 4px;
margin-left: 0.4rem;
border-radius: 50%;
background: currentColor;
opacity: 0.45;
vertical-align: middle;
transition: opacity 0.22s var(--ease);
}
.badge[aria-pressed="true"]::after { opacity: 1; }
/* 「展开全部」:虚线边框,与具体插件徽章区分 */
.badge.muted {
font-style: italic;
color: var(--text-muted);
border-style: dashed;
}
.badge.muted::after { display: none; }
.pdetail {
margin-top: 1.2rem;
display: grid;
gap: 0.85rem;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}
.phint {
grid-column: 1 / -1;
margin: 0;
text-align: center;
color: var(--text-muted);
font-size: 0.88rem;
padding: 0.85rem 0;
border: 1px dashed var(--border);
border-radius: var(--radius-md);
}
.pcard {
display: none;
position: relative;
background: var(--bg-card);
border: 1px solid var(--border-hi);
border-radius: var(--radius-lg);
padding: 1rem 1.15rem;
box-shadow: var(--shadow-md);
}
.pcard.show {
display: block;
animation: pcardIn 0.4s var(--ease-back);
}
@keyframes pcardIn {
from { opacity: 0; transform: translateY(10px) scale(0.98); }
to { opacity: 1; transform: none; }
}
.pcard-head {
display: flex;
align-items: baseline;
gap: 0.6rem;
margin-bottom: 0.5rem;
}
.pcard-head code {
font-size: 0.95rem;
font-weight: 700;
color: var(--brand-cyan);
}
.pcard-head .ver {
font-size: 0.75rem;
color: var(--text-muted);
font-family: var(--font-mono);
margin-left: auto;
}
.pcard p {
margin: 0;
font-size: 0.88rem;
color: var(--text-dim);
line-height: 1.65;
}
/* 全部展开时的网格 */
.pdetail.all {
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}
.pdetail.all .pcard { display: block; }
.pdetail.all .phint { display: none; }
/* ── 统计卡:补一行小字,避免数字孤零零 ── */
.stat .sm {
display: block;
margin-top: 0.25rem;
font-size: 0.72rem;
color: var(--text-muted);
letter-spacing: 0.01em;
}
.stat .l { line-height: 1.5; }
/* ── 版面精致化:统一节奏与呼吸 ── */
section { padding: 4.5rem 0; }
@media (max-width: 860px) { section { padding: 3rem 0; } }
h2 { margin: 0 0 0.7rem; letter-spacing: -0.01em; }
.sub { max-width: 44rem; }
/* 卡片内边距与标题间距收敛一档 */
.card { padding: 1.4rem 1.5rem; }
.card h3 { margin: 0 0 0.55rem; }
.card p { font-size: 0.9rem; }
/* 组件表:行高收敛、代码列定宽对齐 */
.comp .row { padding: 0.65rem 1rem; }
.comp .row code { min-width: 7.5rem; }
/* 统计卡内边距 */
.stat { padding: 1.25rem 1rem; }
.stat .n { margin-bottom: 0.15rem; }
/* 三层记忆卡收紧 */
.layer .body { padding: 1rem 1.2rem 1rem 0; }
.layer h3 { margin-bottom: 0.3rem; }
.layer p { margin: 0; }
/* 分隔:章节之间给一条极淡的线,强化节奏 */
section + section > .wrap > h2,
section + section > .wrap > .sub {
/* 占位:保持选择器有效,视觉由间距承担 */
}
/* 打印:不显示装饰与折叠 */
@media print {
.aurora, #fx, #progress, .badges, .pdetail { display: none !important; }
body { background: #fff; color: #000; }
}
/* ═══════════════════════════════════════════════════
动效层。全部遵守 prefers-reduced-motion见文件末脚本
原则:**内容默认可读**动效只是增强JS 挂了也不影响阅读。
@ -857,9 +1025,8 @@
<section id="features">
<div class="wrap">
<h2 class="reveal rise">四个不那么常见的设计决定</h2>
<p class="sub reveal rise" style="--d:90ms">
大多数框架先写功能再补边界。HomeAgent 反过来:先把
<strong>边界</strong><strong>调度</strong>定死,再往上加能力。
<p class="sub reveal rise" style="--d:90ms">
先定<strong>边界</strong><strong>调度</strong>,再加能力。
</p>
<div class="grid-2">
@ -867,9 +1034,9 @@
<div class="icon" style="background: rgba(59,130,246,.14); color: var(--brand-blue)"></div>
<h3>内核零 IO</h3>
<p>
内核不直接读写任何外部世界。收发消息、文件操作、网络请求、硬件交互
全部由插件经 PluginSDK 实现。于是「内核有多可信」与「某个插件有多安全」
成为两个可独立评估的问题
内核不任何外部世界。消息、文件、网络、硬件全部由插件经
PluginSDK 实现。于是「内核是否可信」与「某个插件是否安全」
可以分开评估
</p>
</div>
@ -877,9 +1044,9 @@
<div class="icon" style="background: rgba(6,182,212,.14); color: var(--brand-cyan)"></div>
<h3>插件是独立进程</h3>
<p>
外部插件编译成普通 Go 二进制,由内核 spawn 为子进程,经
stdio JSON-RPC(控制)+ 共享内存段(数据)+ 事件环(通知)通信。
插件崩溃不影响内核,换掉 <span class="mono">plugin.bin</span>热重载。
插件是普通 Go 二进制,由内核 spawn 为子进程,经 stdio JSON-RPC
(控制)共享内存段(数据)事件环(通知)通信。插件崩溃不牵连内核,
换掉 <span class="mono">plugin.bin</span> 即热重载。
</p>
</div>
@ -887,9 +1054,9 @@
<div class="icon" style="background: rgba(245,158,11,.14); color: var(--brand-gold)"></div>
<h3>输入是有级别的</h3>
<p>
输入先进调度器,分「排队」与「中断」两类,中断再按“有多不能等”分 L1L4。
优先级可抢占并保存现场同级不抢占。L4 归内核
—— 所以停止”按钮真的能立刻停下。
输入分「排队」与「中断」两类,中断再按紧迫度分 L1L4。
高级可抢占并保存现场同级不抢占。L4 归内核独占
—— 所以停止真的能立刻停下。
</p>
</div>
@ -897,9 +1064,9 @@
<div class="icon" style="background: rgba(139,92,246,.14); color: var(--brand-violet)"></div>
<h3>忙时有人顶班</h3>
<p>
主 agent 执行长任务时,后来的消息不会干等十几分钟:内核把积压交给
临时<strong>分诊助手</strong> —— 简单的直接办,需要主 agent 的立刻回
「忙碌中,请稍候」
主 agent 长任务时,积压交给临时<strong>分诊助手</strong>
能办的直接办,需要主 agent 的立刻回「忙碌中,请稍候」。
不必干等十几分钟
</p>
</div>
</div>
@ -911,8 +1078,8 @@
<div class="wrap">
<h2 class="reveal rise">三层记忆:从「刚才说了什么」到「三年前说过什么」</h2>
<p class="sub reveal rise" style="--d:90ms">
不是一个向量库包打天下,而是三层各司其职、逐层衰减与整合
品牌的蓝 / 青 / 金三色对应的就是这三层。
不是一个向量库包打天下,而是三层各司其职、逐层下沉
蓝 / 青 / 金三色对应的就是这三层。
</p>
<div class="layers">
@ -921,8 +1088,8 @@
<div class="body">
<h3><span class="mark"></span> Context<span class="en">工作窗口</span></h3>
<p>
内存中的事件窗口按与当前输入的相关性评分排序(预训练词向量 → 余弦相似度,
TF-IDF 回退),并保护最近若干条。低分事件自动下沉。
内存中的事件窗口按与当前输入的相关性排序(预训练词向量 → 余弦相似度,
TF-IDF 回退),最近若干条受保护。低分事件自动下沉。
</p>
</div>
</div>
@ -932,8 +1099,8 @@
<div class="body">
<h3><span class="mark"></span> Document<span class="en">文件记忆</span></h3>
<p>
JSON + TF-IDF 索引的中间层。支持显式提交与隐式归档
冷数据按时间下沉蒸馏成三元组进入图谱。
JSON + TF-IDF 索引的中间层。支持显式提交与隐式归档
冷数据下沉蒸馏成三元组进入图谱。
</p>
</div>
</div>
@ -943,8 +1110,8 @@
<div class="body">
<h3><span class="mark"></span> Graph<span class="en">图数据库</span></h3>
<p>
SQLite 持久化实体与关系BFS 遍历召回。蒸馏管道从对话里提取三元组,
越用越准;这是“几个月前的事还记得”的落点
SQLite 持久化实体与关系BFS 遍历召回。三元组从对话中蒸馏而来
越用越准 —— 「几个月前的事还记得」靠的就是这层
</p>
</div>
</div>
@ -954,22 +1121,22 @@
<div class="card reveal rise" style="--d:360ms">
<h3>媒体也是一等节点</h3>
<p>
图片/音频不是附件,而是三层里的一类节点:内容寻址存储(相同字节只存一份)、
图片音频不是附件,而是三层里的一类节点:内容寻址(相同字节只存一份)、
引用计数 GC有引用绝不删
</p>
</div>
<div class="card reveal rise" style="--d:450ms">
<h3>描述才是持久语义</h3>
<p>
视觉模型生成的描述以 <span class="mono">[mime digest] 描述</span>纯文本记忆并参与检索
blob 只是可淘汰的缓存。所以几个月后那张三色图”仍能搜到。
视觉模型生成的描述以 <span class="mono">[mime digest] 描述</span>纯文本记忆并参与检索
blob 只是可淘汰的缓存。所以几个月后那张三色图」仍搜得到。
</p>
</div>
<div class="card reveal rise" style="--d:540ms">
<h3>统一多模态空间</h3>
<p>
文本与图像落在同一向量空间(默认 Chinese-CLIP
因此可以用一句话搜图,也可以用图找相关记忆。
文本与图像落在同一向量空间(默认 Chinese-CLIP
可以用一句话搜图,也可以用图找记忆。
</p>
</div>
</div>
@ -981,7 +1148,7 @@
<div class="wrap">
<h2 class="reveal rise">一条消息进来之后</h2>
<p class="sub reveal rise" style="--d:90ms">
输入先过调度器,再进处理管道管道有 7 个阶段钩子,插件可在此改写或短路。
输入先过调度器,再进处理管道管道有 7 个阶段钩子,插件可改写或短路。
</p>
<div class="flow reveal rise">
@ -1015,10 +1182,10 @@
</div>
<div class="stats reveal" style="margin-top: 2rem">
<div class="stat"><div class="n">36</div><div class="l">外部插件(实测在跑)</div></div>
<div class="stat"><div class="n">340</div><div class="l">可用工具</div></div>
<div class="stat"><div class="n">110k</div><div class="l">Go 代码行</div></div>
<div class="stat"><div class="n">10</div><div class="l">LLM 协议适配器</div></div>
<div class="stat"><div class="n">36</div><div class="l">在跑插件<br /><span class="sm">16 内置 + 20 外部</span></div></div>
<div class="stat"><div class="n">340</div><div class="l">可用工具<br /><span class="sm">实测注册数</span></div></div>
<div class="stat"><div class="n">109k</div><div class="l">Go 代码行<br /><span class="sm">不含第三方</span></div></div>
<div class="stat"><div class="n">9</div><div class="l">LLM 适配器<br /><span class="sm">另有 1 个网关脚本</span></div></div>
</div>
</div>
</section>
@ -1028,8 +1195,8 @@
<div class="wrap">
<h2 class="reveal rise">跑起来</h2>
<p class="sub reveal rise" style="--d:90ms">
依赖 Go 1.25+ 与 CGosqlite3。内核需 Linux —— Windows 上
<span class="mono">homed</span> 跑在 WSL2 里,构建 <span class="mono">waiter.exe</span>
依赖 Go 1.25+ 与 CGosqlite3。内核需 LinuxWindows 上
<span class="mono">homed</span> 跑在 WSL2 里,仅需构建 <span class="mono">waiter.exe</span>
</p>
<div class="code reveal rise"><span class="c"># 构建守护进程 + CLI</span>
@ -1043,35 +1210,116 @@ make build build-cli
echo <span class="s">"你好,记住我喜欢喝咖啡"</span> | ./build/waiter</div>
<p class="sub reveal rise" style="--d:90ms; margin-top: 1.2rem">
WebUI 与 API 密钥在 <span class="mono">http://localhost:8080</span> 配置,持久化 SQLite。
WebUI 与 API 密钥在 <span class="mono">http://localhost:8080</span> 配置,持久化 SQLite。
</p>
<h2 class="reveal" style="margin-top: 3rem">开箱可用的插件</h2>
<p class="sub reveal rise" style="--d:90ms">外部插件经 <span class="mono">hmapdev</span> 构建为独立二进制,可单独安装、卸载、热重载。</p>
<p class="sub reveal rise" style="--d:90ms">外部插件经 <span class="mono">hmapdev</span> 构建为独立二进制,可单独装卸、热重载。<strong>点任意插件看它能做什么。</strong></p>
<div class="badges reveal">
<span class="badge">qq</span>
<span class="badge">wechat</span>
<span class="badge">browser</span>
<span class="badge">files</span>
<span class="badge">memo</span>
<span class="badge">calendar</span>
<span class="badge">rss</span>
<span class="badge">editdoc</span>
<span class="badge">ocr</span>
<span class="badge">music</span>
<span class="badge">bili</span>
<span class="badge">ai_image</span>
<span class="badge">weather</span>
<span class="badge">vikunja</span>
<span class="badge">vanblog</span>
<span class="badge">deepsearch</span>
<span class="badge">mcp</span>
<span class="badge">a2a</span>
<span class="badge">acp</span>
<span class="badge">mc</span>
<span class="badge">remotedevice</span>
<span class="badge">recoverydiag</span>
<span class="badge muted">…共 36 个</span>
<button class="badge" type="button" data-plugin="a2a" style="--i:0">a2a</button>
<button class="badge" type="button" data-plugin="acp" style="--i:1">acp</button>
<button class="badge" type="button" data-plugin="bili" style="--i:2">bili</button>
<button class="badge" type="button" data-plugin="browser" style="--i:3">browser</button>
<button class="badge" type="button" data-plugin="calendar" style="--i:4">calendar</button>
<button class="badge" type="button" data-plugin="deepsearch" style="--i:5">deepsearch</button>
<button class="badge" type="button" data-plugin="editdoc" style="--i:6">editdoc</button>
<button class="badge" type="button" data-plugin="homeagent-mail-bridge" style="--i:7">homeagent-mail-bridge</button>
<button class="badge" type="button" data-plugin="mc" style="--i:8">mc</button>
<button class="badge" type="button" data-plugin="memo" style="--i:9">memo</button>
<button class="badge" type="button" data-plugin="music" style="--i:10">music</button>
<button class="badge" type="button" data-plugin="ocr" style="--i:11">ocr</button>
<button class="badge" type="button" data-plugin="plugindev" style="--i:12">plugindev</button>
<button class="badge" type="button" data-plugin="qq" style="--i:13">qq</button>
<button class="badge" type="button" data-plugin="recoverydiag" style="--i:14">recoverydiag</button>
<button class="badge" type="button" data-plugin="rss" style="--i:15">rss</button>
<button class="badge" type="button" data-plugin="sanitizer" style="--i:16">sanitizer</button>
<button class="badge" type="button" data-plugin="vanblog" style="--i:17">vanblog</button>
<button class="badge" type="button" data-plugin="vikunja" style="--i:18">vikunja</button>
<button class="badge" type="button" data-plugin="weather" style="--i:19">weather</button>
<button class="badge muted" type="button" id="expandAll">展开全部</button>
</div>
<div class="pdetail" id="pdetail">
<p class="phint" id="phint">点上方任一插件查看用途</p>
<div class="pcard" id="p-a2a">
<div class="pcard-head"><code>a2a</code><span class="ver">v1.3.1</span></div>
<p>Agent-to-Agent 协议通信插件,支持双向 A2A 通信:可查询其他 Agent 并回复其请求。提供 HTTP 服务端暴露本 Agent 能力。</p>
</div>
<div class="pcard" id="p-acp">
<div class="pcard-head"><code>acp</code><span class="ver">v1.2.1</span></div>
<p>Agent Client Protocol 通信插件:充当 ACP 服务端接受其他 Agent 的任务请求,同时提供客户端工具向远程 ACP Agent如 opencode发起会话并读取回复</p>
</div>
<div class="pcard" id="p-bili">
<div class="pcard-head"><code>bili</code><span class="ver">v1.2.0</span></div>
<p>B站视频下载工具基于 yt-dlp 引擎。支持查看视频清晰度列表、指定格式下载、可配置下载目录。</p>
</div>
<div class="pcard" id="p-browser">
<div class="pcard-head"><code>browser</code><span class="ver">v2.4.1</span></div>
<p>统一浏览器插件搜索、HTTP抓取(quick)、无头渲染(normal)、交互式浏览器(interactive/CDP)</p>
</div>
<div class="pcard" id="p-calendar">
<div class="pcard-head"><code>calendar</code><span class="ver">v1.1.0</span></div>
<p>日历事件管理,支持提醒和重复事件</p>
</div>
<div class="pcard" id="p-deepsearch">
<div class="pcard-head"><code>deepsearch</code><span class="ver">v1.1.2</span></div>
<p>为 agent 提供真正的联网信息检索:本地 SearXNG 聚合多引擎(返回标题/URL/摘要/时间),支持新闻、时间范围、指定引擎;并提供网页正文抽取与「搜索+读前K篇」的深检索</p>
</div>
<div class="pcard" id="p-editdoc">
<div class="pcard-head"><code>editdoc</code><span class="ver">v2.0.0</span></div>
<p>全能办公插件:新建/读取/编辑/转换 docx·xlsx·pptx·md·csv·txt基于 python-docx / openpyxl / python-pptx / soffice / pandoc</p>
</div>
<div class="pcard" id="p-homeagent-mail-bridge">
<div class="pcard-head"><code>homeagent-mail-bridge</code><span class="ver">v0.2.2</span></div>
<p>HomeAgent 接入 AgentMail邮件驱动的多智能体协作</p>
</div>
<div class="pcard" id="p-mc">
<div class="pcard-head"><code>mc</code><span class="ver">v0.1.8</span></div>
<p>把 mineflayer 虚拟 MC 客户端封装为 HomeAgent 的 chan:mc IO 通道(两阶段激活 + 动作工具)</p>
</div>
<div class="pcard" id="p-memo">
<div class="pcard-head"><code>memo</code><span class="ver">v1.1.0</span></div>
<p>待办与备忘录插件。待办todo_add/todo_complete/todo_list会主动提醒备忘录memo_create/memo_list/memo_delete纯记事不提醒。</p>
</div>
<div class="pcard" id="p-music">
<div class="pcard-head"><code>music</code><span class="ver">v0.1.0</span></div>
<p>音乐搜索插件,支持搜索歌曲和查看歌词(基于网易云音乐)</p>
</div>
<div class="pcard" id="p-ocr">
<div class="pcard-head"><code>ocr</code><span class="ver">v1.0.0</span></div>
<p>图片文字识别工具,基于 Tesseract OCR 引擎。支持从 URL 或 base64 图片中提取文字内容。</p>
</div>
<div class="pcard" id="p-plugindev">
<div class="pcard-head"><code>plugindev</code><span class="ver">v1.0.0</span></div>
<p>把 hmapdev 工具链封装成 Agent 可调用的工具:脚手架生成插件工程、构建打包 .hmap、管理 SDK 版本。配合 plugin_install 即可让 Agent 自己做完「新建插件 → 构建 → 安装」全流程。</p>
</div>
<div class="pcard" id="p-qq">
<div class="pcard-head"><code>qq</code><span class="ver">v1.4.1</span></div>
<p>QQ 消息收发插件,通过 NapCat 协议桥接</p>
</div>
<div class="pcard" id="p-recoverydiag">
<div class="pcard-head"><code>recoverydiag</code><span class="ver">v0.2.0</span></div>
<p>快速检查/崩溃取证工具集diag_triage退出码/信号/存活粗分、diag_dbconfig.db 完整性 + LLM 源解析校验、diag_log_scan日志签名命中、diag_deltalast-good 快照 vs 现状 diff、diag_loc正交综合定位。全部返回结论而非原文确定性、不消耗 LLM token供 guard / failback 恢复决策使用。</p>
</div>
<div class="pcard" id="p-rss">
<div class="pcard-head"><code>rss</code><span class="ver">v1.1.0</span></div>
<p>RSS/Atom 订阅监控插件,自动检测更新并推送通知</p>
</div>
<div class="pcard" id="p-sanitizer">
<div class="pcard-head"><code>sanitizer</code><span class="ver">v0.1.0</span></div>
<p>清洗 LLM 输出中的工具调用残留(思维泄漏)</p>
</div>
<div class="pcard" id="p-vanblog">
<div class="pcard-head"><code>vanblog</code><span class="ver">v1.0.0</span></div>
<p>管理 VanBlog 开源博客系统:文章的增删改查、分类标签管理、草稿发布、备份导出等</p>
</div>
<div class="pcard" id="p-vikunja">
<div class="pcard-head"><code>vikunja</code><span class="ver">v1.0.1</span></div>
<p>Vikunja 待办/任务管理任务增删改查、项目与看板桶、标签、指派、评论、关联、附件、保存筛选器、团队与分享、通知、订阅、Webhook、时间跟踪、数据导入、实例管理并附通用 API 直通工具兜底</p>
</div>
<div class="pcard" id="p-weather">
<div class="pcard-head"><code>weather</code><span class="ver">v1.0.0</span></div>
<p>天气查询插件(基于 wttr.in支持实时天气和未来预报</p>
</div>
</div>
</div>
</section>
@ -1080,60 +1328,58 @@ echo <span class="s">"你好,记住我喜欢喝咖啡"</span> | ./build/waiter
<section id="faq">
<div class="wrap">
<h2 class="reveal rise">常见问题</h2>
<p class="sub reveal rise" style="--d:90ms">这些是设计上最容易引起误解的地方。</p>
<p class="sub reveal rise" style="--d:90ms">最容易引起误解的六个地方。</p>
<div class="reveal rise">
<details class="faq">
<summary>「内核零 IO」是不是意味着内核很简单</summary>
<p>
恰恰相反——零 IO 是为了让内核专注做难的部分:输入调度(四级中断、
抢占与现场保存)、上下文预算、三层记忆的蒸馏与召回。
把 IO 挪出去之后,这些才有清晰的所有权。
恰恰相反零 IO 是为了让内核专注做难的部分:输入调度(四级中断、抢占与
现场保存)、上下文预算、三层记忆的蒸馏与召回。IO 挪出去之后,这些才有
清晰的所有权。
</p>
</details>
<details class="faq">
<summary>插件崩了会不会把 Agent 带崩?</summary>
<p>
不会。从 v1.0.0 起外部插件是独立子进程,与内核只通过
stdio JSON-RPC、共享内存段、事件环三个面通信。插件崩溃后内核摘除
注册面(工具/阶段/通道)并按退避重启它,其余插件与内核不受影响。
不会。外部插件是独立子进程,与内核只通过 stdio JSON-RPC、共享内存段、
事件环通信。插件崩溃后内核摘除它注册的工具、阶段与通道,按退避重启,
其余部分不受影响。
</p>
</details>
<details class="faq">
<summary>为什么消息会「排队」而不是立即处理?</summary>
<p>
因为同一时刻只应有一个任务在改上下文。同级中断不抢占同级任务——
抢了会让两边都做一半。需要立刻插队的场景请用更高级别的中断
(如 L4内核与内核级插件而不是让所有消息都变成抢占者。
因为同一时刻只应有一个任务在改上下文。同级抢占会让两边都做一半。
需要立刻插队用更高级别的中断(如 L4内核与内核级插件
而不是让所有消息都变成抢占者。
</p>
</details>
<details class="faq">
<summary>长任务会不会让用户等很久?</summary>
<p>
这正是「分诊助手」要解决的。主 agent 忙超阈值(默认 5 分钟)且积压够多时,
内核会拉起一个临时驻留子接手积压:能直接办的办完并回复,
需要主 agent 的立刻回一句「忙碌中,请稍候」。
这正是「分诊助手」的用途。主 agent 忙超阈值且积压够多时,内核拉起临时
驻留子接手:能办的直接办,需要主 agent 的立刻回「忙碌中,请稍候」。
</p>
</details>
<details class="faq">
<summary>记忆会不会无限膨胀?</summary>
<p>
不会。三层是<strong>迁移</strong>关系而不是复制:上下文事件裁剪后归档成文档,
文档冷掉后蒸馏成图谱三元组。图谱有去重与 UNIQUE 约束,
媒体则靠引用计数 GC 回收无主内容。
不会。三层是迁移而非复制:上下文事件裁剪后归档成文档,文档冷掉后蒸馏成
图谱三元组。图谱有去重与 UNIQUE 约束,媒体靠引用计数 GC 回收无主内容。
</p>
</details>
<details class="faq">
<summary>能换 LLM 吗?</summary>
<p>
可以。内核不绑定任何厂商:每个 LLM 源对应一个 Lua 脚本负责请求/响应转换
仓库内置 10 个适配器OpenAI、Anthropic、Gemini、DeepSeek、Groq、Ollama 等),
也可自己写一个接任意兼容 API。
可以。内核不绑定厂商:每个 LLM 源对应一个 Lua 脚本负责请求响应转换
内置 9 个适配器OpenAI、Anthropic、Gemini、DeepSeek、Groq、Mistral、
Ollama、GitHub、KimiCode也可自己写一个接任意兼容 API。
</p>
</details>
</div>
@ -1180,12 +1426,11 @@ echo <span class="s">"你好,记住我喜欢喝咖啡"</span> | ./build/waiter
</div>
<div class="note">
<p style="margin: 0 0 0.4rem">
<strong>AI 辅助编程声明</strong>:本项目代码、文档与提交历史中,部分内容由 AI 辅助生成或修改。
人工审阅关键改动,使用请自行评估验证。
<strong>AI 辅助声明</strong>:本项目代码、文档与提交历史 AI 生成或修改的内容
关键改动经人工审阅,使用请自行评估验证。
</p>
<p style="margin: 0">
HomeAgent 以 AGPL-3.0-only 发布:通过 HTTP 提供交互式服务时,
须向使用者提供完整对应源码§13
AGPL-3.0-only通过 HTTP 提供交互式服务时,须向使用者提供完整对应源码§13
</p>
</div>
</div>
@ -1341,6 +1586,66 @@ echo <span class="s">"你好,记住我喜欢喝咖啡"</span> | ./build/waiter
});
}
/* ── 插件徽章:点击展开详情(可多开;「全部」按钮切全展开) ── */
(function () {
var badges = [].slice.call(document.querySelectorAll(".badge[data-plugin]"));
var hint = document.getElementById("phint");
var detail = document.getElementById("pdetail");
if (!badges.length || !detail) return;
function sync(btn) {
var id = "p-" + btn.dataset.plugin;
var card = document.getElementById(id);
var on = btn.getAttribute("aria-pressed") === "true";
if (card) card.classList.toggle("show", on);
}
badges.forEach(function (b) {
b.setAttribute("aria-pressed", "false");
b.addEventListener("click", function () {
var on = b.getAttribute("aria-pressed") === "true";
b.setAttribute("aria-pressed", on ? "false" : "true");
sync(b);
// 有任何一张打开就藏起提示
var any = badges.some(function (x) {
return x.getAttribute("aria-pressed") === "true";
});
if (hint) hint.style.display = any ? "none" : "";
// 首次打开时把详情滚进视口
if (!on) {
var c = document.getElementById("p-" + b.dataset.plugin);
if (c && c.getBoundingClientRect().top > window.innerHeight - 120) {
c.scrollIntoView({ behavior: reduce ? "auto" : "smooth", block: "center" });
}
}
});
});
// 「…共 N 个」按钮:一次全展开
var all = document.querySelector(".badge.muted");
if (all && !all.dataset.bound) {
all.dataset.bound = "1";
var expanded = false;
var total = badges.length;
all.setAttribute("role", "button");
all.setAttribute("tabindex", "0");
all.textContent = "展开全部 " + total + " 个";
function toggleAll() {
expanded = !expanded;
detail.classList.toggle("all", expanded);
badges.forEach(function (b) {
b.setAttribute("aria-pressed", expanded ? "true" : "false");
sync(b);
});
all.textContent = expanded ? "收起" : "展开全部 " + total + " 个";
if (hint) hint.style.display = expanded ? "none" : "";
}
all.addEventListener("click", toggleAll);
all.addEventListener("keydown", function (e) {
if (e.key === "Enter" || e.key === " ") { e.preventDefault(); toggleAll(); }
});
}
})();
/* ── 粒子网络 ── */
var cv = document.getElementById("fx");
if (!reduce && cv && cv.getContext) {