在窗口角落陪你干活,随对话进度切换神态
29.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/1 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Hrauroras/dsh-plugin-ostan-nanami-san该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
是什么
dsh 原生插件 · desktop
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 34 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件发起外部网络请求
查看扫描证据(共 3 处,展示前 3 条)
- 读取本地文件lib/index.js:595
bytes = await readFile(new URL(file, assetDir)) - 发起网络请求lib/client.js:518
window.fetch(url, { headers: { accept: 'application/json' } }) - 发起网络请求lib/client.js:727
window.fetch(`${API}/interact`, {
扫描于 2026/11/2(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 窗口角落陪伴
- 随对话进度切换神态
OStan 七海 — DeepSeek Harness GUI 的 Q 版桌面伴侣
README
由 DeepSeek 最新模型翻译生成OStan Nanami-San 🐾
DeepSeek Harness GUI 的 Q 版桌面伴侣——你工作时她工作,你成为瓶颈时她等待,回合落定时她欢呼。
OStan Nanami-San,四种姿态
打包的四种姿态:idle(等待)、work(工作中)、wait(需要你点击)、cheer(已完成)。
中文简介
OStan Nanami-San(小名「奈奈酱」)是住在 DSH 窗口右下角的小桌宠:
- 四套神态:待机、干活中(举手示意)、等你(害羞托腮)、完成(举拳欢呼),全部来自同一角色的四张参考立绘。
- 跟着真实进度动:某一轮对话开始 → 进入「干活中」并显示进行中的会话数;正常结束 → 欢呼台词;报错 → 担心脸;需要你确认 → 强制切换为「等你」。
- 互动:单击摸头(+好感度)、右键菜单投喂 / 换状态 / 调大小 / 隐藏、左键拖动换位置。
- 好感度:摸头 +2、投喂 +6,共 6 级称号(初次见面 → 命定之人),进度条实时显示在菜单里。
- 睡觉与干活共存:长时间没互动会打瞌睡,而干活不会叫醒她——你点她一下才醒,并保持清醒一段时间。唯一例外是上面的「等你」。
- 安静:prefers-reduced-motion 下自动关动画;贴图与文字都随框架语言切换。
展开完整文档(README 剩余 1 节)
OStan Nanami-San 🐾
DeepSeek Harness GUI 的 Q 版桌面伴侣——你工作时她工作,你成为瓶颈时她等待,回合落定时她欢呼。
OStan Nanami-San,四种姿态
打包的四种姿态:idle(等待)、work(工作中)、wait(需要你点击)、cheer(已完成)。
中文简介
OStan Nanami-San(小名「奈奈酱」)是住在 DSH 窗口右下角的小桌宠:
- 四套神态:待机、干活中(举手示意)、等你(害羞托腮)、完成(举拳欢呼),全部来自同一角色的四张参考立绘。
- 跟着真实进度动:某一轮对话开始 → 进入「干活中」并显示进行中的会话数;正常结束 → 欢呼台词;报错 → 担心脸;需要你确认 → 强制切换为「等你」。
- 互动:单击摸头(+好感度)、右键菜单投喂 / 换状态 / 调大小 / 隐藏、左键拖动换位置。
- 好感度:摸头 +2、投喂 +6,共 6 级称号(初次见面 → 命定之人),进度条实时显示在菜单里。
- 睡觉与干活共存:长时间没互动会打瞌睡,而干活不会叫醒她——你点她一下才醒,并保持清醒一段时间。唯一例外是上面的「等你」。
- 安静:prefers-reduced-motion 下自动关动画;贴图与文字都随框架语言切换。
它实际上是什么
一个 DSH 插件包,具备标准的双面结构:
| 半边 | 文件 | 职责 |
| 宿主 | lib/index.js | 将实时回合边界投射为一份桌宠状态快照,并提供 /api/ostan-nanami-san/ 以及打包的精灵图 /ostan-nanami-san-assets/。 |
| Web 客户端 | lib/client.js | 将伴侣挂载到框架级 shell.overlay 座位,轮询该快照,渲染精灵图,并掌管所有交互。 |
她是一个窗口内伴侣(与内置的鲸鱼桌宠同类),而非独立的操作系统桌面浮层。
与宿主保持同步
状态是与宿主对账得出的,而不仅仅是从事件累积而来。纯事件账本会以两种方式漂移,而本代码正是为避免这两种漂移而构建:
- 插件挂载时已在运行的会话从未被宣告,因此用户会话在工作时桌宠却呆在待机状态——追踪器在挂载时、每次配置重载时,以及(节流至 1 秒)每次状态轮询时都会采纳实时 agent 注册表(ctx.agents.list()),因此缺口会在一次轮询内愈合,而无需重启;
- 一次遗漏的 turn/end 会让某个会话永远钉在「运行中」——对账会丢弃宿主不再列出的任何 agent。
另外三条规则让这张脸保持诚实:
- 她跟随你正在查看的会话。 这个客户端面没有 sessions.list 可用来读取当前会话,而抓取 DOM 寻找会话标记既脆弱又被禁止——因此该 bundle 在 conversation.chat.turnTail 中安置了一个零像素探针,这是一个会话作用域的插槽,其标准 props 携带 sessionId。探针将该 id 交给浮动伴侣,伴侣在每次轮询时携带它(/state?current=),而宿主将每次读取都收窄到那一个会话。
- 菜单报告的是宿主实际使用的范围,而非客户端请求的范围。 宿主以 following 作答:
- session —— 所报告的 id 是它已记录过的,因此读数属于该会话;
- unknown — 发送了一个 Host 从未见过的 id(一个尚未记录任何轮次的会话)。生效的读数是 Host 全局的,菜单会如实说明这一点,而不是声称一个数字并非来自的范围;
- host — 完全没有报告任何会话。
/state?ids=1 还会返回被跟踪的会话 id。它只为一个调用者而存在——一个用 curl 调试范围的人类——并且只携带会话身份,从不包含标题或消息文本;普通的轮询会省略它。
- 子代理永远不算作用户的工作。 它们的轮次会作为 subagents 出现在快照中用于诊断,但不会驱动宠物:用户没有启动它们,也不会观看它们,所以把它们计入会让宠物看起来忙碌,而可见的会话却处于空闲状态。
- 一个实时问题优先于一个正在运行的轮次。 一个因等待用户而阻塞的轮次没有什么可展示的,所以她会说“正在等你”,而不是看起来忙碌——等待的表情加上一个 正在等你回答… 药丸。该信号是持久的日志真相,而不是实时事件:ask_user_question 会在 ctx.userQuestions 内阻塞该轮次,直到答案到达,因此其未完成的 tool/call 就是待处理的问题,而其匹配的 tool/result 就是答案。turn/end 会无论出于何种原因清除它,因此中止不会让她永远等待下去。
这曾经出过问题,值得记录:早期版本监听了一个 question/request 会话事件,而它并不存在于 SessionEventMap 中。该处理器不可达,所以等待的表情从未出现。tests/host.test.mjs 现在断言,一个凭空发明的事件类型不会改变任何东西。
功能
- 实时状态机。 轮次运行时为 work(带有一个统计忙碌会话数的徽章),结构化问题未回答时为 wait,轮次正常完成后为 cheer 六秒,失败后为担忧表情二十秒,其他情况为 idle。优先级是刻意安排的:等待优先于工作(被阻塞的轮次没有什么可展示),然后是新的失败,再然后是新的成功。用户的取消既不是成功也不是失败,所以她从不为 Ctrl-C 庆祝。
- 步骤读数。 她上方的一个安静药丸会报告工作正在做什么——“正在读文件…”、“正在跑命令…”、“正在搜代码…”——并在轮次结束后保留最后一步一拍(“上一步:正在改代码”)。它只说明步骤的种类,仅此而已;见下面的边界说明。
- 四种姿态,一个角色。 美术素材是从提供的四张参考插图中裁切出来的,因此状态变化是真正的表情变化,而不是着色或晃动。
- 好感度。 抚摸(+2,800 毫秒冷却)和零食(+6,1.5 秒冷却)会累积成六个带称号的等级;升级时会在对话气泡中宣布。
- 随处拖动,随处放下。 位置按浏览器持久保存;调整大小时宠物会被限制在视口内。
- 右键菜单。 实时状态跟随与手动心情覆盖、大小(84–320 px)、暂停动作、重置位置、隐藏——以及一个 🐾 按钮把她叫回来。
- 两种语言。 词典跟随框架语言();切换语言会实时重新读取它。
- 天生安静。 空闲时的闲聊会受到速率限制,并且在 Host 忙碌时保持静默,而减少动态效果会禁用精灵动画。
安装
该包以预构建形式发布:无需构建步骤,无安装脚本,运行时无网络访问。
通过 Harness 插件管理器(它掌管该 profile 的 package.json、其 bundle 列表以及 pnpm run) plugin_manager action: install_bundle target:
或者发布后直接从 GitHub 安装
dsh plugin install github:Hrauroras/dsh-plugin-ostan-nanami-san
在这台 Windows 桌面安装中,它落到了 desktop profile(即应用实际启动时所用的那个——$env:DSH_PROFILE 才是权威依据,而非猜测):
"dependencies": { "dsh-plugin-ostan-nanami-san": "link:C:/Users/A2178/Downloads/dsh-plugin-ostan-nanami-san" },
"dsh": { "profile": { "bundles": ["...", "dsh-plugin-ostan-nanami-san"] } }
link: 规格会安装一个 junction,因此在此处编辑源码会在下次页面加载时到达正在运行的 Host;只有 Host 那一半需要重启 DSH 才能重新导入。
确认它已生效:
curl 'http://127.0.0.1:19387/api/ostan-nanami-san/health'
{"ok":true,"version":"0.6.0","sessions":1}
已经在运行鲸鱼伙伴了?两者可以共处同一框架;她会把自己安排在 order: 88,而鲸鱼宠物在 order: 90。
用法
| 手势 | 效果 |
| 单击 | 摸她的头(好感度 +2) |
| 拖拽 | 移动她;位置会固定下来 |
| 右键单击 | 菜单:摸头、零食、心情覆盖、大小、动态效果、重置、隐藏 |
| 单击徽章区域 | —(徽章统计当前正在工作的会话数) |
隐私与运行时边界
- 仅读取回合、提问和工具边界——会话 id、事件序列以及工具的名称。不读取消息文本、不读取工具参数、不读取文件内容、不读取历史记录、不进行模型调用。
- 无遥测、无外部请求、无额外监听端口、无模型调用、无审批处理。
- 精灵字节通过允许列表(idle|work|wait|cheer + .png)从包中提供;调用方提供的路径永远不会到达磁盘。
- 精灵响应会针对内容哈希 ETag 进行重新验证(no-cache, must-revalidate),而非针对文件名:重新绘制的姿势必须能到达已经持有旧姿势的浏览器。客户端还会在 URL 上附加 ASSET_VERSION,这是唯一能触达已在较旧策略下缓存的浏览器的杠杆。
- 轮询从不因可见性而暂停。 早期版本将 start() 限制在 document.visibilityState === 'visible' 条件下,因此挂载时未报告为可见的帧根本不会轮询——而且由于 visibilitychange 只在变化时触发,没有任何机制能挽救它。症状是“她只在我点击时才更新”,因为点击强制在过期的快照上重新渲染。现在定时器无条件开启,一个 5 秒的看门狗会对其进行校正,并且即使文档报告自身为隐藏状态,会话切换也会立即重新读取。
- 好感度、零食、大小、位置和可见性都保存在浏览器的 localStorage 中,位于 ostan-nanami-san: 下。
- 宿主保留一个有界的内存投影(最多 512 个会话);不会向磁盘写入任何内容。
开发
node --test tests/host.test.mjs tests/client.test.mjs tests/routes.test.mjs # 81 tests
python tools/make_sprites.py # re-cut sprites from sources
python tools/make_preview.py # regenerate docs/poses.png
node tools/trace-state.mjs 40 400 # sample the live snapshot
node tools/simulate-poll.mjs 12 # replay one tab's poll
要查看给定作用域实际返回的内容,直接询问 Host——这也是作用域规则针对真实会话而非猜测的 id 进行验证的方式:
curl 'http://127.0.0.1:19387/api/ostan-nanami-san/state?ids=1' # tracked session ids
curl 'http://127.0.0.1:19387/api/ostan-nanami-san/state?current=' # that session only
curl 'http://127.0.0.1:19387/api/ostan-nanami-san/state?current=ghost' # following=unknown
tools/make_sprites.py 从原始参考插图中重新生成 assets/.png。在任何重新裁剪之后,请提升 lib/client.js 中的 ASSET_VERSION,否则持有旧精灵图的浏览器会继续显示它。
抠图是边界洪水填充,而非颜色阈值。角色绘制中包含大面积的白色区域——衬衫、衣领、袖子、两条过膝袜——被深色线稿包围,因此全局的“与白色的距离”测试会将这些区域打穿成洞。纸白色仅是与图像边界相连的区域,因此脚本从边框开始填充,并让每个被包围的白色像素保持不透明。tools/diagnose_visual.py 将蒙版与抠图并排渲染在洋红色背景上,正是为了进行这项检查,而 tools/diagnose_alpha.py 报告填充吞掉了图集的多少部分(泄漏的填充会吞掉大部分)。构建输出会打印保留的亮色像素数量——对于阈值式裁剪它是 0,而对于正确的裁剪则是数千。
tests/client.test.mjs 会针对一个小型 React 替身渲染真实组件,而这个替身的 hooks 确实能工作:useState 会触发重新渲染,useCallback 会按其依赖数组进行记忆化,effects 会在提交后刷新,并且仅当其依赖发生变化时才会重新运行。正是这三条语义,使得设置状态的 effect 可被观察到,而不是变成无限循环。
这些测试覆盖了边界投影(包括恶意输入)、路由契约(包括路径遍历、超大请求体和条件请求),以及客户端这一半的端到端行为——模块 id、apply/inject 形态、一个没有 shell.overlay 席位的 Host,以及每个渲染状态各一条断言(idle/work/wait/error/cheer),外加 pat、drag、feed、menu、尺寸边界、隐藏与召唤、两个字典以及步骤胶囊。其中两条是隐私断言:fixtures 中使用的工具调用参数不得出现在状态负载的任何地方,并且子代理的步骤绝不能变成用户可见的状态。
其中一条是 hook 顺序守卫:隐藏渲染和可见渲染中的 hook 数量必须完全相同。这不是风格偏好。隐藏分支中曾经有一个提前 return 位于若干 hooks 之上,因此隐藏她会让 React 在下一次渲染时看到更少的 hooks,并抛出 #321,“Invalid hook call”。症状令人抓狂——轮询仍在继续运行(它的 effects 仍然存活),画面冻结在最后一次正常渲染上,而点击或刷新页面会“修复”它,直到下一次隐藏。修复是结构性的:隐藏状态是在渲染结束时选择的一个值,绝不是中途采取的退出。这里添加的任何提前 return 都必须位于所有 hook 之上。
当某些东西确实出问题时
这个伙伴被包裹在一个错误边界中,而该边界会在屏幕上渲染失败文本,而不仅仅是记录它。一个冻结的画面加上仍然活着的轮询,从外部几乎无法诊断;而一个可见的 ⚠ 奈奈酱出错了 加上堆栈则不是这样。右键菜单以微缩形式承载了同样的想法——轮询 / 应用 / 渲染 计数器将“轮询死了”与“请求失败了”与“状态更新了但渲染没有发生”区分开来。
边界必须接收一个元素,绝不能接收一次调用。 早先的一个版本写的是
render() { return this.props.render() } // WRONG — #321 "Invalid hook call"
这会在 React 的渲染上下文之外运行伙伴的 hooks。现在有两条教训被固化进测试中:
- 测试装置无法强制执行 hook 上下文,因此它改为断言形态:边界的子节点必须是一个具有元素类型的元素,绝不能是调用组件的结果;
- 手工打造的替身是一种有盲点的工具,通过它并不构成证据。它在这个 bug 期间一直保持绿色。这就是为什么错误也会被渲染到人类可以读到的地方,也是为什么框架自身的裁决胜过测试装置的裁决。
睡眠与工作共存——问题在于那唯一的例外应要求:忙碌的 Host 不会叫醒她。她会在长时间运行中打盹,用户通过交互叫醒她——那一下戳会设置 awakeUntil,也正是它让她在下一个 tick 不会再次打瞌睡。因为睡觉和工作如今真正共存,空闲闲聊台词在运行期间也被允许:一个睡着的伙伴嘟囔“Zzz……”不再与她所摆的姿势相矛盾。
唯一永远胜出的是等待人类回答的问题:
if (status === 'waiting') mood = 'wait' // outranks sleep AND a manual mood
else if (forced !== 'follow') mood = forced
else if (snapshot === null || snapshot.ok === false) mood = 'idle'
else if (!awake) mood = 'sleep'
else mood = statusMood[status] ?? 'idle'
她会从深睡中醒来发问,并且在得到回答后保持清醒,而不是立刻又倒回去。那次唤醒存在于effect 中,绝不在 render 主体里:在渲染时写入 store 会调度另一次渲染,而那次渲染又会触发另一次轮询——这种副作用不该出现在渲染中,而且它曾让一个测试读到离线的姿态,而不是它刚刚发布的快照。
这个顺序是在两个相反方向上各错了一次之后才得出的:先是打盹压过了工作(于是工作在被点击之前不可见),然后是工作压过了打盹(于是她再也不会在运行中睡着)。两者都是同一个错误——在没有问清用户实际想看到哪种状态的情况下就决定了优先级顺序。
步骤读数在哪里划线
这个药丸回答“正在运行的是哪种步骤”,到此为止。它读取 tool/call 会话事件的 name 字段,并通过 TOOL_LABELS 映射;该事件的 arguments 是模型输出,永远不会进入投影、快照或浏览器——映射表不认识的工具会回退到其原始线上名称,而不是去猜测含义。没有消息文本,没有文件内容,没有命令行,没有回复片段。这就是为什么药丸显示“正在跑命令……”,而从不显示命令是什么。
tools/asar_tool.py 和 tools/asar_grep.py 读取 DSH 自己的 app.asar(列出、提取、正则 grep)——本包中的插件契约就是这样对照已发布的实现来核验的,而不是靠猜测。
美术作品声明
这四个姿势派生自插件所有者为本个人伙伴提供的参考插图。该角色并非本项目原创。 因此,美术作品不受代码的 MIT 许可证覆盖:它仅出于个人使用和演示目的而包含,不得用于商业用途或为营利而再分发。如果你打算将其发布给更广泛的受众,请先自行确认参考插图的来源和许可。
许可证
代码:MIT,见 LICENSE。美术作品:仅限个人使用,见上方声明。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
Hrauroras/dsh-plugin-ostan-nanami-san
在窗口角落陪你干活,随对话进度切换神态
相关插件 · 桌面端
Codex 任务面板chuspeeism/dashi-taskboard
现代化可灵活嵌入的任务面板,支持 Codex、DeepSeek Harness
★ 3,409已汉化DSH
71.7
多智能体自进化开发平台Prism-Shadow/penguin-harness
统一、稳定的 Agent 自进化框架全自动优化:任意模型 · 任意算法 · 任意 Benchmark
★ 3,111已汉化DSH
71.1
桌面宠物PC2005-cloud/dsh-pet
DSH 桌面宠物:一行命令装好即用的透明动画小桌宠,支持多开、大小位置随心配置;还内置 DIY 素材链,能用 AI…
★ 5,341已汉化DSH
71
多端 Agent 工作台GCWing/OpenBitFun
OpenBitFun 是一个高度可定制的开源 Agent 工作台,让任务按你的方式持续推进。
★ 3,449已汉化DSH
70.8
DSH Desktopanywhere-labs/dsh-desktop
为 DeepSeek Harness DSH 插件生态打造的现代化桌面端解决方案。万物皆「插件」,桌面本身也是「插件」。
★ 34,532已汉化DSH
70.7
桌面宠物伴侣OpenPetsHQ/openpets
桌面伴侣平台,带宠物、插件,还能选配本地智能体集成。
★ 1,353已汉化DSH
70.2
这是你的仓库?认领条目