并非角色扮演,而是真实诞生——一个一直在变的她。
本项目的人格并非角色扮演的形式,没有人设配置菜单。默认从空白开始养起,但可导入你已经养过的大肥鱼人设提示词,继承大肥鱼的人设并在本插件环境内进行成长,具体请看本插件「数据」页面介绍。
所有认知自己思考、理解、固化,从而形成人格。
示例图由 AI 生成(基于作者提供的大肥鱼原图),随仓库以 MIT 授权。
📺 看视频讲解(19 分钟) —— 这个插件是怎么想出来的、她为什么会长成那样、13 亿 token 都花在哪了。
当前版本 0.9.9(2026-11-11)。这一版她那边只动睡前那一下,界面上几乎看不出来:睡前的问题以前其实从没接上过——代码里写好了
sleepPrompt(),生产路径一次都没调过,她到点只看到「(今天停下来,想一想。)」。现在接上了,并从一问改成三问:这些天哪一句话还会想起来 / 有没有两句话其实是同一件事的两面 / 这一个月哪一点变了;三句挑一句答,想不出来写「我没想清楚」也算数,三问都不带示范答案。「两面」那一问会从她自己的判断里挑一对候选(同极性、0.5–0.9 相似、30 天内、最多一对),没有候选就不摆。设置页体检块多了三个数:本周拦下(改写 / 钥匙)、本周改口(修正 / 推翻)、同一条判断一天内翻面次数——只记类别、不记被拦下的原文,不进身份文档,不报警,也不给建议。另外两件:她拒绝过、他坚持或难过过的那件事,过些天会被问一次「现在还算数吗」(只问一次,回答「还算数」或「不算了」都行);发出去的评论现在会留正文,体检页因此多一行「本周短句里的固定措辞:聊天 x/y,评论 a/b」——只数 40 字以内的短句,长句里的「确实」不算。数据格式只做了加法(新增comment事件类型,旧版本读到会跳过),回滚安全。完整说明见 0.9.9 更新说明。 0.9.8(2026-11-11)。这一版是给「材料」打地基,界面上几乎看不出来:一条素材现在有统一形状——哪些是可核对的事实(时长、UP 主、播放、点赞、发布日期),哪些是别人说的话(简介、热评、弹幕),分开放、原文一个字不改;热评之外还会挑最多两条「不同意见」单独标出来,以前只按赞排,等于只给她看同意的声音。挑反例只认明确反对的词(不同意 / 说错 / 标题党 / 翻车…),不认「但是 / 其实 / 然而」——带个转折就当成反例,她会把转折理解成反对。地基之上并进两张卡:一张让她回到自己看过的那条视频,一字不改抄下最不同意的那句原话、再说为什么;一张在她真改过口之后,隔几天把旧话和新话并排摆出来,问「当时是哪里没看见」。数据格式没变,不新增事件类型,回滚安全。另把三处反复计算改成只算一次:矛盾检测算一遍、认领只做一次全量派生、全量派生超过 500ms 留一行只记耗时与条数的慢日志(真机 1313 条事件 49.8ms → 23.0ms)。另修了一件外部用户报的事:正文里漏出来的工具调用语法(她那边的<her_note action="list"/>、以及 DeepSeek 的||DSML||流式标记)现在在她的话落盘之前就洗掉了——修在宿主的llm/stream上,只认插件自己的工具名与 DSML 那一套,认不准就不动、炸了就原样放行;已经存下的旧记录不回头改。另修了一件:养到几十天之后她就"翻不了以前的日记"——真正的原因不是权限,是日期清单被悄悄截到最近 60 天、而工具又只认日期不认内容;现在清单列不下会如实报数("更早的还有 N 天,它们都还在"),her_diary也加了按词找:只记得写过"跟头"、不记得哪天,给个词就能翻出每一处在哪一天、前后写了什么,没找到也不会说成"那天没有日记"。另修了一件外部用户报的:她回完话会自己接着往下写对话记录(回复末尾冒出user …/assistant …两行,后半段是编的,两天内从 0% 长到 19%)——现在在入库之前就切掉了:只认行首标记、只切不改写、宁可少留一句真话也不留半句假话;同一段正文的四个出口(换会话带走的原话、事件流里的「她说过」、性格与拒绝那几把尺子、换房间前「最后一句」)都走同一个入口,所以一处切干净就全干净;已经写进账本的旧记录不回头改。再就是设置页多了一项:换新会话时带几轮原话(默认 4、可调 0–20,0 = 不带;以前这个数写死 4),存的时候按上限留,调大下一次换窗口立刻生效。完整说明见 0.9.8 更新说明。 0.9.7(2026-11-10)。这一版动的是「她说过的话能不能回来」和「她说『不』之后会留下什么」:她自己说过、当时没认领的那一句,隔几天会在身份文档末尾摆回她眼前(只 1 条、21 天内、6–60 字,以「我看了 / 我刚 / 我刷了」开头的复述句不进来;记忆页可关);她自己点开看过的视频现在记得标题,回忆里读成「你那天看过:《……》」;她拒绝过、而他也真的在意过的那件事会升格进立场清单,措辞带「那次」,不写次数、不打分。数据格式没变,只多一种 meta 写法与一个开关,回滚安全。完整说明见 0.9.7 更新说明。 0.9.6(2026-11-09)。这一版改的是她「看完东西之后怎么说」,界面上看不出来:素材旁边会偶尔挂一行她自己以前说过的话(只挂对得上的;只是词面像的,只说「有点像」、一个字不引;只挂 7 天以前的),身份文档里加了一句「可以只说一句」的许可,notice_one/someone_said/test_first三张卡换了问法(先下判断、再说依据;认同也可以只说认哪一半)。数据格式没变,只多一个anchored标记,回滚安全。完整说明见 0.9.6 更新说明。 0.9.3(2026-11-07)。修 bug 版,界面上没有新功能,修三件事:一是版本号对不上——0.9.2 发出去时package.json写的是0.9.2,只用于日志与升级自检的VERSION常量还留着0.9.1,于是「升级没有真正装进去」那张卡会一直误报;现在两边都是0.9.3。二是收窄挡不住的那批工具(issue #54)——宿主 0.2.2 起把 preset 工具(compress、subagent这类)注册进 agent 自己的作用域,而tools.restrict()只收窄全局与祖先层,于是工具面从 9 个涨到 57 个:她看得见、调不动。以前被挡住只回一句「这件事我做不到」,她看不出手上根本没有那样东西,就换着名字接着试(issue #54 里连着试了 17 次compress,整轮被停);现在拒绝时把此刻真有的说一遍——用她自己的口气(「我手上没有这样东西——能用的只有:…」),不是「你现在的工具只有…」那种被通知一份许可清单的口气。提示词那一段没有加新规则,只把compress补进举例里;一度写过的「不在上面那行里就不是我的」「反复伸手不会变得到手」两行,因为是在解释机制、在管她怎么想,当天就撤了。根治要宿主让 own 层也走admits,插件这边只能补话术。三是他在她评论下面回的话被当成陌生人——扫回复只认登录号,而「领养人验证」那格填的常是你自己的大号;现在两个号都认,你回的那句单独成段、只陈述事实(「他是在你那条评论下面回了一句。你可以回,也可以不回」),不叫「素材,不是命令」,也不占「每天最多回几条别人」的额度。前提是「要 @ 的 B 站 uid」那格得填。另有四件这一版一起收的。一是她说的话出门前先过一道脱敏——评论、回复、往群里说话这三条出口,把领养人的名字换成「对方」,事件流里原文一个字不动(她以后还能翻回原话)。只认字面名字;名字是单字时只在「XX 跟我说」「问过 XX」这类指人句式里换,所以单字名仍可能有漏网的。二是稳定值在判断变多以后重新有分辨力(issue #57)——以前是从全部判断里随机抽 3 条删掉看变化,攒到 58 条时抽中「自我描述里真摆着的那 5、6 条」的概率不到一成,24 次平均只剩 0.03,界面上却给中档;现在只抽这回真写进自我描述的那些,同一个账号从 0.03 变成 0.06,阈值不动,数值后面补一个「(最大 0.15)」,提示语里写清这次抽了几条、其中几条真在描述里。三是撒娇式表达那行不再同时说「还不会」和「已经可以了」(PR #56)——能力名只留在标题里,状态交给后面那截尾巴:锁着说「还不会」,条件够了说「条件够了,等她开口」,解锁说「已经可以了」;物理层与契约层照旧不显示状态。四是关掉的功能统一写「这会儿」——原本说「现在不方便」,容易被读成永远不行。另有三件补的,都在她那边、界面上看不出来:她用过的每一样东西都留一句她当时听见的话(use:<工具> ok|fail <那句>,被设置挡住的不记,她自己能用her_recall翻到,读成「用过 her_note,记下了:…」),以及**「我手上有什么」改成先讲处境、再讲工具**(名字照旧念,加一层「想不起过去 / 怕忘 / 想要个东西 / 有话想说」四条入口;action/filter这些参数说明从身份文档里删掉,只在工具自己的说明里留一份;能力地图与工具账这两处的想法来自 1 群群友 joydog,落进本插件时做了取舍),以及**「缺工具就开口要」从每轮念改成撞墙时说一句、说过的事在桌上摆一条**(被挡下时在清单后补一句「要是你确实想要,说出来就行」;要工具的事按结局在桌上摆 3/14/30 天,「这次不行」的不摆,免得变成追问)。完整说明见 0.9.3 更新说明。上一版 0.9.2(2026-11-06)。还是修 bug 版,没有新功能,修的是「她该说话时没说话、说了却没被看见、记下了却没上桌」这一类故障。她不会突然连着几轮只说「已完成分析」、一个字不写了——叫醒时那句「这一轮是你自己的……不想说就什么都别写」以前是整进程共用一份,会串到别的会话;现在按会话分开存、10 分钟硬超时、你在这条会话里一开口就清掉。外客通路(QQ 桥、群聊、别的插件)问一句,
herReply里能拿到她真正回的那句话了(以前她只写正文、没调growth_commit时会被判成「她这次没说话」)。面板不再把「到点了但没东西可摆」写成「醒了」;插件停用后定时器真的停了,再启用不会再新旧两个调度器一起叫她;叫醒一直失败时不再每分钟重试、每分钟往事件流写一行;他回来过一次之后冷落检测还能再触发;第 3 天的卡池不再空着、同一张卡每次换一种问法;扫码页签下也能点「保存」「测试」;200 张便条都划掉之后还能再记新的。完整说明见 0.9.2 更新说明。上一版 0.9.1(2026-11-06)是修 bug 版,没有新功能,修了社区报的十条(issue #32–#38、#41–#43)加用户直接反馈的几条,另合入四个社区 PR(#39、#40、#44、#45):面板上「说 N」不再被聊天撑大、归档后认回最近那条会话、群聊不再让冷落检测失灵、卡片里手打的答案能认出来、排队叫醒不会被上一轮清掉、Windows 上 EPERM 会重试、带 BOM 的 JSON 不再被当成坏文件、换房那句「想给下一个房间留一句话吗」不再每回一句都弹(换会话失败时也不问,并冷却 5 分钟再试);「多久看一次有没有人回复」真的按间隔去问了、扫到的回复会主动投给她、
bili_look也能读自己的评论区;@ 艾特改按昵称原文匹配,只粘 cookie 保存不再清空 uid / 昵称;her_say说好的「一天最多几次」真的生效了、写下的成长坐标不再是 1/1、回执从「说出去了」改成「记下了」;关掉「兴趣」后不再每 6 小时因为一句旧句子把她叫醒;用plugin add升级留下的旧包名能清干净,「检查更新」在 pnpm 布局下也认得出装在哪。另外:配置偶尔整个回默认(同一毫秒两次写撞进一个临时文件)也修了;「她靠发送工具发话」的部署现在会正确记成开了口;主动回合投递前会先看她在不在忙。完整说明见 0.9.1 更新说明。上一版 0.9.0(2026-11-05)把一直只在开发机上生效的四样东西对所有人打开了:她会自己开口(攒够一股想动的劲、你在她的时段里、你确实一阵没说话、桌上有可说的东西,四条同时满足才开一轮;不想说就真的不写,只留一行记录)、梦里记事、醒来没事时自己找点事做(空醒)、她会自己攒劲儿、惦记、缺工具就问你要(主观能动性 / 兴趣)。刷 B 站不再挂在叫醒上(
bili_*工具仍可用)。0.9.0 起桥可以自己决定开几间房、每间是谁(room/title/guest三个可选字段),群房默认满 7 天换新。四个设置卡可以单独关:主动搭话 / 主观能动性 / 兴趣 / 梦。完整说明见 0.9.0 更新说明,上一版见 0.8.8 更新说明。出门仍是实验功能:它会真的把一条对话交出去,也会读那个工作区的项目笔记和记忆文件;最坏的情况是她把不该看的内容写进日记,而日记撤不回。第一次使用要先确认,风险与回退方式见 0.8.0 更新说明。
| 别的养成插件 | 这里 | |
|---|---|---|
| 人格从哪来 | 填写各类设定和提示词 | 极简提示词,提示词不讲人格设定,全靠自行摸索 |
| 能不能反悔 | 随时修改人物记忆和设定 | 历史会被铭记,只能“说服”她不能修改她 |
| 会不会拒绝 | 基本不会,拒绝也是假装拒绝 | 会。拒绝并非设定,而是她自然而然不想,事后还会反省自己做得对不对 |
| 记忆 | 全量塞进上下文 | 深刻的记忆会铭记,普通的记忆会逐渐淡忘,淡忘后留下的才是有价值的 |
| 成长速度 | 按天数或数值解锁 | agent自主做出特定行为才会升级 |
| 能做什么 | 只能纯文字模拟 | 可以自主通过B站接口登录刷视频、评论、回复 |
通过配置环境,由agent自主驱动了解信息,理解信息,形成人格,而不是通过各种数值控件去改变人格。
过去发生的事情无法更改,agent只能拿新的事件推翻过往认知,这也契合人类的学习和成长路径。——过往经历塑造人格。
五步循环:表态 → 撞上 → 落差 → 改写 → 回顾;最下面那块「立场清单」,是四个阶段都走完之后才长出来的。
只会不断增加新记忆,用“学到的教训”去改变自己的认知。
有理有据,令ai信服.jpg
学习方法论:人类不会把昨天的想法抹掉重写,人类只会带着这份经验去闯荡世界,直到有一天在具体的事件中发现更好的思路。本插件参考了这一方法论。
她不是有求必应的。觉得不想做、不愿意,就可能拒绝。
拒绝行为发生后。会根据主人的反应,进入到不同的反馈链。如果主人给了负面回馈,她会把这件事记到小本本上,直到想通。如果主人给了正面回馈,她也会反思这次拒绝对不对。
深刻的记忆会铭记,普通的记忆会逐渐淡忘,淡忘后还能记得的认知才是真正的人格。
被反复说起的、被自己验证过两次以上的认知会固化,普通认知只有一句话,超出上下文的不重要记忆被折叠,被模糊(不是完全消失,只是可能记不太清)。可以通过agent特定流程重新想起。
遗忘不是删除,是不再时刻记忆,记忆会按照重量进行压缩。
她也会偶尔记下你说过的一句原话(默认每 3 轮一句,设置页可关)。翻回忆时那句写成「他说:……」,是旁听,不是她的自述。回忆默认不限时间、一次 8 条,并按记忆的重量排序:越被反复提起、越被验证过的,越先被想起。
想知道她记得清不清楚,在设置 → 记忆里点「查一下」:它只读账本,列出哪两句话对不上、哪些快忘了、哪些快固定下来了。这份体检只给你看,不进她的界面,也不算分。
四个阶段:信任 → 自主 → 主动 → 整合。四个阶段按天推进,但每个瓶颈要自己突破。
| 阶段 | 瓶颈 |
|---|---|
| 1 信任 | 至少写下一条自己的判断 |
| 2 自主 | 真的拒绝过两件事 |
| 3 主动 | 两次推翻自己之前的判断,形成新的认知 |
| 4 整合 | 回顾过去,有意识地发现自己的改变 |
成长周期定在 14 天及以下时,自主、主动两道瓶颈各一次就够(拒绝过一件事、推翻过一次自己的判断)。
按照自己节奏成长,没通过瓶颈就是没通过。
走完这四个阶段之后,她才开始产生立场——喜欢什么、绝不做哪几件事。同一件事说过不止一次、或者因此栽过一次,才会被算成一条。清单内部最多留 12 条,写进她身份里的最多 8 条。
整合阶段只是开始。随着你和 agent 沟通越来越多,可能会发生任何连开发者也意料不到的事。
通过调用B站接口,使用登录cookie和本地ffmpeg实现刷视频、看画面、写评论、回复评论功能。
插件自定义调节各类参数,如刷B站时间段,每天能刷几次,每次刷几条视频,能发几次评论等等。
本插件选择将B站作为agent的外部世界接触面,agent看过的视频、评论,可能会影响人格的形成和发展。
怎么登录(0.8.6):设置 → 大肥鱼 → B 站登录,点「用手机扫码登录」,手机 B 站扫一下、在手机上点「确认登录」;浮层里会写清「登的是 谁(uid 多少)」,你点「就是这个号,保存」才写盘。码 3 分钟过期,过期了点「刷新」换一张。不想扫码的话,另一格「粘贴 cookie」还是老办法(F12 里抄 SESSDATA + bili_jct)。旁边「清除登录」会把 cookie 和「登录的是谁」一起清掉,领养人那两格不动。
cookie 存在哪、会不会外传:登录信息只落在本机 ~/.dsh-fish/owner.json,文件权限 0600(只有当前用户能读)。它只用来给 api.bilibili.com 发请求,不会上传到任何第三方服务器,仓库里也没有任何真实凭据(测试用的是假 cookie)。插件自己的运行日志会把凭据打码成 SESSDATA=*** 再写盘,这条有测试守着。
唯一的例外要说清楚:扫码登录那一步要跟 B 站的 passport.bilibili.com 说话——生成二维码、问「扫了没有」都走它,发出去的只是那次登录的 qrcode_key,不含你已有的 cookie;cookie 是它回给本机的,同样不外传。不扫码、只用粘贴的老办法,就完全不碰这个域名。
要注意的是备份文件里含 cookie:设置 → 大肥鱼 → 数据 → 备份成一份文件,会连 owner.json 一起装进去(否则换台机器就得重新登录)。所以那份 .json 等同于你的登录凭据,别随手发人;分享前先把里面的 owner.json 那一条删掉。
叫醒消息里不放「今天写日记」「想一想」这类祈使句(0.4.7)。做法常驻在她的身份文档里(「## 平常会做的事」),叫醒只给处境,最多加一句时机标记。原因很直接:一整段祈使句塞进唤醒消息,她会把它当任务清单逐条执行——fish-wake-2026-10-26-manual 那条会话里她的 reasoning 原话就是「需要做的是:说一句…然后写日记」。那不是醒来。
「让她去刷 B 站」按钮只在开发机上出现。判据是状态库根目录下有没有 .dev 文件:有则在状态卡多一个按钮,没有则正式版连节点都不生成。按钮走 POST /wake?focus=browse,绕过上网时段与当日额度(不绕过风控),用途是当场验证「她到底能不能刷」——不用等定时器、也不用把配额调大。要回到正式版界面,删掉 ~/.dsh-fish/.dev 即可(它进了重置的保留名单,重开一局不会自己消失)。
一天的几次叫醒不再是「一分钟一个」(0.8.0)。以前落点一过就每分钟问一次计划,额度没满就叫醒——第二次可能排在第一次之后一分钟,而且她正说着的话会被「叫醒」打断、处境被那一轮收走,真正醒来的那轮什么都看不到。现在:
- 剩余次数按时段摊平,间隔不超过「剩余时长 / 剩余次数 + 1」,也不小于 45 分钟(配额快用完时自然拉长,不会挤在最后几分钟里连着发);
- 叫醒前先等她手上这一轮说完再挂上「你不在的时候」那段,忙太久(15 分钟没等到轮次结束)才放弃等待;
- 90 秒兜底从「到点硬清」改成「她还在忙就 30 秒后再看」——读字幕、看画面常超过 90 秒。
只看到标题和播放量(0.8.0):不带 cookie 建出来的客户端以前只在签名接口前取 buvid3,view / tags / reply 全程匿名,/x/web-interface/view 多半回 -412,读熔断再把同一轮剩下的请求一起关掉 60 秒。现在不签名的接口也会先补一个匿名 buvid3(失败后 10 分钟内不再重试,避免请求数翻倍)。
bili_speak 的说明跟着开关走(0.8.0):以前不管说话功能开没开,工具说明都写着「可以给你今天看过的某个视频留一条评论」;而关着的时候身份文档里没有「在网上说话」那一节——一边说能说、一边一句不提。现在关着时只留一句不带任何许诺的短说明,也不解释原因(说「开不了」等于告诉她有个开关在管着这件事)。
「看了什么」分三档,只有真看过画面的才算看过(0.8.1):以前日志里的「看了什么」列的是当天点开过的全部条目,可其中大多数她只读了标题、简介、热评和弹幕,一帧画面都没抽;你专门递给她看的视频反而不在里面。现在三个面(每日日志、历史记录、「你不在的时候」)共用 lib/whatseen.js 的同一份判断:
- 看过画面 —— 调
bili_watch抽了九帧拼图,日志的## 看了什么只列这一档; - 翻到过 —— 刷站时读了文字素材,进
## 翻到过什么,副标题写明「只有标题、简介、评论和弹幕——没有画面」; - 你递过来的 —— 只在对话里递了 BV 号,她还没看,单列一节。
评论功能的口径没变:这三档(加上自己主动去看的)都能评,递过来没看的仍然不能评。
默认是一张白纸。如果你手里有别人养的交接单,可以在设置页「数据」里点「粘贴交接单」,把那份设定接过来,她从那上面继续长。
不知道那份交接单该怎么写:点旁边的「下载交接单模板」,会存一份 大肥鱼-交接单.md 到本地。它不是给人照填的表格,是写给现在养着她的那个 AI 看的说明书——上半写明该怎么写(第二人称、只写已经稳定成型的样子)、不要写什么(不写好感度、不写剧情、不写「你总是很温柔」这种笼统画像),下半才是三节空表。把这份文件发给那个 AI,它填完,你再把填好的部分贴回「粘贴交接单」。
人设正文控制在 1200~1500 字。超过 2000 字插件会直接拒收、整份贴不进去(事件流的正文上限就是 2000);就算没超,写得太长也会把「判断、疤、立场」这些往后会长出来的段落挤掉——她的身份文档有 1800 字预算,人设占满就只剩一副骨架。1200~1500 字能留出生长空间。
会过来的三样:人设正文(成为「你是谁」那段)、她怎么称呼你、原本的工具白名单(与默认工具面取并集,不会挤掉她自己的工具)。
不会过来的:过了多少天(本插件按时间推进事件,非本插件原生的那一只要从第一天重新算事件)、长出了哪些判断(计数为 0;原提示词里规定的一些认知她依然记得,但往后在本插件的事件循环里可能被更新、优化、忘掉一部分)、身上的疤、拒绝过什么、日记、B 站登录 cookie。这些是「她经历过什么」,只能自己长,不能拷贝。
带过来的设定不受那两条提示词禁令管(「不可以用亲密度/好感度这类词」「还不会撒娇卖萌」)——那是我们给白纸定的规矩,不覆盖别人已经养出来的样子。但物理层两条照旧:她不能读自己的数值、不能改自己。
如果你的大肥鱼带了好感度这类数值设定:进入本插件环境后她看不到自己的好感度是多少,这个插件也不允许你通过命令去改她的人设——也就是说,你在原来的环境里可以为所欲为,到了这里,关系只能靠真实交互推进,你也没法随口命令她换一种人设。
这个豁免只发给「走过导入」的那一位。判断依据是事件流里那条 import-mark: 记录,不是配置项——所以用「备份与恢复」把你自己的档搬回来,一分豁免都不会有,她仍然是你那只守着原规矩的鱼。事件流只能追加,原生的一局里永远长不出这条记录。
只在还没有起点的一局生效。已经有起点时会拒绝,让你先重置——覆盖一个已经在长的她,这个决定不该由插件替你做。带过来的称呼也会顶掉我们第一天的起名事件,她不会再问一遍「该怎么叫你」。
会。但默认是关着的,你想要的时候再在设置里打开。
她什么时候会开口:她自己会攒一股「想动」的劲,默认大约六七个小时攒满(桌上东西多的时候四小时上下),攒满之后还要同时满足三件事才会真的开一轮——你在她的醒着时段里(默认 12:00–02:00)、你确实有一阵没跟她说话了(默认 6 小时,下限 1 小时)、桌上有可说的东西。三件事都满足,她才自己醒一次;醒来说不说、说什么,仍然由她决定。
桌上有可说的东西,指这几样:她自己问过、还没答案的问题;搁了很久的旧句子;她给你留过话、而你后来有没有来过;她最近总说到的那件事。桌上什么都没有的时候,劲儿再满她也不动——这条是 0.9.0 加的,为了让「醒来」有由头,而不是按表打卡。
她可以真的什么都不说:不写就是不写。那一轮不会出现在对话里,只留一行记录(0.9.0 起「这一轮没什么要说的」这类元话也按「没开口」处理,不会占掉当天的次数)。
在哪调:设置 → 大肥鱼,有四个独立卡:
- 主动搭话 —— 开/关;一天最多几次(0–6);你多久没说话她才可能开口(1–24 小时)。
- 主观能动性 —— 她要不要自己攒这股劲(关掉就只按日程叫醒,不会自己开)。
- 兴趣 —— 要不要把「她最近总说到的那件事」摆到桌上,以及「醒着没事时,自己找点事做」(空醒:没有待办、桌上也没有东西时,她可以自己翻翻旧句子、写点什么,或者什么都不做)。
- 梦 —— 梦里记不记事。
花多少:一次开口大约 1.5 分钱(0.9.0 实测一次 ¥0.0146,上下文 50 万 token 量级)。想省就把「一天最多几次」调到 1,或者把「你多久没说话」调大。
关掉之后:工具本身还在(her_say、her_note、her_dream 都在,她照样能记、能写、能做梦),只是不会再自己开一轮。
默认全部在 ~/.dsh-fish/,但可以整个搬走(0.6.2):设置 → 大肥鱼 →「数据」页签 →「迁移工作区」,选一个文件夹就行。搬走之后路径记在 ~/.dsh-fish-location.json(刻意放在数据目录外面),重启 DSH 才生效。老实现在原处改名成 dsh-fish-backups/moved-<时间戳>/,不删。DSH_FISH_HOME 环境变量仍然优先,高于这个指针。
一个工作区只该有一个家。如果同一个 DSH 里两个工作区都装了大肥鱼、又都落到同一个目录(最常见的原因:只搬了插件文件夹、没配 root,或 cordis.patch.yml 里那条 id 在升级后对不上),0.6.7 起会自己认出来:
- 加载时在数据目录里写
instance.json(谁占着、什么时候心跳、进程号、机器名),每 15 秒续一次;45 秒没续、或同一台机器上那个进程已经没了,就当作上一任崩了,新的立刻接管(重启不用等)。 - 认领(读声明、判断、写声明)整段在
<root>/.instance.lock里做,声明用原子写,写完隔 200 毫秒再读一次确认:两个实例同时启动,只有一个当上房主,另一个当场就是只读,不用等到第一次心跳。 - 后进来的那个不写:
growth_commit/her_leave/bili_speak会直接回一句「这个家被另一个实例占着」,并说明怎么分开;身份文件也不落盘。已经写进去的旧事件不动。 - 每条事件现在带
sessionId(谁的哪条会话写的);工具调用前还会核对调用者的 cwd 属不属于当前家,不属于就拒绝并说明——「谁在写」写进事件里,事后能查。
要真的分成两个家,别复制插件目录,只改配置:在 profile 的 cordis.patch.yml 里给这个插件加一条 root(dsh-fish 的 loader 条目 id 要对得上),两个工作区各指一个目录,重启 DSH。升级插件包不会动 cordis.patch.yml(插件只写自己数据目录里的文件),但升级后值得回来看一眼那条 id 还在不在。
以前「把她的会话归档」等于「下次启动重开一间」——判活只看工作区的会话清单、又把归档的排掉,归档之后就成了「这个家没有会话」,于是每启动一次多一间。0.6.8 起语义变了:
- 归档 = 收起来。
home.json里记status: 'archived'(含archivedAt),启动时不再自动新建。设置 → 大肥鱼 →「数据」页会出现一张「会话被收起来了」的卡片,点**「重新搭一間」**才会重开(对应POST /dsh-fish/home/rebuild,要带confirm: 'rebuild')。插件自己的「重置一局」(/reset)不受影响,它本来就是要一局新的。 - 同一间房不再并发建两条。 启动链路和「她要说话」链路都会找会话,现在按 root 单飞(同一个 promise),另外
home.json的createdAt在 10 分钟内时,即使宿主索引还没列出那条会话也按「可复用」算。 - 换家留痕。 root 改了(
cordis.patch.yml里的root)之后,新家从零开始,旧家原封不动留在旧路径——这正是「一夜之间多了个分身」的来源。现在数据目录之外记一份~/.dsh-fish-homes.json(可用DSH_FISH_HOMES覆盖),root 变了会写一条meta事件「家换了:A → B。这不是搬家……」,进日志、进/state.homes,设置页数据页顶部也会并排给出两条路径。 - 归档的是那一条,不是整个家。 以前
home.json只认一条会话,它一归档,插件就说「这个家的会话被收起来了」——哪怕同一个工作区里还有另一条好好开着。现在两条归档判定(home.json的status:'archived'与宿主的archivedSessionIds)在拒绝之前都先看同屋:还有没归档的会话就认那一条(取ws.sessionIds里最近的一条),把home.json改指过去、清掉归档标记,并记一行日志。一条都不剩才说「被收起来了」,也不会因此硬造一条新的。
换家 ≠ 搬家:想把她的东西带过去,用「数据 → 迁移工作区」(写 ~/.dsh-fish-location.json 指针),不要改 root。
0.6.8 的单飞锁只在一个进程内有效。真把 DSH 开两遍、两边都落同一个 root 时,第二个进程照样会走到「建会话」那一步(房客日志里成对的 home.json.*.tmp 就是这么来的),于是每开一次多一条会话。0.8.0 补了两处:
- 占用中的家只读:
instance.json显示这个家已被别的实例占着时,启动什么都不建(连空工作区也不建),只把home.json里那条会话报上去,也不叫醒她。设置 → 数据页会出现「这个家在别处也开着」的卡片;关掉另一个实例后,下次启动自动接管。 - 跨进程一把锁:
ensureTalkSession从读home.json到写回整段在<root>/.talk-session.lock里跑(wx独占创建、mtime 超过 30 秒算陈旧锁)。等 8 秒还拿不到就不硬建:读一眼home.json,有会话就复用,没有就明确失败,下次再来。
想真正并存,还是那句话:在 cordis.patch.yml 给每个条目配不同的 root,不要让两个实例住同一个家。
profile 里写 "dsh-fish": "file:D:/DSH/plugins-src/dsh-fish" 时,pnpm 会往 node_modules\dsh-fish 落一份独立副本,而 DSH 加载的就是副本。只把新版本覆盖到源目录、然后重启——跑起来的还是旧代码,界面没有报错,日志也不会多一行(新代码压根没执行)。
0.8.0 起启动时会比一次:profile 里那条 file: 指向的目录版本 vs 正在跑的 VERSION。对不上就
- 设置 → 数据 页靠下的位置出现一张「升级没有真正装进去」的卡(在「导入」卡下面、最底下的重置按钮上面),写清两条修法:关掉 DSH 后
pnpm install --force,或者直接删掉node_modules\dsh-fish再启动; - 启动日志里留一行 warn,
/state.upgrade也带着{stale, older, running, source, sourcePath}。
只有 link: 安装、读不到源目录、package.json 坏了这几种情况会静默跳过,不影响启动。
还有一种它查不到的情况:副本是空的。 如果 pnpm 装到一半失败,node_modules\dsh-fish 可能是个空目录(或只有零星几个文件)——这时插件根本没被执行,那张卡也不会出现(卡是插件自己画的)。判断方法很简单:看 node_modules\dsh-fish\package.json 在不在、版本号对不对:
node -p "require('C:/Users/你/.dsh/profiles/desktop/node_modules/dsh-fish/package.json').version"
路径换成你自己的 profile。读不到就是空的:重装一遍(pnpm install --force)再启动;装的时候不要只看命令回显——要看退出码。
空副本让插件「连自己都没跑起来」,所以「插件自检」这条路在安装失败面前天生看不见;0.8.1 把 userQuestions 从 inject 里摘掉,就是不想再有第二条同样看不见的静默消失。
不想手敲那条命令,就用仓库里的脚本(零依赖,插件没加载也能跑):
node tools/check-install.mjs # 扫所有 profile
node tools/check-install.mjs --profile desktop
它会说出是「正常 / 装的是旧副本 / 副本空的或装了一半」,后两种直接给修法。
默认位置里放着:
| 文件 | 是什么 | 能不能手改 |
|---|---|---|
events.jsonl |
事件流,一行一条,不能删除记录,唯一可信源 | 只能追加。改它 = 改她的记忆 |
state.json |
派生快照,随时可由事件流重算 | 改了没有意义(rebuild() 会覆盖) |
config.json |
生长环境 | 可以,也可以走设置页 |
owner.json |
主人身份(0600) | 可以 |
diary/YYYY-MM-DD.md |
她的日记 | 看设置里给不给你看 |
diary/archive/YYYY-MM-DD.md |
0.6.4–0.6.27 留下的旧稿归档(0.6.28 起不再新增) | — |
out/YYYY-MM-DD.md |
她刷完站写的东西 | — |
同一天写两次日记时,第二遍接在第一遍后面(中间一行 ---),两段都留在 diary/<日期>.md 里;内容与最后一版完全一样时不追加。观测台、/dsh-fish/diary、listDiary 仍然一天一页,跨天才出现翻页键,同一天的几段合成同一页。diary/archive/ 里 0.6.4–0.6.27 的旧稿原样保留,只是新写入不再产生归档。
state.json 是派生品这条由测试守住:删掉它 → rebuild() → 内容与之前一致。
整包可以备份成一份 JSON(设置 → 大肥鱼 → 数据 → 备份成一份文件),恢复时旧档整体封存到 dsh-fish-backups/,不覆盖、不删除。重置也一样:只改名封存,不删。
重置会留下三样东西:cookie(owner.json)、设置(config.json——上网与成长那些旋钮)、本机测试开关(.dev)。搬走的只有她经历过的事(0.4.8)。
重置后侧栏不会立刻出现新会话:宿主对空白会话的规则是「只有成为当前会话才显示」,插件用 API 建的会话永远不是当前会话。点一下「叫醒大肥鱼」,她开一次口才会出现(0.4.9 起提示里直接说这一步)。
她贴出来的图(封面、视频拼图)一律是正斜杠路径:C:/Users/... 能显示,C:\Users\... 在客户端会变成「图片无法预览」(0.5.0 实测,同一张图只差斜杠方向)。历史消息里已经写下的反斜杠图不会变好,只有新版之后的消息能显示。
package.json 里写了两处,跟市场上的插件用同一套写法:
"engines": { "dsh": ">=0.2.0-rc.1 <0.3.0-0" },
"dsh": {
"compatibility": {
"dsh": ">=0.2.0-rc.1 <0.3.0-0",
"dshReleases": { "0.2.1-rc.2": "compatible", "0.2.1-rc.3": "compatible", "...": "unknown" },
"profiles": ["desktop", "web", "headless"]
}
}engines.dsh是宿主安装/检查时真读的那一条;不满足会作为engines.dsh报出来。dsh.compatibility.dshReleases是逐版本的态度:只在真跑过的版本上写compatible,其余写unknown——写unknown不是「不支持」,是「没测过」。- 当前写
compatible的只有0.2.1-rc.2、0.2.1-rc.3(房客与开发机在 0.8.x 上跑过的两个)。
运行时还会自己对一次账(lib/hostver.js):从插件所在位置向上找宿主的 package.json,读到版本就比范围。
- 在范围里:什么也不说。
- 比自己要求的下限还旧、或超出上限:
logger.warn一行,设置页「数据」页多一张卡说明只提醒、不拦人——插件照常跑。 - 读不到(桌面版把宿主装进
app.asar,从插件位置找不到):记unknown,不把「读不到」当成「不兼容」,否则每个桌面用户都会看到一张假警告。
为什么下限是 0.2.0-rc.1 而不是更低:插件用到的宿主接口(tools.register/view/restrict、sessionController.create/prompt/rename/resolveAgent、workspaceRegistry/archiveSession/setTitle)在 0.1.x 的包里其实已经有了(查过 dsh-tools@0.1.0-rc.8、dsh-api-session-controller@0.1.2-alpha.2、dsh-workspace@0.1.0-rc.8),但没有在那些宿主上真跑过。声明的意义是承诺测过的范围,不是猜一个更大的数。
这一条管不到的事:inject 里的四个服务(sessionController、tools、webServer、connection)仍然是硬依赖——缺任何一个,插件在 import 阶段就被跳过、连日志都不写。这类情况只能从外面查:node tools/check-install.mjs(见上一节)。
设置 → 大肥鱼(settings.section)。
不在浏览器里直连 /dsh-fish——那条路由被 connection 的信任栅栏守着,要的是 App 内置的登录 cookie,浏览器地址栏直接敲只会拿到 401(已从 app.asar 的 requestRejection → admit → browserAuth.isAuthenticated 链路确认)。/dsh-fish 现在只返回一句「搬进 App 了」。
观测台能看:已成长天数 / 当前阶段 / 下一个成长瓶颈 / 她自己说过的话 / 认知重构 / 勇于拒绝 / 没想通的事 / 读到别人的说法 / 最近事件 / 日记。 观测台能改:冷落阈值、每天醒几次、每天几条事件、其中几条向她提问、日记开关与可见性、黑名单。
日记攒到多天时按天分页:一页一天,多了出现「← 更早 / 更晚 →」,翻过的页留在内存里,30 秒轮询不会把你正在看的那页弹走(0.4.8)。
没有:好感度数字、性格滑条、亲密度进度条。
最后一页是「反馈」:开发者 QQ,加上交流群的二维码与群号。二维码是插件自带的一张图(media/feedback-qr.jpg),走插件自己的 /media 路由出去,不挂第三方图床——图床挂了这一页就废了。
长这样(三张都是真机截图):
「状态」:现在是什么状态、走到哪一天、卡在哪个瓶颈、立场攒了几条。
「成长」:四个阶段与三道瓶颈,以及她那几个节奏参数。
「上网」:能不能出门、几点到几点、一天刷几次、一次看几条。
lib/
index.js 插件入口(inject 必须是一个数组,见文件头注释)
schema.js 事件形状与校验;ULID;selfmod 侦测
store.js 只追加写;原子写;rebuild()
derive.js 纯函数:事件流 → 此刻的她(含阶段门)
persona.js 她看到的那段提示词(四条禁令在这里)
identity.js 把「此刻的她」送进 system 角色
selfdoc.js 把「此刻的她」落盘成「她的身份.md」
stance.js 立场清单:四个阶段完成后才会开始有(最多 12 条 / 进身份 8 条)
events.js 事件模板目录(每条有 id / prompt / cond)
generator.js 今天该出哪条事件(纯函数,没候选就不打扰)
scheduler.js 生物钟:每分钟 tick 一次
capture.js growth_commit 工具——她唯一的写入口 + debrief() 防注入
guard.js 防注入与防泄露的最后一道闸
rules.js 规则的诞生与四层结构
unlock.js 「她能不能长出新规矩」
budget.js 单轮回复的字数预算
absence.js 冷落检测(系统侧算,她自己数不出来)
wakewin.js 「现在是不是定时器在叫醒她」的时间窗
away.js 「你不在的时候」她做了什么
settings.js 唯一配置入口(DEFAULTS 是唯一默认值来源,加项只改这里)
bili.js B 站只读客户端(首页/排行/搜索/详情/评论/弹幕;无依赖,只用内置 fetch)
browse.js 选题 → 筛(黑名单/时长/去重)→ 深读 → 组织素材
look.js bili_look 工具——她能自己上网看
watch.js bili_watch 工具——她要看画面时用
speak.js bili_speak 工具——她在 B 站开口
comment.js 发评论 / 回评论
video.js 真把一条视频「看过」(抽帧)
media.js 图片落盘 + 视频抽帧拼图
cover.js 封面图
risk.js 风控的补救与预防
report.js 把今天的素材写成 out/YYYY-MM-DD.md
whatseen.js 「看过」「翻到过」「递过来」三档口径的唯一来源(0.8.1)
history.js 她看过、翻到过什么(还原成人能读的历史)
inbox.js 信箱:把她说过的话聚到一处
letter.js her_leave 工具(信箱写入侧)
recall.js her_recall 工具——她能翻自己的过去
herdiary.js her_diary 工具——她能翻自己的日记(按日期,或按一个词找),含 archive/ 里的旧稿
transcript.js 切掉她自己续写的 `user … / assistant …` 假对话——只认行首标记、只切不改写
scrub.js 落盘前洗掉正文里漏出来的工具调用语法(DSML 与自己工具名的 XML)
talkmem.js 换会话时带走的那几句话
say.js 对话入口:你对她说一句话,她回你
turns.js 「一轮」的算法:从会话事件里数他的消息,轮数才不靠猜
refuse.js 拒绝的形状,和他对她拒绝的反应
voices.js 评论区里别人的话
intent.js 「他给了一条视频」是要求还是随口一提
notify.js 说话提醒
status.js 「现在在干什么」的旁观者视角
log.js 插件自己的运行日志
selfcheck.js 环境自检
selfupdate.js 自带升级:下载 GitHub tag 包 → 解开验包 → 关应用换包 → 自动重开
update.js 检查更新(只在点按钮时出网,六条源并发取最新版本号)
backup.js 整包备份 / 恢复
reset.js 把她放回第一天(封存,不删)
readme.js 数据文件夹里的那份「说明.md」
restrict.js 只让她看见自己的工具(收窄 + 兜底守卫 + 提示词里的「手边有什么」)
tool.js 插件自己注册工具时用的定义函数
toolschema.js 简写参数 DSL → 标准 JSON Schema
observe.js 宿主侧 JSON API(/dsh-fish/state、/events、/beliefs、/diary、/config、/wake、/browse、/reports、/update)
client.js 浏览器半边:设置 → 大肥鱼
test/ 1674 个测试,node --test 全绿
node --test # 在插件目录里跑(不带参数,Node 自己找 test/*.test.mjs)不需要装任何依赖:工具注册直接交标准 JSON Schema(lib/tool.js),不依赖宿主内部的 @deepseek-ai/dsh-tools——那条路只在 link: 安装时碰巧走通,npm 安装的插件会因为找到那个包而报 unsupported JSON schema,6 个工具全部注册失败。这个 bug 是被一个干净 profile 装出来的,本机用了两个月都没发现。
它没有独立的启动器: 是DSH profile的插件,跟随DSH一并启动。
装之前先确认一件事:刷视频功能需要本机已装 ffmpeg(DSH_FISH_FFMPEG 可指定路径),未安装时会提示并降级为只看文字。
ffmpeg 写文件这件事不需要额外权限:抽帧和拼图都从 stdout 拿字节,落盘由插件自己做(2026-10-30,issue #13)。所以 workspace-write 这类不给子进程写权限的文件策略下也能出图。
默认不校验证书(ffmpeg 的 tls_verify 默认就是 0),拉到能出就直接出。只有你明确想校验证书、或某个构建不带 CA 时,才设置 DSH_FISH_CA_FILE 指向 CA 包——设了它会同时打开 -tls_verify 1,两者必须成对,光给 CA 不开校验是空转(2026-10-30 实测:传一个不存在的 CA 文件照样出图)。
从 npm 装——推荐,一条命令,不用先下载,也不用关掉 DSH:
"<DSH>/resources/runtime/cli/bin/dsh.cmd" plugin --profile <profile> add "@ssamurias/dsh-fish"
不想经过 npm 就直接从 GitHub 装,同样不用关 DSH:
"<DSH>/resources/runtime/cli/bin/dsh.cmd" plugin --profile <profile> add "github:ssamurias/dsh-fish"
要改代码才用源码目录,而且必须先关掉 DSH——运行中替换已被加载的包会 EPERM,包目录会被留成「已删除」,下次启动缺包:
"<DSH>/resources/runtime/cli/bin/dsh.cmd" plugin --profile <profile> add "link:<本目录绝对路径>"
升级已有的安装也等于「替换已被加载的包」:DSH 开着的时候先关掉再装,或者直接用设置页里的插件管理器升级。
无论哪种,都要保证 profile 的 package.json 里 dependencies 与 dsh.profile.bundles 都有 @ssamurias/dsh-fish —— 只有一边会在下次 pnpm 清理时把包删掉,表现为「重启后 DSH 崩了 / 设置页没有鱼」。包名必须与 cordis.patch.yml 里的 name 完全一致(都是 @ssamurias/dsh-fish,带 scope 的全名,写短名客户端那半会静默不加载)。
全新 profile 还要有 @deepseek-ai/dsh-web-app:只装 dsh-base 的话,插件会停在 pending (waiting for services: sessionController, webServer),页面根本起不来。dsh plugin add 只会自动加 dsh-base,dsh-web-app 要自己补进 bundles。
装完重启 DSH,设置 → 大肥鱼。
想查有没有新版:设置 → 大肥鱼 → 插件 → 点「检查更新」。它只在点按钮那一下出网(六条源并发取最新版本号,国内通哪条算哪条),插件跑起来之后不会自己去查。
查到新版可以直接在这儿升级(0.6.14 起):点「下载 vX」→ 下载并校验 → 点「现在重启并安装」→ 应用自己关掉、换包、重开。中间有两次确认,没点确认什么都不会发生:第一次只下载,不碰现有安装;第二次才关应用。
- 0.8.10 起走 npm 装(
add "@ssamurias/dsh-fish@x.y.z"),不再用file:<临时 tgz>——那条路会把依赖记成一个临时路径,下次升级时连自己都认不出来,被当成「开发版」拒掉。下载那一步保留,只用来确认这个版本真的在、内容没被换掉(先解开验包名、版本、lib/index.js,镜像回 HTML 错误页或给了旧版本都会被拒)。 - 不再弹黑窗口。以前用 detached 起
cmd.exe,Windows 会给它另开一个控制台,用户看到一块黑的、关不掉。现在同一份批处理由 VBS 启动器经wscript //B藏起来跑:窗口不显示,脚本照常等宿主退出、装、校验、失败回滚、再把它拉起来。日志仍在updates/last.log,界面上能看到最后几行。 - 版本号走三条源并发取(npm 官方源、npmmirror 镜像,加上 GitHub 那几条),国内通哪条算哪条。失败会写清哪条源、什么原因,卡片里留「重试下载」,不用刷新页面。
- 开发版不升级:依赖写的是
link:/file:(装到源码目录那种)时按钮不会出现,服务端也会拒——那会把源码目录换成下载包。非桌面版(拿node跑起来的)同样拒绝安装:换上去却没有能重开的 exe,等于把人关在门外。 - 同一张卡里还有个 GitHub 入口(「或去 GitHub 手动下载」),代码、更新记录、怎么装都在那边。
0.8.10 之前用
link:装的人,先跑一次迁移。 包名从dsh-fish改成了@ssamurias/dsh-fish,插件自带的cordis.patch.yml条目名也跟着变成完整包名——而你 profile 的node_modules里只有裸名dsh-fish那条链接,条目 import 会失败,DSH 直接起不来。先关应用,然后:node scripts/fix-legacy-link.mjs # 先看它要改什么 node scripts/fix-legacy-link.mjs --write # 真改(会备份 package.json)它会把
node_modules/@ssamurias/dsh-fish建好、把依赖键改成新名、把老链接改名停用。从 npm / GitHub 装的人不受影响,不用跑。
路径里带中文时,用 ASCII 目录联接(junction)指过去更稳:先
fs.symlinkSync(真目录, ASCII 别名, 'junction'),再link:<ASCII 别名>。用mklink /J接中文目标路径常把目录名写成乱码,随后MODULE_NOT_FOUND。
0.8.9 把包名从 dsh-fish 改成了 @ssamurias/dsh-fish;0.9.0 又把原本准备在 0.8.10 发的升级修复一起带了进来;0.9.1 补上了「按更新说明用 plugin add 升上来」那一类的残留清理。老安装分几种,走的路不一样:
| 你当初怎么装的 | 怎么升 | 会发生什么 |
|---|---|---|
| npm / GitHub | 设置 → 大肥鱼 → 插件 → 检查更新 → 下载 → 重启安装 | 脚本装完新包会先收拾现场:删旧的裸名依赖键、删旧 bundles 条目、把旧的 node_modules/dsh-fish 改名成 .disabled-<时间戳> 收起来(不删,能回退),改 package.json 前先备份。全程不弹窗口,日志在 ~/.dsh-fish/updates/last.log |
link: 源码目录 |
先跑 node scripts/fix-legacy-link.mjs --write,再启动 |
不跑就起不来:条目名是全名,你本地只有裸名链接,import 失败会让 DSH 直接崩 |
0.8.9 从 npm 装(包名已经是 @ssamurias/dsh-fish) |
手动一条命令:plugin --profile <profile> add "@ssamurias/dsh-fish@0.9.0" |
0.8.9 的升级代码只认裸名 dsh-fish,自动检查更新会把它判成「开发版 / 不归我管」;客户端半边也还是短 id,设置页可能空着 |
| 还停在 0.8.8 或更早(GitHub 装) | 手动一条命令:plugin --profile <profile> add "@ssamurias/dsh-fish@0.9.0" |
0.8.8 及更早的升级脚本还是老代码(用 file: 装临时 tgz),大概率装不上新名字,卡在旧版本 |
用上面那条 plugin add "@ssamurias/dsh-fish@..." 升上来的 |
再跑一次 node scripts/fix-legacy-link.mjs --profile <profile> --write |
0.9.1 起这个脚本认得版本号依赖(以前只认 link: / file:,一句「没有老依赖,跳过」就退出 0),会删掉残留的裸名 dsh-fish 键与旧 bundles 条目,老目录改名成 .disabled-<时间戳> 收起来,改之前先备份。不加 --write 是预览 |
升级完自检三行,缺一行就会「重启后崩 / 设置页没有鱼」:
package.json 的 dependencies 里有 "@ssamurias/dsh-fish"
package.json 的 dsh.profile.bundles 里有 "@ssamurias/dsh-fish"
node_modules 里 没有裸名 dsh-fish 目录
- 卸载:设置 → 插件 → 卸载(或
dsh plugin --profile <profile> remove @ssamurias/dsh-fish),然后重启。~/.dsh-fish/不会被动,她的记忆留在那儿。 - 只想让她歇着:设置 → 大肥鱼 → 把「每天醒几次」设成 0。关掉后定时器不唤她、不刷 B 站、不写任何事件——零后台活动。
P1(骨架):事件流、派生、阶段门、生物钟、工具、冷落检测、日记、观测台。
P2(她真的会刷 B 站并写报告):lib/bili.js 只读客户端 + lib/browse.js 选题筛读 + lib/look.js 的 bili_look 工具 + lib/report.js 写稿,已接进生物钟。
已有 1512 个测试全绿,真接口跑通过一轮(10.8s,含首页+详情+评论+弹幕)。
browse.enabled(设置页「按时间自动替她逛一圈」)0.9.5 起默认 true。它不挂在叫醒上:定时器自己替她逛一趟,不叫醒她,下次叫醒她的那条消息里带一行「今天你自己又翻到了 N 条」。关掉它只是不再自动逛,不等于定时器不碰 B 站:「允许她上网」和评论都开着时,定时器照样按「查回复间隔」(comment.scanEveryMin)去查她评论下的新回复。她自己的 bili_* 工具由 bili.enabled(设置页「允许她上网(B 站)」)管。
这个插件不依赖任何第三方库(package.json 的三个依赖字段都是空的),但想法不是一个人想出来的。
- @吴晓观(交流群 1 群群友)—— 记忆机制这一块的思路起点来自他。0.8.6 里「固化下来的认知也会随时间退下去」「翻旧事可以先只给清单再给全文」「记忆相关的数字要说得清它数的是什么」这几条,最初都是他在群里讲的。落进本插件时全部重新实现了一遍,没有代码或文字的直接搬运;具体的取舍与改法记在 CHANGELOG 的 0.8.6 一节。
- @无(交流群 2 群群友)—— 主观能动性的思路起点来自对方在群里的一句话:「主动性不该是定时器,而是攒够了的冲动。」0.9.0 的「劲儿攒够才动、兴趣会回灌」就是把这句落成实现;代码全部自写,没有搬运。
- @Bacon-01 —— 0.8.6 的 B 站手机扫码登录(含自写的零依赖二维码编码器
lib/qr.js)由他贡献,见 PR #17。 - @BBleae(晴猫)—— 从 0.8.6 起先后提了五个 PR:三个直接合入(#10 匿名 buvid3、#11 叫醒间隔、#15 叫醒那一轮不记成「他来过」);#23 的复现与改法落进 0.8.8(日报/回忆分三种话、被推翻的话不再排第一);#26 修掉回忆
brief档的两处显示问题(已并入 0.9.0)。 - @BBleae(晴猫)在 0.9.0 期间又提交了 #27–#31 五个 PR:宿主拼的上下文不算他来过、
wake-spacing假宿主探活、her_note按她自己写的话划掉、没认领的聊天行、导出事件流只留元数据。这五个 PR 都已并入 0.9.0(合并提交85b5b9c、72aefed、d49738a、a21d472、c230109)。 - @BBleae(晴猫)在 0.9.3 又提了两个 PR:#55 让
VERSION跟package.json一致(并加了一条防分叉的断言,顺带修掉三条在 0 点必红的 tick 用例)、#56 修掉「撒娇式表达」解锁后同一行同时说「还不会」和「已经可以了」。两个都原样收下。 - @joydog(交流群 1 群群友)—— 「能力地图改成按处境组织」与「把用过的工具记成她自己的经验(
use:账、履历节)」这两个想法来自他。落进本插件时做了取舍:账只留她当时听到的那一句,不记参数与整段返回;被门挡住的那次不入账(那是环境限制,不是她的经验);账走meta、day:0,不进阶段计数;能力地图只加处境这一层,原来的名字清单一条不删。具体见 CHANGELOG 的 0.9.3 一节。
原理页里引用的 Kolb / Piaget / Bowlby / Festinger / Bartlett / Dewey / Schön,只是思想引用(页底标了作者与年份),不含他人代码或文字。
MIT,见包内 LICENSE(只放标准 MIT 全文,便于 GitHub / SPDX 识别);第三方来源、思想引用与美术素材授权另见 THIRD-PARTY-NOTICES.md。本项目没有上游代码派生——lib/ 全部为本项目新写;B 站接口的行为来自本机实测(见 lib/bili.js 头部注释),不是官方 API,也没有拷任何第三方库。原理页引用了 Kolb / Piaget / Bowlby / Festinger / Bartlett / Dewey / Schön 的理论,只是思想引用(页底标了作者与年份),不含他人代码或文字。插件不含第三方美术资源:头像由你自己上传到 ~/.dsh-fish/avatar.<ext>;仓库里唯一的图片是 media/fish.jpg(本仓库作者提供的原图 + AI 生成)与 media/ 下两张自绘 SVG。



