dsh-paofu-console 1.0.5 → 1.1.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.
- package/CHANGELOG.md +52 -0
- package/README.md +32 -3
- package/install.ps1 +53 -0
- package/install.sh +46 -0
- package/lib/index.mjs +8 -0
- package/package.json +9 -13
- package/serve.mjs +100 -0
- package/web/assets/pet/angry.webp +0 -0
- package/web/assets/pet/eat.webp +0 -0
- package/web/assets/pet/happy.webp +0 -0
- package/web/assets/pet/idle.webp +0 -0
- package/web/assets/pet/sleep.webp +0 -0
- package/web/index.html +3274 -3000
- /package/{/346/216/245/344/270/212/346/241/245/346/216/245.md" → CONNECT-BRIDGE.md} +0 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# CHANGELOG
|
|
2
|
+
|
|
3
|
+
## 1.1.1 — 2026-10-30
|
|
4
|
+
|
|
5
|
+
**只改文档**,代码与 1.1.0 一致。
|
|
6
|
+
|
|
7
|
+
- README 顶部改成对外简介:卖点、安装命令、三个渠道入口(GitHub / npm / Gitee)
|
|
8
|
+
- 修掉 README 里残留的旧文件名引用(`接上桥接.md` → `CONNECT-BRIDGE.md`)
|
|
9
|
+
|
|
10
|
+
## 1.1.0
|
|
11
|
+
|
|
12
|
+
- 情绪页改版:坐标盘 → **情绪脑图**
|
|
13
|
+
- 头部轮廓(贝塞尔)+ 7 条脑沟 + 4 条斜向回沟
|
|
14
|
+
- 情绪锚点从 12 个扩到 24 个(兴奋/雀跃/期待/开心/满足/亲近/温柔/安心/平静/好奇/认真/害羞/生气/烦躁/不安/焦虑/委屈/疏离/难过/失落/疲惫/困/放空/苦恼)
|
|
15
|
+
- 每个锚点从底部内核拉一条二次贝塞尔连线,离当前情绪越近越亮,线上有光点流动
|
|
16
|
+
- 标签贪心避让 + 悬停强制显示;当前情绪收进左上角胶囊
|
|
17
|
+
- 手机端导航:横滑 + 右缘渐隐 + 右下「全部 ▾」底部面板(按分组两列列出全部页面,当前项高亮,切换后自动滚到中间)
|
|
18
|
+
- 新增深链:`?page=mood` 直接打开指定页面
|
|
19
|
+
- 修复图片 404:桌面预览服务器补 `/meme/`、`/bg.js` 转发,剥离 `/__paofu__`,修掉 `/dsh-paofu-console/meme/…` 自跳转循环,静态资源找不到时回落到 console 目录;插件 handler 补 `/meme/` 反代
|
|
20
|
+
- 文档:安装示例版本号更新;`接上桥接.md` 更名 `CONNECT-BRIDGE.md`(原中文名在 zip / 跨平台下会乱码)
|
|
21
|
+
|
|
22
|
+
## 1.0.8
|
|
23
|
+
|
|
24
|
+
- 删掉右上角遗留的「声音 · 关」胶囊:它从加进页面起就没有绑任何事件,是个死控件(音量与播放本来就在「界面设置 → 背景音乐」里)
|
|
25
|
+
|
|
26
|
+
## 1.0.7
|
|
27
|
+
|
|
28
|
+
- 找回最初设计里的两样东西:
|
|
29
|
+
- **背景鱼群**:画布矢量小鱼(青绿→蓝渐变、尾巴摆动、随机游弋与折返),铺在内容之下的背景层,半透明不抢字
|
|
30
|
+
- **鲸鱼空灵声**:WebAudio 现场合成(低频正弦滑音 + 泛音 + 低通),16–42 秒随机一次,不占素材、不联网
|
|
31
|
+
- 右上角工具条新增两枚开关:`鱼群` / `鲸声`,状态存本机,刷新后保持
|
|
32
|
+
- 鲸声受浏览器自动播放限制:页面首次点击后才会出声(和背景音乐同一个规矩)
|
|
33
|
+
|
|
34
|
+
## 1.0.6
|
|
35
|
+
|
|
36
|
+
- 新增 **Ctrl+滚轮缩放整个界面**(60%–160%,与设置里的「界面缩放」同一份值,会记住)
|
|
37
|
+
- 缩放时底部弹出「界面缩放 N%」提示,`Ctrl+0` 一键回到 100%
|
|
38
|
+
- 滚轮事件用捕获阶段并阻止冒泡,鼠标停在记忆网/情绪盘上也不会误转 3D 视角
|
|
39
|
+
- 记忆网络修复:挂在「不在会话列表里的私聊」上的记忆不再被丢弃(自动生成虚拟会话节点),节点从几个恢复到全部 59 条
|
|
40
|
+
- 记忆网络节点补上点击命中(松手位移 ≤8px、18px 内取最近点)→ 点节点直接开详情抽屉
|
|
41
|
+
|
|
42
|
+
## 0.1.1
|
|
43
|
+
|
|
44
|
+
- 工具条最左新增「桌宠」开关(藏起来也能找回,状态记忆)
|
|
45
|
+
- 设置新增「桌宠」区:大小 60–160%、状态下拉、撞墙反弹开关、自定义形象(PNG/GIF/WebP ≤2.5MB,本机存储)、恢复默认
|
|
46
|
+
- 桌宠换成真帧动画(转圈圈 / 开心 / 吃饭 / 打瞌睡 / 生气跺脚,各 51 帧)
|
|
47
|
+
- 新增独立预览服务器 `serve.mjs`(不装 DSH 也能看)
|
|
48
|
+
- 新增一键安装脚本 `install.ps1` / `install.sh`
|
|
49
|
+
|
|
50
|
+
## 0.1.0
|
|
51
|
+
|
|
52
|
+
- 首个版本:`/dsh-paofu-console` 前缀路由、静态页、`/api` `/data` 反代 9896、DSH 细栏、Esc 退出
|
package/README.md
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 大肥鱼状态台(dsh-paofu-console)
|
|
2
|
+
|
|
3
|
+
给 DeepSeek Harness 配的一块本地面板:装成插件、跟 DSH 共用地址,打开就能看。自定义主题、BGM、主题色会随音乐律动渐变;同步适配手机界面,布局和玩法都能自己调。
|
|
4
|
+
|
|
5
|
+
在线状态、未读数、用量余额、日记、记忆、承诺账本、小说、系统拓扑、运行状况,全都摊平在一页里,一眼扫完——不用翻会话、翻日志、翻表格。
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
dsh plugin install dsh-paofu-console
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
本地运行、零依赖、不调模型,数据不外传。
|
|
12
|
+
|
|
13
|
+
| 渠道 | 地址 |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| GitHub | https://github.com/pennyliu68-wq/ds-big-fish-status-panel |
|
|
16
|
+
| npm | https://www.npmjs.com/package/dsh-paofu-console |
|
|
17
|
+
| Gitee | https://gitee.com/the-concept-of-esuns-world/ds-big-fish-status-panel |
|
|
18
|
+
|
|
19
|
+
---
|
|
2
20
|
|
|
3
21
|
**DeepSeek Harness 插件版**。装上以后 DSH 里多一个地址:
|
|
4
22
|
|
|
@@ -76,7 +94,7 @@ node -v
|
|
|
76
94
|
```json
|
|
77
95
|
{
|
|
78
96
|
"dependencies": {
|
|
79
|
-
"dsh-paofu-console": "1.0
|
|
97
|
+
"dsh-paofu-console": "1.1.0"
|
|
80
98
|
},
|
|
81
99
|
"dsh": {
|
|
82
100
|
"profile": {
|
|
@@ -115,7 +133,7 @@ curl -s -o /dev/null -w '%{http_code}\n' '<你的 DSH 地址>/dsh-paofu-console/
|
|
|
115
133
|
|
|
116
134
|
## 想让它显示真实的 QQ 桥接数据
|
|
117
135
|
|
|
118
|
-
看包里的
|
|
136
|
+
看包里的 `CONNECT-BRIDGE.md`。核心是一句话:**桥接不在就用示例数据,不报错**。
|
|
119
137
|
|
|
120
138
|
数据服务会读这些位置:
|
|
121
139
|
|
|
@@ -155,6 +173,17 @@ cordis.patch.yml 注册一条宿主行
|
|
|
155
173
|
icon.svg 图标
|
|
156
174
|
```
|
|
157
175
|
|
|
176
|
+
## 更新记录
|
|
177
|
+
|
|
178
|
+
### 1.1.0
|
|
179
|
+
- 情绪页换成「情绪脑图 · 3D」:头部轮廓 + 脑沟纹理,24 个情绪锚点从内核拉线,越近越亮、线上有光点,标签自动避让
|
|
180
|
+
- 手机端导航支持横滑并新增「全部 ▾」底部面板,一屏看不到的页面都在里面
|
|
181
|
+
- 支持深链 `?page=mood` 直接打开指定页面
|
|
182
|
+
- 修复桌面窗口 / 插件页里表情图、桌宠图 404(/meme、/assets 转发)
|
|
183
|
+
|
|
184
|
+
### 1.0.5 及更早
|
|
185
|
+
见仓库的 Releases 页。
|
|
186
|
+
|
|
158
187
|
## 已知限制
|
|
159
188
|
|
|
160
189
|
- 两个入口都只绑 `127.0.0.1`,**外网访问不到**(面板没有密码,这是故意的)
|
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.
|
|
3
|
+
"version": "1.1.1",
|
|
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
|
-
"
|
|
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
|