dsh-paofu-console 1.0.5 → 1.1.0

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 ADDED
@@ -0,0 +1,45 @@
1
+ # CHANGELOG
2
+
3
+ ## 1.1.0
4
+
5
+ - 情绪页改版:坐标盘 → **情绪脑图**
6
+ - 头部轮廓(贝塞尔)+ 7 条脑沟 + 4 条斜向回沟
7
+ - 情绪锚点从 12 个扩到 24 个(兴奋/雀跃/期待/开心/满足/亲近/温柔/安心/平静/好奇/认真/害羞/生气/烦躁/不安/焦虑/委屈/疏离/难过/失落/疲惫/困/放空/苦恼)
8
+ - 每个锚点从底部内核拉一条二次贝塞尔连线,离当前情绪越近越亮,线上有光点流动
9
+ - 标签贪心避让 + 悬停强制显示;当前情绪收进左上角胶囊
10
+ - 手机端导航:横滑 + 右缘渐隐 + 右下「全部 ▾」底部面板(按分组两列列出全部页面,当前项高亮,切换后自动滚到中间)
11
+ - 新增深链:`?page=mood` 直接打开指定页面
12
+ - 修复图片 404:桌面预览服务器补 `/meme/`、`/bg.js` 转发,剥离 `/__paofu__`,修掉 `/dsh-paofu-console/meme/…` 自跳转循环,静态资源找不到时回落到 console 目录;插件 handler 补 `/meme/` 反代
13
+ - 文档:安装示例版本号更新;`接上桥接.md` 更名 `CONNECT-BRIDGE.md`(原中文名在 zip / 跨平台下会乱码)
14
+
15
+ ## 1.0.8
16
+
17
+ - 删掉右上角遗留的「声音 · 关」胶囊:它从加进页面起就没有绑任何事件,是个死控件(音量与播放本来就在「界面设置 → 背景音乐」里)
18
+
19
+ ## 1.0.7
20
+
21
+ - 找回最初设计里的两样东西:
22
+ - **背景鱼群**:画布矢量小鱼(青绿→蓝渐变、尾巴摆动、随机游弋与折返),铺在内容之下的背景层,半透明不抢字
23
+ - **鲸鱼空灵声**:WebAudio 现场合成(低频正弦滑音 + 泛音 + 低通),16–42 秒随机一次,不占素材、不联网
24
+ - 右上角工具条新增两枚开关:`鱼群` / `鲸声`,状态存本机,刷新后保持
25
+ - 鲸声受浏览器自动播放限制:页面首次点击后才会出声(和背景音乐同一个规矩)
26
+
27
+ ## 1.0.6
28
+
29
+ - 新增 **Ctrl+滚轮缩放整个界面**(60%–160%,与设置里的「界面缩放」同一份值,会记住)
30
+ - 缩放时底部弹出「界面缩放 N%」提示,`Ctrl+0` 一键回到 100%
31
+ - 滚轮事件用捕获阶段并阻止冒泡,鼠标停在记忆网/情绪盘上也不会误转 3D 视角
32
+ - 记忆网络修复:挂在「不在会话列表里的私聊」上的记忆不再被丢弃(自动生成虚拟会话节点),节点从几个恢复到全部 59 条
33
+ - 记忆网络节点补上点击命中(松手位移 ≤8px、18px 内取最近点)→ 点节点直接开详情抽屉
34
+
35
+ ## 0.1.1
36
+
37
+ - 工具条最左新增「桌宠」开关(藏起来也能找回,状态记忆)
38
+ - 设置新增「桌宠」区:大小 60–160%、状态下拉、撞墙反弹开关、自定义形象(PNG/GIF/WebP ≤2.5MB,本机存储)、恢复默认
39
+ - 桌宠换成真帧动画(转圈圈 / 开心 / 吃饭 / 打瞌睡 / 生气跺脚,各 51 帧)
40
+ - 新增独立预览服务器 `serve.mjs`(不装 DSH 也能看)
41
+ - 新增一键安装脚本 `install.ps1` / `install.sh`
42
+
43
+ ## 0.1.0
44
+
45
+ - 首个版本:`/dsh-paofu-console` 前缀路由、静态页、`/api` `/data` 反代 9896、DSH 细栏、Esc 退出
package/README.md CHANGED
@@ -1,166 +1,177 @@
1
- # 状态台(dsh-paofu-console)
2
-
3
- **DeepSeek Harness 插件版**。装上以后 DSH 里多一个地址:
4
-
5
- ```
6
- <你的 DSH 地址>/dsh-paofu-console/
7
- ```
8
-
9
- 打开就是整块状态台:在线状态、未读数、用量与余额、表情库、记忆、小说、技能、承诺、时间线。
10
-
11
- - **零依赖**,纯 Node 标准库,`npm install` 都不用跑
12
- - **自带数据服务**:插件自己在本机回环起一个服务(默认端口 9896),不用另开命令行
13
- - **只读**:不调用模型、不改文件(只有「刷新」和表情上传会动自己的 `data/`)
14
- - 没有桥接也能跑,只是在线、未读那几块空着
15
-
16
- ---
17
-
18
- ## 最省事:把一句话贴给 DSH
19
-
20
- 解压后,在 **DSH 里新建一个对话**,把下面这段原样贴进去,把尖括号换成你解压出来的实际位置:
21
-
22
- > 我解压了一个 DSH 插件 `dsh-paofu-console` 在 `<把解压后的完整路径贴这里>`。
23
- > 帮我:1)复制到我当前的 DSH profile 的 `node_modules` 下;2)在 profile 的 `package.json` 里把
24
- > `dsh-paofu-console` 加进 `dependencies` 和 `dsh.profile.bundles`;3)重启后告诉我
25
- > `<DSH地址>/dsh-paofu-console/` 能不能打开、有没有报错。
26
-
27
- DSH 会自己找 profile、改包清单、重启验证。人只需要看最后一句结果。
28
-
29
- **如果 DSH 说找不到 profile**,把下面这句也贴给它:
30
-
31
- > 用 `dsh doctor`,或者看一眼 `%USERPROFILE%\.dsh\profiles` 下面有哪些目录,挑里面有 `package.json` 和 `node_modules` 的那个。
32
-
33
- 下面是手动装的完整步骤,装不上时对着查。
34
-
35
- ---
36
-
37
- ## 手动安装
38
-
39
- ### 第一步:确认 Node 版本
40
-
41
- ```bash
42
- node -v
43
- ```
44
-
45
- 要 **20 或更高**。没有的话去 <https://nodejs.org> 装 LTS 版。
46
-
47
- ### 第二步:找到你的 DSH profile 目录
48
-
49
- 一般在这两个位置之一:
50
-
51
- ```
52
- %USERPROFILE%\.dsh\profiles\desktop
53
- %USERPROFILE%\.dsh\profiles\web
54
- ```
55
-
56
- 看哪个目录里有 `package.json` 和 `node_modules` 就是它(桌面版通常是 `desktop`)。
57
-
58
- ### 第三步:放进 node_modules
59
-
60
- 把整个 `dsh-paofu-console` 文件夹复制到:
61
-
62
- ```
63
- <profile目录>\node_modules\dsh-paofu-console\
64
- ```
65
-
66
- **或者**直接交给 DeepSeek Harness 处理,把下面这段话贴给它:
67
-
68
- > 我解压了一个 DSH 插件 `dsh-paofu-console` 在 `<路径>`,帮我用 npm/软链接装进当前的 DSH profile,
69
- > 然后在 `~/.dsh/profiles/<profile>/package.json` 的 `dependencies` 里加这个包,
70
- > 并把它加进 `dsh.profile.bundles` 数组。
71
-
72
- ### 第四步:让 profile 认识它
73
-
74
- 打开 `<profile目录>\package.json`,改两个地方:
75
-
76
- ```json
77
- {
78
- "dependencies": {
79
- "dsh-paofu-console": "1.0.5"
80
- },
81
- "dsh": {
82
- "profile": {
83
- "bundles": [
84
- "...其它插件",
85
- "dsh-paofu-console"
86
- ]
87
- }
88
- }
89
- }
90
- ```
91
-
92
- ### 第五步:重启 DSH
93
-
94
- 桌面版一般会热加载;没反应就完全退出再开一次。
95
-
96
- ---
97
-
98
- ## 验证装好了没
99
-
100
- 启动 DSH 后,控制台里应该出现:
101
-
102
- ```
103
- [paofu-console] 数据服务 http://<回环地址>:9896
104
- ```
105
-
106
- 然后访问(端口换成你 DSH 实际用的):
107
-
108
- ```bash
109
- curl -s -o /dev/null -w '%{http_code}\n' '<你的 DSH 地址>/dsh-paofu-console/'
110
- ```
111
-
112
- `200` 就是成了。
113
-
114
- ---
115
-
116
- ## 想让它显示真实的 QQ 桥接数据
117
-
118
- 看包里的 `接上桥接.md`。核心是一句话:**桥接不在就用示例数据,不报错**。
119
-
120
- 数据服务会读这些位置:
121
-
122
- | 面板上的东西 | 读的路径 |
123
- | --- | --- |
124
- | 在线、未读数、谁最近说过话 | `<桥接>/api/status` |
125
- | 会话列表 | `<桥接>/state/social-v2.json` |
126
- | 日记 | `<桥接>/state/diary/*.md` |
127
- | 表情库 | `<桥接>/memes/` |
128
- | 语音 | `<桥接>/audio/` |
129
- | 用量、余额 | `<桥接>/scripts/` 里的四个导出脚本 |
130
-
131
- ## 环境变量(都可选)
132
-
133
- | 变量 | 默认 | 作用 |
134
- | --- | --- | --- |
135
- | `PAFU_BRIDGE` | 自动找(家目录 / 文档 / 当前目录) | 桥接根目录 |
136
- | `PAFU_BRIDGE_PORT` | 桥接的默认口 | 桥接的 HTTP 端口 |
137
- | `PAFU_PORT` | `9896` | 数据服务端口,被占了会复用现成的 |
138
- | `PAFU_CONSOLE` | 包内目录 | 面板数据根目录(下挂 `data/`) |
139
- | `PAFU_TOKEN` | 读 `<BRIDGE>/state/console-token` | 桥接控制台令牌 |
140
-
141
- ## 自带什么
142
-
143
- `data/` 里全是**示例数据**,直接改文本就换成你自己的:
144
-
145
- `mood.json`(心情)、`promises.json`(承诺账本)、`skills.json`(技能)、
146
- `novel.md`(小说,支持 Markdown)、`history.json`(时间线)、`memory.json`(记忆导出)。
147
-
148
- ## 目录
149
-
150
- ```
151
- lib/index.mjs 宿主:挂路由 + 起数据服务 + 反代
152
- web/index.html 整个前端(单文件,无构建)
153
- data/ 面板自己的数据(示例)
154
- cordis.patch.yml 注册一条宿主行
155
- icon.svg 图标
156
- ```
157
-
158
- ## 已知限制
159
-
160
- - 两个入口都只绑 `127.0.0.1`,**外网访问不到**(面板没有密码,这是故意的)
161
- - 用量/余额卡片依赖桥接侧导出脚本,纯离线时这两块是空的
162
- - 3D 记忆网络需要浏览器支持 WebGL
163
-
164
- ## 许可
165
-
166
- MIT,见 `LICENSE`。
1
+ # 状态台(dsh-paofu-console)
2
+
3
+ **DeepSeek Harness 插件版**。装上以后 DSH 里多一个地址:
4
+
5
+ ```
6
+ <你的 DSH 地址>/dsh-paofu-console/
7
+ ```
8
+
9
+ 打开就是整块状态台:在线状态、未读数、用量与余额、表情库、记忆、小说、技能、承诺、时间线。
10
+
11
+ - **零依赖**,纯 Node 标准库,`npm install` 都不用跑
12
+ - **自带数据服务**:插件自己在本机回环起一个服务(默认端口 9896),不用另开命令行
13
+ - **只读**:不调用模型、不改文件(只有「刷新」和表情上传会动自己的 `data/`)
14
+ - 没有桥接也能跑,只是在线、未读那几块空着
15
+
16
+ ---
17
+
18
+ ## 最省事:把一句话贴给 DSH
19
+
20
+ 解压后,在 **DSH 里新建一个对话**,把下面这段原样贴进去,把尖括号换成你解压出来的实际位置:
21
+
22
+ > 我解压了一个 DSH 插件 `dsh-paofu-console` 在 `<把解压后的完整路径贴这里>`。
23
+ > 帮我:1)复制到我当前的 DSH profile 的 `node_modules` 下;2)在 profile 的 `package.json` 里把
24
+ > `dsh-paofu-console` 加进 `dependencies` 和 `dsh.profile.bundles`;3)重启后告诉我
25
+ > `<DSH地址>/dsh-paofu-console/` 能不能打开、有没有报错。
26
+
27
+ DSH 会自己找 profile、改包清单、重启验证。人只需要看最后一句结果。
28
+
29
+ **如果 DSH 说找不到 profile**,把下面这句也贴给它:
30
+
31
+ > 用 `dsh doctor`,或者看一眼 `%USERPROFILE%\.dsh\profiles` 下面有哪些目录,挑里面有 `package.json` 和 `node_modules` 的那个。
32
+
33
+ 下面是手动装的完整步骤,装不上时对着查。
34
+
35
+ ---
36
+
37
+ ## 手动安装
38
+
39
+ ### 第一步:确认 Node 版本
40
+
41
+ ```bash
42
+ node -v
43
+ ```
44
+
45
+ 要 **20 或更高**。没有的话去 <https://nodejs.org> 装 LTS 版。
46
+
47
+ ### 第二步:找到你的 DSH profile 目录
48
+
49
+ 一般在这两个位置之一:
50
+
51
+ ```
52
+ %USERPROFILE%\.dsh\profiles\desktop
53
+ %USERPROFILE%\.dsh\profiles\web
54
+ ```
55
+
56
+ 看哪个目录里有 `package.json` 和 `node_modules` 就是它(桌面版通常是 `desktop`)。
57
+
58
+ ### 第三步:放进 node_modules
59
+
60
+ 把整个 `dsh-paofu-console` 文件夹复制到:
61
+
62
+ ```
63
+ <profile目录>\node_modules\dsh-paofu-console\
64
+ ```
65
+
66
+ **或者**直接交给 DeepSeek Harness 处理,把下面这段话贴给它:
67
+
68
+ > 我解压了一个 DSH 插件 `dsh-paofu-console` 在 `<路径>`,帮我用 npm/软链接装进当前的 DSH profile,
69
+ > 然后在 `~/.dsh/profiles/<profile>/package.json` 的 `dependencies` 里加这个包,
70
+ > 并把它加进 `dsh.profile.bundles` 数组。
71
+
72
+ ### 第四步:让 profile 认识它
73
+
74
+ 打开 `<profile目录>\package.json`,改两个地方:
75
+
76
+ ```json
77
+ {
78
+ "dependencies": {
79
+ "dsh-paofu-console": "1.1.0"
80
+ },
81
+ "dsh": {
82
+ "profile": {
83
+ "bundles": [
84
+ "...其它插件",
85
+ "dsh-paofu-console"
86
+ ]
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ ### 第五步:重启 DSH
93
+
94
+ 桌面版一般会热加载;没反应就完全退出再开一次。
95
+
96
+ ---
97
+
98
+ ## 验证装好了没
99
+
100
+ 启动 DSH 后,控制台里应该出现:
101
+
102
+ ```
103
+ [paofu-console] 数据服务 http://<回环地址>:9896
104
+ ```
105
+
106
+ 然后访问(端口换成你 DSH 实际用的):
107
+
108
+ ```bash
109
+ curl -s -o /dev/null -w '%{http_code}\n' '<你的 DSH 地址>/dsh-paofu-console/'
110
+ ```
111
+
112
+ `200` 就是成了。
113
+
114
+ ---
115
+
116
+ ## 想让它显示真实的 QQ 桥接数据
117
+
118
+ 看包里的 `CONNECT-BRIDGE.md`。核心是一句话:**桥接不在就用示例数据,不报错**。
119
+
120
+ 数据服务会读这些位置:
121
+
122
+ | 面板上的东西 | 读的路径 |
123
+ | --- | --- |
124
+ | 在线、未读数、谁最近说过话 | `<桥接>/api/status` |
125
+ | 会话列表 | `<桥接>/state/social-v2.json` |
126
+ | 日记 | `<桥接>/state/diary/*.md` |
127
+ | 表情库 | `<桥接>/memes/` |
128
+ | 语音 | `<桥接>/audio/` |
129
+ | 用量、余额 | `<桥接>/scripts/` 里的四个导出脚本 |
130
+
131
+ ## 环境变量(都可选)
132
+
133
+ | 变量 | 默认 | 作用 |
134
+ | --- | --- | --- |
135
+ | `PAFU_BRIDGE` | 自动找(家目录 / 文档 / 当前目录) | 桥接根目录 |
136
+ | `PAFU_BRIDGE_PORT` | 桥接的默认口 | 桥接的 HTTP 端口 |
137
+ | `PAFU_PORT` | `9896` | 数据服务端口,被占了会复用现成的 |
138
+ | `PAFU_CONSOLE` | 包内目录 | 面板数据根目录(下挂 `data/`) |
139
+ | `PAFU_TOKEN` | 读 `<BRIDGE>/state/console-token` | 桥接控制台令牌 |
140
+
141
+ ## 自带什么
142
+
143
+ `data/` 里全是**示例数据**,直接改文本就换成你自己的:
144
+
145
+ `mood.json`(心情)、`promises.json`(承诺账本)、`skills.json`(技能)、
146
+ `novel.md`(小说,支持 Markdown)、`history.json`(时间线)、`memory.json`(记忆导出)。
147
+
148
+ ## 目录
149
+
150
+ ```
151
+ lib/index.mjs 宿主:挂路由 + 起数据服务 + 反代
152
+ web/index.html 整个前端(单文件,无构建)
153
+ data/ 面板自己的数据(示例)
154
+ cordis.patch.yml 注册一条宿主行
155
+ icon.svg 图标
156
+ ```
157
+
158
+ ## 更新记录
159
+
160
+ ### 1.1.0
161
+ - 情绪页换成「情绪脑图 · 3D」:头部轮廓 + 脑沟纹理,24 个情绪锚点从内核拉线,越近越亮、线上有光点,标签自动避让
162
+ - 手机端导航支持横滑并新增「全部 ▾」底部面板,一屏看不到的页面都在里面
163
+ - 支持深链 `?page=mood` 直接打开指定页面
164
+ - 修复桌面窗口 / 插件页里表情图、桌宠图 404(/meme、/assets 转发)
165
+
166
+ ### 1.0.5 及更早
167
+ 见仓库的 Releases 页。
168
+
169
+ ## 已知限制
170
+
171
+ - 两个入口都只绑 `127.0.0.1`,**外网访问不到**(面板没有密码,这是故意的)
172
+ - 用量/余额卡片依赖桥接侧导出脚本,纯离线时这两块是空的
173
+ - 3D 记忆网络需要浏览器支持 WebGL
174
+
175
+ ## 许可
176
+
177
+ MIT,见 `LICENSE`。
package/install.ps1 ADDED
@@ -0,0 +1,53 @@
1
+ # 安装 dsh-paofu-console 到本机 DSH
2
+ #
3
+ # powershell -ExecutionPolicy Bypass -File install.ps1
4
+ #
5
+ # 做的事:拷到 profile 的 node_modules,改 package.json 的依赖与 bundles,
6
+ # 都先备份;不动你已有的任何插件。
7
+
8
+ $ErrorActionPreference = 'Stop'
9
+
10
+ $here = Split-Path -Parent $MyInvocation.MyCommand.Path
11
+ $profileDir = Join-Path $env:USERPROFILE '.dsh\profiles\desktop'
12
+ $pkgPath = Join-Path $profileDir 'package.json'
13
+ $target = Join-Path $profileDir 'node_modules\dsh-paofu-console'
14
+
15
+ if (-not (Test-Path $pkgPath)) {
16
+ Write-Host "找不到 DSH profile:$profileDir" -ForegroundColor Red
17
+ Write-Host "这个插件需要 DSH 桌面版(默认在 %USERPROFILE%\.dsh\profiles\desktop)。"
18
+ exit 1
19
+ }
20
+
21
+ $stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
22
+ Copy-Item $pkgPath "$pkgPath.bak-paofu-$stamp"
23
+ Write-Host "已备份 profile 配置:package.json.bak-paofu-$stamp"
24
+
25
+ if (Test-Path $target) { Remove-Item $target -Recurse -Force }
26
+ New-Item -ItemType Directory -Path $target -Force | Out-Null
27
+ Copy-Item (Join-Path $here 'lib') (Join-Path $target 'lib') -Recurse -Force
28
+ Copy-Item (Join-Path $here 'web') (Join-Path $target 'web') -Recurse -Force
29
+ foreach ($f in @('package.json','cordis.patch.yml','README.md','LICENSE','icon.svg')) {
30
+ $src = Join-Path $here $f
31
+ if (Test-Path $src) { Copy-Item $src (Join-Path $target $f) -Force }
32
+ }
33
+ Write-Host "已安装到:$target"
34
+
35
+ $json = Get-Content $pkgPath -Raw -Encoding UTF8 | ConvertFrom-Json
36
+ if (-not $json.dependencies) {
37
+ $json | Add-Member -NotePropertyName dependencies -NotePropertyValue ([pscustomobject]@{}) -Force
38
+ }
39
+ $json.dependencies | Add-Member -NotePropertyName 'dsh-paofu-console' -NotePropertyValue '0.1.1' -Force
40
+
41
+ if (-not $json.dsh) { $json | Add-Member -NotePropertyName dsh -NotePropertyValue ([pscustomobject]@{}) -Force }
42
+ if (-not $json.dsh.profile) { $json.dsh | Add-Member -NotePropertyName profile -NotePropertyValue ([pscustomobject]@{}) -Force }
43
+ $bundles = @($json.dsh.profile.bundles)
44
+ if ($bundles -notcontains 'dsh-paofu-console') {
45
+ $bundles += 'dsh-paofu-console'
46
+ $json.dsh.profile | Add-Member -NotePropertyName bundles -NotePropertyValue $bundles -Force
47
+ }
48
+
49
+ $json | ConvertTo-Json -Depth 20 | Set-Content $pkgPath -Encoding UTF8
50
+ Write-Host "已登记到 dsh.profile.bundles" -ForegroundColor Green
51
+ Write-Host ""
52
+ Write-Host "重启 DSH 后打开: http://127.0.0.1:57514/dsh-paofu-console/" -ForegroundColor Cyan
53
+ Write-Host "(端口以你自己的 DSH 为准;Esc 退出)"
package/install.sh ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env bash
2
+ # 安装 dsh-paofu-console 到本机 DSH(macOS / Linux)
3
+ # bash install.sh
4
+ set -euo pipefail
5
+
6
+ HERE="$(cd "$(dirname "$0")" && pwd)"
7
+ PROFILE="${DSH_PROFILE:-$HOME/.dsh/profiles/desktop}"
8
+ PKG="$PROFILE/package.json"
9
+ TARGET="$PROFILE/node_modules/dsh-paofu-console"
10
+
11
+ if [ ! -f "$PKG" ]; then
12
+ echo "找不到 DSH profile:$PROFILE" >&2
13
+ exit 1
14
+ fi
15
+
16
+ STAMP="$(date +%Y%m%d-%H%M%S)"
17
+ cp "$PKG" "$PKG.bak-paofu-$STAMP"
18
+ echo "已备份:$PKG.bak-paofu-$STAMP"
19
+
20
+ rm -rf "$TARGET"
21
+ mkdir -p "$TARGET"
22
+ cp -R "$HERE/lib" "$TARGET/lib"
23
+ cp -R "$HERE/web" "$TARGET/web"
24
+ for f in package.json cordis.patch.yml README.md LICENSE icon.svg; do
25
+ [ -f "$HERE/$f" ] && cp "$HERE/$f" "$TARGET/$f"
26
+ done
27
+ echo "已安装到:$TARGET"
28
+
29
+ node - "$PKG" <<'NODE'
30
+ const fs = require('node:fs')
31
+ const pkgPath = process.argv[2]
32
+ const p = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
33
+ p.dependencies = p.dependencies || {}
34
+ p.dependencies['dsh-paofu-console'] = '0.1.1'
35
+ p.dsh = p.dsh || {}
36
+ p.dsh.profile = p.dsh.profile || {}
37
+ const bundles = new Set(p.dsh.profile.bundles || [])
38
+ bundles.add('dsh-paofu-console')
39
+ p.dsh.profile.bundles = [...bundles]
40
+ fs.writeFileSync(pkgPath, JSON.stringify(p, null, 2) + '\n')
41
+ console.log('已登记到 dsh.profile.bundles')
42
+ NODE
43
+
44
+ echo
45
+ echo "重启 DSH 后打开: http://127.0.0.1:57514/dsh-paofu-console/"
46
+ echo "(端口以你自己的 DSH 为准;Esc 退出)"
package/lib/index.mjs CHANGED
@@ -812,6 +812,14 @@ export function createHandler() {
812
812
  return;
813
813
  }
814
814
 
815
+ // 页面里的相对路径(/api /data /meme /bg.js)也直接转到数据服务,
816
+ // 这样插件页不依赖前端 shim 也能取到数据。
817
+ if (pathname.startsWith('/meme/')) { proxyToData(req, res, pathname, url.search); return; }
818
+ if (pathname === '/bg.js' || pathname.startsWith('/api/') || pathname.startsWith('/data/') || pathname.startsWith('/meme/')) {
819
+ proxyToData(req, res, pathname, url.search);
820
+ return;
821
+ }
822
+
815
823
  const method = String(req.method || 'GET').toUpperCase();
816
824
  if (method !== 'GET' && method !== 'HEAD') { sendJson(res, 405, { ok: false, error: 'method not allowed' }); return; }
817
825
 
package/package.json CHANGED
@@ -1,20 +1,9 @@
1
1
  {
2
2
  "name": "dsh-paofu-console",
3
- "version": "1.0.5",
3
+ "version": "1.1.0",
4
4
  "private": false,
5
5
  "description": "状态台:给 DeepSeek Harness 配的本地状态面板(单页,自带数据服务,零依赖,不调用模型)",
6
6
  "license": "MIT",
7
- "author": {
8
- "name": "esun888"
9
- },
10
- "repository": {
11
- "type": "git",
12
- "url": "git+https://gitee.com/the-concept-of-esuns-world/ds-big-fish-status-panel.git"
13
- },
14
- "homepage": "https://gitee.com/the-concept-of-esuns-world/ds-big-fish-status-panel",
15
- "bugs": {
16
- "url": "https://gitee.com/the-concept-of-esuns-world/ds-big-fish-status-panel/issues"
17
- },
18
7
  "type": "module",
19
8
  "main": "./lib/index.mjs",
20
9
  "exports": {
@@ -29,7 +18,11 @@
29
18
  "icon.svg",
30
19
  "README.md",
31
20
  "LICENSE",
32
- "接上桥接.md"
21
+ "CONNECT-BRIDGE.md",
22
+ "CHANGELOG.md",
23
+ "install.ps1",
24
+ "install.sh",
25
+ "serve.mjs"
33
26
  ],
34
27
  "engines": {
35
28
  "node": ">=20"
@@ -44,5 +37,8 @@
44
37
  "bundle": {
45
38
  "patch": "./cordis.patch.yml"
46
39
  }
40
+ },
41
+ "scripts": {
42
+ "start": "node serve.mjs"
47
43
  }
48
44
  }
package/serve.mjs ADDED
@@ -0,0 +1,100 @@
1
+ // 独立预览:不装 DSH 也能看这个界面。
2
+ // node serve.mjs → http://127.0.0.1:8788/
3
+ // node serve.mjs 9000 → 换端口
4
+ // 数据仍然来自本机状态台数据服务(127.0.0.1:9896),没有它页面会提示「数据服务没有响应」。
5
+
6
+ import fs from 'node:fs'
7
+ import http from 'node:http'
8
+ import path from 'node:path'
9
+ import { fileURLToPath } from 'node:url'
10
+
11
+ const HERE = path.dirname(fileURLToPath(import.meta.url))
12
+ const WEB = path.join(HERE, 'web')
13
+ const CONSOLE_ROOT = 'D:/qq-bridge/state/agents/console'
14
+ const PORT = Number(process.argv[2] || 8788)
15
+ const PREFIX = '/dsh-paofu-console'
16
+ const UPSTREAM = { host: '127.0.0.1', port: 9896 }
17
+
18
+ const MIME = {
19
+ '.html': 'text/html; charset=utf-8',
20
+ '.css': 'text/css; charset=utf-8',
21
+ '.js': 'text/javascript; charset=utf-8',
22
+ '.json': 'application/json; charset=utf-8',
23
+ '.svg': 'image/svg+xml',
24
+ '.png': 'image/png',
25
+ '.jpg': 'image/jpeg',
26
+ '.webp': 'image/webp',
27
+ '.gif': 'image/gif',
28
+ '.ico': 'image/x-icon',
29
+ }
30
+
31
+ function sendFile(res, file) {
32
+ let st
33
+ try {
34
+ st = fs.statSync(file)
35
+ } catch {
36
+ res.writeHead(404, { 'content-type': 'text/plain; charset=utf-8' })
37
+ res.end('not found')
38
+ return
39
+ }
40
+ if (!st.isFile()) return sendFile(res, path.join(WEB, 'index.html'))
41
+ res.writeHead(200, {
42
+ 'content-type': MIME[path.extname(file).toLowerCase()] || 'application/octet-stream',
43
+ 'content-length': st.size,
44
+ 'cache-control': 'no-store',
45
+ })
46
+ fs.createReadStream(file).pipe(res)
47
+ }
48
+
49
+ function proxy(req, res, p, search) {
50
+ const up = http.request(
51
+ { host: UPSTREAM.host, port: UPSTREAM.port, method: req.method, path: p + search, headers: req.headers, timeout: 15000 },
52
+ (u) => {
53
+ res.writeHead(u.statusCode || 502, u.headers)
54
+ u.pipe(res)
55
+ },
56
+ )
57
+ up.on('timeout', () => up.destroy(new Error('timeout')))
58
+ up.on('error', (e) => {
59
+ if (res.headersSent) return res.end()
60
+ res.writeHead(503, { 'content-type': 'application/json; charset=utf-8' })
61
+ res.end(JSON.stringify({ ok: false, error: '状态台数据服务(127.0.0.1:9896)没有响应', detail: String(e.message) }))
62
+ })
63
+ req.pipe(up)
64
+ }
65
+
66
+ http
67
+ .createServer((req, res) => {
68
+ const url = new URL(req.url || '/', `http://${req.headers.host || '127.0.0.1'}`)
69
+ let p = url.pathname
70
+
71
+ if (p === PREFIX) {
72
+ res.writeHead(302, { location: PREFIX + '/' })
73
+ return res.end()
74
+ }
75
+ const hadPrefix = p.startsWith(PREFIX + '/')
76
+ if (hadPrefix) p = p.slice(PREFIX.length)
77
+ if (p.startsWith('/__paofu__')) p = p.slice('/__paofu__'.length) || '/'
78
+ if (!hadPrefix && p !== '/') {
79
+ res.writeHead(302, { location: PREFIX + p })
80
+ return res.end()
81
+ }
82
+
83
+ if (p.startsWith('/api/') || p.startsWith('/data/') || p.startsWith('/meme/') || p === '/bg.js') return proxy(req, res, p, url.search)
84
+
85
+ if (p === '/' || p.endsWith('/')) p += 'index.html'
86
+ let file = path.normalize(path.join(WEB, p))
87
+ const altFile = path.normalize(path.join(CONSOLE_ROOT, p))
88
+ // 插件页面优先;页内资源(桌宠 webp、备份图等)在本机 console 目录里,找不到就回落到它
89
+ if (!fs.existsSync(file) && fs.existsSync(altFile)) file = altFile
90
+ const rootOk = file.startsWith(WEB) || file.startsWith(path.normalize(CONSOLE_ROOT))
91
+ if (!rootOk) {
92
+ res.writeHead(403)
93
+ return res.end('forbidden')
94
+ }
95
+ sendFile(res, file)
96
+ })
97
+ .listen(PORT, '127.0.0.1', () => {
98
+ console.log(`状态台(独立预览): http://127.0.0.1:${PORT}${PREFIX}/`)
99
+ console.log('数据服务需要另开:node D:/qq-bridge/state/agents/console/server.mjs')
100
+ })
Binary file
Binary file
Binary file
Binary file
Binary file