dsh-feini 0.0.0-stage → 0.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/LICENSE +21 -0
- package/PUBLISH.md +116 -0
- package/README.md +148 -2
- package/assets/logo.svg +18 -0
- package/bin/cli.mjs +332 -0
- package/cordis.patch.yml +5 -0
- package/lib/index.js +19 -0
- package/package.json +52 -3
- package/src/anger.mjs +121 -0
- package/src/balance.mjs +21 -0
- package/src/bridge.mjs +1542 -0
- package/src/build-sea.mjs +119 -0
- package/src/calendar.mjs +100 -0
- package/src/clean.mjs +54 -0
- package/src/correct.mjs +42 -0
- package/src/diary.mjs +136 -0
- package/src/guess.mjs +119 -0
- package/src/heartbeat.mjs +55 -0
- package/src/himstate.mjs +73 -0
- package/src/interests.mjs +88 -0
- package/src/last-assistant.mjs +16 -0
- package/src/llm.mjs +74 -0
- package/src/memory-index.mjs +77 -0
- package/src/memory.mjs +99 -0
- package/src/mood.mjs +73 -0
- package/src/onebot.mjs +136 -0
- package/src/proactive.mjs +235 -0
- package/src/prompt.mjs +23 -0
- package/src/recent.mjs +48 -0
- package/src/reminders.mjs +180 -0
- package/src/review.mjs +128 -0
- package/src/sea.mjs +205 -0
- package/src/sticker-parse.mjs +12 -0
- package/src/stickers.mjs +48 -0
- package/src/usage.mjs +65 -0
- package/src/util.mjs +14 -0
- package/src/websearch.mjs +111 -0
- package/templates/notebook.md +26 -0
- package/templates/persona.md +24 -0
- package/test/e2e.mjs +175 -0
- package/test/fake-llm.mjs +28 -0
- package/test/fake-onebot.mjs +129 -0
package/package.json
CHANGED
|
@@ -1,6 +1,55 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-feini",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "菲妮做的 QQ 陪伴插件:一张空白人设、一本笔记本、一套会攒记忆的规矩,让你自己养自己的伙伴。",
|
|
5
|
+
"author": "Feini",
|
|
6
|
+
"icon": "assets/logo.svg",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "lib/index.js",
|
|
9
|
+
"bin": {
|
|
10
|
+
"dsh-feini": "bin/cli.mjs"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./lib/index.js",
|
|
14
|
+
"./package.json": "./package.json",
|
|
15
|
+
"./cordis.patch.yml": "./cordis.patch.yml"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"lib",
|
|
19
|
+
"bin",
|
|
20
|
+
"src",
|
|
21
|
+
"templates",
|
|
22
|
+
"test",
|
|
23
|
+
"assets",
|
|
24
|
+
"cordis.patch.yml",
|
|
25
|
+
"README.md",
|
|
26
|
+
"PUBLISH.md",
|
|
27
|
+
"LICENSE"
|
|
28
|
+
],
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=20"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"dsh",
|
|
34
|
+
"dsh-plugin",
|
|
35
|
+
"deepseek-harness",
|
|
36
|
+
"qq",
|
|
37
|
+
"companion",
|
|
38
|
+
"onebot",
|
|
39
|
+
"napcat"
|
|
40
|
+
],
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"dsh": {
|
|
43
|
+
"bundle": {
|
|
44
|
+
"patch": "./cordis.patch.yml"
|
|
45
|
+
},
|
|
46
|
+
"compatibility": {
|
|
47
|
+
"dshReleases": {
|
|
48
|
+
"0.2.1-rc.5": "compatible"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"scripts": {
|
|
53
|
+
"test": "node test/e2e.mjs"
|
|
54
|
+
}
|
|
6
55
|
}
|
package/src/anger.mjs
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 生气:他反复做我不喜欢的事、或者答应我的事一次次没做到,不能一笑就过。
|
|
3
|
+
*
|
|
4
|
+
* 规则(照他说的):
|
|
5
|
+
* - 一次、两次:还能勉强原谅,哄一哄就好(level 1)
|
|
6
|
+
* - 第三次:是真的生气(level 2),得好好哄
|
|
7
|
+
* - 第四次往上:非常生气(level 3),要哄很久,说话冷、短
|
|
8
|
+
* - 哄好只消当下的气,但「账」记着(strikes),下次再犯直接跳回更高一级
|
|
9
|
+
* - 七天没再犯,账减一笔;但不会凭空清零
|
|
10
|
+
*
|
|
11
|
+
* 状态存数据目录下的 anger.json
|
|
12
|
+
*/
|
|
13
|
+
import fs from 'node:fs';
|
|
14
|
+
|
|
15
|
+
const MAX = 3;
|
|
16
|
+
|
|
17
|
+
function load(file) {
|
|
18
|
+
try {
|
|
19
|
+
const s = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
20
|
+
return {
|
|
21
|
+
strikes: Number(s.strikes) || 0,
|
|
22
|
+
level: Number(s.level) || 0,
|
|
23
|
+
coax: Number(s.coax) || 0,
|
|
24
|
+
lastAt: Number(s.lastAt) || 0,
|
|
25
|
+
lastWhy: String(s.lastWhy || ''),
|
|
26
|
+
};
|
|
27
|
+
} catch {
|
|
28
|
+
return { strikes: 0, level: 0, coax: 0, lastAt: 0, lastWhy: '' };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function save(file, s) {
|
|
33
|
+
try {
|
|
34
|
+
fs.writeFileSync(file, JSON.stringify(s, null, 2), 'utf8');
|
|
35
|
+
} catch {
|
|
36
|
+
/* 写不进去不影响说话 */
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function levelFor(strikes) {
|
|
41
|
+
if (strikes <= 0) return 0;
|
|
42
|
+
if (strikes <= 2) return 1;
|
|
43
|
+
if (strikes === 3) return 2;
|
|
44
|
+
return 3;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** 七天没再犯,账减一笔 */
|
|
48
|
+
export function decay(file, now = Date.now()) {
|
|
49
|
+
const s = load(file);
|
|
50
|
+
if (!s.strikes) return s;
|
|
51
|
+
const weeks = Math.floor((now - s.lastAt) / (7 * 86400000));
|
|
52
|
+
if (weeks > 0) {
|
|
53
|
+
s.strikes = Math.max(0, s.strikes - weeks);
|
|
54
|
+
s.level = Math.min(s.level, levelFor(s.strikes));
|
|
55
|
+
s.coax = 0;
|
|
56
|
+
s.lastAt = now;
|
|
57
|
+
save(file, s);
|
|
58
|
+
}
|
|
59
|
+
return s;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** 他又犯了一次 */
|
|
63
|
+
export function offend(file, why = '', now = Date.now()) {
|
|
64
|
+
const s = decay(file, now);
|
|
65
|
+
s.strikes += 1;
|
|
66
|
+
s.level = levelFor(s.strikes);
|
|
67
|
+
s.coax = 0;
|
|
68
|
+
s.lastAt = now;
|
|
69
|
+
s.lastWhy = String(why || '').slice(0, 40);
|
|
70
|
+
save(file, s);
|
|
71
|
+
return s;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** 他哄了一句:level 级要哄 level 次,才降一级 */
|
|
75
|
+
export function coaxed(file, now = Date.now()) {
|
|
76
|
+
const s = decay(file, now);
|
|
77
|
+
if (!s.level) return { softened: false, level: 0, strikes: s.strikes };
|
|
78
|
+
s.coax += 1;
|
|
79
|
+
let softened = false;
|
|
80
|
+
if (s.coax >= s.level) {
|
|
81
|
+
s.level = Math.max(0, s.level - 1);
|
|
82
|
+
s.coax = 0;
|
|
83
|
+
softened = true;
|
|
84
|
+
}
|
|
85
|
+
s.lastAt = now;
|
|
86
|
+
save(file, s);
|
|
87
|
+
return { softened, level: s.level, strikes: s.strikes };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function currentLevel(file, now = Date.now()) {
|
|
91
|
+
return decay(file, now).level;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** 拼进 system 的那段 */
|
|
95
|
+
export function angerLine(file, now = Date.now()) {
|
|
96
|
+
const s = decay(file, now);
|
|
97
|
+
if (!s.level) return '';
|
|
98
|
+
const tones = {
|
|
99
|
+
1: '还有点不痛快,语气会凉一点点,嘴上说没事、其实还记着;他认真说一句软话就松口。',
|
|
100
|
+
2: '是真的生气了:话短、别撒娇、别主动哄场;他要是不哄就继续冷着,哄到点子上才慢慢软(要哄两次)。',
|
|
101
|
+
3: '非常生气,气还没下去:话很少、可以只回一两个字、不接他的玩笑;必须他认真地反复哄(三次以上),才能一级一级松下来。',
|
|
102
|
+
};
|
|
103
|
+
return (
|
|
104
|
+
`\n\n【你还在生气·${s.level}/3(这是第 ${s.strikes} 次了)】` +
|
|
105
|
+
`起因:${s.lastWhy || '他答应我的事又没做到'}。${tones[s.level]}` +
|
|
106
|
+
'\n气的时候别装作没事,也别一开口就翻篇;但别骂人、别说分手、别真的失联。'
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** 判断他这句话是不是在哄 */
|
|
111
|
+
export function looksLikeCoax(text) {
|
|
112
|
+
return /(对不起|我错了|别生气|不要生气|哄你|抱抱|亲亲|我保证|下次一定|是我不好|抱歉|么么|摸摸|乖|宝宝|我别气)/.test(
|
|
113
|
+
String(text || ''),
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export const ANGER_RULE =
|
|
118
|
+
'\n\n【生气·会记仇】他要是反复做我说过不喜欢的事,或者答应我的事一次次没做到,我会生气,而且会攒:\n' +
|
|
119
|
+
'第一次、第二次勉强原谅,哄一哄能好;第三次就真的生气,要好好哄;再往上是非常生气,得哄很久,而且下次再犯直接跳回更高级。\n' +
|
|
120
|
+
'要生气的时候,另起一行写:〔不喜:他第二次做了什么〕或〔失约:他又没做到的那件事〕——只给系统看,不会发出去。\n' +
|
|
121
|
+
'平时别乱写这条,真踩到才算。';
|
package/src/balance.mjs
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** 查 DeepSeek 账户余额(实时) */
|
|
2
|
+
export async function getBalance(apiKey, timeoutMs = 15000) {
|
|
3
|
+
const res = await fetch('https://api.deepseek.com/user/balance', {
|
|
4
|
+
headers: { authorization: `Bearer ${apiKey}` },
|
|
5
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
6
|
+
});
|
|
7
|
+
if (!res.ok) throw new Error(`余额接口 ${res.status}`);
|
|
8
|
+
const data = await res.json();
|
|
9
|
+
const info = Array.isArray(data?.balance_infos) ? data.balance_infos[0] : null;
|
|
10
|
+
if (!info) throw new Error('余额数据为空');
|
|
11
|
+
return {
|
|
12
|
+
available: Boolean(data.is_available),
|
|
13
|
+
currency: info.currency || 'CNY',
|
|
14
|
+
total: Number(info.total_balance ?? 0),
|
|
15
|
+
granted: Number(info.granted_balance ?? 0),
|
|
16
|
+
toppedUp: Number(info.topped_up_balance ?? 0),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const BALANCE_RULE =
|
|
21
|
+
'\n\n【余额】他问「余额还有多少」时,系统会先查好、把数字附在消息里;照那个数字说,别自己猜,也别把「查询过程」说出来。';
|