dsh-world 0.0.0-stage → 0.6.4
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.
- package/CHANGELOG.md +298 -0
- package/CONTRIBUTING.md +161 -0
- package/INSTALL.md +311 -0
- package/LICENSE +21 -0
- package/README.md +229 -2
- package/client/index.js +719 -0
- package/cordis.patch.yml +6 -0
- package/lib/archive.d.ts +6 -0
- package/lib/archive.js +49 -0
- package/lib/archiveSelection.d.ts +14 -0
- package/lib/archiveSelection.js +27 -0
- package/lib/compaction.d.ts +124 -0
- package/lib/compaction.js +273 -0
- package/lib/compactionRegion.d.ts +42 -0
- package/lib/compactionRegion.js +210 -0
- package/lib/console/homeApply.d.ts +24 -0
- package/lib/console/homeApply.js +97 -0
- package/lib/console/routes.d.ts +66 -0
- package/lib/console/routes.js +161 -0
- package/lib/console/snapshot.d.ts +54 -0
- package/lib/console/snapshot.js +58 -0
- package/lib/ecosystem/bridge/bridge.d.ts +38 -0
- package/lib/ecosystem/bridge/bridge.js +142 -0
- package/lib/ecosystem/bridge/route.d.ts +9 -0
- package/lib/ecosystem/bridge/route.js +46 -0
- package/lib/ecosystem/qq/panel.d.ts +71 -0
- package/lib/ecosystem/qq/panel.js +171 -0
- package/lib/ecosystem/qq/route.d.ts +47 -0
- package/lib/ecosystem/qq/route.js +152 -0
- package/lib/ecosystem/qq/snowluma-start.d.ts +7 -0
- package/lib/ecosystem/qq/snowluma-start.js +37 -0
- package/lib/ecosystem/qq/supervisor.d.ts +32 -0
- package/lib/ecosystem/qq/supervisor.js +67 -0
- package/lib/ecosystem/qq-native/batch.d.ts +15 -0
- package/lib/ecosystem/qq-native/batch.js +23 -0
- package/lib/ecosystem/qq-native/home.d.ts +24 -0
- package/lib/ecosystem/qq-native/home.js +30 -0
- package/lib/ecosystem/qq-native/index.d.ts +145 -0
- package/lib/ecosystem/qq-native/index.js +429 -0
- package/lib/ecosystem/qq-native/native-bridge.d.ts +54 -0
- package/lib/ecosystem/qq-native/native-bridge.js +290 -0
- package/lib/ecosystem/qq-native/outbox.d.ts +18 -0
- package/lib/ecosystem/qq-native/outbox.js +59 -0
- package/lib/ecosystem/qq-native/replies.d.ts +29 -0
- package/lib/ecosystem/qq-native/replies.js +29 -0
- package/lib/ecosystem/qq-native/sdkInstall.d.ts +35 -0
- package/lib/ecosystem/qq-native/sdkInstall.js +79 -0
- package/lib/ecosystem/qq-native/snowluma.d.ts +104 -0
- package/lib/ecosystem/qq-native/snowluma.js +636 -0
- package/lib/ecosystem/shared/context.d.ts +28 -0
- package/lib/ecosystem/shared/context.js +84 -0
- package/lib/ecosystem/shared/identity.d.ts +15 -0
- package/lib/ecosystem/shared/identity.js +36 -0
- package/lib/ecosystem/shared/outlets.d.ts +43 -0
- package/lib/ecosystem/shared/outlets.js +70 -0
- package/lib/ecosystem/shared/sessions.d.ts +16 -0
- package/lib/ecosystem/shared/sessions.js +52 -0
- package/lib/ecosystem/shared/turn.d.ts +34 -0
- package/lib/ecosystem/shared/turn.js +119 -0
- package/lib/ecosystem/wechat/archive.d.ts +24 -0
- package/lib/ecosystem/wechat/archive.js +62 -0
- package/lib/ecosystem/wechat/home.d.ts +22 -0
- package/lib/ecosystem/wechat/home.js +38 -0
- package/lib/ecosystem/wechat/images.d.ts +5 -0
- package/lib/ecosystem/wechat/images.js +49 -0
- package/lib/ecosystem/wechat/index.d.ts +43 -0
- package/lib/ecosystem/wechat/index.js +212 -0
- package/lib/ecosystem/wechat/messages.d.ts +35 -0
- package/lib/ecosystem/wechat/messages.js +44 -0
- package/lib/ecosystem/wechat/presence.d.ts +6 -0
- package/lib/ecosystem/wechat/presence.js +56 -0
- package/lib/ecosystem/wechat/reading.d.ts +18 -0
- package/lib/ecosystem/wechat/reading.js +89 -0
- package/lib/ecosystem/wechat/sending.d.ts +31 -0
- package/lib/ecosystem/wechat/sending.js +219 -0
- package/lib/ecosystem/wechat/supervisor.d.ts +39 -0
- package/lib/ecosystem/wechat/supervisor.js +138 -0
- package/lib/faults.d.ts +10 -0
- package/lib/faults.js +13 -0
- package/lib/history.d.ts +16 -0
- package/lib/history.js +80 -0
- package/lib/hostContract.d.ts +25 -0
- package/lib/hostContract.js +1 -0
- package/lib/http.d.ts +18 -0
- package/lib/http.js +39 -0
- package/lib/index.d.ts +204 -0
- package/lib/index.js +449 -0
- package/lib/life/activity.d.ts +14 -0
- package/lib/life/activity.js +97 -0
- package/lib/life/alarm.d.ts +39 -0
- package/lib/life/alarm.js +132 -0
- package/lib/life/alarmTimer.d.ts +22 -0
- package/lib/life/alarmTimer.js +49 -0
- package/lib/life/diary.d.ts +4 -0
- package/lib/life/diary.js +9 -0
- package/lib/life/earlyStop.d.ts +19 -0
- package/lib/life/earlyStop.js +25 -0
- package/lib/life/home.d.ts +36 -0
- package/lib/life/home.js +78 -0
- package/lib/life/host.d.ts +20 -0
- package/lib/life/host.js +23 -0
- package/lib/life/journal.d.ts +20 -0
- package/lib/life/journal.js +59 -0
- package/lib/life/lifeStore.d.ts +16 -0
- package/lib/life/lifeStore.js +105 -0
- package/lib/life/messages.d.ts +17 -0
- package/lib/life/messages.js +53 -0
- package/lib/life/notify.d.ts +25 -0
- package/lib/life/notify.js +79 -0
- package/lib/life/photoTools.d.ts +9 -0
- package/lib/life/photoTools.js +51 -0
- package/lib/life/photos.d.ts +27 -0
- package/lib/life/photos.js +104 -0
- package/lib/life/pricing.d.ts +4 -0
- package/lib/life/pricing.js +30 -0
- package/lib/life/runtime.d.ts +58 -0
- package/lib/life/runtime.js +487 -0
- package/lib/life/toolRegistry.d.ts +26 -0
- package/lib/life/toolRegistry.js +83 -0
- package/lib/life/tools.d.ts +24 -0
- package/lib/life/tools.js +47 -0
- package/lib/life/types.d.ts +88 -0
- package/lib/life/types.js +1 -0
- package/lib/persona.d.ts +10 -0
- package/lib/persona.js +29 -0
- package/lib/promptSection.d.ts +36 -0
- package/lib/promptSection.js +108 -0
- package/lib/qq-line.d.ts +2 -0
- package/lib/qq-line.js +115 -0
- package/lib/runtime.d.ts +24 -0
- package/lib/runtime.js +260 -0
- package/lib/self.d.ts +10 -0
- package/lib/self.js +36 -0
- package/lib/sourceArchive.d.ts +27 -0
- package/lib/sourceArchive.js +173 -0
- package/lib/store.d.ts +30 -0
- package/lib/store.js +191 -0
- package/lib/timeContext.d.ts +3 -0
- package/lib/timeContext.js +13 -0
- package/lib/types.d.ts +127 -0
- package/lib/types.js +1 -0
- package/lib/workspacePermissions.d.ts +18 -0
- package/lib/workspacePermissions.js +22 -0
- package/lib/worldPrompt.d.ts +47 -0
- package/lib/worldPrompt.js +49 -0
- package/lib/worldScope.d.ts +22 -0
- package/lib/worldScope.js +26 -0
- package/lib/worldSwitch.d.ts +50 -0
- package/lib/worldSwitch.js +89 -0
- package/package.json +114 -6
- package/scripts/enable-tool-free-compaction.ps1 +33 -0
- package/scripts/update-world.mjs +168 -0
- package/src/ecosystem/README.md +17 -0
- package/src/ecosystem/wechat/windows/README.md +134 -0
- package/src/ecosystem/wechat/windows/adapter.py +619 -0
- package/src/ecosystem/wechat/windows/binding.py +52 -0
- package/src/ecosystem/wechat/windows/engine/LICENSE +43 -0
- package/src/ecosystem/wechat/windows/engine/NOTICE.md +13 -0
- package/src/ecosystem/wechat/windows/engine/bridge.cpp +229 -0
- package/src/ecosystem/wechat/windows/engine/build.ps1 +19 -0
- package/src/ecosystem/wechat/windows/engine/profiles.json +58 -0
- package/src/ecosystem/wechat/windows/groups.py +27 -0
- package/src/ecosystem/wechat/windows/incoming.py +202 -0
- package/src/ecosystem/wechat/windows/messages.py +75 -0
- package/src/ecosystem/wechat/windows/native.py +180 -0
- package/src/ecosystem/wechat/windows/outgoing.py +95 -0
- package/src/ecosystem/wechat/windows/presence.py +109 -0
- package/src/ecosystem/wechat/windows/quotes.py +76 -0
- package/src/ecosystem/wechat/windows/reading.py +55 -0
- package/src/ecosystem/wechat/windows/requirements.txt +1 -0
- package/src/ecosystem/wechat/windows/sender.py +178 -0
- package/src/ecosystem/wechat/windows/snapshot.py +67 -0
- package/src/ecosystem/wechat/windows/stickers.py +60 -0
- package/src/ecosystem/wechat/windows/wechat.ps1 +75 -0
- package/templates/alarm.md +49 -0
- package/templates/world-prompt.md +51 -0
package/INSTALL.md
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# 交给她的安装说明
|
|
2
|
+
|
|
3
|
+
这份文件不是给人看的,是给 **DSH 里的陪伴角色**看的:谁把仓库地址发过来,谁就照着这份说明,把 `dsh-world` 装进 DSH、把 QQ 接上,最后让 QQ 里的她和人说话。
|
|
4
|
+
|
|
5
|
+
先说清 QQ 现在长什么样:**只有一条路——插件自己连 OneBot**(代码在 `src/ecosystem/qq-native/`,对外叫「原生通道」)。以前那个外部的桥进程已经在 2026-10-27 整段拆掉了,连它那几个配置项一起没了。所以这份说明里不会出现第二个进程,只有两样东西:插件,和负责登录 QQ 的 SnowLuma。
|
|
6
|
+
|
|
7
|
+
一句话说清边界:**第二步只有人能做——装 SnowLuma、拿手机扫码登录。这两件事你替不了,其余步骤你自己做。**
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 第零步:先摸清四件事
|
|
12
|
+
|
|
13
|
+
动任何文件之前,先把这四样查出来,后面每条命令都要用。
|
|
14
|
+
|
|
15
|
+
| 要知道的 | 怎么查 |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `DSH_HOME` | Windows 默认 `C:\Users\<用户名>\.dsh`;看目录里有没有 `profiles`、`worlds` |
|
|
18
|
+
| 用哪个 profile | 列 `<DSH_HOME>/profiles/` 下的目录,挑 `package.json` 里 `dependencies` 有你正在跑的那些插件的那个 |
|
|
19
|
+
| node 版本 | `node -v`,必须 ≥ 22.16(dsh-world 的要求) |
|
|
20
|
+
| pnpm 在哪 | 先试 `pnpm -v`;没有就用 DSH 自带的:`<DSH 安装目录>\resources\runtime\x64\primary-runtime\dependencies\pnpm\bin\pnpm.cjs`,用 `node <那个 pnpm.cjs> <命令>` 调用 |
|
|
21
|
+
|
|
22
|
+
> macOS / Linux 的路径换成对应位置即可,命令不变。
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 已有 world:用编译包更新
|
|
27
|
+
|
|
28
|
+
已经装过 `dsh-world` 时,保留原 profile 和世界目录,从 [CI 运行记录](https://github.com/chenkezhen480/dsh-world/actions) 的 Artifacts 下载 `.tgz`,不要另建 world。更新成品无需 Git、npm 或 TypeScript 编译器;需要 Node ≥ 22.16、系统 `tar` 和 DSH 自带 pnpm。
|
|
29
|
+
|
|
30
|
+
1. 从应用菜单正常退出 DSH,等待微信适配器一并退出。脚本会拒绝在 DSH 或适配器仍运行时更新,不强制结束进程。
|
|
31
|
+
2. 使用仓库的 `scripts/update-world.mjs`,或已安装包的 `node_modules/dsh-world/scripts/update-world.mjs`。老版本尚无此文件时,可从仓库单独下载这个脚本,无需克隆或安装源码依赖。
|
|
32
|
+
3. 执行以下命令,将三个路径替换为实际值。`--pnpm` 指向桌面版启动日志中显示的 `pnpm.cjs` 或 `pnpm.mjs`;常见位置是 `<DSH 安装目录>/resources/runtime/primary-runtime/dependencies/pnpm/bin/pnpm.mjs`,旧安装也可能多一层 `x64`。
|
|
33
|
+
|
|
34
|
+
```powershell
|
|
35
|
+
node .\scripts\update-world.mjs `
|
|
36
|
+
--profile '<DSH_HOME>/profiles/desktop' `
|
|
37
|
+
--package '<下载目录>/dsh-world-0.6.4.tgz' `
|
|
38
|
+
--pnpm '<DSH 自带 pnpm 的入口文件>'
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`node` 可以使用本机 Node 或 DSH 提供的 Node 命令。macOS / Linux 使用同一脚本和参数,将换行符换成相应 shell 的写法即可。
|
|
42
|
+
|
|
43
|
+
脚本先检查包名和编译入口,再把整个 profile(含依赖)、`worlds` 和 `sessions` 备份到 `<DSH_HOME>/backups/dsh-world-<profile>-<随机后缀>/`。符号链接保留为链接,不复制链接指向的外部目录。安装包也保存到备份目录,profile 长期引用这份副本,下载文件随后移动或删除不影响启动。**不要删除当前 profile 仍在引用的备份目录。** 完整备份所需空间约为上述目录总大小;首次复制可能较慢。
|
|
44
|
+
|
|
45
|
+
更新只调用 pnpm 替换插件包,依赖安装脚本禁用,不安装或修补 SnowLuma SDK。随后核对编译入口、更新脚本、profile 配置、其他插件和世界/会话文件摘要。她的人设、日记、提示词、原会话及原模块配置保持原样,不自动迁移旧 QQ 配置,也不解锁微信待核对消息。外置微信状态不在该备份内,更新脚本不操作它。
|
|
46
|
+
|
|
47
|
+
失败会恢复整个旧 profile,保留 `failed-profile` 和备份供排查。若恢复也失败,保持 DSH 关闭,按报错给出的备份路径人工恢复;世界与会话备份不自动覆盖当前目录。检查覆盖包内容、文件摘要和入口语法;桌面版依赖宿主自己的模块加载器,脚本不尝试在普通 Node 中加载宿主人设或会话服务。正常完成后再启动 DSH,检查世界控制台健康状态。脚本不会自动启动 DSH、发消息或改她的自定义提示词。更新过程中请保持 DSH 关闭;若更新进程异常终止后遗留锁文件,先确认没有更新进程,再按报错路径处理锁文件及备份。
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 第一步:把 dsh-world 装进 profile
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
git clone https://github.com/chenkezhen480/dsh-world.git
|
|
55
|
+
|
|
56
|
+
cd dsh-world
|
|
57
|
+
npm ci # 仓库带 package-lock.json,能装全 devDependencies
|
|
58
|
+
npm pack # 会先 typecheck + build,产出 dsh-world-<版本>.tgz
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
QQ 功能额外依赖 **SnowLuma SDK(`@snowluma/sdk`)**。首次在控制台手动开启 QQ 时,若缺少 SDK,插件使用宿主提供的包管理器按需安装到当前 DSH profile,禁用安装脚本并检查 SDK 的 Node 要求;安装成功后提示重启 DSH,再启用 QQ。仅安装或启动 dsh-world 不会下载 SDK,不使用 QQ 时无需安装。插件不修补 SDK,也不自动升级 Node。
|
|
62
|
+
|
|
63
|
+
拿到 `dsh-world-0.6.4.tgz` 的**绝对路径**,然后:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
cd <DSH_HOME>/profiles/<你的 profile>
|
|
67
|
+
node <pnpm.cjs 路径> add <tgz 的绝对路径>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
包公开发布到 npm 后,也可在同一个 profile 目录执行:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
node <pnpm.cjs 路径> add dsh-world@latest --ignore-scripts --registry=https://registry.npmjs.org/
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
这条命令也可将旧的本地 `.tgz` 引用切换到 npm 版本;之后更新继续执行同一命令。操作前退出 DSH 并备份原 profile 和世界数据,完成后重启,保留后文的 bundle 登记及个人配置。`scripts/update-world.mjs` 仍只接受本地 `.tgz`,其完整备份和失败恢复流程见前文。
|
|
77
|
+
|
|
78
|
+
也可以自行安装;宿主未提供按需安装能力时,在同一个 profile 目录安装满足声明范围的 SDK(当前为 `^2.2.1`),确认 DSH 使用的 Node 满足 SDK 要求后再重启:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
node <pnpm.cjs 路径> add @snowluma/sdk@^2.2.1
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**不要用 `link:` 指向 clone 下来的目录。** 那样会加载项目自带的一份 Cordis,和 DSH 自己的打架。README 里也写了这句,别忽略。
|
|
85
|
+
|
|
86
|
+
接着改两个文件:
|
|
87
|
+
|
|
88
|
+
**1. `<profile>/package.json`** —— 在 `dsh.profile.bundles` 数组里加一项 `"dsh-world"`:
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
"dsh": { "profile": { "bundles": [ "…", "dsh-world" ] } }
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**2. `<profile>/cordis.patch.yml`** —— 让插件知道 QQ 从哪儿接进来:
|
|
95
|
+
|
|
96
|
+
- 文件里**已经有** `- id: dsh-world` 的话,只补 `config` 下这一段
|
|
97
|
+
- **没有**的话,整段贴到文件末尾
|
|
98
|
+
|
|
99
|
+
```yaml
|
|
100
|
+
- insert:
|
|
101
|
+
- id: dsh-world
|
|
102
|
+
name: dsh-world
|
|
103
|
+
config:
|
|
104
|
+
qqNative:
|
|
105
|
+
enabled: true
|
|
106
|
+
wsUrl: ws://127.0.0.1:3003 # OneBot 的 WS 服务端口(不是 HTTP 那个)
|
|
107
|
+
accessToken: '<OneBot 的 WS 服务端自己的 token>'
|
|
108
|
+
allowPrivate: [ '3475994805' ] # 谁能私聊她,留空 = 谁都不理
|
|
109
|
+
allowGroups: [ '681528723' ] # 群白名单
|
|
110
|
+
autoReply: true # false = 只看不回
|
|
111
|
+
contextMessages: 6 # 每轮带上最近的几条
|
|
112
|
+
groupTrigger: mention # 群里被叫到才接(@ / 被引用 / 命中 groupKeywords);all = 每句都接
|
|
113
|
+
groupKeywords: []
|
|
114
|
+
bindHomeSession: none # owner = 群各自独立、主人私聊用她的家会话;all = 都用家会话;none = 各建一个
|
|
115
|
+
snowlumaHome: 'D:\SnowLuma' # 去哪儿读 SnowLuma 的 config/runtime.json(控制台那扇门要用);不填按 D:\SnowLuma、C:\SnowLuma、E:\SnowLuma、~/SnowLuma、~/snowluma 挨个认
|
|
116
|
+
supervise: true # 看门狗:QQ 开着时端口不通就把 SnowLuma 拉起来;不想让插件动手就写 false
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
> 这一段**先照抄**:token、白名单、端口这些真值要等第二步人把 SnowLuma 装好才有,第五步再填。
|
|
120
|
+
> `qqNative.enabled` 写 `false`(或者整段不写)= 不接 QQ,控制台「QQ」页提示通道未开启。
|
|
121
|
+
> 写 `true` 也只是**允许**接 QQ:还要在控制台「概览 → 接入」把 QQ 拨开;缺少 SDK 时会按需安装并提示重启。没装 SDK 不影响插件的其他功能。
|
|
122
|
+
> 示例里 `bindHomeSession` 写了 `none`,是为了第一次联调不往她真正生活着的家会话里写东西;通道顺了以后改回默认的 `owner`(群各自独立、主人私聊用她的家会话)。
|
|
123
|
+
> 路径写 Windows 绝对路径,用正斜杠或单反斜杠都行。
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 第二步:装 SnowLuma,扫码登录,开 OneBot,把参数交给你(**只有人能做**)
|
|
128
|
+
|
|
129
|
+
### 2.1 装 SnowLuma 并扫码登录 QQ
|
|
130
|
+
|
|
131
|
+
- 下载:<https://github.com/SnowLuma/SnowLuma/releases/latest> 选 `SnowLuma-v<版本>-win-x64.zip`(完整版自带 Node 运行时;Lite 版要本机 Node 22.13+)
|
|
132
|
+
- 解压到任意目录,双击 `launcher.bat`
|
|
133
|
+
- 用**启动日志里打印的初始密码**登录 WebUI(地址也在日志里,通常是 `http://localhost:5099`)
|
|
134
|
+
- 按引导:同意条款 → 设置新密码 → **接入 QQ 进程(扫码)**
|
|
135
|
+
|
|
136
|
+
> **为什么这两件事不能自动化**:SnowLuma 的 EULA §5.4 明确禁止「通过自动化脚本部署」和「并入第三方安装包」。所以插件既不代装、也不代启动它,只连它开出来的 OneBot;装好一次之后,插件再也不碰它的安装目录。这不是我们偷懒,是对面写死的规矩。
|
|
137
|
+
> 另外扫码本身也要人拿手机。装好一次之后,以后重启不用再扫。
|
|
138
|
+
|
|
139
|
+
### 2.2 在 SnowLuma 里开 OneBot,把参数交给你
|
|
140
|
+
|
|
141
|
+
让人在 SnowLuma WebUI 里:
|
|
142
|
+
|
|
143
|
+
1. 开启 **WebSocket 服务端** → 记下端口(示例里写 `3003`,**以它页面上显示的为准**)
|
|
144
|
+
2. 开启 **HTTP API** → 也记下端口,但插件**不用**它,记下来只是为了别填错
|
|
145
|
+
3. 如果设了 accessToken,记下来 —— 你要的是 **WebSocket 服务端自己那个**
|
|
146
|
+
|
|
147
|
+
然后人把这几样告诉你:**WS 端口、WS 服务端的 accessToken(可能为空)、放行的 QQ 号、放行的群号**。
|
|
148
|
+
|
|
149
|
+
> **分不清两个 token 就看这里。** SnowLuma 给 HTTP 和 WebSocket 各生成一份 token,插件走的是 WebSocket 那条握手,拿 HTTP 那份会得到 `401`,卡上会直接写出来:`WS 错误: Unexpected server response: 401`。token 存在 SnowLuma 的 `config/onebot_*.json` 里 —— **认 `enableWebSocket` 为真的那个文件**,里面的 token 就是你要的。
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 第三步:重启一次 DSH
|
|
154
|
+
|
|
155
|
+
前两步改的都是「DSH 启动时才读」的东西:`bundles`、`cordis.patch.yml`。
|
|
156
|
+
|
|
157
|
+
所以现在**重启 DSH**。重启后验证两件事:
|
|
158
|
+
|
|
159
|
+
1. 打开 DSH 设置里的「世界控制台」,能看到世界卡——说明 dsh-world 起来了
|
|
160
|
+
2. 按一次「开始」,在「概览 → 接入」开启 QQ,再切到顶部 **QQ 页面**。状态是 `● 她自己的通道没连上`——说明 `qqNative.enabled` 生效了,只是还没填对参数(第五步才填)
|
|
161
|
+
|
|
162
|
+
> QQ 页在 `qqNative.enabled: true`、接入开关已开启且世界已经开始时展示详细状态;其他时候页面提示未开启。
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 第四步:确认你自己能做的都做完了
|
|
167
|
+
|
|
168
|
+
跑一遍这个判断,全绿再进第五步:
|
|
169
|
+
|
|
170
|
+
| 检查 | 怎么验 | 期望 |
|
|
171
|
+
|---|---|---|
|
|
172
|
+
| dsh-world 已加载 | 浏览器打开 `http://127.0.0.1:<DSH 端口>/dsh-world/console/snapshot` | 返回 JSON,有 `worldId`、`life`、`native`。`qq` 那个字段现在恒为 `null`(拆掉的桥留下的),不用管它,看 `native` |
|
|
173
|
+
| 通道认了配置 | `http://127.0.0.1:<DSH 端口>/dsh-world/qq/native` | 返回的 `url` 是你填的 `wsUrl`;没连上时 `connected: false`、`lastError` 里写着原因。通道没开时这个端点返回 `null` |
|
|
174
|
+
| 世界在跑 | 控制台右上角是「停止」状态 | 通道跟着生活线一起起,世界没开始它不连 |
|
|
175
|
+
|
|
176
|
+
> 用浏览器而不是 curl:DSH 的 webServer 会校验 Host 头,curl 直接打会被挡。同源请求不受影响。
|
|
177
|
+
|
|
178
|
+
到这里,**你这一侧全部就绪**。剩下的是人必须插手的部分——也就是第二步已经做完的那两件事;做完之后你接手继续。
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 第五步:把参数填进去,接上(你来做)
|
|
183
|
+
|
|
184
|
+
拿到第二步那几个值,把第一步那段 `qqNative` 改真:
|
|
185
|
+
|
|
186
|
+
```yaml
|
|
187
|
+
qqNative:
|
|
188
|
+
enabled: true
|
|
189
|
+
wsUrl: ws://127.0.0.1:3003
|
|
190
|
+
accessToken: '<第二步拿到的 WS 服务端 token,没有就留空>'
|
|
191
|
+
allowPrivate: [ '3475994805' ] # 谁能私聊她;没填 ownerQQ 时,她自己开口的话推给这里面的第一个人
|
|
192
|
+
allowGroups: [ '681528723' ] # 要放行的群
|
|
193
|
+
autoReply: true
|
|
194
|
+
contextMessages: 6
|
|
195
|
+
groupTrigger: mention
|
|
196
|
+
groupKeywords: [ '小鱼' ]
|
|
197
|
+
bindHomeSession: owner
|
|
198
|
+
snowlumaHome: 'D:\SnowLuma'
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
改完重载插件(或者重启一次 DSH)就生效。**没有第二个进程要起**,QQ 这条线跑在插件自己的进程里。
|
|
202
|
+
|
|
203
|
+
两个坑,都会让人以为「装坏了」:
|
|
204
|
+
|
|
205
|
+
- **`wsUrl` 要填 OneBot 的 WebSocket 服务端端口**,不是 HTTP 那个。填错会一直连不上、日志刷重连。
|
|
206
|
+
- **`allowPrivate` / `allowGroups` 留空等于谁都不理**,不是「所有人都理」。白名单挡下的消息会计数,卡上显示 `· 挡下 N`。这是故意的,别指望它默认全接。
|
|
207
|
+
|
|
208
|
+
### 谁和谁共用一个会话
|
|
209
|
+
|
|
210
|
+
`bindHomeSession` 管的是这件事,值得单独说清楚:
|
|
211
|
+
|
|
212
|
+
| 值 | 效果 |
|
|
213
|
+
|---|---|
|
|
214
|
+
| `owner`(默认) | 主人私聊用她的「家会话」(`~/.dsh/worlds/<世界>/life.json` 里的 `homeSessionId`),**每个群各自一个独立会话**。群里聊的不会串到私聊,私聊里的记忆也不会漏进群 |
|
|
215
|
+
| `all` | 群里、私聊都用家会话,记忆完全共享;群里人多的时候上下文容易串味 |
|
|
216
|
+
| `none` | 谁都不绑:群各自一个,私聊也另建一个独立会话 |
|
|
217
|
+
|
|
218
|
+
> 自己开发调试这条通道时建议先写 `none`:测试回合不会写进她真正生活着的那条线,等通道彻底顺了再改回 `owner`。
|
|
219
|
+
|
|
220
|
+
规则是**每条消息现算的**,改完重载插件,下一条消息就按新规矩落会话。旧的频道会话留在原处不动(不自动拆,也不删)。
|
|
221
|
+
|
|
222
|
+
### 群里她什么时候接话
|
|
223
|
+
|
|
224
|
+
默认 `groupTrigger: mention`:只有这三种算在叫她,其余的**只记进上下文、不开口,也不烧一轮 token**:
|
|
225
|
+
|
|
226
|
+
- 被 `@` 到
|
|
227
|
+
- 引用她刚说过的那句话
|
|
228
|
+
- 文本命中 `groupKeywords` 里的词
|
|
229
|
+
|
|
230
|
+
写 `all` 就是群里每句都接 —— 那意味着群里每一条消息都会让她跑完一轮、还往群里冒一条,没人说话的时候也一样。**除非那个群本来就是你和她两个人的地方,否则别写 `all`。**
|
|
231
|
+
|
|
232
|
+
`contextMessages` 控制每轮带几条最近的上下文(默认 6)——群里那些没叫她的消息,价值就在这里:她看得见,但不接。
|
|
233
|
+
|
|
234
|
+
### 她自己开口
|
|
235
|
+
|
|
236
|
+
她在家里自己开的那一轮(闹钟、世界线)说完的话,会推一份给主人的 QQ:`ownerQQ`,空着就取 `allowPrivate` 的第一个人(白名单不止一人时一定要填)。有人说话的轮次是在回那个人,不另推。静默(`mutedUntil`,或卡上「静默到这个点」)期间也不推。
|
|
237
|
+
|
|
238
|
+
### 控制台 QQ 页面上有什么
|
|
239
|
+
|
|
240
|
+
「世界控制台」顶部「QQ」页里的状态卡写的是:`● 她自己连着 ws://…`(或「她自己的通道没连上」)+ `收 N 个会话 · 发 N 条[ · 失败 N][ · 挡下 N][ · 会自己回 / 只看不回]`,出问题会跟一句 `lastError`;下面一行是看门狗的状态(SnowLuma 通不通、拉起过几次、为什么拉不起来)。
|
|
241
|
+
|
|
242
|
+
下面是一排控件:
|
|
243
|
+
|
|
244
|
+
- **「会自己回话 / 只看不回」** —— 等于 `autoReply`。想只验链路通不通就先关掉:她会收、但一个字都不回,也不开会话、不花 AI 的额度。
|
|
245
|
+
- **「静默到这个点 / 立刻恢复」** —— 等于 `mutedUntil`:到点前只收不回、上下文照记,到点自己醒。
|
|
246
|
+
- **私聊 / 群白名单** —— 等于 `allowPrivate` / `allowGroups`,多个用逗号隔开;留空就是谁都不收。
|
|
247
|
+
- **「打开 SnowLuma 控制台」** —— 见下。
|
|
248
|
+
- **「拉起 SnowLuma」** —— 手动把 SnowLuma 拉起来一次,和看门狗走同一条路。
|
|
249
|
+
- **「刷新」** —— 重新拉一次快照。
|
|
250
|
+
|
|
251
|
+
这些都是**活的**:改完下一条消息就生效,不用重启。临时覆盖存在 `~/.dsh/worlds/<世界>/qq-native.json`;profile 里的值仍然是最底下的默认。
|
|
252
|
+
|
|
253
|
+
「概览 → 接入」里的 QQ 那一行管的是**通道本身**:关掉就断开这条 OneBot 连接,QQ 页提示未开启;再打开就恢复。状态记在 `world.json`。配置里没写 `qqNative.enabled: true` 时,这个开关按不动(控制台会明说)。
|
|
254
|
+
|
|
255
|
+
### SnowLuma 控制台那扇门
|
|
256
|
+
|
|
257
|
+
插件读 `snowlumaHome/config/runtime.json` 找 SnowLuma 的 WebUI 地址与端口,按钮点开就用系统浏览器打开、**带着登录票据**(`?token=…`),不用手输密码。
|
|
258
|
+
|
|
259
|
+
- **第一次**要先填一次 SnowLuma 的**面板密码**:那边只认密码,会话令牌只活在它的进程内存里。填对一次之后,密码记在 `<世界目录>/panel.json`(权限 600),以后点开就直接进。
|
|
260
|
+
- `snowlumaHome` 不填时,按 `D:\SnowLuma`、`C:\SnowLuma`、`E:\SnowLuma`、`~/SnowLuma`、`~/snowluma` 挨个认,认的是「里面有 `config/runtime.json`」这一条。
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
### 阳台:让本机别的程序也能跟她说上话
|
|
265
|
+
|
|
266
|
+
插件自己开一条 WebSocket(**默认关着**;在控制台 QQ 卡片上点「开这条线」就是 `ws://127.0.0.1:3210`,只认口令)。机器上任何会读写一行 JSON 的程序都能接上来,递一句话给她、听她回一句。设置页那张 QQ 卡上有地址、口令,还有一个「复制这条命令」——复下来的是一个现成的小程序,粘到对面就能用:
|
|
267
|
+
|
|
268
|
+
DSH_QQ_BRIDGE_URL=ws://127.0.0.1:3210 DSH_QQ_BRIDGE_TOKEN=… node "<运行目录>/lib/qq-line.js" <这条线叫什么> <会话标识>
|
|
269
|
+
|
|
270
|
+
一条线就是她的一间屋子(`channel` 是 `qq-bridge`,会话标识是线名),和 QQ 那几条互不打扰。递话、回话都是一行 JSON:
|
|
271
|
+
|
|
272
|
+
递给她 {"text":"…","from":"谁"} 直接说一句
|
|
273
|
+
{"kind":"ring"} 只敲一下门,不说话
|
|
274
|
+
她回话 {"kind":"reply","threadId":"…","text":"…","hold"?:true}
|
|
275
|
+
{"kind":"error","message":"…"}
|
|
276
|
+
|
|
277
|
+
她可以在回话里带上怎么对待门外,这两个词不会被当成话发出去:`[安静]`(这条线半小时内不再敲得动门)与 `[待一会]`/`[在忙]`(对面收到 `hold`)。口令存在世界目录的 `qq-bridge.json` 里,重启 DSH 对面那份不用改;端口在 `qqNative.bridge.port`(`0` = 不开,默认 3210)。
|
|
278
|
+
|
|
279
|
+
那张卡上会显示「阳台开着 ws://127.0.0.1:<端口> · 连着几条线 · 收了几句、回了几句、她开口几次」,出问题就看同一行的 `lastError`。
|
|
280
|
+
|
|
281
|
+
## 验证清单
|
|
282
|
+
|
|
283
|
+
按顺序过一遍,哪条不过就查下表:
|
|
284
|
+
|
|
285
|
+
1. `http://127.0.0.1:<DSH 端口>/dsh-world/qq/native` → `connected: true`,`url` 是你填的那个 ws 地址
|
|
286
|
+
2. DSH 里「世界控制台」→ QQ 卡:`● 她自己连着 ws://…`,`挡下 0`
|
|
287
|
+
3. QQ 上用一个在白名单里的号给她私聊发一条 → 她回
|
|
288
|
+
4. 群里 @ 她 → 她回;群里说一句没叫她的 → 她**不回**,但卡上的会话计数和上下文在走
|
|
289
|
+
5. 「概览 → 接入」里关掉 QQ → 通道断开、QQ 页提示未开启 → 再打开 → QQ 页恢复详细状态
|
|
290
|
+
|
|
291
|
+
## 出问题看这里
|
|
292
|
+
|
|
293
|
+
| 现象 | 真正的原因 |
|
|
294
|
+
|---|---|
|
|
295
|
+
| QQ 页提示通道未开启 | 检查 `qqNative.enabled: true` 是否位于正确的 `config:` 下、世界是否已开始,以及「概览 → 接入」的 QQ 开关是否已开启;若连 QQ 页入口都没有,再核对安装版本 |
|
|
296
|
+
| 卡上写 `WS 错误: Unexpected server response: 401` | `accessToken` 填成了 HTTP 服务的 token。要用 **WS 服务端自己那个**:SnowLuma 的 `config/onebot_*.json` 里 `enableWebSocket` 为真的那个文件 |
|
|
297
|
+
| 一直连不上,日志刷重连 | `wsUrl` 的端口填成了 HTTP API 那个。要填 WebSocket 服务端的端口,端口号以 SnowLuma 页面上显示的为准 |
|
|
298
|
+
| 私聊发了没反应,卡上「挡下 N」在涨 | 那个 QQ 号不在 `allowPrivate` 里。白名单留空 = 谁都不理,抬手加上去 |
|
|
299
|
+
| 群里 @ 她了,还是不接 | 群里默认 `groupTrigger: mention`,只有 @、引用她的消息、命中 `groupKeywords` 才算叫她;另外确认群号在 `allowGroups` 里(要数字,别写成别的字) |
|
|
300
|
+
| 她收得到但一个字不回 | `autoReply` 关着(卡上写着「只看不回」),或者卡上那个勾被拨掉了 |
|
|
301
|
+
| 她自己开口的话没推到 QQ | `ownerQQ` 和 `allowPrivate` 都空着(没处发);或者正在静默;或者那一轮是在回别人的话 |
|
|
302
|
+
| 卡上写着「排队待发」 | 发送失败的消息在队里,每 3 秒重试一次,最多留 5 分钟;通道连回来就会发出去 |
|
|
303
|
+
| 点「打开 SnowLuma 控制台」说「还差一次面板密码」 | 第一次要先填一次 SnowLuma 的面板密码,填对了就记在 `<世界目录>/panel.json`,之后不用再填 |
|
|
304
|
+
| 点那扇门说「没找到 SnowLuma 的控制台配置」 | `snowlumaHome` 没填或填错;它要的是 SnowLuma 的**安装目录**(里面得有 `config/runtime.json`) |
|
|
305
|
+
| 设置页「模块」里的 QQ 开关按不动 | 配置里没写 `qqNative.enabled: true`,控制台不会凭空打开一个没配的模块 |
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## 一句话总结给主人听
|
|
310
|
+
|
|
311
|
+
「装好了。以后重启电脑只要两件事:DSH 起来(QQ 那条通道跟着生活线一起起)、SnowLuma 自己重连。除非换 QQ 号,否则不用再扫码。」
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ckz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,230 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dsh-world
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
给 DSH 里的陪伴角色一个会记得、会生活的世界。
|
|
4
|
+
|
|
5
|
+
装上以后,她会记得你们在每个窗口里说过的话;有一个自己的家,自己决定接下来做什么、做到几点,想你了会主动来找你;每天晚上回想这一天,写日记,也改写一份关于自己的自述。开关和人设都在 DSH 设置里的「世界控制台」,由你掌握。
|
|
6
|
+
|
|
7
|
+
插件只用 DSH 原本开放的扩展接口,不改宿主的一行代码。
|
|
8
|
+
|
|
9
|
+
当前版本 **0.6.4**。完整变更和升级说明见 [更新日志](CHANGELOG.md#064--2026-10-29)。
|
|
10
|
+
|
|
11
|
+
## 她能做到什么
|
|
12
|
+
|
|
13
|
+
### 记得:像人一样记
|
|
14
|
+
|
|
15
|
+
- **近期记忆**:你们最近数轮的对话原文,每次开始对话和每次压缩之后都放在她眼前,谁、什么时候、说了什么,一字不差。轮数在控制台里填,默认 200。
|
|
16
|
+
- **日记**:人生里重要的事,她自己写进日记,一天一篇。这是她的长期记忆。
|
|
17
|
+
- **我是谁**:她写给自己的一份自述,随着她变化而改写。每晚回顾前,插件会留一份当时的版本,改过的都找得回来。
|
|
18
|
+
- **范围内的原文留着**:按天归档用户和助手的正文。近期记忆以外的事,她可以自己去翻。
|
|
19
|
+
|
|
20
|
+
日记和自述都由她自己动笔,插件从不替她写。
|
|
21
|
+
|
|
22
|
+
**为什么不用向量库或记忆系统?** 一个人的生活,量没有那么大。在这个量级上,把原文留在眼前、需要时按原话去找,比切碎了再拼回来更准,也少一道会出错的环节。可参考:
|
|
23
|
+
|
|
24
|
+
- Chan et al., 2024. *Don't Do RAG: When Cache-Augmented Generation is All You Need for Knowledge Tasks*. arXiv:2412.15605
|
|
25
|
+
- Sen et al., 2026. *Is Grep All You Need? How Agent Harnesses Reshape Agentic Search*. arXiv:2605.15184
|
|
26
|
+
|
|
27
|
+
### 生活:她自己的日子
|
|
28
|
+
|
|
29
|
+
- **家**:她有一个自己的会话「<名字>的家」,和一个房间(工作目录),在里面过自己的日子。
|
|
30
|
+
- **自己定节奏**:她说好接下来做什么、做到几点,到点了再决定继续还是换一件。什么都不定,就休息到第二天早上。
|
|
31
|
+
- **主动找你**:想你的时候,她可以把一句话送到你面前(Windows 系统通知,或你接上的桌宠等程序)。
|
|
32
|
+
- **每日回顾**:每天晚上 23:00,她回想当天的聊天和做过的事,写日记,更新「我是谁」。
|
|
33
|
+
- **每天额度**:可以给家里每天的花费设个上限,超过了会提醒她一次,由她自己决定收尾。
|
|
34
|
+
- **大事先问**:删改房间外的文件、装软件、花钱、以你的名义对外发消息等,约定好先问你。
|
|
35
|
+
|
|
36
|
+
### 世界控制台:开关在你手里
|
|
37
|
+
|
|
38
|
+
DSH 设置里的「世界控制台」:
|
|
39
|
+
|
|
40
|
+
- **开始 / 停止**:按下开始,她才住进来;按下停止,记忆、人设和生活线一起安静下来,家还在,等你回来。
|
|
41
|
+
- **人设**:分层写她是谁:名字、她是谁、性格、说话方式、愿景、补充,旁边实时预览她读到的样子。全部留空时沿用宿主或当前预设的人设,控制台不自动回填。
|
|
42
|
+
- **世界提示词**:你想对她说的话,以及她的世界的说明。
|
|
43
|
+
- **相册**:家会话可用 `keep_photo` 收藏本轮最新消息中的图片(含本轮已读取的微信图片和引用图),`list_photos` 分页查看说明,`forget_photo` 移除收藏。控制台顶部「相册」页查看照片,点开才加载图片;照片不会自动加入之后每轮上下文。旧相册首次打开时导入,原文件保留。
|
|
44
|
+
- **应用并压缩家会话**:人设和世界提示词页面里的热加载入口,操作方法见下方[注意事项](#注意事项)。
|
|
45
|
+
- **工作区权限**:选择世界工作区新建会话的默认权限,选项沿用宿主提供的权限预设,默认完全权限。保存后对新会话生效;已有会话及其手动权限不会被重新覆盖。
|
|
46
|
+
- **概览与记录**:她此刻在做什么、下个闹钟、近期记忆有多少轮、今天花了多少;还有活动记录、日记和压缩记录。
|
|
47
|
+
- **接入开关**:配置里启用了微信(`wechat: true`)或 QQ(`qqNative.enabled: true`)后,概览里有一张「接入」卡片,状态记在 `world.json`。微信开着才注册工具并拉起适配器(配了 `wechatAdapter` 时),关掉就撤掉;QQ 开着才加载通道,关掉就断开连接。微信默认开,QQ 默认关。首次手动开启 QQ 时,缺少 SnowLuma SDK 就按需安装,完成后提示重启 DSH;SDK 已就绪时直接切换,无需重启。
|
|
48
|
+
- **微信 / QQ 页面**:顶部各有一个独立入口,详细状态和设置不再挤在概览里。微信页查看连接、待发送与待核对数量,重启适配器并调整读取条数和图片缓冲;QQ 页管理 OneBot、白名单、静默和 SnowLuma。通道关闭或世界停止时,页面提示未开启。
|
|
49
|
+
- **归档范围**:默认 `workspace`,归档家所在工作区的普通会话,包含独立微信群会话;`home` 仅当前家会话。保存范围后提示重启,重启前沿用原范围。启动时分页回扫所选范围内的会话日志,按消息实际时间重选最近配置轮数,下次请求前替换旧记忆块;没有时间过期。旧归档保留,范围外记录不再注入。旧配置 `world` 迁为 `workspace`。
|
|
50
|
+
- **注入范围**:世界记忆、世界提示词、世界线工具和微信/QQ 通道仅进入世界工作区内匹配预设的普通会话,其他工作区即使用相同预设也不会收到。归档选为 `home` 时,同工作区的其他会话仍可读取家记忆。
|
|
51
|
+
|
|
52
|
+
> **对世界工作区以外的影响(只有这两项)**:
|
|
53
|
+
> 1. **人设**:控制台人设映射到系统提示词的人设槽位,所有匹配该世界预设的普通会话都会带上,不限工作区。
|
|
54
|
+
> 2. **只留对话的压缩**(启用后):它替换的是整个 profile 的压缩方式,其他工作区的会话压缩时也会去掉工具调用过程,只留一段对话摘要。写代码等依赖工具过程的会话,压缩后会丢掉这些细节。
|
|
55
|
+
>
|
|
56
|
+
> 除此之外,记忆、世界提示词、世界线、工具、通道和归档都不会进入工作区以外的会话。
|
|
57
|
+
|
|
58
|
+
### 注意事项
|
|
59
|
+
|
|
60
|
+
**修改人设、世界提示词后,需要手动热加载,才能让已有家会话及时用上新内容。** 先保存修改,再到「人设」或「世界提示词」页点击 **「应用并压缩家会话」**。仅保存或重新打开控制台,不会立即刷新家会话。
|
|
61
|
+
|
|
62
|
+
任务会等家空闲后执行一次,不打断当前对话;完成后的下一轮使用已保存的人设、名字、世界提示词和「我是谁」。压缩会调用模型并重建上下文缓存,没有可压缩内容时只刷新配置。面板显示执行结果或失败原因,停止世界会取消任务。
|
|
63
|
+
|
|
64
|
+
这个按钮只作用于家会话;其他已有会话在各自下一次成功压缩或重新加载时更新,新建会话直接读取已保存内容。
|
|
65
|
+
|
|
66
|
+
### 只留下你们之间的话的压缩
|
|
67
|
+
|
|
68
|
+
对话太长需要压缩时,dsh-world 自带的压缩方式会去掉工具调用的过程,把你们之间的交流整理成一段摘要。她记住的是你,不是那些命令。
|
|
69
|
+
|
|
70
|
+
### 桌宠和其他程序
|
|
71
|
+
|
|
72
|
+
dsh-world 开放了一个本地的「桥」:桌宠之类的程序可以把你说的话送进她的家,也可以接收她的回复和主动找你的话。协议见文末。
|
|
73
|
+
|
|
74
|
+
微信作为独立模块接入同一个家,使用她的独立账号收发指定私聊或群聊。她可用 `wechat_chats` 查询已配置目标,用 `wechat_history` 主动分页查看群消息,无需等别人 @;读完以同一个 `chatId` 调用 `wechat_send` 自主联系对方或回复消息,文字、图片和表情共用同一发送队列;`wechat_delivery` 查询确认结果。普通最终回答不会自动转发到微信。Windows 适配器和配置步骤见 [微信模块](src/ecosystem/wechat/windows/README.md)。B 站尚未接入。
|
|
75
|
+
|
|
76
|
+
**群聊动静**:适配器在线时,已配置群里未 @ 她的消息只更新未读数、最后发言人和时间,不唤醒模型,也不把正文加入上下文。她原有的闹钟响起时,会附上一行群聊概况,包括未读消息或安静了多久;是否去看、是否发言,由她自己决定。成功读取群的最新一页后清零未读,自己的发言不计入未读;计数保存在适配器状态中,重启保留。插件不会改写你的 `alarm.md`、`world-prompt.md` 或「我是谁」。
|
|
77
|
+
|
|
78
|
+
> **微信支持版本**:目前仅适配 **Windows x64 微信 `4.1.15.13`、`4.1.15.56` 的指定构建**。适配器会核对 `Weixin.dll` 的文件大小和 SHA256;其他构建(包括版本号相同但文件指纹不同的构建)会在加载原生桥前被拒绝。macOS、Linux 客户端暂不支持。升级微信前请确认新构建已有适配;各版本的实测范围见 [微信模块](src/ecosystem/wechat/windows/README.md)。
|
|
79
|
+
|
|
80
|
+
> **微信图片接收**:私聊普通图片会先缓冲最多 3 秒,合并紧随的同一发言人的一条说明文字后进入模型,每轮最多两张图,更多图片留到后续轮次。开始处理后才到达的文字排到下一轮,继续使用同一会话已有的图片上下文。群聊仍需真实 @ 她才触发看图。图片及附件引用只进入对应会话总日志,不自动写入共享记忆块;合并的真实文字按原归档范围保存,是否另行留存图片中的信息由她自己判断。缓存不可用时明确标记未读取,不操作界面下载。
|
|
81
|
+
|
|
82
|
+
> **微信风控与账号风险**:当前桥不是微信官方 API,接收端解密读取本地消息数据库,发送端向微信进程加载 DLL 并调用内部函数,存在账号功能受限或封禁风险。微信安全中心 [2026 年 1 月 29 日公告(媒体转载)](https://www.thepaper.cn/newsDetail_forward_32493057) 将违规获取聊天记录、联系人数据,以及通过模拟按键、自动化脚本操控微信等列为治理内容。仅用于家庭群、低频聊天,或改用 Computer Use,都不能保证账号安全;公开资料没有可靠的封号概率或安全发送阈值。
|
|
83
|
+
|
|
84
|
+
> **微信表情包接收**:私聊里你发来的原生表情包会按消息中的地址从腾讯 CDN 下载,md5 与消息一致才接受,并取第一帧作为图片交给她;这是适配器主动联网的功能,可在适配器配置里写 `"fetchStickers": false` 关闭,读取失败时她会看到明确的“未读取”原因。动图只取第一帧;群聊里的表情包目前不会交给她,群里发表情包后再 @ 她,她只能收到触发文字和其他已支持的上下文。原生表情包也不会进入插件的记忆归档。
|
|
85
|
+
|
|
86
|
+
> **视频号与朋友圈(预留)**:目前聊天中分享的视频号卡片会被跳过,不进入她的会话或共享记忆;收到卡片后没有回复,不代表微信监听掉线。视频号需要另行接入卡片解析和视频内容读取。朋友圈的浏览、发布也需要独立的操作能力,现有私聊/群聊发送接口不能发布朋友圈。这些能力暂只记录为微信模块的后续扩展,尚未实现。
|
|
87
|
+
|
|
88
|
+
> **微信退出重开**:保持适配器运行,退出微信后它会暂停收发并等待;她原来的账号重新登录后,会自动重新绑定进程并沿用消息游标恢复监听,无需重启 DSH。若退出发生在消息处理或发送途中,且结果尚未确认,则停止并保留待核对记录,不会自动重复回复;按微信模块中的 `Acknowledge` 流程核对后恢复。
|
|
89
|
+
|
|
90
|
+
> **微信首次接入与升级**:开启插件的微信开关本身不会启动 Windows 适配器;可手动启动,或在配置里写 `wechatAdapter` 让插件随微信模块启动和停止它(见适配器 README)。无论哪种,都需要配套适配器并完成账号及聊天目标注册后,微信工具才可使用。这套原生桥不依赖 `dsh-plugin-weixin` 或 iLink。升级插件和适配器后,两者均需重启,不能让旧适配器进程继续运行新版协议;保留原配置、游标和回执。
|
|
91
|
+
|
|
92
|
+
> **QQ 走插件自己那条原生通道**:插件直接连 SnowLuma 提供的 OneBot WebSocket,自己收、自己发(代码在 [`src/ecosystem/qq-native/`](src/ecosystem/qq-native/index.ts)),中间没有第二个进程,也不需要别的 QQ 实现。SnowLuma 负责登录 QQ 并对外提供 OneBot 的 HTTP/WS 服务;它按自己的 EULA 不许被自动化脚本部署,装法与参数怎么拿见 [INSTALL.md](INSTALL.md)。这条通道的配置都在 profile 的 `cordis.patch.yml` 里(见下文「设置」),控制台上改过的设置存在世界目录的 `qq-native.json`。
|
|
93
|
+
|
|
94
|
+
> **QQ 的记忆与开关**:QQ 消息由这条通道送进家里,插件没有为它做微信那样的渠道身份。按 `bindHomeSession`(默认 `owner`),主人的私聊用她的家会话,因此按普通家会话归档;每个群各挂一个独立会话(标题形如 `QQ · <群名>`),挂在她的房间工作区下、用同一个 `agentPreset`——所以在默认的 `archiveScope: workspace` 下,**群里的对话和微信群一样会进归档、进记忆块**,归档里只有会话、没有渠道标记。写 `none` 时私聊也另建一个这样的独立会话。群里的消息默认只有被叫到才接话,其余只进本轮上下文、不开口也不花额度。控制台「接入」里的 QQ 开关决定这条通道连不连。微信开关则会立即注册或撤掉 `wechat_chats`、`wechat_history`、`wechat_send`、`wechat_delivery`,并拉起或停止适配器。微信默认开、QQ 默认关,没在配置里启用的模块不能从控制台打开。
|
|
95
|
+
|
|
96
|
+
外部生态接入代码统一放在 [`src/ecosystem/`](src/ecosystem/README.md):`wechat/` 包含微信宿主模块、Windows 收发适配器和原生桥;`qq-native/` 是插件自己连 OneBot 的那条 QQ 通道(`qq/` 里是与它配套的控制台接口和 SnowLuma 控制台那扇门);`shared/` 保存通用身份协议、群会话路由与消息出口;`bridge/` 为桌宠等本地程序提供通用桥。后续平台在同一目录下独立扩展,核心记忆、人设和生活线保持独立。
|
|
97
|
+
|
|
98
|
+
微信原生发送引擎单独适用非商业许可,详见该模块的许可说明。
|
|
99
|
+
|
|
100
|
+
### QQ
|
|
101
|
+
|
|
102
|
+
QQ 走插件自己那条原生通道:直接连 SnowLuma 开出来的 OneBot WebSocket,收文本、发文本,中途没有别的进程。代码在 [`src/ecosystem/qq-native/`](src/ecosystem/qq-native/index.ts)。
|
|
103
|
+
|
|
104
|
+
**额外依赖 SnowLuma SDK(`@snowluma/sdk`)**:首次手动开启 QQ 时,缺少 SDK 就调用宿主包管理器装到当前 DSH profile,禁用安装脚本,不修补 SDK 文件;安装完成后提示重启 DSH,再按保存的开关启用 QQ。安装失败会显示原因,运行环境要求以 SDK 自身说明为准,不自动升级 Node。不使用 QQ 时无需 SDK,不影响其他功能;也可自行安装兼容版本,见 [安装说明](INSTALL.md#第一步把-dsh-world-装进-profile)。
|
|
105
|
+
|
|
106
|
+
在 profile 的 `cordis.patch.yml` 里打开 `qqNative`(`enabled: true` 只是允许它存在)、填上 WS 地址与 token,再到控制台「概览 → 接入」把 QQ 拨开,切到顶部「QQ」页查看:连着哪个地址、收过几个会话、发过几条、挡下几条、排队待发几条、会自己回还是只看不回,一眼看到。页面里能直接拨「会自己回话 / 只看不回」,设「静默到某个时间点」(只收不回,到点自己醒),改私聊和群的白名单(留空就是谁都不收,改完不用重启),也能打开 SnowLuma 控制台、手动拉起 SnowLuma。这些改动记在世界目录的 `qq-native.json`,盖在配置之上。没配 `qqNative.enabled` 时,QQ 页提示通道未开启。
|
|
107
|
+
|
|
108
|
+
参数不对不会崩,只会连不上:卡上会把原因写在 `lastError` 里(比如 `WS 错误: Unexpected server response: 401`,说明填的是 HTTP 那份 token,该换成 WebSocket 那份)。QQ 页在通道启用、世界已经开始时展示详细状态,其他时候提示未开启。
|
|
109
|
+
|
|
110
|
+
**群里默认只接被叫到的**(`groupTrigger: mention`):被 @、引用她刚说过的话、或文本命中 `groupKeywords` 才算叫她,其余消息只进本轮上下文,不开口也不花额度;写 `all` 就是每句都接,代价是群里每一条都会让她跑完一轮。`@全体` 是群公告,不算叫她。`bindHomeSession` 决定谁和她的家会话共用一个入口,默认 `owner`。
|
|
111
|
+
|
|
112
|
+
**她怎么说话**:同一会话 `batchQuietMs`(默认 10 秒)内连着来的几句攒成一条再问她(最多等 30 秒),群里每句前面带着是谁说的。她的回答按空行分成几条发,中间停一下;回话里写 `[[img:路径]]`、`[[face:id]]`、`[[at:QQ号]]` 会变成图片、QQ 表情和 @,`[[sticker:开心]]` 按备注挑一个收藏表情单发(也可以写第几个),`[[qzone:正文]]` 发一条所有人可见的 QQ 空间说说。发不出去的消息先排队,每 3 秒重试,最多留 5 分钟。她在家里自己开的那一轮(闹钟、世界线)说完的话,也会推一份给主人(`ownerQQ`,空着取 `allowPrivate` 的第一个);有人说话的轮次是在回那个人,不另推。
|
|
113
|
+
|
|
114
|
+
**看门狗**(`supervise`,默认开):QQ 开着时每 30 秒探一次 `wsUrl` 的端口,不通就按 `snowlumaHome` 把 SnowLuma 拉起来(本机有 `SnowLuma-watchdog` 计划任务时借它跑,能活过 DSH 重启;没有就直接起进程,只活到 DSH 退出)。拉不起来的原因写在卡上。不想让插件动手就设成 `false`,卡上的「拉起 SnowLuma」按钮照旧能用。
|
|
115
|
+
|
|
116
|
+
卡上那个「打开 SnowLuma 控制台」的按钮,读 `snowlumaHome` 下 `config/runtime.json` 里的地址与端口,带着一次性登录票据打开系统浏览器——第一次要先填一次 SnowLuma 的面板密码,之后记在世界目录的 `panel.json` 里(权限 600),不用再输。
|
|
117
|
+
|
|
118
|
+
## 安装
|
|
119
|
+
|
|
120
|
+
需要 DSH 桌面版,世界控制台和生活线都依赖它。
|
|
121
|
+
|
|
122
|
+
**最省事的办法**:把这个仓库地址交给她,让她照 [INSTALL.md](INSTALL.md) 自己装。那份说明是写给模型看的——每一步都有命令、判定和失败对照表,连同 QQ 怎么接进来、哪两个动作必须人来做,一路写到底。
|
|
123
|
+
|
|
124
|
+
**自己装**:
|
|
125
|
+
|
|
126
|
+
```powershell
|
|
127
|
+
npm ci
|
|
128
|
+
npm pack
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
用 DSH 自带的 pnpm 把生成的 `dsh-world-*.tgz` 装进你的 profile。不要用 `link:` 指向项目目录,否则会加载项目自己的一份 Cordis。装好后重启 DSH,打开设置里的「世界控制台」,按需填写人设,按「开始」。
|
|
132
|
+
|
|
133
|
+
也可从 [CI](.github/workflows/ci.yml) 对应运行的 Artifacts 下载检查通过的编译安装包;Windows 和 Linux 分别提供产物。本机复现检查的命令见 [贡献协议](CONTRIBUTING.md#ci-与安装包验证)。
|
|
134
|
+
|
|
135
|
+
**已有 world 更新**:正常退出 DSH 后,用 [`scripts/update-world.mjs`](scripts/update-world.mjs) 指定原 profile、下载的 `.tgz` 和 DSH 自带 pnpm。脚本先备份完整 profile、世界及会话,再更新并校验;失败恢复旧 profile,保留她已有文件。安装成品无需 Git、npm 或 TypeScript,完整命令与恢复说明见 [已有 world 升级](INSTALL.md#已有-world用编译包更新)。
|
|
136
|
+
|
|
137
|
+
**换用只留对话的压缩方式**(可选):
|
|
138
|
+
|
|
139
|
+
```powershell
|
|
140
|
+
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\enable-tool-free-compaction.ps1 -profilePath '<你的 DSH profile 目录>'
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
脚本会把 profile 里原版的压缩条目换成 `dsh-world/compaction`,并留一份备份。它对整个 profile 生效,不限世界工作区,见上文「对世界工作区以外的影响」。
|
|
144
|
+
|
|
145
|
+
## 设置
|
|
146
|
+
|
|
147
|
+
大多数东西在世界控制台里改。其余的写在 profile 的 `cordis.patch.yml` 里,按 id 覆盖插件那一行,只写想改的项:
|
|
148
|
+
|
|
149
|
+
```yaml
|
|
150
|
+
- id: dsh-world
|
|
151
|
+
name: dsh-world
|
|
152
|
+
config:
|
|
153
|
+
companionName: 小鱼 # 她的名字(控制台人设里写了名字时以人设为准),默认 TA
|
|
154
|
+
partnerName: 伙伴 # 她对你的称呼,默认 伙伴
|
|
155
|
+
worldId: default # 世界名;换一个就是另一个世界、另一份记忆
|
|
156
|
+
agentPreset: standard # 她所在的预设
|
|
157
|
+
timeZone: Asia/Seoul # 默认系统时区
|
|
158
|
+
life: true # 生活线,默认开启
|
|
159
|
+
archiveScope: workspace # workspace:家的工作区;home:仅当前家会话
|
|
160
|
+
fallbackWakeTime: '09:00' # 没定闹钟时,早上几点叫醒她
|
|
161
|
+
diaryDir: C:/path/to/日记 # 日记目录,默认在世界目录里
|
|
162
|
+
toast: true # 主动找你时发 Windows 系统通知
|
|
163
|
+
# toastAppId: com.deepseek.dsh # 通知身份,默认在开始菜单里找 DSH 桌面版(com.deepseek.dsh 或 electron.app.DeepSeek Harness)
|
|
164
|
+
bridge: false # 打开本地的桥
|
|
165
|
+
wechat: false # 打开独立微信接口,需另行启动 Windows 适配器
|
|
166
|
+
outlets: [] # 接收她的话的本地程序,见文末
|
|
167
|
+
allowedHosts: [] # 通过反向代理从局域网访问控制台时,放行的域名或 IP
|
|
168
|
+
qqNative: # 插件自己连 OneBot(原生通道);不写这一块就是不接 QQ
|
|
169
|
+
enabled: false # 打开通道:连上、控制台里出 QQ 卡
|
|
170
|
+
wsUrl: ws://127.0.0.1:3003 # OneBot 的 WS 服务地址(不是 HTTP 那个)
|
|
171
|
+
accessToken: '' # OneBot WS 服务端自己的 token,与 HTTP 那份不是一码事
|
|
172
|
+
allowPrivate: [] # 谁能私聊她;留空 = 谁都不理
|
|
173
|
+
ownerQQ: '' # 她自己开口的话推给谁;空着取 allowPrivate 的第一个
|
|
174
|
+
allowGroups: [] # 群白名单
|
|
175
|
+
autoReply: true # false = 只看不回
|
|
176
|
+
contextMessages: 6 # 每轮带上最近的几条
|
|
177
|
+
batchQuietMs: 10000 # 同一会话这几毫秒内的话攒成一条问她;0 = 一条一问
|
|
178
|
+
groupTrigger: mention # mention:@ 她/引用她/命中关键词才接;all:每句都接
|
|
179
|
+
groupKeywords: [] # groupTrigger: mention 时算「在叫她」的词
|
|
180
|
+
mutedUntil: '' # 静默到这个时间(ISO):只收不回,到点自己醒
|
|
181
|
+
bindHomeSession: owner # owner:主人私聊用家会话、群各自独立;all:都用;none:各建一个
|
|
182
|
+
snowlumaHome: '' # SnowLuma 安装目录:控制台那扇门、看门狗和「拉起 SnowLuma」都靠它
|
|
183
|
+
supervise: true # 看门狗:端口不通就把 SnowLuma 拉起来
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**改她的措辞**:世界提示词可以直接在控制台里改。闹钟响时、提前停下时、每日回顾时她收到的话,在世界目录里放一份 `alarm.md` 就能按段覆盖,段落名和可用的占位符见 `templates/alarm.md`。插件写给她的话一律用第一人称「我」,读起来是她自己的念头。
|
|
187
|
+
|
|
188
|
+
**时间**:建议把预设里 `time-context` 条目的 `refreshIntervalMs` 设为 `0`,让她每一步都知道现在几点。
|
|
189
|
+
|
|
190
|
+
## 她的东西放在哪
|
|
191
|
+
|
|
192
|
+
都在 `<DSH_HOME>/worlds/<worldId>/` 下(`DSH_HOME` 默认是用户目录下的 `.dsh`):
|
|
193
|
+
|
|
194
|
+
| 位置 | 是什么 |
|
|
195
|
+
|---|---|
|
|
196
|
+
| `conversations/` | 按天归档的聊天原文(给人看的导出,正本在 `archive.sqlite`) |
|
|
197
|
+
| `room/` | 她的房间;`room/我是谁.md` 是她的自述 |
|
|
198
|
+
| `diary/` | 她的日记(可用 `diaryDir` 换位置) |
|
|
199
|
+
| `persona.md`、`world-prompt.md`、`alarm.md` | 你写给她的人设、世界提示词和闹钟措辞 |
|
|
200
|
+
| `world.json` | 世界是否在运行、每天额度、近期记忆轮数和选定归档范围 |
|
|
201
|
+
| `activity/` | 她在家里用过的工具,只记录,不进记忆 |
|
|
202
|
+
| `photos/album.sqlite` | 收藏的图片、说明与标签;首次导入旧相册后仍保留原文件 |
|
|
203
|
+
| `wechat.json` | 本机微信模块的地址、令牌和协议版本,不应公开 |
|
|
204
|
+
| `wechat-outbox.sqlite` | 微信工具安排的发送队列和确认状态 |
|
|
205
|
+
| `qq-native.json` | 控制台上 QQ 卡改过的设置(会不会自己回话、静默到几点、白名单、阳台端口),盖在 profile 默认之上 |
|
|
206
|
+
| `panel.json` | SnowLuma 控制台那扇门的登录票据,权限 600,不应公开 |
|
|
207
|
+
|
|
208
|
+
备份时整个目录一起备份即可,最好先停止 DSH。
|
|
209
|
+
|
|
210
|
+
## 桥与推送协议
|
|
211
|
+
|
|
212
|
+
给桌宠等本地程序用。
|
|
213
|
+
|
|
214
|
+
**把话送进她的家**(`bridge: true`):插件启动时写出 `<世界目录>/bridge.json`,内容是 `{ origin, token, name, ... }`。向 `POST {origin}/dsh-world/bridge/say` 发 `{ "text": "..." }`,请求头带 `x-dsh-world-token: <token>`,会立即返回 `202`。这句话会作为你本人说的话进入她的家和记忆。
|
|
215
|
+
|
|
216
|
+
**接收她的话**(`outlets`):每个目标写一个 `name`,地址用 `url`(其中 `{origin}` 会被替换),或者用 `urlFile` + `path`(端口会变的程序用这个);再用 `kinds` 选择要接收哪些:`reply` 是桥上那句话的回复,`busy` 表示她正忙,`reach` 是她主动找你。插件会向目标 `POST`:
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{ "text": "她的话(纯文本)", "kind": "reply", "name": "她的名字", "images": ["http://…"], "image": "表情名" }
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
目标回复 2xx 就算送到。送不到的会显示在控制台的「健康」里。
|
|
223
|
+
|
|
224
|
+
## 参与贡献
|
|
225
|
+
|
|
226
|
+
**PR 统一提到 `dev` 分支**,`main` 由维护者从 `dev` 并入后发布,详见 [贡献协议](CONTRIBUTING.md#分支与-pr)。新增 QQ、B 站等生态模块前,请阅读 [贡献协议](CONTRIBUTING.md):平台代码放在 `src/ecosystem/<channel>/`,复用统一身份、会话和归档能力;涉及内核的修改必须说明原因、影响、兼容性与验证结果。几条硬性要求:一个 PR 只做一件事;平台 SDK 只能是可选依赖,模块默认关闭,新依赖要先开 Issue;她的主动性来自她自己的安排,插件不往对话里推提醒,改动生活线核心或给她新增工具之前先开 Issue 讨论。
|
|
227
|
+
|
|
228
|
+
## 许可
|
|
229
|
+
|
|
230
|
+
MIT
|