# 更新记录 这个插件还没有版本化发布。下面是开发轮次 —— 每一轮都是**先发现一个问题,再改**,而不是按功能清单往下做。 ## 第一轮 —— 落地第一版 store、实例与类型、任务队列、执行器、侧边栏条目、bot 页面、设置页。 底座决定了几件事后来一直没变:**store 是串行写队列 + 随机临时文件名 + 原子改名**(并发写不会写坏 JSON),**执行器与界面订阅同一次轮询**(不会各说各话),**客户端半自带全部样式**(不依赖可能还没挂载的样式表)。 ## 第二轮 —— 记忆从索引改成本体是文件 原来记忆是 store 里的一个数组。改成 `$DSH_HOME$DSH_HOME/bot/memory/` 下的一棵 `.md` 文件树: - 根文件全文进上下文,子目录只贡献 `name` + `description`; - `MEMORY.md` 的存在本身就是「这一层是记忆」的声明; - 设置页读的是同一棵树,并从磁盘**重新导入**。 **修掉一个真 bug**:第一次 `bot_remember` 把 `USER.md` 的 `name` / `description` 覆盖成了通用值 —— 因为写入在读文件时种子还不存在。修法是先 `ensureMemoryTree()`。回归测试断言 `name === "user"`。 ## 第三轮 —— 可治理性 - **来源标签**:`user` / `agent` / `tool`。旧数据默认按 `agent` 读 —— 那是更保守的读法(工具写的东西是声称); - **时效**:`ageDays` + `stale` 标记,**算不出时用 `-1`** —— 未知不参与比较; - **敏感信息两道门**:硬门(身份证号/社保号/银行卡号/密码/令牌)**任何设置都拒**;软门(健康/财务/法律/家庭私事)默认排除、可开; - 测试专门验证**放宽软门不会连带放宽硬门** —— 那正是它们必须是两道门的理由。 ## 第四轮 —— 审批链条 - `awaiting` 成为任务的合法中间态,**不是错误分支**; - 停下时带上**工具名和完整参数**(截断到 1200 字)—— 用户批准的是一个具体动作; - waiver 只匹配完全相同的工具名,**永远带过期时间**; - **修掉一个死循环**:`resolveParkedTask` 会把任务放回队列并置 `approved`,但执行器重跑时 `guarded` 分支**没有看 `task.approved`**,于是同一个边界反复拦下 —— 而用户看到的是一模一样的问题,会以为自己那次点击没生效。修法是让批准参与判断。 **这个缺陷是审计逼出来的**,静态查符号查不出它 —— 是把「approve 之后会发生什么」整条链读完才发现的。 ## 第五轮 —— 限额全部可调,界面去噪 - **去掉所有写死的配额**。默认值收敛到 `LIMIT_DEFAULTS` 一处,`0` 一律表示不限(`STATE_VERSION` 和 `DEFAULT_PRIORITY` 保留为常量,因为它们不是配额); - 界面上去掉一切**非交互元素**的边框 —— 一个框只在它是输入框或可点时出现。没有边框的列表读起来安静得多。 ## 第六轮 —— 自主时间改为理由驱动 原来那句 `AUTONOMY_BRIEF` 的第一句是「现在是你的自由时间,没有人在跟你说话。你可以用工具去查点你自己想知道的东西……」—— 那是「闲着就做点什么」,**它答不出「为什么是这件事,为什么是现在」**。 改成条件驱动:空闲降为**前置条件**,必须有可检查的条件成立(4 个),找不到理由就明确报告,**而不是被悄悄填满活动**。权限默认只读。 ## 第七轮 —— MCP 客户端 - **streamable HTTP** 的最小实现:一次 POST、一个 JSON-RPC 对象、一个响应,**同时接受 `application/json` 和 SSE**; - 工具名 `mcp__服务器__工具` —— 沿用生态约定,**从别的客户端复制过来即可用**; - **测试做成按钮**:一个配好了但没有任何工具的地址,和一个能用只是恰好什么都没提供的地址**看起来完全一样**,所以要有一次真的探测,而且结果要留下来; - **状态灯三态**:绿/红/灰 —— 「没人看过」和「它没问题」不是同一个说法; - 端到端验证:起一个**不依赖任何 MCP SDK** 的独立进程 server,让客户端连上去。两边各自实现对了才通得过。 顺带修掉一个真静默失败:`pollTelegram` 原本 `if (!response.ok) return;` —— 而且 Telegram 在 `ok: false` 时返回 HTTP 200,于是 token 被撤销这类错误会一直静默下去。 ## 第八轮 —— 周期工作两种语义 `continuity: continue | fresh`。两种答案都对,看是什么活:每日摘要要拿着上一份,每周审计要相反。 ## 第九轮 —— 界面收口 - **侧边栏条目的宽度**:`:has()` 只撑开了一层,而外壳在 glyph 容器与行之间还有一层,于是 `…` 停在行中间。改成撑开两层 + 标记 `width:100%`,缩进从 `margin-left` 改成 `padding-left`(否则那一百个百分比会把行推出容器); - **输入框改成与 DSH 同形**:卡片式(文字在上、控制行在下)、圆形发送按钮、共用**同一根宽度轴** `calc(clamp(680px, 宽 × 0.64, 920px) + 32px)`。宽度不一致是真实的成本 —— 用户会以为这是两个不同的东西; - **头像可由用户上传**:按**内容类型**校验而不是看文件名(文件名是上传方完全控制的那部分); - **类型可编辑**:同一个表单既建新类型也改已有的,内置的也能改。 ## 还没做 **远程执行**、**RAG 自动切换**、**浏览器集成**(分本地与云端的那个)、**语音**、**跨设备**、**专属邮箱入口**。 前两项和浏览器那项是同一个根因:**这是个本机插件,没有云**。它们应该被当成取舍写下来,而不是挂在待办上。逐条对照见 [功能对照](docs/feature-matrix.md)。