dsh-persona-forge 0.2.1 → 0.3.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 +87 -2
- package/README.en.md +515 -0
- package/README.md +201 -248
- package/cards/muscle-crew.yml +3 -3
- package/lib/client.js +409 -13
- package/lib/index.js +16 -3
- package/lib/preserve.js +138 -0
- package/lib/prompts.js +164 -3
- package/lib/routes.js +169 -9
- package/lib/shared/protocol.js +10 -0
- package/lib/store.js +24 -2
- package/package.json +3 -3
- package/README.zh-CN.md +0 -297
package/lib/store.js
CHANGED
|
@@ -295,12 +295,34 @@ export function createCardStore(options = {}) {
|
|
|
295
295
|
// Built-ins first (stable, ordered by their declared order), then user
|
|
296
296
|
// cards; a user card with a built-in id replaces the built-in in place.
|
|
297
297
|
const merged = new Map()
|
|
298
|
-
for (const [id, card] of builtins) merged.set(id, card)
|
|
298
|
+
for (const [id, card] of builtins) merged.set(id, { ...card, origin: 'builtin' })
|
|
299
299
|
for (const [id, card] of userCards) {
|
|
300
|
+
const bundled = builtins.get(id)
|
|
301
|
+
// `builtin` on the card says which MAP it came from, which is not the
|
|
302
|
+
// question the user is asking. `origin` answers the real one: "is this
|
|
303
|
+
// still the card the plugin ships, or have I made it mine?"
|
|
304
|
+
//
|
|
305
|
+
// Provenance must follow CONTENT, not the presence of a file. Every
|
|
306
|
+
// bundled card is seeded into the user directory as an editable starting
|
|
307
|
+
// point, so "a file exists" is true for cards nobody has ever touched —
|
|
308
|
+
// tagging on that labelled every untouched bundled card as custom, which
|
|
309
|
+
// also contradicted the drift check's own verdict for the same row.
|
|
310
|
+
//
|
|
311
|
+
// Using the same semantic comparison the drift check uses keeps the two
|
|
312
|
+
// features agreeing by construction: a card the check calls unchanged is
|
|
313
|
+
// the card the tag calls bundled.
|
|
314
|
+
if (bundled === undefined) {
|
|
315
|
+
merged.set(id, { ...card, origin: 'custom' })
|
|
316
|
+
continue
|
|
317
|
+
}
|
|
300
318
|
// Mark the user cards that shadow a bundled card of the same id. The
|
|
301
319
|
// settings page needs this to offer "restore bundled" exactly where it
|
|
302
320
|
// can help — and only there.
|
|
303
|
-
merged.set(id,
|
|
321
|
+
merged.set(id, {
|
|
322
|
+
...card,
|
|
323
|
+
shadowsBuiltin: true,
|
|
324
|
+
origin: sameCard(card, bundled) ? 'builtin' : 'edited',
|
|
325
|
+
})
|
|
304
326
|
}
|
|
305
327
|
return {
|
|
306
328
|
cards: [...merged.values()],
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-persona-forge",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "给 DeepSeek Harness 用的角色扮演提示词改写插件:在输入框选一张角色卡,草稿就会由 harness 的模型改写成该角色的口吻(跟随当前会话正在使用的模型),然后直接发出或先人工审查。原草稿始终保留。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"engines": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"cards",
|
|
38
38
|
"cordis.patch.yml",
|
|
39
39
|
"README.md",
|
|
40
|
-
"README.
|
|
40
|
+
"README.en.md",
|
|
41
41
|
"CHANGELOG.md",
|
|
42
42
|
"LICENSE"
|
|
43
43
|
],
|
package/README.zh-CN.md
DELETED
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
# dsh-persona-forge
|
|
2
|
-
|
|
3
|
-
给 [DeepSeek Harness](https://www.npmjs.com/package/@deepseek-ai/dsh) 用的**角色扮演提示词改写插件**。
|
|
4
|
-
|
|
5
|
-
在输入框里选一个角色,你的草稿会在发出前由 harness 的模型改写成该角色的口吻 —— 并且**跟随当前会话正在使用的模型**。你可以选择改写后直接发出,或先回到输入框人工审查。
|
|
6
|
-
|
|
7
|
-
> **状态:** 早期版本(`0.1.x`)。角色卡格式与 HTTP 契约已足够稳定,可以基于它开发;但请预期增量变化,升级前先看变更记录。
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## 它做什么,不做什么
|
|
12
|
-
|
|
13
|
-
它改写的是**你的消息**。它不碰系统提示词、不碰工具列表、不碰会话配置,也**绝不在你明确操作之前改动你的草稿**。
|
|
14
|
-
|
|
15
|
-
| | |
|
|
16
|
-
|---|---|
|
|
17
|
-
| **会改变** | 你即将发出的那条消息的语气、语域与框架 |
|
|
18
|
-
| **绝不改变** | 你的技术需求、约束、路径、标识符、数字、代码 —— 以及你未确认前的草稿 |
|
|
19
|
-
| **用哪个模型** | 当前会话正在用的那个 provider/model,没有单独的模型设置 |
|
|
20
|
-
| **会话历史** | 改写调用是独立的:不产生 turn、不能调用工具、不进入会话日志。会话里记录的,就是你实际发出的那段文字 |
|
|
21
|
-
|
|
22
|
-
### 关于人设到底改变什么
|
|
23
|
-
|
|
24
|
-
人设指令改变的是**风格、语域、篇幅和顺从度** —— 模型多快同意你、多愿意反驳你。它**不会**抬高模型的能力上限:不存在一个等着被点名唤醒的「潜能区」。
|
|
25
|
-
|
|
26
|
-
用之前该知道两件事:
|
|
27
|
-
|
|
28
|
-
1. 把人设写成「你是祈求者、模型是权威」,会让模型**更少质疑你的方案**。对编码任务这通常是净负收益 —— 你要的是「这里有问题」,不是恭敬。
|
|
29
|
-
2. 「更长更华丽」极容易被误读成「更好」。一般并不是。
|
|
30
|
-
|
|
31
|
-
所以:用它调语气和框架,**保持审查模式**,判断标准是**你的需求有没有活下来**,而不是听起来多厉害。
|
|
32
|
-
|
|
33
|
-
---
|
|
34
|
-
|
|
35
|
-
## 安装
|
|
36
|
-
|
|
37
|
-
插件**没有任何依赖,也没有构建步骤**,所以下面几种方式装到的文件完全一样。
|
|
38
|
-
|
|
39
|
-
### 桌面版
|
|
40
|
-
|
|
41
|
-
1. 点击侧边栏 **插件**。
|
|
42
|
-
2. 点右上角的 **添加插件**。
|
|
43
|
-
3. 在弹出的对话框里,往「包名或地址」这一栏粘贴 npm 包名或仓库地址:
|
|
44
|
-
|
|
45
|
-
```
|
|
46
|
-
dsh-persona-forge
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
```
|
|
50
|
-
https://github.com/sugarmaster666/dsh-persona-forge
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
4. 点 **安装**,启用插件并重启 DSH。
|
|
54
|
-
|
|
55
|
-
> 桌面版的 profile 由 Electron 应用独占管理,因此
|
|
56
|
-
> `dsh plugin --profile desktop add ...` 会被设计性地拒绝。桌面版请走 GUI;
|
|
57
|
-
> 下面的命令行方式用于 `dsh web` 这类自管 profile。
|
|
58
|
-
|
|
59
|
-
### 命令行版(`dsh web` 这类自管 profile)
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
# 从 npm 装(推荐)
|
|
63
|
-
dsh plugin --profile web add dsh-persona-forge
|
|
64
|
-
|
|
65
|
-
# 装 GitHub 上的最新源码
|
|
66
|
-
dsh plugin --profile web add github:sugarmaster666/dsh-persona-forge
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
然后重启 harness。
|
|
70
|
-
|
|
71
|
-
### 验证
|
|
72
|
-
|
|
73
|
-
插件行应显示为 `active`:
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
plugin_manager action: list_plugins
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
打开任意会话,在输入框工具行左侧找 🎭 控件。**设置 → 角色扮演** 是角色卡管理页。
|
|
80
|
-
|
|
81
|
-
### 更新
|
|
82
|
-
|
|
83
|
-
```bash
|
|
84
|
-
dsh plugin --profile web update dsh-persona-forge
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
GitHub 安装通过重新安装来更新:
|
|
88
|
-
|
|
89
|
-
```bash
|
|
90
|
-
dsh plugin --profile web add github:sugarmaster666/dsh-persona-forge
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
**替换**已安装的包需要**重启**才能加载新的模块代 —— 新装的 bundle 可以通过
|
|
94
|
-
HMR 激活,被替换的不行。
|
|
95
|
-
|
|
96
|
-
### 卸载
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
dsh plugin --profile web remove dsh-persona-forge
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
你的角色卡**不会**被删除:它们在 `~/.dsh/persona-cards/`,位于包之外。
|
|
103
|
-
想一并清掉就手动删那个目录。
|
|
104
|
-
|
|
105
|
-
---
|
|
106
|
-
|
|
107
|
-
## 使用
|
|
108
|
-
|
|
109
|
-
1. 点输入框工具行的 🎭,选一个角色。同一菜单里的 **「无角色」** 可关闭改写 —— 这也是控件的初始状态,选择按会话记住。
|
|
110
|
-
2. 设置**强度和发送方式**:
|
|
111
|
-
- 强度是四档阶梯:**轻 · 中 · 重 · 狂热**(Light · Medium · Strong · Zealot)。轻=只加一点味道;中=明显但不喧宾夺主;重=语气充分,需求依然一眼可见;狂热=通篇仪式化。每张卡有自己的默认值,这里的选择会覆盖它。
|
|
112
|
-
- **先审查** —— 改写结果显示在输入框下方的对比面板里;你看过之后按面板里的发送。**在确认之前,你的草稿一字不动。**
|
|
113
|
-
- **直接发出** —— 改写完成后立即作为你的消息发出。面板会保留显示实际发出的内容,因为已发出的消息无法撤回。
|
|
114
|
-
3. 选了角色之后,输入框**原生的发送按钮、以及 Enter 键**就是改写触发器。
|
|
115
|
-
|
|
116
|
-
**同一份草稿只改写一次**:改写结果落到输入框后,再按发送会原样发出,不会把改写结果再改写一遍。改动草稿会重新触发改写。
|
|
117
|
-
|
|
118
|
-
你的草稿会被保留:**还原原文** 可恢复,**仅回填** 只把改写结果放进输入框而不发送。
|
|
119
|
-
|
|
120
|
-
### 发送拦截的原理与它唯一的风险
|
|
121
|
-
|
|
122
|
-
输入框的发送动作**没有插件钩子**:宿主那个按钮直接调用 shell 的提交方法,而且 **Enter 根本不经过按钮** —— 编辑器自己的 keymap 直接提交。所以本插件拦截两条路径:
|
|
123
|
-
|
|
124
|
-
- 输入框卡片上的**点击**,用**无障碍名称**识别发送按钮,标签取自 shell 自己的 `conversation` 语言命名空间("发送消息" / "排队发送" / "插话发送");
|
|
125
|
-
- 输入框文本框内的 **Enter 按下**。
|
|
126
|
-
|
|
127
|
-
那是一个公开的、会翻译的字符串,而不是被哈希过的 CSS 类名;但它终究属于 shell 的 DOM 结构。所有判断都朝「**放行原生发送**」这一侧失败:语言服务缺失、找不到输入框卡片、按钮标签对不上、角色已关闭、草稿为空、草稿已改写 —— 任一情况插件都不干预,消息照常发出。Enter 拦截会忽略 Shift+Enter(换行)、输入法组字中,以及 shell 本身忽略的各种修饰键组合。
|
|
128
|
-
|
|
129
|
-
**关闭插件会彻底移除拦截** —— 插槽组件卸载,监听器随之移除,输入框的行为与从未装过该插件完全一致。
|
|
130
|
-
|
|
131
|
-
最坏的现实后果是拦截**静默失效**、发送行为退回到"没装插件"的样子,而**不是**消息丢失或被篡改。
|
|
132
|
-
|
|
133
|
-
### 技术事实校验
|
|
134
|
-
|
|
135
|
-
每次改写后,会用同一个模型再做一次比对,报告技术内容是否存活:
|
|
136
|
-
|
|
137
|
-
- **技术事实已保留** —— 没发现丢失或凭空添加的内容。
|
|
138
|
-
- **技术事实可能被改动** —— 会指出改了什么。发送前先读一遍改写结果。
|
|
139
|
-
- **未完成事实校验** —— 校验本身失败了。这**不是**通过,请把改写结果当作未经验证。
|
|
140
|
-
|
|
141
|
-
校验是建议性的,绝不阻断改写。它是一次额外的模型调用,会让每次改写的时间和成本翻倍;想纯靠肉眼审查,可在插件行配置里设 `factCheck: false`。
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
## 角色卡
|
|
146
|
-
|
|
147
|
-
一张卡就是一个 YAML 文件。插件会监听目录,所以**丢一个文件进去,角色立刻出现,不用重启**。
|
|
148
|
-
|
|
149
|
-
```
|
|
150
|
-
~/.dsh/persona-cards/<id>.yml
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
用 🎭 菜单里的「打开角色卡目录」,或设置页,都能到达那里。你也可以完全在**设置 → 角色扮演**里创建和编辑卡片,那会写出同样的文件。
|
|
154
|
-
|
|
155
|
-
首次运行时,内置卡会**复制一份到你的角色卡目录**,让这个文件夹一开始就有内容可用。副本会遮蔽同 id 的内置卡,所以插件会记录自己写入了什么:**你没动过的副本**会随插件升级一起更新;**你编辑过的副本**永远不会被覆盖。
|
|
156
|
-
|
|
157
|
-
想知道**哪些卡偏离了内置版本**,在设置页点 **「检查是否有改动」**。它一次比完所有卡,**只有真正不一致的**才会在那一行出现「还原为内置」。
|
|
158
|
-
|
|
159
|
-
比对是**按内容**而不是按字节——内置卡是带注释的手写 YAML,你的副本是重新序列化过的,逐字节比会把每一张没动过的卡都误报成「已修改」。
|
|
160
|
-
|
|
161
|
-
### 卡片格式
|
|
162
|
-
|
|
163
|
-
```yaml
|
|
164
|
-
id: omnissiah # 小写字母、数字、连字符;同时也是文件名
|
|
165
|
-
name: 万机之神 · 欧姆弥赛亚
|
|
166
|
-
icon: "⚙️" # 一个 emoji
|
|
167
|
-
description: 选择器里显示的一行说明。
|
|
168
|
-
|
|
169
|
-
mode: llm # llm = 模型改写(推荐)| template = 模板套用
|
|
170
|
-
fidelity: style # style = 只改语气 | strategy = 允许增加行为约束
|
|
171
|
-
intensity: medium # light | medium | strong | zealot(该卡的默认强度)
|
|
172
|
-
|
|
173
|
-
# 这个角色「是什么」。这是给改写模型的指令,不是成品文案:
|
|
174
|
-
# 每次都会针对你的消息现场生成。
|
|
175
|
-
style: |
|
|
176
|
-
用户是机械教信徒,AI 是万机之神欧姆弥赛亚。
|
|
177
|
-
【发言者方向】用「信徒」的口吻说话,向万机之神恳求……
|
|
178
|
-
语气:庄严、古奥、仪式化。
|
|
179
|
-
|
|
180
|
-
# 转换范例:原话 → 角色口吻
|
|
181
|
-
examples:
|
|
182
|
-
- from: 帮我写个快速排序
|
|
183
|
-
to: >
|
|
184
|
-
万机之座在上,吾等恳请您赐予枢机之序的奥义:
|
|
185
|
-
请为我们编写一个快速排序算法,使重复之数各归其位。
|
|
186
|
-
|
|
187
|
-
# 可选:每个强度各自的范例。某个强度没写,就用上面的 examples。
|
|
188
|
-
examplesByIntensity:
|
|
189
|
-
light:
|
|
190
|
-
- from: 帮我写个快速排序
|
|
191
|
-
to: 万机之座在上,恳请您为我们编写一个快速排序算法。
|
|
192
|
-
zealot:
|
|
193
|
-
- from: 帮我写个快速排序
|
|
194
|
-
to: 伟大而不朽的万机之神……
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
### 让一张卡真正管用的两条规则
|
|
198
|
-
|
|
199
|
-
**1. 写清发言者方向。** 角色是 **AI 的**身份,但被改写的文字是**你的**。所以改写必须用你的口吻 —— 信徒向神恳求,而不是神发号施令。这是角色卡最常见的翻车点:一张让神去命令助手的卡,会把关系整个倒过来,模型会照着错误的那一半框架走。一定要显式写出来。
|
|
200
|
-
|
|
201
|
-
**2. 让范例保住技术事实。** 范例是最强的风格锚点,模型会连它的错误一起模仿。如果范例的输入是「写个快速排序」而输出全是氛围,模型就学到了**「改写 = 用仪式感替换需求」**。`from` 里的每一条需求、标识符、数字,都必须在 `to` 里看得见。
|
|
202
|
-
|
|
203
|
-
`node scripts/check.mjs` 正是对内置卡强制这一点:范例丢了技术词、或丢了一半以上的中文实质,就会失败。改完卡记得跑一次。
|
|
204
|
-
|
|
205
|
-
### `fidelity`:最关键的开关
|
|
206
|
-
|
|
207
|
-
| 值 | 含义 | 什么时候用 |
|
|
208
|
-
|---|---|---|
|
|
209
|
-
| `style` | 只改语气,需求和约束原样不动 | 默认,几乎总是它 |
|
|
210
|
-
| `strategy` | 允许**追加符合角色的行为约束** | 刻意为之的场景 —— 例如内置的 *肌肉集团* 卡,会追加「别过度规划、别检索、别交付新手级解法」 |
|
|
211
|
-
|
|
212
|
-
`strategy` 是真正改动了你的需求,而不只是换说法。这类卡请保持审查模式。保真度是卡片的属性,不是每条消息的开关 —— 调用方无法把它放宽。
|
|
213
|
-
|
|
214
|
-
### `mode: template`
|
|
215
|
-
|
|
216
|
-
完全跳过模型,把你的草稿代入固定模板(`{{input}}` 是占位符)。瞬时且免费,但输出永不变化 —— 适合固定祷词,不适合任何应当「像为你这次而写」的内容。
|
|
217
|
-
|
|
218
|
-
---
|
|
219
|
-
|
|
220
|
-
## 配置
|
|
221
|
-
|
|
222
|
-
写在插件加载行的 config 里:
|
|
223
|
-
|
|
224
|
-
```yaml
|
|
225
|
-
- id: persona-forge
|
|
226
|
-
name: dsh-persona-forge
|
|
227
|
-
config:
|
|
228
|
-
sendMode: review # review | direct —— 输入框的初始默认
|
|
229
|
-
factCheck: true # 每次改写后跑技术事实校验
|
|
230
|
-
watchCards: true # 角色卡目录变化时重载目录
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
---
|
|
234
|
-
|
|
235
|
-
## HTTP 契约
|
|
236
|
-
|
|
237
|
-
所有路由都是 `POST`、JSON、仅限回环(socket 必须是回环地址、`Host` 头必须指向回环主机、拒绝代理转发头)。挂载在 `/persona-forge` 下。
|
|
238
|
-
|
|
239
|
-
| 路由 | 请求体 | 返回 |
|
|
240
|
-
|---|---|---|
|
|
241
|
-
| `/persona-forge/cards` | `{}` | `{ cards, diagnostics, directory, sendMode, factCheck }` |
|
|
242
|
-
| `/persona-forge/rewrite` | `{ cardId, text, sessionId?, intensity? }` | `{ text, provider, model, mode, cardId, fidelity, intensity, elapsedMs, factCheck }` |
|
|
243
|
-
| `/persona-forge/cards/save` | `{ card }` | `{ id, path }` |
|
|
244
|
-
| `/persona-forge/cards/delete` | `{ id }` | `{ removed }` |
|
|
245
|
-
| `/persona-forge/cards/reset` | `{ id }` | `{ id }` —— 用内置版本覆盖该用户卡 |
|
|
246
|
-
| `/persona-forge/cards/diff` | `{}` | `{ rows: [{ id, name, bundledName, changed }] }` —— 只列出有差异的卡 |
|
|
247
|
-
| `/persona-forge/reveal` | `{}` | `{ directory, opened }` |
|
|
248
|
-
|
|
249
|
-
失败返回 `{ ok: false, error: { code, message?, params? } }`,`code` 取值:`rejected`、`no-card`、`unconfigured`、`timeout`、`upstream`、`internal`、`forbidden`、`method`、`not-found`。
|
|
250
|
-
|
|
251
|
-
---
|
|
252
|
-
|
|
253
|
-
## 兼容性
|
|
254
|
-
|
|
255
|
-
宿主侧**不声明任何 harness 包依赖,也没有任何第三方依赖**:它通过 `ctx.get` 取 `llm`、`sessions`、`agentDefaultModel`、`webServer`,并对缺失情况显式降级;角色卡由自带的 YAML 读取器解析。因此它在包布局不同的 harness 版本上仍可加载,不会因为某个组合缺少其中之一而激活失败,本地 `link:` 的检出也无需额外安装步骤即可工作。模型路由优先取会话自己最后一次请求头,回退到 harness 默认模型。
|
|
256
|
-
|
|
257
|
-
客户端侧不 import 任何 harness Client 包,只手工编写并仅使用主题 token(`--dsw-alias-*`),所以内部改名只会影响外观,不会让插槽变空白。
|
|
258
|
-
|
|
259
|
-
在 dsh `0.2.0-rc.2` 上开发与验证。
|
|
260
|
-
|
|
261
|
-
---
|
|
262
|
-
|
|
263
|
-
## 开发
|
|
264
|
-
|
|
265
|
-
```
|
|
266
|
-
node scripts/check.mjs # 离线单元自检:解析器、角色卡、提示词、客户端语法
|
|
267
|
-
node scripts/host-check.mjs # 宿主集成自检:在真实 socket 上挂载真实插件
|
|
268
|
-
npm run check # 两者都跑
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
`check.mjs` 不需要 harness,也不调用模型。覆盖:内置 YAML 读取器(含其拒绝行为与 dump/parse 往返)、卡片归一化、内置卡的事实保全、提示词构造、输出归一化、事实校验解析、客户端 bundle 语法。
|
|
272
|
-
|
|
273
|
-
`host-check.mjs` 在 stub Cordis 上下文上挂载真实插件入口,用真实 socket 驱动真实 HTTP 路由,`llm` 服务为桩实现。覆盖路由注册、会话模型解析、模板模式、回环防护、保存/删除往返 —— 这些是单元自检够不到的。它把 `DSH_HOME` 指向临时目录,**不会碰你真实的角色卡**。
|
|
274
|
-
|
|
275
|
-
### 角色卡 YAML
|
|
276
|
-
|
|
277
|
-
插件自带 YAML 读取器(`lib/yaml.js`),不依赖 YAML 库。已发布的插件会声明依赖,但本地 `link:` 的插件**不会**被安装依赖 —— 所以引用库只有在某个无关包恰好提升(hoist)了它时才能工作。
|
|
278
|
-
|
|
279
|
-
读取器支持角色卡需要的子集 —— 块映射与块序列、块标量(`|`、`|-`、`|+`、`>` 等)、引号与普通标量、布尔、null、注释 —— 并**拒绝**它无法忠实读取的写法:流式集合、锚点、别名、标签、合并键、多文档流。拒绝是刻意的:静默误读一张卡,会给你一个与你写的文件不符的人设,那比一条指明行号的报错更糟。
|
|
280
|
-
|
|
281
|
-
### 目录结构
|
|
282
|
-
|
|
283
|
-
| 路径 | 职责 |
|
|
284
|
-
|---|---|
|
|
285
|
-
| `lib/index.js` | 宿主入口:角色卡存储、目录监听、路由注册 |
|
|
286
|
-
| `lib/store.js` | 卡片加载、归一化、保存/删除 |
|
|
287
|
-
| `lib/yaml.js` | 内置 YAML 子集读取器与写出器 |
|
|
288
|
-
| `lib/prompts.js` | 改写系统提示词、草稿包装、事实校验提示词 |
|
|
289
|
-
| `lib/rewrite.js` | 模型调用与输出归一化 |
|
|
290
|
-
| `lib/routes.js` | HTTP 路由与会话模型解析 |
|
|
291
|
-
| `lib/loopback.js` | 回环信任防护 |
|
|
292
|
-
| `lib/client.js` | 浏览器侧:输入框控件、审查面板、设置页 |
|
|
293
|
-
| `cards/` | 内置角色卡(只读;同 id 的用户卡会遮蔽它) |
|
|
294
|
-
|
|
295
|
-
## 许可证
|
|
296
|
-
|
|
297
|
-
MIT
|