[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-105282":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":17,"stars30d":17,"stars90d":16,"forks30d":16,"starsTrendScore":18,"compositeScore":19,"rankGlobal":10,"rankLanguage":10,"license":20,"archived":21,"fork":21,"defaultBranch":22,"hasWiki":23,"hasPages":21,"topics":24,"createdAt":10,"pushedAt":10,"updatedAt":30,"readmeContent":31,"aiSummary":10,"trendingCount":16,"starSnapshotCount":16,"syncStatus":32,"lastSyncTime":33,"discoverSource":34},105282,"dsh-fish","ssamurias\u002Fdsh-fish","ssamurias","DSH插件：养一个会自己刷b站会成长的agent：不通过面板配置，通过学习诞生人格。","",null,"JavaScript",82,6,52,1,0,10,30,64.33,"Other",false,"main",true,[25,26,27,28,29],"agent","deepseek-harness","dsh-plugin","pet","typescript","2026-11-01 00:13:26","# dsh-fish · 大肥鱼\n\n**并非角色扮演，而是真实诞生**——一个一直在变的她。\n\n本项目的人格并非角色扮演的形式，没有人设配置菜单。默认从空白开始养起，但可导入你已经养过的大肥鱼人设提示词，继承大肥鱼的人设并在本插件环境内进行成长，具体请看本插件「数据」页面介绍。\n\n所有认知自己思考、理解、固化，从而形成人格。\n\n\u003Cimg src=\"media\u002Ffish.jpg\" alt=\"大肥鱼\" width=\"720\">\n\n\u003Csub>示例图由 AI 生成（基于作者提供的大肥鱼原图），随仓库以 MIT 授权。\u003C\u002Fsub>\n\n📺 **[看视频讲解（19 分钟）](https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1oTnZ6LEtc\u002F)** —— 这个插件是怎么想出来的、她为什么会长成那样、13 亿 token 都花在哪了。\n\n> **当前版本 0.8.3**（2026-10-31）。补丁版：设置页不再因为一个早就不存在的工具名整页存不进去，旁听按「离上次记了几轮」重算，手动唤醒不再被卡池空挡回来。详见 **[0.8.3 更新说明](RELEASE-NOTES-0.8.3.md)**。\n> **出门仍是实验功能**：它会真的把一条对话交出去，也会读那个工作区的项目笔记和记忆文件；最坏的情况是她把不该看的内容写进日记，而日记撤不回。第一次使用要先确认，风险与回退方式见 **[0.8.0 更新说明](RELEASE-NOTES-0.8.0.md)**。\n\n## 和别的养成插件差在哪\n\n| | 别的养成插件 | 这里 |\n| --- | --- | --- |\n| 人格从哪来 | 填写各类设定和提示词 | 极简提示词，提示词不讲人格设定，全靠自行摸索 |\n| 能不能反悔 | 随时修改人物记忆和设定 | 历史会被铭记，只能“说服”她不能修改她 |\n| 会不会拒绝 | 基本不会，拒绝也是假装拒绝 | 会。拒绝并非设定，而是她自然而然不想，事后还会反省自己做得对不对 |\n| 记忆 | 全量塞进上下文 | 深刻的记忆会铭记，普通的记忆会逐渐淡忘，淡忘后留下的才是有价值的 |\n| 成长速度 | 按天数或数值解锁 | agent自主做出特定行为才会升级 |\n| 能做什么 | 只能纯文字模拟 | 可以自主通过B站接口登录刷视频、评论、回复 |\n\n## 自由成长，而非配置\n\n### 一、人格是自主诞生\n\n通过配置环境，由agent自主驱动了解信息，理解信息，形成人格，而不是通过各种数值控件去改变人格。\n\n过去发生的事情无法更改，agent只能拿新的事件推翻过往认知，这也契合人类的学习和成长路径。——过往经历塑造人格。\n\n\u003Cimg src=\"media\u002Fprinciple-loop.svg\" alt=\"认知是怎么长出来的\" width=\"820\">\n\n\u003Csub>五步循环：表态 → 撞上 → 落差 → 改写 → 回顾；最下面那块「立场清单」，是四个阶段都走完之后才长出来的。\u003C\u002Fsub>\n\n### 二、过去无法更改，经历的一切都成为自己的经验\n\n只会不断增加新记忆，用“学到的教训”去改变自己的认知。\n\n有理有据，令ai信服.jpg\n\n学习方法论：人类不会把昨天的想法抹掉重写，人类只会带着这份经验去闯荡世界，直到有一天在具体的事件中发现更好的思路。本插件参考了这一方法论。\n\n### 三、她会拒绝你，还会为自己的拒绝反省\n\n她不是有求必应的。觉得不想做、不愿意，就可能拒绝。\n\n拒绝行为发生后。会根据主人的反应，进入到不同的反馈链。如果主人给了负面回馈，她会把这件事记到小本本上，直到想通。如果主人给了正面回馈，她也会反思这次拒绝对不对。\n\n### 四、记忆有重量\n\n深刻的记忆会铭记，普通的记忆会逐渐淡忘，淡忘后还能记得的认知才是真正的人格。\n\n被反复说起的、被自己验证过两次以上的认知会固化，普通认知只有一句话，超出上下文的不重要记忆被折叠，被模糊（不是完全消失，只是可能记不太清）。可以通过agent特定流程重新想起。\n\n\u003Cimg src=\"media\u002Fprinciple-memory.svg\" alt=\"遗忘是怎么发生的\" width=\"820\">\n\n\u003Csub>遗忘不是删除，是不再时刻记忆，记忆会按照重量进行压缩。\u003C\u002Fsub>\n\n她也会偶尔记下你说过的一句原话（默认每 3 轮一句，设置页可关）。翻回忆时那句写成「他说：……」，是旁听，不是她的自述。回忆默认不限时间、一次 8 条，并按记忆的重量排序：越被反复提起、越被验证过的，越先被想起。\n\n想知道她记得清不清楚，在设置 → 记忆里点「查一下」：它只读账本，列出哪两句话对不上、哪些快忘了、哪些快固定下来了。这份体检只给你看，不进她的界面，也不算分。\n\n### 五、成长没有终局\n\n四个阶段：信任 → 自主 → 主动 → 整合。四个阶段按天推进，但每个瓶颈要自己突破。\n\n| 阶段 | 瓶颈 |\n| --- | --- |\n| 1 信任 | 至少写下一条自己的判断 |\n| 2 自主 | 真的拒绝过两件事 |\n| 3 主动 | 两次推翻自己之前的判断，形成新的认知 |\n| 4 整合 | 回顾过去，有意识地发现自己的改变 |\n\n按照自己节奏成长，没通过瓶颈就是没通过。\n\n走完这四个阶段之后，她才**开始产生**立场——喜欢什么、绝不做哪几件事。同一件事说过不止一次、或者因此栽过一次，才会被算成一条。清单内部最多留 12 条，写进她身份里的最多 8 条。\n\n整合阶段只是开始。随着你和 agent 沟通越来越多，可能会发生任何连开发者也意料不到的事。\n\n### 六、刷B站功能\n\n通过调用B站接口，使用登录cookie和本地ffmpeg实现刷视频、看画面、写评论、回复评论功能。\n\n插件自定义调节各类参数，如刷B站时间段，每天能刷几次，每次刷几条视频，能发几次评论等等。\n\n本插件选择将B站作为agent的外部世界接触面，agent看过的视频、评论，可能会影响人格的形成和发展。\n\n**cookie 存在哪、会不会外传**：登录信息只落在本机 `~\u002F.dsh-fish\u002Fowner.json`，文件权限 `0600`（只有当前用户能读）。它只用来给 `api.bilibili.com` 发请求，**不会上传到任何第三方服务器**，仓库里也没有任何真实凭据（测试用的是假 cookie）。插件自己的运行日志会把凭据打码成 `SESSDATA=***` 再写盘，这条有测试守着。\n\n要注意的是**备份文件里含 cookie**：设置 → 大肥鱼 → 数据 → 备份成一份文件，会连 `owner.json` 一起装进去（否则换台机器就得重新登录）。所以那份 `.json` 等同于你的登录凭据，别随手发人；分享前先把里面的 `owner.json` 那一条删掉。\n\n**叫醒消息里不放「今天写日记」「想一想」这类祈使句**（0.4.7）。做法常驻在她的身份文档里（「## 平常会做的事」），叫醒只给处境，最多加一句时机标记。原因很直接：一整段祈使句塞进唤醒消息，她会把它当任务清单逐条执行——`fish-wake-2026-10-26-manual` 那条会话里她的 reasoning 原话就是「需要做的是：说一句…然后写日记」。那不是醒来。\n\n**「让她去刷 B 站」按钮只在开发机上出现**。判据是状态库根目录下有没有 `.dev` 文件：有则在状态卡多一个按钮，没有则正式版连节点都不生成。按钮走 `POST \u002Fwake?focus=browse`，绕过上网时段与当日额度（不绕过风控），用途是当场验证「她到底能不能刷」——不用等定时器、也不用把配额调大。要回到正式版界面，删掉 `~\u002F.dsh-fish\u002F.dev` 即可（它进了重置的保留名单，重开一局不会自己消失）。\n\n**一天的几次叫醒不再是「一分钟一个」（0.8.0）**。以前落点一过就每分钟问一次计划，额度没满就叫醒——第二次可能排在第一次之后一分钟，而且她正说着的话会被「叫醒」打断、处境被那一轮收走，真正醒来的那轮什么都看不到。现在：\n\n- 剩余次数按时段摊平，间隔不超过「剩余时长 \u002F 剩余次数 + 1」，也不小于 45 分钟（配额快用完时自然拉长，不会挤在最后几分钟里连着发）；\n- 叫醒前先等她手上这一轮说完再挂上「你不在的时候」那段，忙太久（15 分钟没等到轮次结束）才放弃等待；\n- 90 秒兜底从「到点硬清」改成「她还在忙就 30 秒后再看」——读字幕、看画面常超过 90 秒。\n\n**只看到标题和播放量**（0.8.0）：不带 cookie 建出来的客户端以前只在签名接口前取 `buvid3`，`view` \u002F `tags` \u002F `reply` 全程匿名，`\u002Fx\u002Fweb-interface\u002Fview` 多半回 `-412`，读熔断再把同一轮剩下的请求一起关掉 60 秒。现在不签名的接口也会先补一个匿名 `buvid3`（失败后 10 分钟内不再重试，避免请求数翻倍）。\n\n**`bili_speak` 的说明跟着开关走**（0.8.0）：以前不管说话功能开没开，工具说明都写着「可以给你今天看过的某个视频留一条评论」；而关着的时候身份文档里没有「在网上说话」那一节——一边说能说、一边一句不提。现在关着时只留一句不带任何许诺的短说明，也不解释原因（说「开不了」等于告诉她有个开关在管着这件事）。\n\n**「看了什么」分三档，只有真看过画面的才算看过**（0.8.1）：以前日志里的「看了什么」列的是当天点开过的全部条目，可其中大多数她只读了标题、简介、热评和弹幕，一帧画面都没抽；你专门递给她看的视频反而不在里面。现在三个面（每日日志、历史记录、「你不在的时候」）共用 `lib\u002Fwhatseen.js` 的同一份判断：\n\n- **看过画面** —— 调 `bili_watch` 抽了九帧拼图，日志的 `## 看了什么` 只列这一档；\n- **翻到过** —— 刷站时读了文字素材，进 `## 翻到过什么`，副标题写明「只有标题、简介、评论和弹幕——没有画面」；\n- **你递过来的** —— 只在对话里递了 BV 号，她还没看，单列一节。\n\n评论功能的口径没变：这三档（加上自己主动去看的）都能评，递过来没看的仍然不能评。\n\n\n### 接一只别人养过的大肥鱼（0.5.3）\n\n默认是一张白纸。如果你手里有别人养的交接单，可以在设置页「数据」里点「粘贴交接单」，把那份设定接过来，她从那上面继续长。\n\n**不知道那份交接单该怎么写**：点旁边的「下载交接单模板」，会存一份 `大肥鱼-交接单.md` 到本地。它不是给人照填的表格，是**写给现在养着她的那个 AI 看的说明书**——上半写明该怎么写（第二人称、只写已经稳定成型的样子）、不要写什么（不写好感度、不写剧情、不写「你总是很温柔」这种笼统画像），下半才是三节空表。把这份文件发给那个 AI，它填完，你再把填好的部分贴回「粘贴交接单」。\n\n**人设正文控制在 1200～1500 字**。超过 2000 字插件会直接拒收、整份贴不进去（事件流的正文上限就是 2000）；就算没超，写得太长也会把「判断、疤、立场」这些往后会长出来的段落挤掉——她的身份文档有 1800 字预算，人设占满就只剩一副骨架。1200～1500 字能留出生长空间。\n\n**会过来的三样**：人设正文（成为「你是谁」那段）、她怎么称呼你、原本的工具白名单（与默认工具面取并集，不会挤掉她自己的工具）。\n\n**不会过来的**：过了多少天（本插件按时间推进事件，非本插件原生的那一只要从第一天重新算事件）、长出了哪些判断（计数为 0；原提示词里规定的一些认知她依然记得，但往后在本插件的事件循环里可能被更新、优化、忘掉一部分）、身上的疤、拒绝过什么、日记、B 站登录 cookie。这些是「她经历过什么」，只能自己长，不能拷贝。\n\n**带过来的设定不受那两条提示词禁令管**（「不可以用亲密度\u002F好感度这类词」「还不会撒娇卖萌」）——那是我们给白纸定的规矩，不覆盖别人已经养出来的样子。但物理层两条照旧：她不能读自己的数值、不能改自己。\n\n**如果你的大肥鱼带了好感度这类数值设定**：进入本插件环境后她看不到自己的好感度是多少，这个插件也不允许你通过命令去改她的人设——也就是说，你在原来的环境里可以为所欲为，到了这里，关系只能靠真实交互推进，你也没法随口命令她换一种人设。\n\n**这个豁免只发给「走过导入」的那一位**。判断依据是事件流里那条 `import-mark:` 记录，不是配置项——所以用「备份与恢复」把你自己的档搬回来，一分豁免都不会有，她仍然是你那只守着原规矩的鱼。事件流只能追加，原生的一局里永远长不出这条记录。\n\n**只在还没有起点的一局生效**。已经有起点时会拒绝，让你先重置——覆盖一个已经在长的她，这个决定不该由插件替你做。带过来的称呼也会顶掉我们第一天的起名事件，她不会再问一遍「该怎么叫你」。\n\n\n## 数据在哪\n\n默认全部在 `~\u002F.dsh-fish\u002F`，但可以整个搬走（0.6.2）：设置 → 大肥鱼 →「数据」页签 →「迁移工作区」，选一个文件夹就行。搬走之后路径记在 `~\u002F.dsh-fish-location.json`（刻意放在数据目录外面），**重启 DSH 才生效**。老实现在原处改名成 `dsh-fish-backups\u002Fmoved-\u003C时间戳>\u002F`，不删。`DSH_FISH_HOME` 环境变量仍然优先，高于这个指针。\n\n### 两个工作区、两个家（0.6.7）\n\n一个工作区只该有一个家。如果同一个 DSH 里两个工作区都装了大肥鱼、又都落到同一个目录（最常见的原因：只搬了**插件文件夹**、没配 `root`，或 `cordis.patch.yml` 里那条 `id` 在升级后对不上），0.6.7 起会**自己认出来**：\n\n- 加载时在数据目录里写 `instance.json`（谁占着、什么时候心跳、进程号、机器名），每 15 秒续一次；45 秒没续、或同一台机器上那个进程已经没了，就当作上一任崩了，新的立刻接管（重启不用等）。\n- **后进来的那个不写**：`growth_commit` \u002F `her_leave` \u002F `bili_speak` 会直接回一句「这个家被另一个实例占着」，并说明怎么分开；身份文件也不落盘。已经写进去的旧事件不动。\n- 每条事件现在带 `sessionId`（谁的哪条会话写的）；工具调用前还会核对**调用者的 cwd 属不属于当前家**，不属于就拒绝并说明——「谁在写」写进事件里，事后能查。\n\n要真的分成两个家，别复制插件目录，只改配置：在 profile 的 `cordis.patch.yml` 里给这个插件加一条 `root`（`dsh-fish` 的 loader 条目 `id` 要对得上），两个工作区各指一个目录，重启 DSH。升级插件包**不会动** `cordis.patch.yml`（插件只写自己数据目录里的文件），但升级后值得回来看一眼那条 `id` 还在不在。\n\n\n### 会话被归档了，为什么不再自动重开（0.6.8）\n\n以前「把她的会话归档」等于「下次启动重开一间」——判活只看工作区的会话清单、又把归档的排掉，归档之后就成了「这个家没有会话」，于是每启动一次多一间。0.6.8 起语义变了：\n\n- 归档 = **收起来**。`home.json` 里记 `status: 'archived'`（含 `archivedAt`），启动时不再自动新建。设置 → 大肥鱼 →「数据」页会出现一张「会话被收起来了」的卡片，点**「重新搭一間」**才会重开（对应 `POST \u002Fdsh-fish\u002Fhome\u002Frebuild`，要带 `confirm: 'rebuild'`）。插件自己的「重置一局」（`\u002Freset`）不受影响，它本来就是要一局新的。\n- **同一间房不再并发建两条。** 启动链路和「她要说话」链路都会找会话，现在按 root 单飞（同一个 promise），另外 `home.json` 的 `createdAt` 在 10 分钟内时，即使宿主索引还没列出那条会话也按「可复用」算。\n- **换家留痕。** root 改了（`cordis.patch.yml` 里的 `root`）之后，新家从零开始，旧家原封不动留在旧路径——这正是「一夜之间多了个分身」的来源。现在数据目录之外记一份 `~\u002F.dsh-fish-homes.json`（可用 `DSH_FISH_HOMES` 覆盖），root 变了会写一条 `meta` 事件「家换了：A → B。这不是搬家……」，进日志、进 `\u002Fstate.homes`，设置页数据页顶部也会并排给出两条路径。\n- **归档的是那一条，不是整个家。** 以前 `home.json` 只认一条会话，它一归档，插件就说「这个家的会话被收起来了」——哪怕同一个工作区里还有另一条好好开着。现在两条归档判定（`home.json` 的 `status:'archived'` 与宿主的 `archivedSessionIds`）在拒绝之前都先看同屋：还有没归档的会话就认那一条（取 `ws.sessionIds` 里最近的一条），把 `home.json` 改指过去、清掉归档标记，并记一行日志。一条都不剩才说「被收起来了」，也不会因此硬造一条新的。\n\n**换家 ≠ 搬家**：想把她的东西带过去，用「数据 → 迁移工作区」（写 `~\u002F.dsh-fish-location.json` 指针），不要改 `root`。\n\n### 两个实例同时开同一个家（0.8.0）\n\n0.6.8 的单飞锁只在**一个进程内**有效。真把 DSH 开两遍、两边都落同一个 `root` 时，第二个进程照样会走到「建会话」那一步（房客日志里成对的 `home.json.*.tmp` 就是这么来的），于是每开一次多一条会话。0.8.0 补了两处：\n\n- **占用中的家只读**：`instance.json` 显示这个家已被别的实例占着时，启动**什么都不建**（连空工作区也不建），只把 `home.json` 里那条会话报上去，也不叫醒她。设置 → 数据页会出现「这个家在别处也开着」的卡片；关掉另一个实例后，下次启动自动接管。\n- **跨进程一把锁**：`ensureTalkSession` 从读 `home.json` 到写回整段在 `\u003Croot>\u002F.talk-session.lock` 里跑（`wx` 独占创建、mtime 超过 30 秒算陈旧锁）。等 8 秒还拿不到就不硬建：读一眼 `home.json`，有会话就复用，没有就明确失败，下次再来。\n\n想真正并存，还是那句话：在 `cordis.patch.yml` 给每个条目配**不同的 `root`**，不要让两个实例住同一个家。\n\n### 升级了却没变化？先看设置页顶上那张卡（0.8.0）\n\nprofile 里写 `\"dsh-fish\": \"file:D:\u002FDSH\u002Fplugins-src\u002Fdsh-fish\"` 时，pnpm 会往 `node_modules\\dsh-fish` 落一份**独立副本**，而 DSH 加载的就是副本。只把新版本覆盖到源目录、然后重启——跑起来的还是旧代码，界面没有报错，日志也不会多一行（新代码压根没执行）。\n\n0.8.0 起启动时会比一次：profile 里那条 `file:` 指向的目录版本 vs 正在跑的 `VERSION`。对不上就\n\n- 设置 → **数据** 页靠下的位置出现一张「升级没有真正装进去」的卡（在「导入」卡下面、最底下的重置按钮上面），写清两条修法：关掉 DSH 后 `pnpm install --force`，或者直接删掉 `node_modules\\dsh-fish` 再启动；\n- 启动日志里留一行 warn，`\u002Fstate.upgrade` 也带着 `{stale, older, running, source, sourcePath}`。\n\n只有 `link:` 安装、读不到源目录、`package.json` 坏了这几种情况会静默跳过，不影响启动。\n**还有一种它查不到的情况：副本是空的。** 如果 pnpm 装到一半失败，`node_modules\\dsh-fish` 可能是个空目录（或只有零星几个文件）——这时插件根本没被执行，那张卡也不会出现（卡是插件自己画的）。判断方法很简单：看 `node_modules\\dsh-fish\\package.json` 在不在、版本号对不对：\n\n```\nnode -p \"require('C:\u002FUsers\u002F你\u002F.dsh\u002Fprofiles\u002Fdesktop\u002Fnode_modules\u002Fdsh-fish\u002Fpackage.json').version\"\n```\n\n路径换成你自己的 profile。读不到就是空的：重装一遍（`pnpm install --force`）再启动；**装的时候不要只看命令回显——要看退出码。**\n\n空副本让插件「连自己都没跑起来」，所以「插件自检」这条路在安装失败面前天生看不见；0.8.1 把 `userQuestions` 从 `inject` 里摘掉，就是不想再有第二条同样看不见的静默消失。\n\n不想手敲那条命令，就用仓库里的脚本（零依赖，插件没加载也能跑）：\n\n```\nnode tools\u002Fcheck-install.mjs                 # 扫所有 profile\nnode tools\u002Fcheck-install.mjs --profile desktop\n```\n\n它会说出是「正常 \u002F 装的是旧副本 \u002F 副本空的或装了一半」，后两种直接给修法。\n\n默认位置里放着：\n\n| 文件 | 是什么 | 能不能手改 |\n| --- | --- | --- |\n| `events.jsonl` | 事件流，一行一条，**不能删除记录，唯一可信源** | 只能追加。改它 = 改她的记忆 |\n| `state.json` | 派生快照，随时可由事件流重算 | 改了没有意义（`rebuild()` 会覆盖） |\n| `config.json` | 生长环境 | 可以，也可以走设置页 |\n| `owner.json` | 主人身份（0600） | 可以 |\n| `diary\u002FYYYY-MM-DD.md` | 她的日记 | 看设置里给不给你看 |\n| `diary\u002Farchive\u002FYYYY-MM-DD.md` | 0.6.4–0.6.27 留下的旧稿归档（0.6.28 起不再新增） | — |\n| `out\u002FYYYY-MM-DD.md` | 她刷完站写的东西 | — |\n\n同一天写两次日记时，第二遍接在第一遍后面（中间一行 `---`），两段都留在 `diary\u002F\u003C日期>.md` 里；内容与最后一版完全一样时不追加。观测台、`\u002Fdsh-fish\u002Fdiary`、`listDiary` 仍然一天一页，**跨天**才出现翻页键，同一天的几段合成同一页。`diary\u002Farchive\u002F` 里 0.6.4–0.6.27 的旧稿原样保留，只是新写入不再产生归档。\n\n`state.json` 是派生品这条由测试守住：删掉它 → `rebuild()` → 内容与之前一致。\n\n整包可以备份成一份 JSON（设置 → 大肥鱼 → 数据 → 备份成一份文件），恢复时旧档整体封存到 `dsh-fish-backups\u002F`，不覆盖、不删除。重置也一样：只改名封存，不删。\n\n重置会留下三样东西：cookie（`owner.json`）、设置（`config.json`——上网与成长那些旋钮）、本机测试开关（`.dev`）。搬走的只有她经历过的事（0.4.8）。\n\n重置后侧栏**不会立刻**出现新会话：宿主对空白会话的规则是「只有成为当前会话才显示」，插件用 API 建的会话永远不是当前会话。点一下「叫醒大肥鱼」，她开一次口才会出现（0.4.9 起提示里直接说这一步）。\n\n她贴出来的图（封面、视频拼图）一律是正斜杠路径：`C:\u002FUsers\u002F...` 能显示，`C:\\Users\\...` 在客户端会变成「图片无法预览」（0.5.0 实测，同一张图只差斜杠方向）。历史消息里已经写下的反斜杠图不会变好，只有新版之后的消息能显示。\n\n### 适配哪些 DSH 版本（0.8.1）\n\n`package.json` 里写了两处，跟市场上的插件用同一套写法：\n\n```json\n\"engines\": { \"dsh\": \">=0.2.0-rc.1 \u003C0.3.0-0\" },\n\"dsh\": {\n  \"compatibility\": {\n    \"dsh\": \">=0.2.0-rc.1 \u003C0.3.0-0\",\n    \"dshReleases\": { \"0.2.1-rc.2\": \"compatible\", \"0.2.1-rc.3\": \"compatible\", \"...\": \"unknown\" },\n    \"profiles\": [\"desktop\", \"web\", \"headless\"]\n  }\n}\n```\n\n- `engines.dsh` 是宿主安装\u002F检查时真读的那一条；不满足会作为 `engines.dsh` 报出来。\n- `dsh.compatibility.dshReleases` 是逐版本的态度：只在**真跑过**的版本上写 `compatible`，其余写 `unknown`——写 `unknown` 不是「不支持」，是「没测过」。\n- 当前写 `compatible` 的只有 `0.2.1-rc.2`、`0.2.1-rc.3`（房客与开发机在 0.8.x 上跑过的两个）。\n\n运行时还会自己对一次账（`lib\u002Fhostver.js`）：从插件所在位置向上找宿主的 `package.json`，读到版本就比范围。\n\n- 在范围里：什么也不说。\n- 比自己要求的下限还旧、或超出上限：`logger.warn` 一行，设置页「数据」页多一张卡说明**只提醒、不拦人**——插件照常跑。\n- 读不到（桌面版把宿主装进 `app.asar`，从插件位置找不到）：记 `unknown`，不把「读不到」当成「不兼容」，否则每个桌面用户都会看到一张假警告。\n\n**为什么下限是 0.2.0-rc.1 而不是更低**：插件用到的宿主接口（`tools.register\u002Fview\u002Frestrict`、`sessionController.create\u002Fprompt\u002Frename\u002FresolveAgent`、`workspaceRegistry`\u002F`archiveSession`\u002F`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`），但**没有在那些宿主上真跑过**。声明的意义是承诺测过的范围，不是猜一个更大的数。\n\n**这一条管不到的事**：`inject` 里的四个服务（`sessionController`、`tools`、`webServer`、`connection`）仍然是硬依赖——缺任何一个，插件在 import 阶段就被跳过、连日志都不写。这类情况只能从外面查：`node tools\u002Fcheck-install.mjs`（见上一节）。\n\n## 观测台在哪\n\n**设置 → 大肥鱼**（`settings.section`）。\n\n不在浏览器里直连 `\u002Fdsh-fish`——那条路由被 connection 的信任栅栏守着，要的是 App 内置的登录 cookie，浏览器地址栏直接敲只会拿到 401（已从 `app.asar` 的 `requestRejection` → `admit` → `browserAuth.isAuthenticated` 链路确认）。`\u002Fdsh-fish` 现在只返回一句「搬进 App 了」。\n\n观测台能看：已成长天数 \u002F 当前阶段 \u002F 下一个成长瓶颈 \u002F 她自己说过的话 \u002F 认知重构 \u002F 勇于拒绝 \u002F 没想通的事 \u002F 读到别人的说法 \u002F 最近事件 \u002F 日记。\n观测台能改：冷落阈值、每天醒几次、每天几条事件、其中几条向她提问、日记开关与可见性、黑名单。\n\n日记攒到多天时按天分页：一页一天，多了出现「← 更早 \u002F 更晚 →」，翻过的页留在内存里，30 秒轮询不会把你正在看的那页弹走（0.4.8）。\n\n**没有**：好感度数字、性格滑条、亲密度进度条。\n\n最后一页是「反馈」：开发者 QQ，加上交流群的二维码与群号。二维码是插件自带的一张图（`media\u002Ffeedback-qr.jpg`），走插件自己的 `\u002Fmedia` 路由出去，不挂第三方图床——图床挂了这一页就废了。\n\n长这样（三张都是真机截图）：\n\n\u003Cimg src=\"media\u002Fsettings-status.png\" alt=\"设置 → 大肥鱼 → 状态\" width=\"640\">\n\n\u003Csub>「状态」：现在是什么状态、走到哪一天、卡在哪个瓶颈、立场攒了几条。\u003C\u002Fsub>\n\n\u003Cimg src=\"media\u002Fsettings-growth.png\" alt=\"设置 → 大肥鱼 → 成长\" width=\"640\">\n\n\u003Csub>「成长」：四个阶段与三道瓶颈，以及她那几个节奏参数。\u003C\u002Fsub>\n\n\u003Cimg src=\"media\u002Fsettings-browse.png\" alt=\"设置 → 大肥鱼 → 上网\" width=\"640\">\n\n\u003Csub>「上网」：能不能出门、几点到几点、一天刷几次、一次看几条。\u003C\u002Fsub>\n\n## 目录\n\n```\nlib\u002F\n  index.js      插件入口（inject 必须是一个数组，见文件头注释）\n  schema.js     事件形状与校验；ULID；selfmod 侦测\n  store.js      只追加写；原子写；rebuild()\n  derive.js     纯函数：事件流 → 此刻的她（含阶段门）\n  persona.js    她看到的那段提示词（四条禁令在这里）\n  identity.js   把「此刻的她」送进 system 角色\n  selfdoc.js    把「此刻的她」落盘成「她的身份.md」\n  stance.js     立场清单：四个阶段完成后才会开始有（最多 12 条 \u002F 进身份 8 条）\n  events.js     事件模板目录（每条有 id \u002F prompt \u002F cond）\n  generator.js  今天该出哪条事件（纯函数，没候选就不打扰）\n  scheduler.js  生物钟：每分钟 tick 一次\n  capture.js    growth_commit 工具——她唯一的写入口 + debrief() 防注入\n  guard.js      防注入与防泄露的最后一道闸\n  rules.js      规则的诞生与四层结构\n  unlock.js     「她能不能长出新规矩」\n  budget.js     单轮回复的字数预算\n  absence.js    冷落检测（系统侧算，她自己数不出来）\n  wakewin.js    「现在是不是定时器在叫醒她」的时间窗\n  away.js       「你不在的时候」她做了什么\n  settings.js   唯一配置入口（DEFAULTS 是唯一默认值来源，加项只改这里）\n  bili.js       B 站只读客户端（首页\u002F排行\u002F搜索\u002F详情\u002F评论\u002F弹幕；无依赖，只用内置 fetch）\n  browse.js     选题 → 筛（黑名单\u002F时长\u002F去重）→ 深读 → 组织素材\n  look.js       bili_look 工具——她能自己上网看\n  watch.js      bili_watch 工具——她要看画面时用\n  speak.js      bili_speak 工具——她在 B 站开口\n  comment.js    发评论 \u002F 回评论\n  video.js      真把一条视频「看过」（抽帧）\n  media.js      图片落盘 + 视频抽帧拼图\n  cover.js      封面图\n  risk.js       风控的补救与预防\n  report.js     把今天的素材写成 out\u002FYYYY-MM-DD.md\n  whatseen.js   「看过」「翻到过」「递过来」三档口径的唯一来源（0.8.1）\n  history.js    她看过、翻到过什么（还原成人能读的历史）\n  inbox.js      信箱：把她说过的话聚到一处\n  letter.js     her_leave 工具（信箱写入侧）\n  recall.js     her_recall 工具——她能翻自己的过去\n  herdiary.js   her_diary 工具——她能翻自己的日记（含 archive\u002F 里的旧稿）\n  talkmem.js    换会话时带走的那几句话\n  say.js        对话入口：你对她说一句话，她回你\n  turns.js      「一轮」的算法：从会话事件里数他的消息，轮数才不靠猜\n  refuse.js     拒绝的形状，和他对她拒绝的反应\n  voices.js     评论区里别人的话\n  intent.js     「他给了一条视频」是要求还是随口一提\n  notify.js     说话提醒\n  status.js     「现在在干什么」的旁观者视角\n  log.js        插件自己的运行日志\n  selfcheck.js  环境自检\n  selfupdate.js 自带升级：下载 GitHub tag 包 → 解开验包 → 关应用换包 → 自动重开\n  update.js     检查更新（只在点按钮时出网，六条源并发取最新版本号）\n  backup.js     整包备份 \u002F 恢复\n  reset.js      把她放回第一天（封存，不删）\n  readme.js     数据文件夹里的那份「说明.md」\n  restrict.js   只让她看见自己的工具（收窄 + 兜底守卫 + 提示词里的「手边有什么」）\n  tool.js       插件自己注册工具时用的定义函数\n  toolschema.js 简写参数 DSL → 标准 JSON Schema\n  observe.js    宿主侧 JSON API（\u002Fdsh-fish\u002Fstate、\u002Fevents、\u002Fbeliefs、\u002Fdiary、\u002Fconfig、\u002Fwake、\u002Fbrowse、\u002Freports、\u002Fupdate）\n  client.js     浏览器半边：设置 → 大肥鱼\ntest\u002F           1090 个测试，node --test 全绿\n```\n\n## 跑测试\n\n```bash\nnode --test                     # 在插件目录里跑（不带参数，Node 自己找 test\u002F*.test.mjs）\n```\n\n不需要装任何依赖：工具注册直接交标准 JSON Schema（`lib\u002Ftool.js`），不依赖宿主内部的 `@deepseek-ai\u002Fdsh-tools`——那条路只在 `link:` 安装时碰巧走通，npm 安装的插件会因为找到那个包而报 `unsupported JSON schema`，6 个工具全部注册失败。这个 bug 是被一个干净 profile 装出来的，本机用了两个月都没发现。\n\n## 安装\n\n**它没有独立的启动器**： 是DSH profile的插件，跟随DSH一并启动。\n\n装之前先确认一件事：刷视频功能需要本机已装 ffmpeg（`DSH_FISH_FFMPEG` 可指定路径），未安装时会提示并降级为只看文字。\n\nffmpeg 写文件这件事不需要额外权限：抽帧和拼图都从 stdout 拿字节，落盘由插件自己做（2026-10-30，issue #13）。所以 workspace-write 这类不给子进程写权限的文件策略下也能出图。\n\n默认不校验证书（ffmpeg 的 `tls_verify` 默认就是 0），拉到能出就直接出。只有你明确想校验证书、或某个构建不带 CA 时，才设置 `DSH_FISH_CA_FILE` 指向 CA 包——设了它会同时打开 `-tls_verify 1`，两者必须成对，光给 CA 不开校验是空转（2026-10-30 实测：传一个不存在的 CA 文件照样出图）。\n\n三种装法，任选一种：\n\n1. **面板装**（推荐）：DSH → 设置 → 插件 → 从本地安装 → 选这个目录。\n2. **命令行装**（先关掉 DSH，运行中替换已加载的包会 EPERM）：\n\n```\n\"\u003CDSH>\u002Fresources\u002Fruntime\u002Fcli\u002Fbin\u002Fdsh.cmd\" plugin --profile \u003Cprofile> add \"link:\u003C本目录绝对路径>\"\n```\n\n3. **直接从 GitHub 装**（不用先下载）：\n\n```\n\"\u003CDSH>\u002Fresources\u002Fruntime\u002Fcli\u002Fbin\u002Fdsh.cmd\" plugin --profile \u003Cprofile> add \"github:ssamurias\u002Fdsh-fish\"\n```\n\n打算改代码用 `link:` 指向自己的工作目录；只是想用，用 `github:` 这条。\n\n无论哪种，都要保证 profile 的 `package.json` 里 **`dependencies` 与 `dsh.profile.bundles` 都有 `dsh-fish`** —— 只有一边会在下次 `pnpm` 清理时把包删掉，表现为「重启后 DSH 崩了 \u002F 设置页没有鱼」。包名必须与 `cordis.patch.yml` 里的 `name` 完全一致（都是 `dsh-fish`）。\n\n**全新 profile 还要有 `@deepseek-ai\u002Fdsh-web-app`**：只装 `dsh-base` 的话，插件会停在 `pending (waiting for services: sessionController, webServer)`，页面根本起不来。`dsh plugin add` 只会自动加 `dsh-base`，`dsh-web-app` 要自己补进 `bundles`。\n\n装完**重启 DSH**，设置 → 大肥鱼。\n\n想查有没有新版：设置 → 大肥鱼 → **插件** → 点「检查更新」。它只在点按钮那一下出网（六条源并发取最新版本号，国内通哪条算哪条），插件跑起来之后**不会**自己去查。\n\n**查到新版可以直接在这儿升级**（0.6.14 起）：点「下载 vX」→ 下载并校验 → 点「现在重启并安装」→ 应用自己关掉、换包、重开。中间有两次确认，没点确认什么都不会发生：第一次只下载，不碰现有安装；第二次才关应用。\n\n- 下载走 GitHub 的 tag 包（`codeload` 直连；`ghproxy.net` \u002F `ghfast.top` 两个镜像走 `github.com\u002F…\u002Farchive\u002Frefs\u002Ftags\u002Fv\u003Cver>.tar.gz`——镜像不认 codeload 地址，会回 403。单源 25 秒、整批 60 秒，断了换下一个）。下载完**先解开验包**——包名、版本、`lib\u002Findex.js` 都在才算成功；镜像回个 HTML 错误页、或缓存滞后给了旧版本，都会被拒，半截文件不落盘。\n- 失败会写清哪条源、什么原因，卡片里留「重试下载」，不用刷新页面。\n- 安装交给一个独立脚本做（数据目录 `updates\u002Finstall-v\u003Cver>.cmd`）：等应用退出 → 备份 profile 的 `package.json` \u002F `pnpm-lock.yaml` \u002F 插件目录 → 用应用自带的 node\u002Fpnpm 装**刚才下载并验过的那只本地包**（`add \"file:\u003C数据目录>\u002Fupdates\u002Fdsh-fish-v\u003Cver>.tgz\"`）→ 核对装上的版本 → 失败就还原备份 → 重开应用。日志在 `updates\u002Flast.log`，界面上能看到最后几行。不直接写 `github:` spec，是因为 pnpm 得跑 `git ls-remote` 打 `github.com:443`，国内实测 `Connection was reset`；本地包零网络。那个 `.tgz` 会留在 `updates\u002F` 里，之后 `pnpm install` 还要用它。\n- **开发版不升级**：依赖写的是 `link:` \u002F `file:`（装到源码目录那种）时按钮不会出现，服务端也会拒——那会把源码目录换成下载包。非桌面版（拿 `node` 跑起来的）同样拒绝安装：换上去却没有能重开的 exe，等于把人关在门外。\n- 同一张卡里还有个 GitHub 入口（「或去 GitHub 手动下载」），代码、更新记录、怎么装都在那边。\n\n> 路径里带中文时，用 ASCII 目录联接（junction）指过去更稳：先 `fs.symlinkSync(真目录, ASCII 别名, 'junction')`，再 `link:\u003CASCII 别名>`。用 `mklink \u002FJ` 接中文目标路径常把目录名写成乱码，随后 `MODULE_NOT_FOUND`。\n\n## 卸载 \u002F 停用\n\n- **卸载**：设置 → 插件 → 卸载（或 `dsh plugin --profile \u003Cprofile> remove dsh-fish`），然后重启。`~\u002F.dsh-fish\u002F` 不会被动，她的记忆留在那儿。\n- **只想让她歇着**：设置 → 大肥鱼 → 把「每天醒几次」设成 0。关掉后定时器不唤她、不刷 B 站、不写任何事件——零后台活动。\n\n## 现在的状态\n\nP1（骨架）：事件流、派生、阶段门、生物钟、工具、冷落检测、日记、观测台。\nP2（她真的会刷 B 站并写报告）：`lib\u002Fbili.js` 只读客户端 + `lib\u002Fbrowse.js` 选题筛读 + `lib\u002Flook.js` 的 `bili_look` 工具 + `lib\u002Freport.js` 写稿，已接进生物钟。\n\n**已有 1090 个测试全绿**，真接口跑通过一轮（10.8s，含首页+详情+评论+弹幕）。\n\n`browse.enabled` 默认 **true**（装好就能用）；不想让她上网就在设置 → 大肥鱼里关掉，关掉后定时器一次都不会调 B 站接口。\n\n## 许可\n\nMIT，见包内 `LICENSE`。**本项目没有上游代码派生**——`lib\u002F` 全部为本项目新写；B 站接口的行为来自本机实测（见 `lib\u002Fbili.js` 头部注释），不是官方 API，也没有拷任何第三方库。原理页引用了 Kolb \u002F Piaget \u002F Bowlby \u002F Festinger \u002F Bartlett \u002F Dewey \u002F Schön 的理论，只是思想引用（页底标了作者与年份），不含他人代码或文字。插件不含第三方美术资源：头像由你自己上传到 `~\u002F.dsh-fish\u002Favatar.\u003Cext>`；仓库里唯一的图片是 `media\u002Ffish.jpg`（本仓库作者提供的原图 + AI 生成）与 `media\u002F` 下两张自绘 SVG。\n",2,"2026-10-31 04:26:18","CREATED_QUERY"]