dsh-pet 0.1.4 → 0.1.6
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/README.en.md +10 -10
- package/README.md +11 -11
- package/assets/config.jsonc +88 -0
- package/assets/thumb//344/270/211/347/220/203/346/212/233/346/216/245.webm +0 -0
- package/assets/thumb//344/270/213/344/272/224/345/255/220/346/243/213.webm +0 -0
- package/assets/thumb//344/270/234/345/274/240/350/245/277/346/234/233.webm +0 -0
- package/assets/thumb//344/270/255/347/247/213/350/265/217/346/234/210/345/220/203/346/234/210/351/245/274.webm +0 -0
- package/assets/thumb//344/274/230/351/233/205/345/245/263/344/273/206/350/210/236.webm +0 -0
- package/assets/thumb//345/201/267/345/220/203/351/233/266/351/243/237/350/242/253/346/212/223/344/275/217.webm +0 -0
- package/assets/thumb//345/206/231/344/273/243/347/240/201.webm +0 -0
- package/assets/thumb//345/206/231/347/246/217/345/255/227.webm +0 -0
- package/assets/thumb//345/207/255/347/251/272/347/224/237/350/212/261.webm +0 -0
- package/assets/thumb//345/212/250/347/211/251/347/216/257/347/273/225.webm +0 -0
- package/assets/thumb//345/216/237/345/234/260/344/270/223/345/277/203/347/216/251/351/255/224/346/226/271.webm +0 -0
- package/assets/thumb//345/216/237/345/234/260/345/260/217/346/206/251/346/262/211/347/234/240.webm +0 -0
- package/assets/thumb//345/216/237/345/234/260/345/267/246/350/275/254/345/245/224/350/267/221.webm +0 -0
- package/assets/thumb//345/216/237/345/234/260/346/225/262/345/207/273/346/241/214/351/235/242/344/272/222/345/212/250.webm +0 -0
- package/assets/thumb//345/216/237/345/234/260/346/274/202/346/265/256/350/270/217/346/255/245.webm +0 -0
- package/assets/thumb//345/216/237/345/234/260/350/267/263/350/267/203/346/212/223/347/242/216/345/244/264/351/241/266/347/211/251/345/223/201.webm +0 -0
- package/assets/thumb//345/216/237/345/234/260/350/271/262/344/270/213/347/216/251/347/216/251/345/205/267/346/261/275/350/275/246.webm +0 -0
- package/assets/thumb//345/216/237/345/234/260/351/207/215/345/212/233/344/270/213/350/271/262/345/216/213/347/274/251.webm +0 -0
- package/assets/thumb//345/217/230/351/270/275/345/255/220.webm +0 -0
- package/assets/thumb//345/217/257/347/210/261/345/256/205/350/210/236.webm +0 -0
- package/assets/thumb//345/220/203Token.webm +0 -0
- package/assets/thumb//345/220/203/345/206/260/346/267/207/346/267/213/350/236/215/345/214/226.webm +0 -0
- package/assets/thumb//345/220/203/345/215/210/351/244/220.webm +0 -0
- package/assets/thumb//345/220/203/345/244/247/351/227/270/350/237/271.webm +0 -0
- package/assets/thumb//345/220/203/345/271/264/347/263/225.webm +0 -0
- package/assets/thumb//345/220/203/346/227/251/351/244/220.webm +0 -0
- package/assets/thumb//345/220/203/346/231/232/351/244/220.webm +0 -0
- package/assets/thumb//345/220/203/346/261/244/345/234/206.webm +0 -0
- package/assets/thumb//345/220/203/347/231/275/351/245/255.webm +0 -0
- package/assets/thumb//345/220/203/347/262/275/345/255/220.webm +0 -0
- package/assets/thumb//345/220/203/347/263/226/350/221/253/350/212/246.webm +0 -0
- package/assets/thumb//345/220/203/350/205/212/345/205/253/347/262/245.webm +0 -0
- package/assets/thumb//345/220/203/350/245/277/347/223/234.webm +0 -0
- package/assets/thumb//345/220/203/351/207/215/351/230/263/347/263/225.webm +0 -0
- package/assets/thumb//345/220/203/351/225/277/345/257/277/351/235/242.webm +0 -0
- package/assets/thumb//345/220/203/351/235/222/345/233/242.webm +0 -0
- package/assets/thumb//345/220/203/351/245/272/345/255/220.webm +0 -0
- package/assets/thumb//345/220/271/346/260/224/347/220/203.webm +0 -0
- package/assets/thumb//345/220/271/347/254/233/345/255/220.webm +0 -0
- package/assets/thumb//345/223/210/346/254/240/350/277/236/345/244/251.webm +0 -0
- package/assets/thumb//345/240/206/351/233/252/344/272/272.webm +0 -0
- package/assets/thumb//345/244/247/345/217/243/345/220/203/351/233/266/351/243/237.webm +0 -0
- package/assets/thumb//345/245/263/344/273/206/345/261/210/350/206/235/347/244/274/344/273/252.webm +0 -0
- package/assets/thumb//345/260/217/345/271/205/345/272/246/345/216/237/345/234/260360/345/272/246/346/227/213/350/275/254/345/261/225/347/244/272.webm +0 -0
- package/assets/thumb//345/260/217/346/217/220/347/220/264/346/274/224/345/245/217.webm +0 -0
- package/assets/thumb//345/276/205/346/234/272/345/221/274/345/220/270/344/274/221/351/227/262.webm +0 -0
- package/assets/thumb//346/202/240/351/227/262/345/223/274/346/255/214.webm +0 -0
- package/assets/thumb//346/211/221/345/205/213/351/255/224/346/234/257.webm +0 -0
- package/assets/thumb//346/211/223/347/236/214/347/235/241/350/242/253/346/203/212/351/206/222.webm +0 -0
- package/assets/thumb//346/212/275/351/231/200/350/236/272.webm +0 -0
- package/assets/thumb//346/213/206/347/244/274/347/211/251.webm +0 -0
- package/assets/thumb//346/217/222/350/214/261/350/220/270/350/265/217/350/217/212.webm +0 -0
- package/assets/thumb//346/221/207/346/211/207/347/272/263/345/207/211.webm +0 -0
- package/assets/thumb//346/222/270/347/214/253.webm +0 -0
- package/assets/thumb//346/224/266/347/272/242/345/214/205.webm +0 -0
- package/assets/thumb//346/224/276/345/255/224/346/230/216/347/201/257.webm +0 -0
- package/assets/thumb//346/224/276/346/262/263/347/201/257.webm +0 -0
- package/assets/thumb//346/224/276/347/203/237/350/212/261.webm +0 -0
- package/assets/thumb//346/224/276/351/243/216/347/255/235.webm +0 -0
- package/assets/thumb//346/225/264/344/275/223/346/215/242/350/243/205/350/257/225/350/211/262.webm +0 -0
- package/assets/thumb//346/230/257/345/225/212/357/274/214/345/220/203/344/273/200/344/271/210.webm +0 -0
- package/assets/thumb//346/231/250/351/227/264/345/210/267/347/211/231.webm +0 -0
- package/assets/thumb//346/266/256/347/201/253/351/224/205.webm +0 -0
- package/assets/thumb//346/267/261/345/272/246/346/200/235/350/200/203/347/242/216/347/242/216/345/277/265.webm +0 -0
- package/assets/thumb//347/202/271/345/207/273/345/233/236/345/272/224-/345/202/262/345/250/207/347/224/237/346/260/224.webm +0 -0
- package/assets/thumb//347/202/271/345/207/273/345/233/236/345/272/224-/345/205/203/346/260/224/346/214/245/346/211/213.webm +0 -0
- package/assets/thumb//347/202/271/345/207/273/345/233/236/345/272/224-/345/256/263/347/276/236/346/203/212/350/256/266.webm +0 -0
- package/assets/thumb//347/202/271/345/207/273/345/233/236/345/272/224-/345/274/200/345/277/203/350/267/203/345/212/250.webm +0 -0
- package/assets/thumb//347/202/271/345/207/273/345/233/236/345/272/224-/346/214/240/347/227/222/345/222/257/345/222/257/347/254/221.webm +0 -0
- package/assets/thumb//347/205/247/351/225/234/345/255/220.webm +0 -0
- package/assets/thumb//347/216/251/346/260/264/346/236/252.webm +0 -0
- package/assets/thumb//347/216/251/346/270/270/346/210/217/346/260/224/346/200/245/350/264/245/345/235/217.webm +0 -0
- package/assets/thumb//347/224/250/351/262/270/351/261/274/345/260/276/345/267/264/346/213/215/346/211/223/345/234/260/351/235/242.webm +0 -0
- package/assets/thumb//347/251/277/351/222/210/344/271/236/345/267/247.webm +0 -0
- package/assets/thumb//350/210/236/347/213/256/345/244/264.webm +0 -0
- package/assets/thumb//350/215/241/347/247/213/345/215/203.webm +0 -0
- package/assets/thumb//350/220/214/345/214/226/345/260/217/345/271/275/347/201/265.webm +0 -0
- package/assets/thumb//350/223/235/351/262/270/347/216/260/344/270/226.webm +0 -0
- package/assets/thumb//350/235/264/350/235/266/350/234/234/350/234/202/347/216/257/347/273/225/345/244/264/351/241/266/345/274/200/350/212/261.webm +0 -0
- package/assets/thumb//350/236/203/350/237/271/350/265/260/350/267/257.webm +0 -0
- package/assets/thumb//350/242/253/345/220/223/344/270/200/350/267/263.webm +0 -0
- package/assets/thumb//350/242/253/350/220/275/345/217/266/346/267/271/346/262/241.webm +0 -0
- package/assets/thumb//350/242/253/351/274/240/346/240/207/346/213/226/346/213/275/346/202/254/347/251/272/345/217/215/351/246/210.webm +0 -0
- package/assets/thumb//350/243/205/347/202/271/345/234/243/350/257/236/346/240/221.webm +0 -0
- package/assets/thumb//350/256/250/347/263/226/345/215/227/347/223/234/347/201/257.webm +0 -0
- package/assets/thumb//350/266/205/345/244/247/344/274/270/346/207/222/350/205/260.webm +0 -0
- package/assets/thumb//350/270/242/346/257/275/345/255/220.webm +0 -0
- package/assets/thumb//350/275/273/345/277/253/346/221/207/346/221/206/350/210/236.webm +0 -0
- package/assets/thumb//350/275/273/345/277/253/350/256/260/345/275/225.webm +0 -0
- package/assets/thumb//351/252/221/346/234/250/351/251/254.webm +0 -0
- package/assets/thumb//351/262/270/351/261/274/345/220/220/346/263/241/346/263/241/347/211/271/346/225/210.webm +0 -0
- package/lib/client.js +1105 -693
- package/lib/index.js +172 -125
- package/package.json +20 -6
- package/src/client/app.ts +488 -0
- package/src/client/config.ts +122 -0
- package/src/client/constants.ts +9 -0
- package/src/client/index.ts +15 -0
- package/src/client/pickers.ts +32 -0
- package/src/client/settings.ts +325 -0
- package/src/client/types.ts +37 -0
- package/src/env.d.ts +6 -0
- package/src/host/index.ts +204 -0
- package/assets/thumb//345/260/217/345/271/205/345/272/246/345/216/237/345/234/260 360 /345/272/246/346/227/213/350/275/254/345/261/225/347/244/272.webm +0 -0
- package/assets/thumb//347/202/271/345/207/273/345/233/236/345/272/224 - /345/202/262/345/250/207/347/224/237/346/260/224/357/274/210/344/276/247/350/272/253/345/261/225/347/244/272/357/274/211.webm +0 -0
- package/assets/thumb//347/202/271/345/207/273/345/233/236/345/272/224 - /345/256/263/347/276/236/346/203/212/350/256/266.webm +0 -0
- package/assets/thumb//347/202/271/345/207/273/345/233/236/345/272/224 - /345/274/200/345/277/203/350/267/203/345/212/250.webm +0 -0
- package/assets/thumb//350/242/253/345/220/223/344/270/200/350/267/263/357/274/210/347/202/270/346/257/233/357/274/211.webm +0 -0
package/lib/index.js
CHANGED
|
@@ -1,135 +1,182 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* 【这个文件是什么】
|
|
7
|
-
* 本文件运行在 DSH 的 Node 服务端(不是浏览器)。它的唯一职责是:
|
|
8
|
-
* 在 DSH 的 Web 服务器上注册一个 `/pet/` 前缀的 HTTP 路由,
|
|
9
|
-
* 把插件包里的动画 WebM 文件流式返回给浏览器。
|
|
10
|
-
*
|
|
11
|
-
* 【为什么需要它】
|
|
12
|
-
* DSH 的 `/plugins/` 路由只服务"客户端 JS bundle",不服务视频等静态资源。
|
|
13
|
-
* 所以浏览器半侧(lib/client.js)要播放动画,必须有一个专门的路由来取文件。
|
|
14
|
-
* 这正是 DSH 官方提供的扩展点:`ctx.webServer.register()`。
|
|
15
|
-
*
|
|
16
|
-
* 【路由结构】
|
|
17
|
-
* /pet/thumb/<动画名>.webm → 读插件包内 assets/thumb/(360×360 播放变体)
|
|
18
|
-
* /pet/full/<动画名>.webm → 读 $DSH_HOME/pet-assets/(原始 1200×1200,需先下载)
|
|
19
|
-
*
|
|
20
|
-
* 【安全性】
|
|
21
|
-
* 路径做了"防穿越"校验(resolveAsset):请求里的路径规范化后必须仍在
|
|
22
|
-
* assets 根目录内,否则返回 400。防止 /pet/../../etc/passwd 这类攻击。
|
|
23
|
-
*
|
|
24
|
-
* ============================================================================
|
|
25
|
-
*/
|
|
26
|
-
import { createReadStream, existsSync } from 'node:fs';
|
|
27
|
-
import { stat } from 'node:fs/promises';
|
|
28
|
-
import { join, normalize, resolve, sep } from 'node:path';
|
|
29
|
-
import { fileURLToPath } from 'node:url';
|
|
30
|
-
// 官方 API:解析 DSH 主目录($DSH_HOME,默认 ~/.dsh)——full 资源存放位置
|
|
31
|
-
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths';
|
|
32
|
-
|
|
33
|
-
// 插件行 id(与 cordis.patch.yml 一致)
|
|
34
|
-
const name = 'pet';
|
|
35
|
-
/** 需要注入的服务:webServer(Web 服务器路由注册表) */
|
|
36
|
-
const inject = ['webServer'];
|
|
37
|
-
|
|
38
|
-
/** 本包目录(src 和安装后都适用——import.meta.url 指向 lib/,上一级即包根) */
|
|
39
|
-
const PACKAGE_ROOT = resolve(fileURLToPath(new URL('..', import.meta.url)));
|
|
40
|
-
|
|
41
|
-
/** 路由前缀:/pet/thumb/<name>.webm、/pet/full/<name>.webm */
|
|
42
|
-
const ROUTE_PREFIX = '/pet';
|
|
1
|
+
import { createReadStream, existsSync } from "node:fs";
|
|
2
|
+
import { readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join, normalize, resolve, sep } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { resolveDshHome } from "@deepseek-ai/dsh-home-paths";
|
|
43
6
|
|
|
7
|
+
//#region src/host/index.ts
|
|
8
|
+
const name = "pet";
|
|
9
|
+
const inject = ["webServer"];
|
|
10
|
+
/** 本包目录:宿主构建产物位于 lib/,其上一级即包根。 */
|
|
11
|
+
const PACKAGE_ROOT = resolve(fileURLToPath(new URL("..", import.meta.url)));
|
|
12
|
+
/** 路由前缀 */
|
|
13
|
+
const ROUTE_PREFIX = "/pet";
|
|
44
14
|
/** 不同扩展名对应的 Content-Type 映射 */
|
|
45
15
|
const MIME = {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
16
|
+
".webm": "video/webm",
|
|
17
|
+
".mp4": "video/mp4",
|
|
18
|
+
".png": "image/png",
|
|
19
|
+
".json": "application/json; charset=utf-8",
|
|
20
|
+
".jsonc": "application/json; charset=utf-8"
|
|
50
21
|
};
|
|
51
|
-
|
|
52
22
|
/**
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
* @returns 规范化后的绝对文件路径;非法(穿越)时返回 undefined
|
|
57
|
-
*/
|
|
23
|
+
* 规范化并校验请求路径,确保它在 assets 根目录内(防路径穿越)。
|
|
24
|
+
* @returns 规范化后的绝对文件路径;非法(穿越)时返回 undefined
|
|
25
|
+
*/
|
|
58
26
|
function resolveAsset(root, rel) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
27
|
+
if (rel.length === 0) return void 0;
|
|
28
|
+
const candidate = normalize(join(root, rel));
|
|
29
|
+
const rootWithSep = root.endsWith(sep) ? root : root + sep;
|
|
30
|
+
if (candidate !== root && !candidate.startsWith(rootWithSep)) return void 0;
|
|
31
|
+
return candidate;
|
|
32
|
+
}
|
|
33
|
+
/** 流式返回一个文件(带 Content-Type / 长度 / 缓存头)。 */
|
|
34
|
+
async function sendFile(res, file, contentType) {
|
|
35
|
+
const { size } = await stat(file);
|
|
36
|
+
res.writeHead(200, {
|
|
37
|
+
"content-type": contentType,
|
|
38
|
+
"content-length": size,
|
|
39
|
+
"cache-control": "public, max-age=3600"
|
|
40
|
+
});
|
|
41
|
+
const stream = createReadStream(file);
|
|
42
|
+
stream.on("error", () => res.destroy());
|
|
43
|
+
stream.pipe(res);
|
|
44
|
+
}
|
|
45
|
+
/** 支持的角落白名单(与 client 端一致) */
|
|
46
|
+
const CORNERS = [
|
|
47
|
+
"top-left",
|
|
48
|
+
"top-right",
|
|
49
|
+
"bottom-left",
|
|
50
|
+
"bottom-right"
|
|
51
|
+
];
|
|
52
|
+
/** 发送 JSON 响应 */
|
|
53
|
+
function sendJson(res, status, obj) {
|
|
54
|
+
const body = JSON.stringify(obj);
|
|
55
|
+
res.writeHead(status, {
|
|
56
|
+
"content-type": "application/json; charset=utf-8",
|
|
57
|
+
"content-length": Buffer.byteLength(body)
|
|
58
|
+
});
|
|
59
|
+
res.end(body);
|
|
60
|
+
}
|
|
61
|
+
/** 收集请求体(文本) */
|
|
62
|
+
function readBody(req) {
|
|
63
|
+
return new Promise((resolve2, reject) => {
|
|
64
|
+
const chunks = [];
|
|
65
|
+
req.on("data", (c) => chunks.push(c));
|
|
66
|
+
req.on("end", () => resolve2(Buffer.concat(chunks).toString("utf8")));
|
|
67
|
+
req.on("error", reject);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/** 校验并归一化用户配置:只接受 { pets: [{ id, size, position }] } */
|
|
71
|
+
function sanitizeUserConfig(raw) {
|
|
72
|
+
const o = raw && typeof raw === "object" ? raw : {};
|
|
73
|
+
const arr = Array.isArray(o.pets) ? o.pets : null;
|
|
74
|
+
if (!arr || !arr.length) return null;
|
|
75
|
+
const out = [];
|
|
76
|
+
for (const p of arr) {
|
|
77
|
+
if (!p || typeof p !== "object") return null;
|
|
78
|
+
const id = String(p.id ?? "");
|
|
79
|
+
if (!id || id.length > 64 || /[\\/:\x00-\x1f]/.test(id)) return null;
|
|
80
|
+
const size = Number(p.size);
|
|
81
|
+
if (!Number.isFinite(size) || size <= 0) return null;
|
|
82
|
+
const pos = p.position && typeof p.position === "object" ? p.position : {};
|
|
83
|
+
const corner = String(pos.corner ?? "");
|
|
84
|
+
if (!CORNERS.includes(corner)) return null;
|
|
85
|
+
const marginX = Number(pos.marginX);
|
|
86
|
+
const marginY = Number(pos.marginY);
|
|
87
|
+
if (!Number.isFinite(marginX) || !Number.isFinite(marginY)) return null;
|
|
88
|
+
out.push({
|
|
89
|
+
id,
|
|
90
|
+
size,
|
|
91
|
+
position: {
|
|
92
|
+
corner,
|
|
93
|
+
marginX,
|
|
94
|
+
marginY
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return { pets: out };
|
|
67
99
|
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* 宿主插件主体:注册 `/pet` 前缀路由。
|
|
71
|
-
* @param ctx - 插件上下文;ctx.webServer 是 Web 服务器服务
|
|
72
|
-
* @param config - 本行的配置(来自 patch 树)
|
|
73
|
-
*/
|
|
74
100
|
function apply(ctx, config) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
101
|
+
const thumbRoot = join(PACKAGE_ROOT, "assets", "thumb");
|
|
102
|
+
const fullRoot = config.fullRoot ?? join(resolveDshHome(), "pet-assets");
|
|
103
|
+
const userConfigPath = join(resolveDshHome(), "pet-config.json");
|
|
104
|
+
ctx.effect(() => ctx.webServer.register({
|
|
105
|
+
kind: "prefix",
|
|
106
|
+
path: ROUTE_PREFIX,
|
|
107
|
+
handler: async (req, res) => {
|
|
108
|
+
const url = new URL(req.url ?? "/", "http://localhost");
|
|
109
|
+
const rest = decodeURIComponent(url.pathname.slice(ROUTE_PREFIX.length + 1));
|
|
110
|
+
if (rest === "config") {
|
|
111
|
+
if (req.method === "GET") {
|
|
112
|
+
try {
|
|
113
|
+
const raw = await readFile(userConfigPath, "utf8");
|
|
114
|
+
sendJson(res, 200, JSON.parse(raw));
|
|
115
|
+
} catch {
|
|
116
|
+
sendJson(res, 200, {});
|
|
117
|
+
}
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (req.method === "PUT") {
|
|
121
|
+
try {
|
|
122
|
+
const body = await readBody(req);
|
|
123
|
+
const parsed = JSON.parse(body);
|
|
124
|
+
const clean = sanitizeUserConfig(parsed);
|
|
125
|
+
if (!clean) {
|
|
126
|
+
sendJson(res, 400, { error: "invalid pet config: expected { pets:[{id,size,position:{corner,marginX,marginY}}] }" });
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
await writeFile(userConfigPath, JSON.stringify(clean, null, 2), "utf8");
|
|
130
|
+
sendJson(res, 200, { ok: true });
|
|
131
|
+
} catch {
|
|
132
|
+
sendJson(res, 400, { error: "invalid JSON body" });
|
|
133
|
+
}
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (req.method === "DELETE") {
|
|
137
|
+
try {
|
|
138
|
+
await rm(userConfigPath, { force: true });
|
|
139
|
+
} catch {}
|
|
140
|
+
sendJson(res, 200, { ok: true });
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
sendJson(res, 405, { error: "method not allowed" });
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (rest === "config.jsonc") {
|
|
147
|
+
const cfgFile = join(PACKAGE_ROOT, "assets", "config.jsonc");
|
|
148
|
+
if (!existsSync(cfgFile)) {
|
|
149
|
+
res.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
|
|
150
|
+
res.end("dsh-pet: config.jsonc not found");
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
await sendFile(res, cfgFile, MIME[".jsonc"] ?? "application/octet-stream");
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const [scope, ...nameParts] = rest.split("/");
|
|
157
|
+
if (scope !== "thumb" && scope !== "full") {
|
|
158
|
+
res.writeHead(400, { "content-type": "text/plain; charset=utf-8" });
|
|
159
|
+
res.end("dsh-pet: expected /pet/{thumb|full}/<file>");
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const fileName = nameParts.join("/");
|
|
163
|
+
const root = scope === "thumb" ? thumbRoot : fullRoot;
|
|
164
|
+
const file = resolveAsset(root, fileName);
|
|
165
|
+
if (file === void 0) {
|
|
166
|
+
res.writeHead(400, { "content-type": "text/plain; charset=utf-8" });
|
|
167
|
+
res.end("dsh-pet: invalid path");
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (!existsSync(file)) {
|
|
171
|
+
res.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
|
|
172
|
+
res.end(scope === "full" ? `dsh-pet: original asset not downloaded yet — run the fetch-assets script to populate ${fullRoot}` : "dsh-pet: asset not found");
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const ext = file.slice(file.lastIndexOf(".")).toLowerCase();
|
|
176
|
+
await sendFile(res, file, MIME[ext] ?? "application/octet-stream");
|
|
177
|
+
}
|
|
178
|
+
}), "dsh-pet: /pet asset route");
|
|
132
179
|
}
|
|
133
180
|
|
|
134
|
-
|
|
135
|
-
export { apply, inject, name };
|
|
181
|
+
//#endregion
|
|
182
|
+
export { apply, inject, name };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-pet",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "A floating desktop pet for the DeepSeek Harness Web UI: idle breathing, occasional direction turns, random actions, and screen wandering.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|
|
@@ -45,16 +45,22 @@
|
|
|
45
45
|
"types": "./lib/types/client/index.d.ts",
|
|
46
46
|
"default": "./lib/client.js"
|
|
47
47
|
},
|
|
48
|
+
"./src/*": "./src/*",
|
|
48
49
|
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
49
50
|
"./package.json": "./package.json"
|
|
50
51
|
},
|
|
51
52
|
"files": [
|
|
52
53
|
"lib",
|
|
54
|
+
"src",
|
|
53
55
|
"assets/thumb",
|
|
56
|
+
"assets/config.jsonc",
|
|
54
57
|
"cordis.patch.yml"
|
|
55
58
|
],
|
|
56
59
|
"scripts": {
|
|
57
|
-
"
|
|
60
|
+
"bundle": "tsdown",
|
|
61
|
+
"watch": "tsdown --watch",
|
|
62
|
+
"prepare": "npm run bundle",
|
|
63
|
+
"prepack": "npm run bundle && node scripts/prepack-check.js"
|
|
58
64
|
},
|
|
59
65
|
"license": "MIT",
|
|
60
66
|
"dsh": {
|
|
@@ -70,10 +76,18 @@
|
|
|
70
76
|
},
|
|
71
77
|
"peerDependencies": {
|
|
72
78
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
73
|
-
"@deepseek-ai/dsh-
|
|
74
|
-
"@deepseek-ai/dsh-
|
|
75
|
-
"@deepseek-ai/dsh-
|
|
76
|
-
"@deepseek-ai/dsh-
|
|
79
|
+
"@deepseek-ai/dsh-client-runtime": "^0.1.1-rc.1",
|
|
80
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.1-rc.1",
|
|
81
|
+
"@deepseek-ai/dsh-home-paths": "^0.1.1-rc.1",
|
|
82
|
+
"@deepseek-ai/dsh-host-webserver": "^0.1.1-rc.1",
|
|
77
83
|
"react": "^18.2.0"
|
|
84
|
+
},
|
|
85
|
+
"devDependencies": {
|
|
86
|
+
"@types/node": "^26.2.0",
|
|
87
|
+
"@types/react": "^18.2.0",
|
|
88
|
+
"@types/react-dom": "^18.2.0",
|
|
89
|
+
"rolldown": "^1.0.0-beta.7",
|
|
90
|
+
"tsdown": "^0.8.0",
|
|
91
|
+
"typescript": "^5.5.0"
|
|
78
92
|
}
|
|
79
93
|
}
|