diff --git a/site/index.html b/site/index.html index 46e2bbd..9dc8dbf 100644 --- a/site/index.html +++ b/site/index.html @@ -291,6 +291,134 @@ .grid-2, .grid-3 { grid-template-columns: 1fr; } } + /* ── 整屏翻页 ── + 用 mandatory(一滑一页)。前提是**每节都必须塞得进一屏** —— + mandatory 下比视口高的节,超出部分会永久滚不到。 + 为此 features 的 5 条设计决定已各自独立成节(见 stageB2), + architecture 的流程图也单独成节。 + 实测 proximity 不满足需求:滑 500px 落在 500,离最近边界 395px, + 距离太远不触发吸附 —— 那样只是"有时粘一下",不是翻页。 */ + html { + scroll-snap-type: y mandatory; + scroll-padding-top: 4.5rem; + } + section { + min-height: calc(100svh - 4.5rem); + display: flex; + flex-direction: column; + justify-content: center; + scroll-snap-align: start; + } + section > .wrap { width: min(1120px, 92vw); margin: 0 auto; } + /* 吸附容器不能有 transform 祖先:会让 snap 失效(实测过)。 + 故 .wrap 上不加任何位移类动画,入场只做透明度。 */ + @media (prefers-reduced-motion: reduce) { + html { scroll-snap-type: none; } + } + /* 窄屏/矮屏放宽:手机可视高度小且地址栏收缩会变,强制一屏反而难受 */ + @media (max-width: 860px), (max-height: 620px) { + html { scroll-snap-type: none; } + section { min-height: 0; } + } + + /* ── 五个决定的索引(总起页)── */ + .idx { + list-style: none; + margin: 2.2rem 0 0; + padding: 0; + display: grid; + gap: 0.5rem; + } + .idx li { + display: flex; + align-items: center; + gap: 0.85rem; + padding: 0.7rem 1rem; + font-size: 0.95rem; + color: var(--text-dim); + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: var(--radius-md); + transition: border-color .25s var(--ease), color .25s var(--ease), transform .25s var(--ease); + } + .idx li:hover { border-color: var(--border-hi); color: var(--text); transform: translateX(3px); } + .idx li span { + flex: 0 0 auto; + font-family: var(--font-mono); + font-size: 0.75rem; + color: var(--brand-cyan); + } + + /* ── 交错行:文/图左右互换 ── + 为什么用 grid 而不是 flex 的 order 翻转:order 只改视觉次序, + 键盘 Tab 与读屏仍按 DOM —— 这里 DOM 始终「标题在前」, + 翻的只是视觉,所以两者都正确。 */ + .alt { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 3.2rem; + align-items: center; + margin-top: 3.4rem; + } + .alt.flip .alt-copy { order: 2; } + .alt.flip .alt-visual { order: 1; } + .alt-n { + display: inline-block; + font-family: var(--font-mono); + font-size: 0.75rem; + letter-spacing: 0.08em; + color: var(--brand-cyan); + border: 1px solid var(--border); + border-radius: var(--radius-pill); + padding: 0.1rem 0.55rem; + margin-bottom: 0.7rem; + } + .alt-copy h3 { + font-size: clamp(1.15rem, 2vw, 1.5rem); + margin: 0 0 0.7rem; + letter-spacing: -0.01em; + } + .alt-copy p { margin: 0; color: var(--text-dim); line-height: 1.8; } + .alt-visual { min-width: 0; } + .alt-visual svg { width: 100%; height: auto; display: block; } + .dv-note { + margin: 0.6rem 0 0; + text-align: center; + font-size: 0.75rem; + color: var(--text-muted); + } + @media (max-width: 860px) { + .alt { grid-template-columns: 1fr; gap: 1.6rem; margin-top: 2.6rem; } + .alt.flip .alt-copy, .alt.flip .alt-visual { order: 0; } + } + + /* ── 示意图图元 ── */ + .dv-bound { fill: none; stroke: var(--border); stroke-width: 1.5; stroke-dasharray: 6 5; } + .dv-box { fill: var(--bg-card); stroke: var(--border-hi); stroke-width: 1.4; } + .dv-accent { fill: rgba(6, 182, 212, 0.10); stroke: var(--brand-cyan); } + .dv-run { fill: rgba(59, 130, 246, 0.10); stroke: var(--brand-blue); } + .dv-l4 { fill: rgba(139, 92, 246, 0.13); stroke: var(--brand-violet); } + .dv-l3 { fill: rgba(59, 130, 246, 0.11); stroke: var(--brand-blue); } + .dv-l2 { fill: rgba(6, 182, 212, 0.10); stroke: var(--brand-cyan); } + .dv-l1 { fill: rgba(245, 158, 11, 0.10); stroke: var(--brand-gold); } + .dv-t { fill: var(--text); font-size: 15px; font-weight: 700; text-anchor: middle; } + .dv-ts { fill: var(--text); font-size: 12.5px; font-weight: 600; text-anchor: middle; } + .dv-s { fill: var(--text-muted); font-size: 10.5px; text-anchor: middle; } + .dv-lab { fill: var(--text-dim); font-size: 11px; text-anchor: middle; } + .dv-labs { fill: var(--text-muted); font-size: 9.5px; text-anchor: middle; } + .dv-cap { fill: var(--text-muted); font-size: 10px; } + .dv-seg { fill: rgba(119,128,154,.07); stroke: var(--border-hi); stroke-width: 1.4; stroke-dasharray: 5 4; } + .dv-hd { fill: rgba(139,92,246,.12); stroke: var(--brand-violet); } + .dv-ar { fill: rgba(6,182,212,.09); stroke: var(--border-hi); } + .dv-off { fill: none; stroke: var(--border); stroke-width: 1.2; stroke-dasharray: 4 4; } + .dv-offt { fill: var(--text-muted); font-size: 11.5px; text-anchor: middle; text-decoration: line-through; } + .dv-no path { stroke: var(--brand-gold); stroke-width: 1.6; opacity: .85; } + .dv-line { fill: none; stroke: var(--border-hi); stroke-width: 1.4; } + .dv-dash { stroke-dasharray: 4 4; } + .dv-pk { fill: none; stroke: var(--brand-gold); stroke-width: 2; } + .dv-arrow { fill: none; stroke: var(--brand-cyan); stroke-width: 1.6; stroke-dasharray: 4 4; } + .dv-x { fill: var(--text-muted); font-size: 10px; text-anchor: middle; } + /* ── 三层记忆:用品牌三色 ── */ .layers { display: grid; gap: 0.9rem; } .layer { @@ -385,7 +513,7 @@ /* ── 连接线:中轴上的一小段,带流动感 ── */ .lnk { position: relative; - height: 2.1rem; + height: 1.15rem; width: 2px; margin: 0 auto; background: var(--border-hi); @@ -461,8 +589,8 @@ position: relative; z-index: 1; max-width: 34rem; - margin: 0.75rem auto 0; - padding: 2.4rem 1rem 2.6rem; + margin: 0.5rem auto 0; + padding: 1.7rem 1rem 1.9rem; border: 1px dashed rgba(6, 182, 212, 0.4); border-radius: var(--radius-md); background: rgba(6, 182, 212, 0.045); @@ -1306,11 +1434,10 @@
- HomeAgent 是内核 + 插件的双层 Agent 框架。内核只管 - LLM 编排、记忆与调度;所有外部能力(消息、文件、网络、设备) - 都是可独立安装、崩溃不牵连内核的插件。 + 内核只管编排、记忆与调度,消息 / 文件 / 网络 / 设备 + 一律交给插件。插件崩了不牵连内核 —— 换掉一个二进制就热重载。
- 先定边界与调度,再加能力。 +
+ 大多数 Agent 框架先堆功能、边界后补。这里反过来 —— 五个决定,都是先把「谁能碰什么」定死。
+- 内核不碰任何外部世界。消息、文件、网络、硬件全部由插件经 - PluginSDK 实现。于是「内核是否可信」与「某个插件是否安全」 - 可以分开评估。 + 内核不读文件、不发网络、不碰硬件。它只做三件事: + 编排、记忆、调度。外面的一切 —— 消息、文件、网络、设备 —— + 都由插件接管。于是「内核可信吗」和「这个插件安全吗」 + 成了两个可以分开回答的问题,而不是一次押上整块。
- 插件是普通 Go 二进制,由内核 spawn 为子进程,经 stdio JSON-RPC - (控制)、共享内存段(数据)、事件环(通知)通信。插件崩溃不牵连内核, - 换掉 plugin.bin 即热重载。 -
-- 输入分「排队」与「中断」两类,中断再按紧迫度分 L1–L4。 - 高级可抢占并保存现场,同级不抢占。L4 归内核独占 - —— 所以「停止」真的能立刻停下。 -
-- 主 agent 忙长任务时,积压交给临时分诊助手: - 能办的直接办,需要主 agent 的立刻回「忙碌中,请稍候」。 - 不必干等十几分钟。 -
+箭头只进出插件 —— 内核一列都没有
+ 插件是静态编译的单个文件:目标机上没有 Go、没有 libc、 + 没有容器、没有运行时,拷过去就能跑。 + 本体同样不要求你先装什么 —— 没有数据库、没有缓存、没有消息队列, + 记忆与索引都在进程内。所谓部署,就是把文件放上去。 +
+实测:statically linked,无动态依赖
++ 控制信令走 stdio,真正的数据走一块共享内存。 + 变长内容只传一个相对偏移,两边 mmap 到不同地址也能各自解引用。 + 所以上下文在插件里是零拷贝改写的 —— + 不是「序列化出去、传字符串、再反序列化回来」,而是两边看着同一块内存。 +
+实测整段写入+读回 3.5µs
++ 输入先分两类:可以等的,和不能等的。 + 不能等的再按紧迫度排 L1–L4:高级别可以抢占,被抢占的现场压进栈、稍后原样恢复。 + 同一时刻只有一个任务在改上下文,所以不会两边各做一半。 + L4 归内核独占 —— 「停止」按下去就真的停。 +
++ 主 agent 被长任务占住、积压又够多时,内核把这些消息转给一个 + 临时驻留的分诊助手。能当场办的就办了; + 非等主 agent 不可的,立刻回一句「忙碌中,请稍候」。 + 你不必对着对话框猜它还在不在。 +
+homed常驻内核进程:LLM 编排、记忆管理、输入调度、插件生命周期PluginSDK面向内核的接口:注册工具 / 挂阶段钩子 / 订阅事件 / 声明输出通道外部插件经 hmapdev 构建为独立二进制,可单独装卸、热重载。点任意插件看它能做什么。