@sophiacyl/dsh-plugin-waves 0.0.0-stage → 0.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/DSH-GO-VERIFICATION.md +57 -0
  2. package/ICON.png +0 -0
  3. package/LICENSE +674 -0
  4. package/README.md +251 -2
  5. package/cordis.patch.yml +8 -0
  6. package/install.ps1 +0 -0
  7. package/install.sh +209 -0
  8. package/lib/client.js +1511 -0
  9. package/lib/host/aliashint.js +70 -0
  10. package/lib/host/attachments.js +25 -0
  11. package/lib/host/command.js +34 -0
  12. package/lib/host/consts.js +16 -0
  13. package/lib/host/dataguide.js +35 -0
  14. package/lib/host/imagebridge.js +41 -0
  15. package/lib/host/native-result.js +91 -0
  16. package/lib/host/native.js +191 -0
  17. package/lib/host/proxy.js +59 -0
  18. package/lib/host/results.js +67 -0
  19. package/lib/host/service.js +263 -0
  20. package/lib/host/tool.js +185 -0
  21. package/lib/host/troubleshoot.js +31 -0
  22. package/lib/host/worldbook.js +80 -0
  23. package/lib/index.js +74 -0
  24. package/locale/en.json +6 -0
  25. package/locale/zh.json +6 -0
  26. package/package.json +136 -4
  27. package/service/ICON.png +0 -0
  28. package/service/ai/AI_DATA.md +221 -0
  29. package/service/knowledge/additional/manual.jsonl +5 -0
  30. package/service/knowledge/wiki/baike.jsonl +1231 -0
  31. package/service/knowledge/wiki/chengjiu.jsonl +36 -0
  32. package/service/knowledge/wiki/gonglve.jsonl +383 -0
  33. package/service/knowledge/wiki/huodong.jsonl +427 -0
  34. package/service/knowledge/wiki/renwu.jsonl +412 -0
  35. package/service/knowledge/wiki/tujian.jsonl +2889 -0
  36. package/service/knowledge/wiki/zixun.jsonl +47 -0
  37. package/service/plugins/__init__.py +0 -0
  38. package/service/pyproject.toml +40 -0
  39. package/service/rover/__init__.py +0 -0
  40. package/service/rover/ai_core/__init__.py +0 -0
  41. package/service/rover/ai_core/models.py +50 -0
  42. package/service/rover/ai_core/rag/__init__.py +5 -0
  43. package/service/rover/ai_core/rag/knowledge.py +23 -0
  44. package/service/rover/ai_core/register.py +86 -0
  45. package/service/rover/ai_core/resource.py +6 -0
  46. package/service/rover/ai_core/skills/__init__.py +0 -0
  47. package/service/rover/ai_core/skills/operations.py +8 -0
  48. package/service/rover/api.py +720 -0
  49. package/service/rover/api_render.py +161 -0
  50. package/service/rover/app_life.py +154 -0
  51. package/service/rover/aps.py +47 -0
  52. package/service/rover/avatar.py +85 -0
  53. package/service/rover/bot.py +133 -0
  54. package/service/rover/builtin.py +152 -0
  55. package/service/rover/cards/__init__.py +26 -0
  56. package/service/rover/cards/_shared.py +129 -0
  57. package/service/rover/cards/char_list.py +258 -0
  58. package/service/rover/cards/char_panel.py +1353 -0
  59. package/service/rover/cards/echo_list.py +206 -0
  60. package/service/rover/cards/matrix_roles.py +25 -0
  61. package/service/rover/cards/rank_boards.py +714 -0
  62. package/service/rover/cards/rank_total.py +664 -0
  63. package/service/rover/compat.py +215 -0
  64. package/service/rover/config.py +163 -0
  65. package/service/rover/custom_panel.py +220 -0
  66. package/service/rover/data_store.py +31 -0
  67. package/service/rover/gss.py +19 -0
  68. package/service/rover/handler.py +191 -0
  69. package/service/rover/help/__init__.py +0 -0
  70. package/service/rover/help/draw_new_plugin_help.py +332 -0
  71. package/service/rover/help/model.py +16 -0
  72. package/service/rover/help/utils.py +7 -0
  73. package/service/rover/hooks.py +420 -0
  74. package/service/rover/html_actions.py +236 -0
  75. package/service/rover/i18n.py +19 -0
  76. package/service/rover/knowledge.py +235 -0
  77. package/service/rover/logger.py +102 -0
  78. package/service/rover/main.py +33 -0
  79. package/service/rover/media.py +222 -0
  80. package/service/rover/message_models.py +23 -0
  81. package/service/rover/models.py +92 -0
  82. package/service/rover/native_media.py +64 -0
  83. package/service/rover/ocr.py +79 -0
  84. package/service/rover/pool.py +43 -0
  85. package/service/rover/restart.py +36 -0
  86. package/service/rover/segment.py +143 -0
  87. package/service/rover/server.py +131 -0
  88. package/service/rover/status/__init__.py +0 -0
  89. package/service/rover/status/models.py +10 -0
  90. package/service/rover/status/plugin_status.py +17 -0
  91. package/service/rover/subscribe.py +148 -0
  92. package/service/rover/sv.py +403 -0
  93. package/service/rover/templates/char_list.html +182 -0
  94. package/service/rover/templates/char_panel.html +465 -0
  95. package/service/rover/templates/echo_list.html +221 -0
  96. package/service/rover/templates/rank_all_total.html +193 -0
  97. package/service/rover/templates/rank_board.html +107 -0
  98. package/service/rover/templates/rank_level_total.html +57 -0
  99. package/service/rover/templates/rank_matrix_total.html +66 -0
  100. package/service/rover/templates/rank_phantom_total.html +180 -0
  101. package/service/rover/templates/rank_slash_total.html +38 -0
  102. package/service/rover/trigger.py +98 -0
  103. package/service/rover/utils/__init__.py +0 -0
  104. package/service/rover/utils/boardcast/__init__.py +0 -0
  105. package/service/rover/utils/boardcast/models.py +15 -0
  106. package/service/rover/utils/cookie_manager/__init__.py +0 -0
  107. package/service/rover/utils/cookie_manager/qrlogin.py +24 -0
  108. package/service/rover/utils/database/__init__.py +0 -0
  109. package/service/rover/utils/database/base_models.py +1771 -0
  110. package/service/rover/utils/database/models.py +80 -0
  111. package/service/rover/utils/database/startup.py +60 -0
  112. package/service/rover/utils/default_bg/bg.jpg +0 -0
  113. package/service/rover/utils/download_resource/__init__.py +0 -0
  114. package/service/rover/utils/download_resource/download_core.py +164 -0
  115. package/service/rover/utils/download_resource/download_file.py +46 -0
  116. package/service/rover/utils/fonts/__init__.py +0 -0
  117. package/service/rover/utils/fonts/fonts.py +33 -0
  118. package/service/rover/utils/image/__init__.py +0 -0
  119. package/service/rover/utils/image/convert.py +51 -0
  120. package/service/rover/utils/image/image_tools.py +30 -0
  121. package/service/rover/utils/image/utils.py +70 -0
  122. package/service/rover/utils/plugins_config/__init__.py +0 -0
  123. package/service/rover/utils/plugins_config/gs_config.py +506 -0
  124. package/service/rover/utils/plugins_config/models.py +182 -0
  125. package/service/rover/web_app.py +3 -0
  126. package/service/rover/webconsole/__init__.py +0 -0
  127. package/service/rover/webconsole/mount_app.py +26 -0
  128. package/service/tools/migrate.py +351 -0
  129. package/service/tools/regression.py +87 -0
  130. package/service/tools/smoke.py +63 -0
  131. package/service/tools/update_plugins.py +212 -0
  132. package/service/tools/verify_actions.py +104 -0
  133. package/service/tools/verify_card.py +82 -0
  134. package/service/tools/wwdata.py +665 -0
  135. package/tests/compat.test.js +181 -0
  136. package/tests/imagebridge.test.js +58 -0
  137. package/tests/media.test.js +68 -0
  138. package/tests/native.test.js +127 -0
  139. package/tests/runtime.test.js +69 -0
  140. package/tests/service.test.js +48 -0
package/README.md CHANGED
@@ -1,3 +1,252 @@
1
- # Temporary Holding Version
1
+ <p align="center">
2
+ <a href="https://github.com/Loping151/XutheringWavesUID"><img src="./ICON.png" width="200" height="200" alt="dsh-plugin-waves"></a>
3
+ </p>
4
+ <h1 align="center">dsh-plugin-waves</h1>
5
+ <p align="center">XutheringWavesUID 的 DeepSeek Harness 版本 · v0.0.3</p>
2
6
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
7
+ 这是 [XutheringWavesUID](https://github.com/Loping151/XutheringWavesUID) 的 dsh 版:同一套鸣潮查询、
8
+ 面板、伤害计算与评分、排行,由 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)
9
+ 提供原生渲染能力。
10
+
11
+ 已内置 [RoverSign](https://github.com/Loping151/RoverSign)(签到)与 [ScoreEcho](https://github.com/Loping151/ScoreEcho)(声骸识图评分)。
12
+
13
+ 图文结果直接以 HTML 卡片呈现;卡片里的角色可以点击,其余命令、算法、素材、模板全部与 [XutheringWavesUID](https://github.com/Loping151/XutheringWavesUID) 一致。
14
+
15
+ 为模型提供了原生数据接口,模型完全可读用户数据。可自行搭配其他工具使用,比如让AI将数据自行填入其他排轴/伤害计算等网页工具(需对应工具支持)。
16
+
17
+ 开新会话首次发送指令将同时发送你好,此为dsh目前固有限制,否则无法显示指令结果。
18
+
19
+ ## npm 测试版与市场安装
20
+
21
+ 本适配版以独立包 `@sophiacyl/dsh-plugin-waves@0.1.0-beta.1` 发布,来源为 `Sophiacyl/dsh-plugin-waves` 的 `release/npm` 分支;原始项目与作者信息保留,许可证为 GPL-3.0。
22
+
23
+ ```sh
24
+ dsh plugin --profile web add @sophiacyl/dsh-plugin-waves@0.1.0-beta.1
25
+ ```
26
+
27
+ 请勿与原版 `dsh-plugin-waves` 同时启用:两者提供相同的 `/ww` 命令、后端端口和网页路由。已安装原版时先停用原版;本包不会自动迁移其登录态或修改其数据。首次安装需要联网下载 Python 依赖、无头浏览器和上游游戏资源,体积会明显大于 npm 包。`ww登录` 可能使库街区 App 的登录态失效;重新登录库街区也可能使插件凭据失效。
28
+
29
+ 测试版的聊天媒体卡片最终显示仍待用户验收,不以静态市场扫描冒充视觉验收。
30
+
31
+ ## dsh-go 原生适配(本分支)
32
+
33
+ 本分支是基于 [Loping151/dsh-plugin-waves](https://github.com/Loping151/dsh-plugin-waves) 的 dsh-go 测试适配,保留上游历史及 GPL-3.0 许可证。适配代码位于本 fork 的 `dsh-go` 分支;聊天新媒体卡片的 App 内最终显示仍待确认,详见 [验证记录](./DSH-GO-VERIFICATION.md)。
34
+
35
+ 支持 DSH `0.2.2-rc.1` 和 dsh-go 原生界面:
36
+
37
+ - 输入框上方「鸣潮」胶囊打开查询面板;「全部功能」内提供「鸣潮查询」「鸣潮设置」。
38
+ - `waves` / `waves_panel` 聊天结果通过 `dsh-go/media` 返回本机文件图片;原生查询面板使用 `asset:文件名` 由 App 带权限读取。两条显示通道分开处理,避免把面板资源引用用于无插件归属的聊天工具卡片。`/ww` 始终保留摘要,可在查询面板点「刷新结果」查看最近的图。
39
+ - HTML 面板在本机无头 Chromium 中截图后生成不超过 1 MiB、4096 像素边长及 400 万像素的原生图片。原来的 Web 卡片和配置页仍保留。
40
+ - 原生设置支持分组、分页、单项保存。敏感项不回显,使用系统文件选择器导入单项 UTF-8 文本;文件上传项也使用系统选择器。文件选择需要支持 files 能力的较新 App。
41
+ - Linux ARM64 + Python 3.12 已实测 8 个计算扩展加载、OCR 初始化与识别、39 个上游功能模块、帮助命令截图。账号数据查询和伤害结果仍需用户自行登录并配置相应 token。
42
+ - 安装准备改为异步、有超时、可取消;失败不启动服务,连续崩溃 5 次后停止重试。Python 默认复用受支持的系统版本。
43
+
44
+ 手机安装本适配分支(保留克隆目录,它同时保存插件环境和运行数据):
45
+
46
+ ```sh
47
+ PLUGIN_DIR="${DSH_HOME:-$HOME/.dsh}/dsh-go/plugins/dsh-plugin-waves"
48
+ git clone --branch dsh-go --single-branch \
49
+ https://github.com/Sophiacyl/dsh-plugin-waves.git "$PLUGIN_DIR"
50
+ dsh plugin --profile web add "link:$PLUGIN_DIR"
51
+ ```
52
+
53
+ 目录已存在时先检查现有安装,不要覆盖或删除。`$DSH_HOME` 未设置时默认为 `~/.dsh`。代码更新后可重载该插件;无需为素材下载重启整个引擎。首次启动会下载上游素材,健康接口的 `resources_ready` 独立报告准备状态。
54
+
55
+ 宿主与原生协议回归(路径按本机安装调整):
56
+
57
+ ```sh
58
+ DSH_TEST_RUNTIME=/opt/dsh \
59
+ DSH_GO_KIT=$HOME/.dsh/skills/dsh-go-plugin/kit npm test
60
+ WAVES_AUTOSTART=0 node $HOME/.dsh/skills/dsh-go-plugin/kit/bin/check.mjs . --load
61
+ ```
62
+
63
+ `WAVES_AUTOSTART=0` 仅用于隔离验证,防止检查器启动第二个后端。初次环境安装使用 `bash install.sh --env-only`;浏览器若缺系统库,需另执行 `service/.venv/bin/python -m playwright install-deps chromium`。本分支使用 `rapidocr` 3.x 和 headless OpenCV,避免旧 OCR 引入图形版 OpenCV。
64
+
65
+ ## 用例
66
+
67
+ <table>
68
+ <tr>
69
+ <td nowrap valign="top">
70
+ <img src="./assets/demo-help.png" width="525" height="720" alt="帮助卡片">
71
+ <img src="./assets/demo-matrix-team.png" width="2000" height="1063" alt="矩阵配队建议">
72
+ <img src="./assets/demo-echo-swap.png" width="440" height="720" alt="声骸互换分析">
73
+ <img src="./assets/demo-echo-swap-result.png" width="488" height="720" alt="分析结论">
74
+ </td>
75
+ </tr>
76
+ </table>
77
+
78
+ ## TODO
79
+
80
+ - [ ] 修修补补,完成迁移
81
+ - [ ] 补充游戏常识库:挑战规则、矩阵挑战的模板声骸配置、模态规则等(缺少尝试胡言乱语为已知问题,可以通过鼓励搜索解决,但不如固化常识知识)
82
+ - [ ] 补充库街区wiki文字攻略接口,注入常规配队知识
83
+ - [ ] 尝试寻找文字轴数据源
84
+ - [ ] 提供更多接口工具,便于在此之上自行搭建其他项目
85
+
86
+ 本仓库仅迁移 XutheringWavesUID 内置方法和接口,以及处理通用知识,使用本插件数据接口继续开发应新建插件以实现功能解耦。
87
+
88
+ ## 安装
89
+
90
+ 上游已验证 DSH `0.1.0-rc.7`、`0.2.0-rc.2` 与 `0.2.1-rc.2`。本适配分支另通过了 DSH `0.2.2-rc.1` 的真实宿主库兼容测试(工具定义、参数校验、模拟服务调用与结果展示元数据),不代表 Python 后端和手机原生界面已完成验证。需要 Node.js 22.19+ 或 24.2+(DSH 0.2.1 在 24.0/24.1 上会静默退出)。DSH 0.2 支持斜杠命令携带图片和单个文件;旧版可继续执行无附件命令。
91
+
92
+ Linux / macOS:
93
+
94
+ ```sh
95
+ mkdir -p ~/dsh-plugins && cd ~/dsh-plugins # 放哪都行, 换成你自己的目录
96
+ git clone https://github.com/Loping151/dsh-plugin-waves.git && cd dsh-plugin-waves
97
+ dsh plugin --profile web add file:.
98
+ dsh web
99
+ ```
100
+
101
+ Windows(PowerShell):
102
+
103
+ ```powershell
104
+ mkdir -Force ~\dsh-plugins; cd ~\dsh-plugins
105
+ git clone https://github.com/Loping151/dsh-plugin-waves.git; cd dsh-plugin-waves
106
+ dsh plugin --profile web add file:.
107
+ dsh web
108
+ ```
109
+
110
+ 第一次启动时插件会自己把环境装好(一般来说):建虚拟环境、装依赖、拉取三个上游插件、生成数据目录,
111
+ 几分钟后服务就绪,不需要手动跑任何脚本。之后在对话里绑定账号即可用:
112
+ `ww登录` 保存登录态,与库街区登录冲突,同时登录办法需自行查找,`ww绑定<特征码>` 需要自行提供有效库街区token才可使用,原理为:街区点击他人主页查看信息,故至少需要一个登录态。
113
+
114
+ 安装若卡住或失败,直接问 dsh 里的模型——插件会把完整排障步骤转交给它。
115
+
116
+ 缺什么会尽量自己装:`uv`、Python 3.10–3.13(`uv` 拉官方构建,计算内核按版本分发)、
117
+ 以及 `git`(Linux 走发行版包管理器,Windows 走 winget/choco/scoop)。装不上会说明要手工补什么,也可以直接问 dsh 里的模型。
118
+
119
+ <details>
120
+ <summary>手动安装 / 从机器人部署迁入数据</summary>
121
+
122
+ ```sh
123
+ ./install.sh # 等价于自动安装
124
+
125
+ # 从聊天机器人版迁过来: 指向那边 gsuid_core 的 data 目录,
126
+ # 会迁入绑定关系、登录态、WavesToken、面板与抽卡记录、自定义素材,
127
+ # 并把归属改写到本地使用者名下(源库只读取快照, 不会改动)
128
+ ./install.sh --src ~/gsuid_core/data
129
+ ```
130
+
131
+ Windows 用 `install.ps1`,参数一一对应(若提示无法运行脚本,先 `Set-ExecutionPolicy -Scope Process Bypass`):
132
+
133
+ ```powershell
134
+ powershell -ExecutionPolicy Bypass -File .\install.ps1
135
+ powershell -ExecutionPolicy Bypass -File .\install.ps1 -Src C:\gsuid_core\data
136
+ ```
137
+
138
+ </details>
139
+
140
+ ## 用法
141
+
142
+ 两种用法:
143
+
144
+ - **`/ww 深塔`、`/ww 椿面板`**——斜杠命令,host 直接执行,**不经过模型**,最快。
145
+ - **直接说话**——「看下我的深塔」「椿的面板怎么样」,模型理解后调用工具。
146
+ 注意不带斜杠时哪怕原样打 `ww深塔` 也会先经过模型,慢一些但同样能用。
147
+
148
+ `ww帮助` 出全量命令图,本机的运维命令并在同一张图里。下表命令都可以放在 `/ww ` 后面用:
149
+
150
+ | 类别 | 常用 |
151
+ |---|---|
152
+ | 账号 | `ww查询` `ww体力` `ww探索` `ww库洛币` `ww积分` `ww日历` |
153
+ | 深渊 | `ww深塔` `ww海墟` `ww矩阵` `ww全息` |
154
+ | 面板 | `ww<角色>面板` `ww<角色>伤害` `ww<角色>优化` `ww<角色>权重` `ww刷新面板` |
155
+ | 排行 | `ww<角色>总排行` `ww练度总排行` `ww无尽总排行` `ww矩阵总排行` |
156
+ | 资料 | `ww<角色>攻略` `ww<角色>图鉴` `ww<角色>养成` `ww武器列表` `ww套装列表` |
157
+ | 唤取 | `ww抽卡记录` `ww导入抽卡链接` `ww抽卡登录` |
158
+ | 其它 | `ww签到` `ww兑换码` `ww声骸` `ww练度` `ww评分`(连声骸截图一起发)`ww公告` |
159
+ | 运维 | `ww更新插件` `ww重启服务` `ww服务状态` |
160
+
161
+ 只有单人使用,没有用户身份概念:签到覆盖全部已登录账号、不筛活跃。
162
+ 群成员管理、群排行、公告订阅、订阅签到结果、联系主人这类只在群聊里成立的命令不注册。
163
+ 内置 HTTP 接口见 [docs/api.md](./docs/api.md)。
164
+
165
+ 带截图的命令(`ww评分`、`ww分析`)可通过 `/ww 评分` 或 `/ww 分析` 携带图片直接执行,不经过模型。
166
+ 普通聊天图片保持原始附件,不会被插件替换成提示文字,也不会改写模型能力。使用支持图片的模型时,
167
+ 插件仅暂存当前输入的附件引用,在明确调用 `waves(with_image=true)` 时转交鸣潮服务;文本模型是否接收图片由宿主决定。
168
+ 模型还可以用 `waves_panel` 工具按自定义数据(跨角色借声骸、手填词条)渲一张假设面板——
169
+ 只在本地渲染,不写用户数据、不上传总排行。
170
+
171
+ 图片卡(评分/面板等)会经本地轻量 OCR(RapidOCR)把文字抽进给模型的摘要,
172
+ 纯文本模型也能读到卡上数值;设置里"图片文字摘要(OCR)"可关。
173
+
174
+ 内置游戏知识库(`service/knowledge/`):库洛 wiki 全站文本按小节整理(图鉴/攻略/百科等
175
+ 5000+ 节,图片以原 URL 内嵌)+ 人工补充的机制常识(挑战周期、换期语义、配队细则)。
176
+ 用户话里首次提到角色名/机制词时自动附带对应条目(每会话每条只注入一次),模型也可主动检索。
177
+ 设置里"内置知识增强(测试)"可关掉自动注入,主动检索不受影响。
178
+
179
+ ## Token
180
+
181
+ 伤害计算、评分与排行都要 `WavesToken`,**评分与排行是同一个 token,只填一处**:
182
+ `service/data/XutheringWavesUID/config.json` 的 `WavesToken`。
183
+
184
+ token 的申请方式与使用条件与本体一致,请阅读:
185
+
186
+ - [XutheringWavesUID 本体仓库](https://github.com/Loping151/XutheringWavesUID)——申请入口与条件都在它的 README
187
+ - [0428 声明](https://github.com/Loping151/XutheringWavesUID/blob/main/assets/0428.md)——本插件相关的重要声明
188
+
189
+ 没有 token 时查询类功能照常可用,适合单人使用。
190
+
191
+ ## 更新
192
+
193
+ `service/plugins/` 是三个上游仓库的原样克隆,本地差异全部写在运行时里,所以上游更新不会冲突。
194
+ 在对话里发 `ww更新插件`,完成后 `ww重启服务`;或者:
195
+
196
+ ```sh
197
+ cd service && .venv/bin/python tools/update_plugins.py
198
+ ```
199
+
200
+ 默认从 GitHub 拉;连不上时自动改用 `cnb.cool/gscore-mirror`,反过来镜像不通也会切回 GitHub(已有仓库会把 origin 一并改掉)。
201
+ 只有网络类错误才切源,仓库不存在、认证失败、无法快进这些会照原样报出来。
202
+
203
+ 上游若用到了本运行时还没提供的接口,不会静默失败:更新命令会把缺失的模块和适配步骤
204
+ 直接交给 dsh 里的模型,让它改好运行时再让你重启。
205
+
206
+ ## 配置
207
+
208
+ | 文件 | 内容 |
209
+ |---|---|
210
+ | `service/data/config.json` | 服务自身:监听地址、命令前缀、日志、命令超时、缓存上限 |
211
+ | `service/data/XutheringWavesUID/config.json` | 查询与计算:token、代理、渲染、面板刷新 |
212
+ | `service/data/RoverSign/config.json` | 签到 |
213
+ | `service/data/ScoreEcho/config.json` | 识图评分 |
214
+
215
+ 这些也可以在 dsh 侧栏的**插件 → 鸣潮**页里直接改,共 60 余项(只留下本地场景用得上的),敏感项显示为掩码。
216
+ 数据目录首次运行自动生成,不需要预先准备。
217
+
218
+ ## 结构
219
+
220
+ ```
221
+ assets/ README 用例图
222
+ docs/ 人读文档(内置 HTTP 接口)
223
+ lib/ dsh 侧:斜杠命令、模型工具、反代 /waves-api、托管服务、浏览器卡片
224
+ service/ai/ 给模型读的数据/脚本指南
225
+ service/knowledge/ 内置游戏知识库(wiki 文本 + 人工补充,AI 检索与自动注入)
226
+ service/rover/ 运行时:命令分发、数据库、配置、调度、渲染、接口
227
+ service/plugins/ 上游插件原样克隆(勿手改,改动请写进 hooks)
228
+ service/tools/ 安装、迁移、更新与自检脚本
229
+ ```
230
+
231
+ 本地与上游的全部差异集中在 `service/rover/hooks.py`。
232
+
233
+ ## 自检
234
+
235
+ 宿主适配回归测试(不读取账号数据):
236
+
237
+ ```sh
238
+ npm test
239
+ ```
240
+
241
+ ```sh
242
+ cd service
243
+ .venv/bin/python tools/regression.py # 批量跑只读命令
244
+ .venv/bin/python tools/verify_actions.py # 校验卡片点击与角色对应
245
+ .venv/bin/python tools/verify_card.py # 真实浏览器验证渲染与点击
246
+ .venv/bin/python tools/update_plugins.py --check-only # 上游更新后的兼容性自检
247
+ ```
248
+
249
+ ## 许可
250
+
251
+ [GPL-3.0](./LICENSE),与上游 [XutheringWavesUID](https://github.com/Loping151/XutheringWavesUID) 一致。
252
+ `service/plugins/` 安装时克隆的其它上游仓库遵循各自许可。使用前请阅读上游说明与声明。
@@ -0,0 +1,8 @@
1
+ - insert:
2
+ - id: waves-plugin
3
+ name: '@sophiacyl/dsh-plugin-waves'
4
+ config:
5
+ port: 9777
6
+ autoStart: true
7
+ # 设为 false 则模型看不到本插件, 只能用 /ww 命令(省上下文)
8
+ exposeToModel: true
package/install.ps1 ADDED
Binary file
package/install.sh ADDED
@@ -0,0 +1,209 @@
1
+ #!/usr/bin/env bash
2
+ # 一键安装: 缺的先自己装, 再建虚拟环境、拉插件、注册进 dsh。
3
+ # 可选迁入既有部署: ./install.sh --src /path/to/gsuid_core/data
4
+ set -euo pipefail
5
+
6
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ SERVICE="$ROOT/service"
8
+ PROFILE="${DSH_PROFILE:-web}"
9
+ # 计算内核按 CPython 版本分发, 仅这些版本有对应包
10
+ SUPPORTED=(3.13 3.12 3.11 3.10)
11
+ # Reuse a supported system interpreter, especially the bundled ARM64 Python.
12
+ if [ -z "${PYTHON_VERSION:-}" ]; then
13
+ PYTHON_VERSION="$(python3 -c 'import sys; v=f"{sys.version_info.major}.{sys.version_info.minor}"; print(v if v in ("3.10", "3.11", "3.12", "3.13") else "3.13")' 2>/dev/null || printf '3.13')"
14
+ fi
15
+
16
+ # 由插件在首次启动时调用: 只准备环境, 不碰 dsh 自身
17
+ ENV_ONLY=0
18
+ if [ "${1:-}" = "--env-only" ]; then ENV_ONLY=1; shift; fi
19
+
20
+ step() { printf '\n\033[36m==> %s\033[0m\n' "$1"; }
21
+ fail() { printf '\033[31m%s\033[0m\n' "$1" >&2; exit 1; }
22
+ have() { command -v "$1" >/dev/null 2>&1; }
23
+
24
+ refresh_path() {
25
+ export PATH="$HOME/.local/bin:$HOME/.cargo/bin:/usr/local/bin:/opt/homebrew/bin:$PATH"
26
+ }
27
+
28
+ # 非交互: 有密码的 sudo 会卡住首次启动, 只在 root / sudo -n 可用时装
29
+ pkg_install() {
30
+ if have brew; then
31
+ brew install "$@"
32
+ return $?
33
+ fi
34
+ local sudo=()
35
+ if [ "$(id -u)" -ne 0 ]; then
36
+ have sudo || return 1
37
+ sudo -n true >/dev/null 2>&1 || return 1
38
+ sudo=(sudo -n)
39
+ fi
40
+ if have apt-get; then
41
+ DEBIAN_FRONTEND=noninteractive "${sudo[@]}" apt-get update -qq
42
+ DEBIAN_FRONTEND=noninteractive "${sudo[@]}" apt-get install -y "$@"
43
+ elif have dnf; then
44
+ "${sudo[@]}" dnf install -y "$@"
45
+ elif have yum; then
46
+ "${sudo[@]}" yum install -y "$@"
47
+ elif have pacman; then
48
+ "${sudo[@]}" pacman -Sy --noconfirm "$@"
49
+ elif have zypper; then
50
+ "${sudo[@]}" zypper --non-interactive install "$@"
51
+ elif have apk; then
52
+ "${sudo[@]}" apk add --no-cache "$@"
53
+ else
54
+ return 1
55
+ fi
56
+ }
57
+
58
+ printf '%s\n' "${SUPPORTED[@]}" | grep -qx "$PYTHON_VERSION" \
59
+ || fail "Python $PYTHON_VERSION 不受支持, 可选: ${SUPPORTED[*]}"
60
+
61
+ refresh_path
62
+
63
+ # curl/wget: 装 uv 用
64
+ if ! have curl && ! have wget; then
65
+ step "安装 curl"
66
+ pkg_install curl || fail "缺少 curl/wget, 自动安装失败, 请先装其中一个"
67
+ fi
68
+
69
+ SYSTEM_PYTHON=""
70
+ if have python3 && [ "$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')" = "$PYTHON_VERSION" ]; then
71
+ SYSTEM_PYTHON="$(command -v python3)"
72
+ fi
73
+
74
+ if [ -z "$SYSTEM_PYTHON" ] && ! have uv; then
75
+ step "安装 uv"
76
+ if have curl; then
77
+ curl -LsSf https://astral.sh/uv/install.sh | sh >/dev/null 2>&1 || true
78
+ else
79
+ wget -qO- https://astral.sh/uv/install.sh | sh >/dev/null 2>&1 || true
80
+ fi
81
+ refresh_path
82
+ if ! have uv && have python3; then
83
+ python3 -m pip install --user -q uv >/dev/null 2>&1 || true
84
+ refresh_path
85
+ fi
86
+ fi
87
+ if [ -z "$SYSTEM_PYTHON" ]; then
88
+ have uv || fail "缺少 uv 且自动安装失败, 请先安装受支持的 Python 或 uv"
89
+ fi
90
+
91
+ if ! have git; then
92
+ step "安装 git"
93
+ pkg_install git || fail "缺少 git 且自动安装失败, 请用系统包管理器安装(apt/dnf/brew install git)"
94
+ fi
95
+
96
+ if [ "$ENV_ONLY" != "1" ] && ! have dsh; then
97
+ if have npm; then
98
+ step "安装 dsh (npm -g @deepseek-ai/dsh)"
99
+ npm install -g @deepseek-ai/dsh || true
100
+ refresh_path
101
+ fi
102
+ have dsh || fail "缺少 dsh, 请先安装 DeepSeek Harness: npm i -g @deepseek-ai/dsh"
103
+ fi
104
+
105
+ step "准备 Python $PYTHON_VERSION"
106
+ # 系统没有对应版本时, uv 直接拉官方构建, 不必先装发行版 Python
107
+ if [ -z "$SYSTEM_PYTHON" ]; then uv python install "$PYTHON_VERSION" >/dev/null; fi
108
+
109
+ step "创建虚拟环境 (Python $PYTHON_VERSION)"
110
+ cd "$SERVICE"
111
+ if [ ! -x .venv/bin/python ]; then
112
+ if [ -n "$SYSTEM_PYTHON" ]; then
113
+ "$SYSTEM_PYTHON" -m venv .venv
114
+ else
115
+ uv venv --python "$PYTHON_VERSION" --seed .venv
116
+ fi
117
+ fi
118
+ ACTUAL="$(.venv/bin/python -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')"
119
+ printf '%s\n' "${SUPPORTED[@]}" | grep -qx "$ACTUAL" \
120
+ || fail "虚拟环境是 Python $ACTUAL, 不在支持范围; 删掉 service/.venv 重跑"
121
+
122
+ step "安装依赖"
123
+ # Old RapidOCR required GUI OpenCV; remove that conflicting cv2 distribution
124
+ # before installing the headless-only stack (inside this venv only).
125
+ .venv/bin/python - <<'PY'
126
+ import importlib.metadata as m, subprocess, sys
127
+ for name in ("rapidocr-onnxruntime", "opencv-python"):
128
+ try:
129
+ m.version(name)
130
+ except m.PackageNotFoundError:
131
+ continue
132
+ subprocess.run([sys.executable, "-m", "pip", "uninstall", "-y", name], check=True)
133
+ PY
134
+ .venv/bin/python - <<'PY'
135
+ import pathlib, subprocess, sys
136
+ try:
137
+ import tomllib
138
+ except ImportError:
139
+ subprocess.run([sys.executable, "-m", "pip", "install", "tomli"], check=True)
140
+ import tomli as tomllib
141
+ requirements = tomllib.loads(pathlib.Path("pyproject.toml").read_text())["project"]["dependencies"]
142
+ subprocess.run([sys.executable, "-m", "pip", "install", "--disable-pip-version-check", *requirements], check=True)
143
+ # Both OpenCV distributions own cv2; repairing headless restores any removed files.
144
+ subprocess.run([sys.executable, "-m", "pip", "install", "--force-reinstall", "--no-deps", "opencv-python-headless>=4.9,<5"], check=True)
145
+ PY
146
+ .venv/bin/python - <<'PY'
147
+ import cv2, cryptography, fastapi, sqlmodel, PIL, jinja2, lxml, msgspec, rapidocr, onnxruntime
148
+ print("依赖加载自检通过")
149
+ PY
150
+
151
+ step "准备原生卡片截图浏览器"
152
+ .venv/bin/python -m playwright install --only-shell chromium
153
+ .venv/bin/python - <<'PY'
154
+ import asyncio
155
+ from playwright.async_api import async_playwright
156
+ async def check():
157
+ async with async_playwright() as p:
158
+ browser = await p.chromium.launch(args=["--disable-gpu", "--disable-dev-shm-usage"])
159
+ await browser.close()
160
+ try:
161
+ asyncio.run(check())
162
+ except Exception:
163
+ raise SystemExit("截图浏览器缺少系统库,请在插件目录执行 service/.venv/bin/python -m playwright install-deps chromium 后重试")
164
+ PY
165
+ mkdir -p data/media
166
+
167
+ step "拉取插件"
168
+ .venv/bin/python tools/update_plugins.py
169
+
170
+ step "初始化数据目录"
171
+ .venv/bin/python tools/migrate.py "$@"
172
+
173
+ if [ "$ENV_ONLY" = "1" ]; then
174
+ echo
175
+ echo "环境就绪。"
176
+ exit 0
177
+ fi
178
+
179
+ step "注册进 dsh profile: $PROFILE"
180
+ dsh plugin --profile "$PROFILE" add "file:$ROOT" >/dev/null
181
+ # 加载器按自身位置解析裸包名, 这里补一条链接
182
+ DSH_NM="$(dirname "$(dirname "$(readlink -f "$(command -v dsh)")")")/node_modules"
183
+ PACKAGE_NAME="$(node -p 'JSON.parse(require("fs").readFileSync(process.argv[1], "utf8")).name' "$ROOT/package.json")"
184
+ PROFILE_PKG="${DSH_HOME:-$HOME/.dsh}/profiles/$PROFILE/node_modules/$PACKAGE_NAME"
185
+ if [ -d "$DSH_NM" ] && [ -d "$PROFILE_PKG" ]; then
186
+ mkdir -p "$(dirname "$DSH_NM/$PACKAGE_NAME")"
187
+ ln -sfn "$PROFILE_PKG" "$DSH_NM/$PACKAGE_NAME"
188
+ fi
189
+ NODE_VER="$(node -v 2>/dev/null | sed 's/^v//')"
190
+ NODE_MAJOR="${NODE_VER%%.*}"; NODE_MINOR="$(echo "$NODE_VER" | cut -d. -f2)"
191
+ if [ -n "$NODE_MAJOR" ] && { [ "$NODE_MAJOR" -lt 22 ] || { [ "$NODE_MAJOR" -eq 24 ] && [ "${NODE_MINOR:-0}" -lt 2 ]; }; }; then
192
+ printf '\n\033[33m注意: 当前 node 为 v%s, dsh 需要 22.19+ 或 24.2+, 启动前请切换\033[0m\n' "$NODE_VER"
193
+ fi
194
+
195
+ cat <<EOF
196
+
197
+ 安装完成。
198
+
199
+ 启动: dsh web
200
+ 自检: cd $SERVICE && .venv/bin/python tools/regression.py
201
+
202
+ 首次使用先在对话里绑定账号:
203
+ ww登录 取得并保存登录态
204
+ ww绑定<特征码> 只查询公开数据时用这个
205
+
206
+ 伤害计算与排行需要 WavesToken, 填在
207
+ $SERVICE/data/XutheringWavesUID/config.json
208
+ 申请方式见 README。
209
+ EOF