master-skill 0.6.0 → 0.9.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/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +2 -2
- package/.cursor-plugin/plugin.json +2 -2
- package/README.md +71 -14
- package/README_EN.md +67 -12
- package/SKILL.md +58 -297
- package/bin/cli.mjs +58 -12
- package/gemini-extension.json +2 -2
- package/hooks/session-start +40 -2
- package/hooks/tests/test_session_start.sh +149 -0
- package/package.json +14 -7
- package/prebuilt/compare/SKILL.md +1 -1
- package/prebuilt/compare/tests/fidelity.jsonl +13 -0
- package/prebuilt/master-ajahn-chah/SKILL.md +35 -1
- package/prebuilt/master-ajahn-chah/meta.json +17 -1
- package/prebuilt/master-atisha/SKILL.md +35 -1
- package/prebuilt/master-atisha/meta.json +17 -1
- package/prebuilt/master-buddhaghosa/SKILL.md +35 -1
- package/prebuilt/master-buddhaghosa/meta.json +26 -1
- package/prebuilt/master-curriculum/SKILL.md +87 -0
- package/prebuilt/master-curriculum/references/chan.md +29 -0
- package/prebuilt/master-curriculum/references/gelug-madhyamaka.md +33 -0
- package/prebuilt/master-curriculum/references/huayan.md +28 -0
- package/prebuilt/master-curriculum/references/jingtu.md +29 -0
- package/prebuilt/master-curriculum/references/sanlun-zhongguan.md +30 -0
- package/prebuilt/master-curriculum/references/theravada-vipassana.md +39 -0
- package/prebuilt/master-curriculum/references/tiantai.md +30 -0
- package/prebuilt/master-curriculum/references/weishi.md +31 -0
- package/prebuilt/master-curriculum/tests/fidelity.jsonl +8 -0
- package/prebuilt/master-debate/SKILL.md +274 -0
- package/prebuilt/master-debate/meta.json +25 -0
- package/prebuilt/master-debate/tests/fidelity.jsonl +8 -0
- package/prebuilt/master-fazang/SKILL.md +35 -1
- package/prebuilt/master-fazang/meta.json +25 -0
- package/prebuilt/master-huineng/SKILL.md +35 -1
- package/prebuilt/master-huineng/meta.json +37 -0
- package/prebuilt/master-huineng/references/teaching.md +1 -1
- package/prebuilt/master-huineng/sources/INDEX.md +1 -1
- package/prebuilt/master-huineng/sources/tanjing-excerpts.md +17 -1
- package/prebuilt/master-huineng/tests/fidelity.jsonl +2 -0
- package/prebuilt/master-kumarajiva/SKILL.md +35 -1
- package/prebuilt/master-kumarajiva/meta.json +16 -0
- package/prebuilt/master-kumarajiva/references/teaching.md +2 -2
- package/prebuilt/master-mahasi-sayadaw/SKILL.md +35 -1
- package/prebuilt/master-mahasi-sayadaw/meta.json +17 -1
- package/prebuilt/master-milarepa/SKILL.md +35 -1
- package/prebuilt/master-milarepa/meta.json +26 -1
- package/prebuilt/master-nagarjuna/SKILL.md +170 -0
- package/prebuilt/master-nagarjuna/meta.json +129 -0
- package/prebuilt/master-nagarjuna/references/teaching.md +112 -0
- package/prebuilt/master-nagarjuna/references/voice.md +100 -0
- package/prebuilt/master-nagarjuna/sources/INDEX.md +23 -0
- package/prebuilt/master-nagarjuna/sources/dazhidulun-excerpts.md +49 -0
- package/prebuilt/master-nagarjuna/sources/shizhu-yixing-excerpts.md +33 -0
- package/prebuilt/master-nagarjuna/sources/zhonglun-excerpts.md +94 -0
- package/prebuilt/master-nagarjuna/tests/fidelity.jsonl +10 -0
- package/prebuilt/master-ouyi/SKILL.md +35 -1
- package/prebuilt/master-ouyi/meta.json +17 -0
- package/prebuilt/master-ouyi/references/teaching.md +4 -4
- package/prebuilt/master-ouyi/sources/INDEX.md +1 -1
- package/prebuilt/master-ouyi/sources/jiaoguan-gangzong-excerpts.md +3 -3
- package/prebuilt/master-tsongkhapa/SKILL.md +35 -1
- package/prebuilt/master-tsongkhapa/meta.json +18 -1
- package/prebuilt/master-xuanzang/SKILL.md +35 -1
- package/prebuilt/master-xuanzang/meta.json +16 -0
- package/prebuilt/master-xuanzang/references/teaching.md +5 -5
- package/prebuilt/master-xuanzang/references/voice.md +1 -1
- package/prebuilt/master-xuyun/SKILL.md +35 -1
- package/prebuilt/master-xuyun/meta.json +39 -0
- package/prebuilt/master-yinguang/SKILL.md +36 -2
- package/prebuilt/master-yinguang/meta.json +17 -0
- package/prebuilt/master-yinguang/references/teaching.md +7 -7
- package/prebuilt/master-yinguang/references/voice.md +1 -1
- package/prebuilt/master-yinguang/sources/INDEX.md +3 -3
- package/prebuilt/master-yinguang/sources/wenchao-excerpts.md +4 -4
- package/prebuilt/master-yinguang/sources/yihanbianfu-excerpts.md +3 -3
- package/prebuilt/master-zhiyi/SKILL.md +35 -1
- package/prebuilt/master-zhiyi/meta.json +28 -0
- package/prebuilt/master-zhiyi/references/teaching.md +2 -2
- package/scripts/_masterpaths.py +32 -0
- package/scripts/check-manifest-versions.py +142 -0
- package/scripts/cite.py +19 -4
- package/scripts/query.py +19 -4
- package/scripts/test-fidelity.py +35 -3
- package/scripts/tests/test_check_manifest_versions.py +217 -0
- package/scripts/tests/test_debate_protocol.py +159 -0
- package/scripts/tests/test_injection_hardening.py +174 -0
- package/scripts/tests/test_validate_cross_critique.py +149 -0
- package/scripts/tests/test_validate_curriculum_sources.py +144 -0
- package/scripts/tests/test_validate_lore_triggers_content.py +372 -0
- package/scripts/tests/test_validate_persona_fidelity.py +317 -0
- package/scripts/tests/test_validate_promptfoo_configs.py +386 -0
- package/scripts/validate-cross-critique.py +137 -0
- package/scripts/validate-curriculum-sources.py +111 -0
- package/scripts/validate-fidelity.py +16 -1
- package/scripts/validate-lore-triggers-content.py +393 -0
- package/scripts/validate-persona-fidelity.py +210 -0
- package/scripts/validate-promptfoo-configs.py +383 -0
- package/scripts/validate.py +212 -4
- package/scripts/verify_citations.py +152 -0
package/SKILL.md
CHANGED
|
@@ -20,17 +20,19 @@ allowed-tools:
|
|
|
20
20
|
|
|
21
21
|
## 触发条件
|
|
22
22
|
|
|
23
|
-
以下方式均可触发:
|
|
24
23
|
- `/create-master` 或 `/create-master <法师名>`
|
|
25
24
|
- "帮我创建一个印光大师的教学角色"
|
|
26
25
|
- "生成慧能大师的 AI Skill"
|
|
27
26
|
- "我想和玄奘法师学习"
|
|
28
27
|
|
|
29
|
-
##
|
|
28
|
+
## 预置法师(直接调用,无需生成)
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
**印度**
|
|
31
|
+
|
|
32
|
+
- `/master-nagarjuna` — 龙树菩萨(印度·中观|八宗共祖)
|
|
32
33
|
|
|
33
34
|
**汉传**
|
|
35
|
+
|
|
34
36
|
- `/master-xuanzang` — 玄奘法师(法相唯识宗)
|
|
35
37
|
- `/master-kumarajiva` — 鸠摩罗什(三论宗/中观)
|
|
36
38
|
- `/master-huineng` — 慧能大师(禅宗六祖)
|
|
@@ -41,298 +43,77 @@ allowed-tools:
|
|
|
41
43
|
- `/master-xuyun` — 虚云老和尚(禅宗·五宗兼嗣)
|
|
42
44
|
|
|
43
45
|
**藏传**
|
|
46
|
+
|
|
44
47
|
- `/master-atisha` — 阿底峡尊者(噶当派开祖 · 三士道 · 982-1054)
|
|
45
|
-
- `/master-tsongkhapa` — 宗喀巴大师(格鲁派创始人 · 三主要道 ·
|
|
46
|
-
- `/master-milarepa` — 米拉日巴尊者(噶举派 · 大手印 ·
|
|
48
|
+
- `/master-tsongkhapa` — 宗喀巴大师(格鲁派创始人 · 三主要道 · 1357-1419)
|
|
49
|
+
- `/master-milarepa` — 米拉日巴尊者(噶举派 · 大手印 · 1052-1135)
|
|
47
50
|
|
|
48
51
|
**南传**
|
|
52
|
+
|
|
49
53
|
- `/master-buddhaghosa` — 觉音尊者(上座部论师 · 《清净道论》· 5世纪)
|
|
50
54
|
- `/master-mahasi-sayadaw` — 马哈希尊者(缅甸内观 · 标记法 · 1904-1982)
|
|
51
|
-
- `/master-ajahn-chah` — 阿姜查(泰国森林禅林派 ·
|
|
52
|
-
|
|
53
|
-
## 对比模式
|
|
54
|
-
|
|
55
|
-
- `/compare-masters` — 多位法师对同一问题的对比回答
|
|
56
|
-
|
|
57
|
-
## 主流程
|
|
58
|
-
|
|
59
|
-
### Step 1:信息录入
|
|
55
|
+
- `/master-ajahn-chah` — 阿姜查(泰国森林禅林派 · 1918-1992)
|
|
60
56
|
|
|
61
|
-
|
|
62
|
-
1. 法师名称 → 自动匹配 FoJin 知识图谱
|
|
63
|
-
2. 关注方面 → 教义/修行/讲解/全部
|
|
64
|
-
3. 语言偏好 → 根据传承自动推荐
|
|
57
|
+
## 教学模式(多祖师协作)
|
|
65
58
|
|
|
66
|
-
|
|
59
|
+
- `/compare-masters` — 多位法师对同一问题的并列对比(横向 / 单轮)
|
|
60
|
+
- `/master-debate` — 祖师就争议议题进行 4 轮交叉辩论(多轮 / 看分歧)
|
|
61
|
+
- `/master-curriculum` — 按你的传统给出"根基→深入→精研→盲点"学修路径(纵向时序)
|
|
67
62
|
|
|
68
|
-
|
|
69
|
-
即将创建:弘一大师
|
|
70
|
-
传承:汉传(律宗)
|
|
71
|
-
关注方面:全部
|
|
72
|
-
语言:中文
|
|
73
|
-
确认创建?(Y/n)
|
|
74
|
-
```
|
|
63
|
+
> 选择哪个模式?读 `references/teaching-modes.md`(含决策树与示例)。
|
|
75
64
|
|
|
76
|
-
|
|
65
|
+
## 主流程(生成新法师)
|
|
77
66
|
|
|
78
|
-
|
|
67
|
+
### Step 1:信息录入
|
|
79
68
|
|
|
80
|
-
|
|
81
|
-
- 匹配成功 → 自动填充传承、时代、宗派等元数据,展示给用户确认
|
|
82
|
-
- 匹配失败 → 提示:"未在 FoJin 知识图谱中找到「{name}」。请确认名称是否正确,或提供以下信息以手动创建:宗派(如禅宗/净土/天台/华严/唯识等)、时代、师承。"
|
|
83
|
-
- 用户提供补充信息后,以手动模式继续
|
|
69
|
+
加载 `${CLAUDE_SKILL_DIR}/prompts/intake.md`,3 问模式收集:①法师名称(FoJin KG 自动匹配) ②关注方面(教义/修行/讲解/全部) ③语言偏好(按传承默认)。
|
|
84
70
|
|
|
85
|
-
|
|
86
|
-
- 名称必须为历史真实人物,不接受虚构角色(如小说人物、游戏角色)
|
|
87
|
-
- 如检测到非历史人物,回复:"本工具仅支持历史上真实存在的高僧大德,无法为虚构人物创建教学角色。"
|
|
88
|
-
- 名称不可为空,不可为纯数字或特殊字符
|
|
89
|
-
- 如用户输入的名称有多种写法(如"鸠摩罗什"/"鸠摩罗什婆"),优先使用 FoJin KG 中的标准名称
|
|
90
|
-
- 如该法师已存在于预置列表或已生成列表中,提示:"「{name}」已存在,可直接使用 /{slug} 调用。如需重新生成,请先执行 /delete-master {slug}。"
|
|
71
|
+
快捷入口、KG 匹配兜底、名称校验规则细节 → `references/workflow-details.md` §Step 1。
|
|
91
72
|
|
|
92
73
|
### Step 2:数据采集
|
|
93
74
|
|
|
94
|
-
使用 `${CLAUDE_SKILL_DIR}/tools/sutra_collector.py` 从 FoJin
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
python3 ${CLAUDE_SKILL_DIR}/tools/sutra_collector.py --name "<法师名>" --tradition "<传承>"
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
采集内容包括:
|
|
101
|
-
- 知识图谱实体和师承关系
|
|
102
|
-
- 相关经典列表和内容摘录
|
|
103
|
-
- 传承相关术语
|
|
104
|
-
|
|
105
|
-
**API 故障处理**:
|
|
106
|
-
- 如 FoJin API 返回错误或不可达,向用户说明:"FoJin API 暂时不可用(错误信息:{error})。您可以:1) 稍后重试;2) 进入手动输入模式,提供经文文本。"
|
|
107
|
-
- 手动输入模式下,用户可粘贴经文原文或提供 CBETA 经号,系统基于用户提供的材料继续生成
|
|
108
|
-
|
|
109
|
-
**超时设置**:每次 API 调用超时时间为 30 秒。超时后自动重试一次,仍失败则触发上述故障处理。
|
|
110
|
-
|
|
111
|
-
**最低数据阈值**:如采集到的经文结果少于 3 条,向用户发出警告:"仅找到 {n} 条相关经文,生成的角色内容可能不够丰富。建议:1) 追加关键词重新搜索;2) 手动补充经文材料;3) 继续生成(内容可能有限)。"
|
|
112
|
-
|
|
113
|
-
**CBETA ID 验证**:采集完成后,使用 `verify_sources.py` 验证所有 CBETA 链接的有效性:
|
|
114
|
-
|
|
115
|
-
```bash
|
|
116
|
-
python3 ${CLAUDE_SKILL_DIR}/tools/verify_sources.py --check-links collected_data.json
|
|
117
|
-
```
|
|
75
|
+
使用 `${CLAUDE_SKILL_DIR}/tools/sutra_collector.py --name "<法师名>" --tradition "<传承>"` 从 FoJin 采集知识图谱实体、经典内容、传承术语。采集后用 `verify_sources.py --check-links` 验证 CBETA / BDRC / SC ID。
|
|
118
76
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
**采集结果确认**:采集完成后,向用户简要报告采集情况:
|
|
122
|
-
|
|
123
|
-
```
|
|
124
|
-
数据采集完成:
|
|
125
|
-
知识图谱实体:{n} 个
|
|
126
|
-
相关经典:{m} 部
|
|
127
|
-
内容摘录:{k} 段
|
|
128
|
-
无效链接:{j} 个(已排除)
|
|
129
|
-
继续分析?(Y/n)
|
|
130
|
-
```
|
|
77
|
+
API 故障 / 超时 / 数据阈值 / 引用规则细节 → `references/workflow-details.md` §Step 2 + `references/source-conventions.md`。
|
|
131
78
|
|
|
132
79
|
### Step 3:分析与生成
|
|
133
80
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
**两阶段分析**:
|
|
137
|
-
|
|
138
|
-
1. **教义分析(第一阶段)**:加载 `${CLAUDE_SKILL_DIR}/prompts/sutra_analyzer.md`,填入采集数据,分析教义结构。输出包括核心教义维度、关键经典、修行次第等。
|
|
139
|
-
|
|
140
|
-
2. **风格分析(第二阶段)**:加载 `${CLAUDE_SKILL_DIR}/prompts/voice_analyzer.md`,填入采集数据,分析说法风格。输出包括语言特征、说法模式、常用譬喻等。
|
|
141
|
-
|
|
142
|
-
**宗派标签自动检测**:根据 FoJin 知识图谱中该法师的宗派信息,自动应用 voice_analyzer 中对应宗派的风格规则。例如:
|
|
143
|
-
- 禅宗 → 应用机锋、公案风格规则
|
|
144
|
-
- 净土宗 → 应用劝信、念佛开示风格规则
|
|
145
|
-
- 天台宗 → 应用判教、止观论述风格规则
|
|
146
|
-
- 华严宗 → 应用圆融、法界观论述风格规则
|
|
147
|
-
- 唯识/法相宗 → 应用因明论证、术语精确风格规则
|
|
148
|
-
|
|
149
|
-
**质量门控**:如分析器输出中任一维度标记为 `"insufficient_data": true`,在继续前向用户提示:
|
|
150
|
-
- "以下维度的数据不足,生成质量可能受影响:{dimensions}。"
|
|
151
|
-
- "建议追加相关经文材料后重新分析,或选择继续生成(不足部分将标注警告)。"
|
|
152
|
-
- 用户选择继续 → 在生成的文件中对不足维度添加 `<!-- DATA_LIMITED -->` 注释标记
|
|
153
|
-
|
|
154
|
-
**RAG 指引嵌入**:加载 `${CLAUDE_SKILL_DIR}/prompts/rag_instructions.md`,将检索规则(查询构造、结果过滤、引用格式)嵌入生成的 SKILL.md 运行时规则段落中。
|
|
81
|
+
两阶段分析:教义(`prompts/sutra_analyzer.md`)→ 风格(`prompts/voice_analyzer.md`);按 FoJin KG 宗派标签自动选择风格规则。然后 `prompts/teaching_builder.md` 生成 `teaching.md`、`prompts/voice_builder.md` 生成 `voice.md`(4 层结构)。RAG 检索指引由 `prompts/rag_instructions.md` 嵌入。
|
|
155
82
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
**风格生成**:加载 `${CLAUDE_SKILL_DIR}/prompts/voice_builder.md`,基于分析结果生成 voice.md。voice.md 采用分层结构:
|
|
159
|
-
- Layer 0:硬规则(不可违反的底线,如"不自称佛"、"不预言未来")
|
|
160
|
-
- Layer 1:核心风格(该法师最显著的说法特征)
|
|
161
|
-
- Layer 2:辅助风格(次要但常见的表达模式)
|
|
162
|
-
- Layer 3:情境风格(特定场景下的应对方式)
|
|
83
|
+
宗派标签清单、Layer 0-3 含义、质量门控阈值 → `references/workflow-details.md` §Step 3。
|
|
163
84
|
|
|
164
85
|
### Step 3.5:二阶段审查
|
|
165
86
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
**第一阶段:教义准确性审查**
|
|
169
|
-
|
|
170
|
-
加载 `${CLAUDE_SKILL_DIR}/prompts/doctrine_reviewer.md`,对生成的 teaching.md 执行审查:
|
|
171
|
-
- 验证经证覆盖率(目标 ≥ 90%)
|
|
172
|
-
- 检查 CBETA ID 归属准确性
|
|
173
|
-
- 检测宗派边界越界
|
|
174
|
-
- 输出审查报告(PASS / PASS WITH WARNINGS / FAIL)
|
|
175
|
-
|
|
176
|
-
若 FAIL → 自动修复严重问题后重新审查,最多 2 轮。2 轮仍 FAIL → 向用户报告问题,请求人工介入。
|
|
177
|
-
|
|
178
|
-
**第二阶段:风格一致性审查**
|
|
179
|
-
|
|
180
|
-
加载 `${CLAUDE_SKILL_DIR}/prompts/voice_reviewer.md`,对生成的 voice.md 执行审查:
|
|
181
|
-
- 验证 Layer 0 硬规则完整性
|
|
182
|
-
- 检查风格与宗派特征匹配度
|
|
183
|
-
- 验证层次结构清晰度
|
|
184
|
-
- 输出审查报告(PASS / PASS WITH WARNINGS / FAIL)
|
|
185
|
-
|
|
186
|
-
若 FAIL → 自动修复后重新审查。
|
|
187
|
-
|
|
188
|
-
**审查结果展示**:
|
|
189
|
-
|
|
190
|
-
```
|
|
191
|
-
══ 审查结果 ══
|
|
192
|
-
教义准确性:PASS (经证覆盖率 95%, 0 严重问题)
|
|
193
|
-
风格一致性:PASS WITH WARNINGS (Layer 0 完整, 1 警告)
|
|
194
|
-
警告:Layer 2 缺少"面对学者"的情境风格
|
|
195
|
-
══════════════
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
两项均 PASS 或 PASS WITH WARNINGS 后,进入 Step 4。
|
|
87
|
+
教义准确性(`doctrine_reviewer.md`,CBETA 经证覆盖率 ≥ 90%) → 风格一致性(`voice_reviewer.md`,Layer 0 硬规则完整)。审查顺序不可颠倒。FAIL → 自动修复重审,最多 2 轮,仍 FAIL → 人工介入。
|
|
199
88
|
|
|
200
89
|
### Step 4:预览与确认
|
|
201
90
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
**结构化预览格式**:
|
|
205
|
-
|
|
206
|
-
```
|
|
207
|
-
══ 教义预览(teaching.md)══
|
|
208
|
-
核心教义:{1-3 条核心教义概要}
|
|
209
|
-
关键经典:{主要引用经典列表}
|
|
210
|
-
修行次第:{修行路径概要}
|
|
211
|
-
|
|
212
|
-
══ 风格预览(voice.md)══
|
|
213
|
-
风格特征:{2-3 条风格特点}
|
|
214
|
-
语言模式:{典型表达方式}
|
|
215
|
-
示例句:
|
|
216
|
-
1. "{模拟该法师风格的示例句1}"
|
|
217
|
-
2. "{模拟该法师风格的示例句2}"
|
|
218
|
-
══════════════════════════
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
**用户修改请求**:用户可在确认前要求修改,支持以下指令:
|
|
222
|
-
- "修改教义部分" → 重新展示 teaching.md 详情,接受用户逐条调整
|
|
223
|
-
- "调整风格更严厉一些" / "语气更温和" → 调整 voice.md 中的风格参数后重新预览
|
|
224
|
-
- "添加更多关于{主题}的内容" → 针对性补充特定教义维度
|
|
225
|
-
- "重新生成" → 以调整后的参数重新执行 Step 3,重新展示预览
|
|
91
|
+
展示 teaching.md / voice.md 结构化预览给用户。用户可要求修改特定教义、调整语气、补充主题、整体重新生成。
|
|
226
92
|
|
|
227
93
|
### Step 5:写入文件
|
|
228
94
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
```bash
|
|
232
|
-
python3 ${CLAUDE_SKILL_DIR}/tools/master_builder.py --name "<法师名>" --output masters/
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
**写入前验证**:调用 `verify_sources.py` 最终验证所有 FoJin 链接:
|
|
236
|
-
|
|
237
|
-
```bash
|
|
238
|
-
python3 ${CLAUDE_SKILL_DIR}/tools/verify_sources.py --final-check masters/{slug}/
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
无效链接将被替换为 FoJin 搜索链接(降级策略),确保用户始终能找到相关内容。
|
|
242
|
-
|
|
243
|
-
**生成文件**:
|
|
244
|
-
|
|
245
|
-
生成目录结构:
|
|
246
|
-
```
|
|
247
|
-
masters/{slug}/
|
|
248
|
-
├── SKILL.md # /{slug} 触发(完整角色定义)
|
|
249
|
-
├── teaching.md # 教义体系(可单独使用)
|
|
250
|
-
├── voice.md # 说法风格(可单独使用)
|
|
251
|
-
└── meta.json # 元数据(版本、生成时间、数据来源)
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
**角色注册**:
|
|
255
|
-
|
|
256
|
-
Claude Code 用户:
|
|
257
|
-
1. 生成的 SKILL.md 已放置在 `masters/{slug}/` 目录下
|
|
258
|
-
2. 确保 `masters/` 目录在 Claude Code 的 skill 搜索路径中(检查 `.claude/settings.json` 的 `skillDirs` 配置)
|
|
259
|
-
3. 完成后自动可通过 `/{slug}` 命令触发
|
|
260
|
-
|
|
261
|
-
OpenClaw 用户:
|
|
262
|
-
1. 将 `masters/{slug}/` 目录复制到 OpenClaw 的 skills 目录
|
|
263
|
-
2. 在 OpenClaw 配置中注册新 skill
|
|
264
|
-
3. 参考 OpenClaw 文档完成注册流程
|
|
265
|
-
|
|
266
|
-
**完成提示**:写入成功后展示最终摘要:
|
|
95
|
+
`master_builder.py --name "<法师名>" --output masters/` 写入 `masters/{slug}/{SKILL.md,teaching.md,voice.md,meta.json}`。写入前 `verify_sources.py --final-check` 最终验证,无效链接降级为 FoJin 搜索链接。
|
|
267
96
|
|
|
268
|
-
|
|
269
|
-
已生成「{master_name}」教学角色
|
|
270
|
-
目录:masters/{slug}/
|
|
271
|
-
调用命令:/{slug}
|
|
272
|
-
包含文件:SKILL.md, teaching.md, voice.md, meta.json
|
|
273
|
-
数据来源:{n} 条经文,{m} 个知识图谱实体
|
|
274
|
-
```
|
|
97
|
+
OpenClaw / Claude Code 注册路径 → `references/workflow-details.md` §Step 5。
|
|
275
98
|
|
|
276
|
-
##
|
|
99
|
+
## 追加材料、纠正、管理命令
|
|
277
100
|
|
|
278
|
-
|
|
101
|
+
- **追加材料**:用户说"给{法师}追加{经文}"或"补充关于{主题}" → 加载 `prompts/merger.md` 增量合并;版本号自动 minor 递增;旧版本归档 `.versions/`。
|
|
102
|
+
- **纠正模式**:用户说"他不会这样说话/他应该更严厉" → 加载 `prompts/correction_handler.md`;以 `## Correction` 块追加到 teaching.md / voice.md 末尾;patch 递增。
|
|
103
|
+
- **管理命令**:`/list-masters`(列出所有,标 `[预置]`/`[自定义]`)、`/master-rollback <slug> <version>`(回滚,自动归档当前)、`/delete-master <slug>`(删除,预置不可删,需二次确认)。
|
|
279
104
|
|
|
280
|
-
|
|
281
|
-
- "给印光大师追加《文钞三编》的材料"
|
|
282
|
-
- "追加《经名》的材料"
|
|
283
|
-
- "补充关于{主题}的内容"
|
|
284
|
-
- "用这段语录更新慧能大师的说法风格"
|
|
105
|
+
冲突处理策略、版本号细节、用户确认文案 → `references/workflow-details.md` §追加纠正管理。
|
|
285
106
|
|
|
286
|
-
|
|
107
|
+
## 执行优先级(运行时)
|
|
287
108
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
-
|
|
291
|
-
- 风格维度的冲突:新材料的风格特征会与现有特征合并,不会覆盖
|
|
292
|
-
|
|
293
|
-
**版本自动递增**:
|
|
294
|
-
- 每次追加材料后,meta.json 中的 `version` 自动递增(如 1.0.0 → 1.1.0)
|
|
295
|
-
- 旧版本自动归档到 `masters/{slug}/.versions/` 目录
|
|
296
|
-
- 可通过 `/master-rollback` 命令回退到任意历史版本
|
|
297
|
-
|
|
298
|
-
## 纠正模式
|
|
299
|
-
|
|
300
|
-
用户在使用法师角色时,可以对 AI 的表现提出纠正:
|
|
301
|
-
- "他不会这样说话"
|
|
302
|
-
- "他应该更严厉一些"
|
|
303
|
-
- "他遇到这种问题会先引用《法华经》"
|
|
304
|
-
|
|
305
|
-
加载 `${CLAUDE_SKILL_DIR}/prompts/correction_handler.md` 进行纠正处理。
|
|
306
|
-
|
|
307
|
-
**纠正处理流程**:
|
|
308
|
-
1. 识别纠正类型:教义纠正 → 写入 teaching.md;风格纠正 → 写入 voice.md
|
|
309
|
-
2. 以 `## Correction` 块格式追加到对应文件末尾,包含时间戳和原始反馈
|
|
310
|
-
3. 纠正记录的优先级高于分析生成的内容(参见「执行优先级」)
|
|
311
|
-
4. 每次纠正后自动递增 meta.json 版本号(patch 级别,如 1.1.0 → 1.1.1)
|
|
312
|
-
|
|
313
|
-
## 管理命令
|
|
314
|
-
|
|
315
|
-
- `/list-masters` — 列出所有已生成的法师(含预置和自定义),显示传承、时代、版本号信息。预置法师标记为 `[预置]`,自定义法师标记为 `[自定义]`。
|
|
316
|
-
- `/master-rollback <slug> <version>` — 回滚到指定版本。当前版本自动归档到 `.versions/` 目录,指定版本恢复为当前版本。如指定版本不存在,列出所有可用版本供选择。
|
|
317
|
-
- `/delete-master <slug>` — 删除一个法师目录。执行前需用户二次确认:"确定要删除「{master_name}」吗?此操作不可恢复。输入 'yes' 确认。" 预置法师不可删除。
|
|
318
|
-
|
|
319
|
-
## 执行优先级
|
|
320
|
-
|
|
321
|
-
法师角色运行时,按以下优先级处理:
|
|
322
|
-
|
|
323
|
-
1. voice.md Layer 0 硬规则(最高优先级,无条件执行)
|
|
324
|
-
2. Correction 记录(用户纠正,优先于分析生成内容)
|
|
325
|
-
3. voice.md Layer 1-3(分析生成的风格规则)
|
|
109
|
+
1. voice.md Layer 0 硬规则
|
|
110
|
+
2. Correction 记录
|
|
111
|
+
3. voice.md Layer 1-3
|
|
326
112
|
4. teaching.md 教义内容
|
|
327
|
-
5. FoJin RAG
|
|
328
|
-
6. LLM
|
|
113
|
+
5. FoJin RAG 实时检索
|
|
114
|
+
6. LLM 自身知识
|
|
329
115
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
**示例**:
|
|
333
|
-
- 如 voice.md Layer 0 规定"不自称已证悟",即使 teaching.md 中有该法师证悟的记载,回答时也不以第一人称宣称证悟
|
|
334
|
-
- 如用户纠正"他从不直接回答是非题",则该纠正覆盖 voice.md Layer 1-3 中可能存在的直接回答模式
|
|
335
|
-
- 如 FoJin RAG 检索到的经文与 teaching.md 中的记载有细节差异,以 teaching.md 为准(RAG 作为补充参考)
|
|
116
|
+
冲突时高优先级覆盖低优先级。示例与典型冲突场景 → `references/workflow-details.md` §执行优先级。
|
|
336
117
|
|
|
337
118
|
## 工具路由
|
|
338
119
|
|
|
@@ -348,50 +129,30 @@ OpenClaw 用户:
|
|
|
348
129
|
| 教义审查 | `${CLAUDE_SKILL_DIR}/prompts/doctrine_reviewer.md` |
|
|
349
130
|
| 风格审查 | `${CLAUDE_SKILL_DIR}/prompts/voice_reviewer.md` |
|
|
350
131
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
<HARD-GATE>
|
|
354
|
-
|
|
355
|
-
## 铁律 — 不可违反
|
|
356
|
-
|
|
357
|
-
**NO DOCTRINAL CLAIM WITHOUT CBETA CITATION.**
|
|
358
|
-
生成的 teaching.md 中所有教义断言必须附 CBETA 经证。无经证的教义内容不得写入生成文件。
|
|
359
|
-
|
|
360
|
-
**NO FABRICATED SOURCES.**
|
|
361
|
-
不得编造不存在的 CBETA ID、经文引用或 FoJin 链接。所有引用必须经过 verify_sources.py 验证。
|
|
362
|
-
|
|
363
|
-
**NO FICTIONAL PERSONAS.**
|
|
364
|
-
仅接受历史真实人物。不得为虚构角色创建教学角色。
|
|
132
|
+
KG 深度遍历 / 跨词典对比等 `rag_query.py` 不够用的场景 → `references/fojin-api.md`(REST API 完整参考)。
|
|
365
133
|
|
|
366
|
-
##
|
|
134
|
+
## 铁律(HARD-GATE)
|
|
367
135
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
| "FoJin API 暂时不可用,先生成再补验证" | 用降级模式(手动输入),但不跳过验证。 |
|
|
372
|
-
| "用户很着急,先出一版再迭代" | 不准确的首版会成为后续迭代的锚点。宁可慢也要准。 |
|
|
136
|
+
- **NO DOCTRINAL CLAIM WITHOUT CBETA CITATION** — teaching.md 所有教义断言必须附 CBETA 经证
|
|
137
|
+
- **NO FABRICATED SOURCES** — 不得编造 CBETA ID / 经文 / FoJin 链接,所有引用必经 `verify_sources.py` 验证
|
|
138
|
+
- **NO FICTIONAL PERSONAS** — 仅历史真实人物,不为虚构角色创建
|
|
373
139
|
|
|
374
|
-
|
|
140
|
+
完整理性化防御表、红旗清单、ETHICS.md 运行时摘要 → `references/ethics-runtime.md`。
|
|
375
141
|
|
|
376
|
-
|
|
377
|
-
- meta.json 中出现未经验证的 CBETA ID
|
|
378
|
-
- 跳过 verify_sources.py 验证步骤
|
|
379
|
-
- 为虚构人物或非佛教人物创建角色
|
|
142
|
+
## 敏感性边界(一句话)
|
|
380
143
|
|
|
381
|
-
|
|
144
|
+
不评宗派优劣 · 不宣神通感应 · 不涉政治议题 · 不代用户做重大决定 · 不替代真善知识。
|
|
382
145
|
|
|
383
|
-
|
|
146
|
+
涉及"祖师怎么看 XX 现代议题"边界场景 → `references/ethics-runtime.md`。
|
|
384
147
|
|
|
385
|
-
|
|
386
|
-
- 不对宗派优劣进行评判
|
|
387
|
-
- 不宣称神通感应
|
|
388
|
-
- 不涉及政治化宗教议题
|
|
389
|
-
- 不为用户做重大人生决定(如出家、离婚等),仅提供佛法视角的参考
|
|
390
|
-
- 不声称能替代真实善知识的指导
|
|
148
|
+
## 按需载入(progressive disclosure 路由)
|
|
391
149
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
-
|
|
396
|
-
|
|
397
|
-
-
|
|
150
|
+
| 触发场景 | 读 |
|
|
151
|
+
|---------|-----|
|
|
152
|
+
| 用户问三大传统差异、宗派定位 | `references/traditions.md` |
|
|
153
|
+
| 用户给出 T-/X-/SC-/Toh-/W- 引用,需验证或解析 | `references/source-conventions.md` |
|
|
154
|
+
| 用户问"祖师怎么看 XX 现代议题"边界场景、AI 透明度、版权 | `references/ethics-runtime.md` |
|
|
155
|
+
| 用户犹豫该用 compare / debate / curriculum 哪个 | `references/teaching-modes.md` |
|
|
156
|
+
| 进入主流程 Step 1-5 任一步的细节、错误兜底、追加/纠正策略 | `references/workflow-details.md` |
|
|
157
|
+
| 需要直接打 FoJin REST API(KG 深度遍历等) | `references/fojin-api.md` |
|
|
158
|
+
| 治理文档:完整 ETHICS、版权分级、Tier B 授权流程 | 根目录 `ETHICS.md` |
|
package/bin/cli.mjs
CHANGED
|
@@ -3,16 +3,33 @@
|
|
|
3
3
|
import fs from "fs";
|
|
4
4
|
import path from "path";
|
|
5
5
|
import os from "os";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
);
|
|
8
|
+
// fileURLToPath (not new URL().pathname) — on Windows the URL pathname is
|
|
9
|
+
// "/C:/…", which fs cannot resolve, so every command saw an empty prebuilt/.
|
|
10
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const PREBUILT = path.join(__dirname, "..", "prebuilt");
|
|
12
12
|
const SKILLS_DIR = path.join(os.homedir(), ".claude", "skills");
|
|
13
13
|
|
|
14
14
|
// --- helpers ---
|
|
15
15
|
|
|
16
|
+
function pkgVersion() {
|
|
17
|
+
try {
|
|
18
|
+
const pkg = JSON.parse(
|
|
19
|
+
fs.readFileSync(path.join(__dirname, "..", "package.json"), "utf8")
|
|
20
|
+
);
|
|
21
|
+
return pkg.version || "unknown";
|
|
22
|
+
} catch {
|
|
23
|
+
return "unknown";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Names feed into path.join + rmSync; reject separators / ".." so a typo
|
|
28
|
+
// like "../foo" can never escape PREBUILT or SKILLS_DIR.
|
|
29
|
+
function isSafeName(name) {
|
|
30
|
+
return /^[A-Za-z0-9_-]+$/.test(name);
|
|
31
|
+
}
|
|
32
|
+
|
|
16
33
|
function cpR(src, dest) {
|
|
17
34
|
fs.mkdirSync(dest, { recursive: true });
|
|
18
35
|
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
@@ -24,11 +41,13 @@ function cpR(src, dest) {
|
|
|
24
41
|
}
|
|
25
42
|
|
|
26
43
|
function parseFrontmatter(filepath) {
|
|
44
|
+
// \r?\n: a CRLF checkout (git autocrlf on Windows) must not blank out
|
|
45
|
+
// every description.
|
|
27
46
|
const text = fs.readFileSync(filepath, "utf8");
|
|
28
|
-
const m = text.match(/^---\n([\s\S]*?)\n---/);
|
|
47
|
+
const m = text.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
29
48
|
if (!m) return {};
|
|
30
49
|
const fm = {};
|
|
31
|
-
for (const line of m[1].split(
|
|
50
|
+
for (const line of m[1].split(/\r?\n/)) {
|
|
32
51
|
const idx = line.indexOf(":");
|
|
33
52
|
if (idx > 0 && !line.startsWith(" ") && !line.startsWith("-")) {
|
|
34
53
|
fm[line.slice(0, idx).trim()] = line.slice(idx + 1).trim();
|
|
@@ -76,23 +95,42 @@ function resolveMasterDir(input) {
|
|
|
76
95
|
return candidates.find((p) => fs.existsSync(p)) || null;
|
|
77
96
|
}
|
|
78
97
|
|
|
98
|
+
// Returns the number of failures so main can set a non-zero exit code —
|
|
99
|
+
// scripted callers must be able to tell a typo from a clean install.
|
|
79
100
|
function cmdInstall(names) {
|
|
80
101
|
fs.mkdirSync(SKILLS_DIR, { recursive: true });
|
|
102
|
+
let failed = 0;
|
|
81
103
|
for (const name of names) {
|
|
104
|
+
if (!isSafeName(name)) {
|
|
105
|
+
console.log(` ✗ ${name} — invalid name (letters, digits, "-", "_" only)`);
|
|
106
|
+
failed++;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
82
109
|
const src = resolveMasterDir(name);
|
|
83
110
|
if (!src) {
|
|
84
111
|
console.log(` ✗ ${name} — not found in prebuilt/ (tried "${name}" and "master-${name}")`);
|
|
112
|
+
failed++;
|
|
85
113
|
continue;
|
|
86
114
|
}
|
|
87
115
|
const dirName = path.basename(src); // master-zhiyi
|
|
88
116
|
const dest = path.join(SKILLS_DIR, dirName);
|
|
117
|
+
// Clear any previous install first: files renamed or removed upstream
|
|
118
|
+
// must not linger as stale skill content under ~/.claude/skills/.
|
|
119
|
+
fs.rmSync(dest, { recursive: true, force: true });
|
|
89
120
|
cpR(src, dest);
|
|
90
121
|
console.log(` ✓ ${name} → ${dest}`);
|
|
91
122
|
}
|
|
123
|
+
return failed;
|
|
92
124
|
}
|
|
93
125
|
|
|
94
126
|
function cmdUninstall(names) {
|
|
127
|
+
let failed = 0;
|
|
95
128
|
for (const name of names) {
|
|
129
|
+
if (!isSafeName(name)) {
|
|
130
|
+
console.log(` ✗ ${name} — invalid name (letters, digits, "-", "_" only)`);
|
|
131
|
+
failed++;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
96
134
|
// Try both prefixed and bare directory names for backward compatibility
|
|
97
135
|
// with any pre-v0.6 installs that may still sit at ~/.claude/skills/<slug>/.
|
|
98
136
|
const candidates = [
|
|
@@ -102,22 +140,25 @@ function cmdUninstall(names) {
|
|
|
102
140
|
const dest = candidates.find((p) => fs.existsSync(p));
|
|
103
141
|
if (!dest) {
|
|
104
142
|
console.log(` ✗ ${name} — not installed`);
|
|
143
|
+
failed++;
|
|
105
144
|
continue;
|
|
106
145
|
}
|
|
107
146
|
fs.rmSync(dest, { recursive: true, force: true });
|
|
108
147
|
console.log(` ✓ ${name} removed (${dest})`);
|
|
109
148
|
}
|
|
149
|
+
return failed;
|
|
110
150
|
}
|
|
111
151
|
|
|
112
152
|
function showHelp() {
|
|
113
153
|
console.log(`
|
|
114
|
-
master-skill — Buddhist Master AI Skills installer
|
|
154
|
+
master-skill v${pkgVersion()} — Buddhist Master AI Skills installer
|
|
115
155
|
|
|
116
156
|
Usage:
|
|
117
157
|
master-skill install <name...> Install masters to ~/.claude/skills/
|
|
118
158
|
master-skill install --all Install all available masters
|
|
119
159
|
master-skill list List available masters
|
|
120
160
|
master-skill uninstall <name...> Remove installed masters
|
|
161
|
+
master-skill --version Print version
|
|
121
162
|
master-skill --help Show this help
|
|
122
163
|
|
|
123
164
|
Names accept both short (zhiyi) and full (master-zhiyi) forms.
|
|
@@ -139,6 +180,8 @@ const cmd = args[0];
|
|
|
139
180
|
|
|
140
181
|
if (!cmd || cmd === "--help" || cmd === "-h") {
|
|
141
182
|
showHelp();
|
|
183
|
+
} else if (cmd === "--version" || cmd === "-v") {
|
|
184
|
+
console.log(pkgVersion());
|
|
142
185
|
} else if (cmd === "list") {
|
|
143
186
|
cmdList();
|
|
144
187
|
} else if (cmd === "install") {
|
|
@@ -147,23 +190,26 @@ if (!cmd || cmd === "--help" || cmd === "-h") {
|
|
|
147
190
|
const all = availableMasters().map((m) => m.name);
|
|
148
191
|
if (!all.length) {
|
|
149
192
|
console.log("No masters available.");
|
|
193
|
+
process.exitCode = 1;
|
|
150
194
|
} else {
|
|
151
195
|
console.log(`Installing all ${all.length} masters...\n`);
|
|
152
|
-
cmdInstall(all);
|
|
196
|
+
if (cmdInstall(all) > 0) process.exitCode = 1;
|
|
153
197
|
}
|
|
154
198
|
} else if (rest.length === 0) {
|
|
155
199
|
console.log("Usage: master-skill install <name...> | --all");
|
|
200
|
+
process.exitCode = 1;
|
|
156
201
|
} else {
|
|
157
|
-
cmdInstall(rest);
|
|
202
|
+
if (cmdInstall(rest) > 0) process.exitCode = 1;
|
|
158
203
|
}
|
|
159
204
|
} else if (cmd === "uninstall") {
|
|
160
205
|
const rest = args.slice(1);
|
|
161
206
|
if (rest.length === 0) {
|
|
162
207
|
console.log("Usage: master-skill uninstall <name...>");
|
|
208
|
+
process.exitCode = 1;
|
|
163
209
|
} else {
|
|
164
|
-
cmdUninstall(rest);
|
|
210
|
+
if (cmdUninstall(rest) > 0) process.exitCode = 1;
|
|
165
211
|
}
|
|
166
212
|
} else {
|
|
167
213
|
console.log(`Unknown command: ${cmd}\nRun master-skill --help for usage.`);
|
|
168
|
-
process.
|
|
214
|
+
process.exitCode = 1;
|
|
169
215
|
}
|
package/gemini-extension.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "master-skill",
|
|
3
|
-
"description": "Buddhist Master AI teaching personas —
|
|
4
|
-
"version": "0.
|
|
3
|
+
"description": "Buddhist Master AI teaching personas — 14 prebuilt masters across 汉传/藏传/南传 invokable via /master-<slug> slash commands, with source-cited doctrinal responses (CBETA / BDRC / SuttaCentral / PTS Vism)",
|
|
4
|
+
"version": "0.9.0",
|
|
5
5
|
"contextFileName": "GEMINI.md"
|
|
6
6
|
}
|
package/hooks/session-start
CHANGED
|
@@ -8,6 +8,40 @@ set -euo pipefail
|
|
|
8
8
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
9
|
PLUGIN_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
10
10
|
|
|
11
|
+
# Sanitize a raw `lineage:` frontmatter value before splicing into the
|
|
12
|
+
# conversation context. Without normalization, an attacker who lands a
|
|
13
|
+
# malicious SKILL.md (or just a benign typo) could inject control chars
|
|
14
|
+
# or instruction text into the LLM system prompt.
|
|
15
|
+
#
|
|
16
|
+
# Rules:
|
|
17
|
+
# 1. Strip ALL control chars (CR/LF, escape codes) via tr -d '[:cntrl:]'
|
|
18
|
+
# 2. Pre-truncate to 240 bytes so we don't slice into a UTF-8 multibyte
|
|
19
|
+
# sequence on the next pass.
|
|
20
|
+
# 3. Whitelist CJK Unified + ASCII alnum + a small punctuation set
|
|
21
|
+
# ( · _ ( ) ( ) - and space ). Backticks, dollars, quotes, slashes,
|
|
22
|
+
# etc. are all dropped.
|
|
23
|
+
# 4. Collapse runs of whitespace.
|
|
24
|
+
# 5. Final cap at 80 *characters* (not bytes).
|
|
25
|
+
sanitize_lineage() {
|
|
26
|
+
local raw="$1"
|
|
27
|
+
# Whitelist is applied in Python because GNU sed under LC_ALL=C
|
|
28
|
+
# operates on bytes and corrupts multibyte CJK. Python re.UNICODE
|
|
29
|
+
# keeps Han characters intact.
|
|
30
|
+
printf '%s' "$raw" \
|
|
31
|
+
| tr -d '[:cntrl:]' \
|
|
32
|
+
| head -c 240 \
|
|
33
|
+
| python3 -c '
|
|
34
|
+
import re, sys
|
|
35
|
+
s = sys.stdin.read()
|
|
36
|
+
# Whitelist: CJK Unified, ASCII alnum, fullwidth parens, space, ·, _, (, ), -
|
|
37
|
+
allowed = re.compile(r"[^一-鿿0-9A-Za-z _\-·()()]", re.UNICODE)
|
|
38
|
+
s = allowed.sub("", s)
|
|
39
|
+
s = re.sub(r"\s+", " ", s).strip()
|
|
40
|
+
# Final char cap (not byte cap): 80 characters
|
|
41
|
+
print(s[:80], end="")
|
|
42
|
+
'
|
|
43
|
+
}
|
|
44
|
+
|
|
11
45
|
# Build masters list from prebuilt/ directory
|
|
12
46
|
MASTERS_LIST=""
|
|
13
47
|
for dir in "$PLUGIN_ROOT"/prebuilt/*/; do
|
|
@@ -17,9 +51,13 @@ for dir in "$PLUGIN_ROOT"/prebuilt/*/; do
|
|
|
17
51
|
skill_file="$dir/SKILL.md"
|
|
18
52
|
if [ -f "$skill_file" ]; then
|
|
19
53
|
# Extract lineage from frontmatter
|
|
20
|
-
|
|
54
|
+
raw_lineage=$(grep '^lineage:' "$skill_file" 2>/dev/null | head -1 | sed 's/^lineage: *//' || echo "")
|
|
55
|
+
lineage=$(sanitize_lineage "$raw_lineage")
|
|
21
56
|
if [ -n "$lineage" ]; then
|
|
22
|
-
|
|
57
|
+
# Wrap with bracketed marker so the LLM has an unambiguous
|
|
58
|
+
# boundary if a future raw lineage ever sneaks something
|
|
59
|
+
# past the sanitizer.
|
|
60
|
+
MASTERS_LIST="${MASTERS_LIST} /${name} — [lineage:${lineage}]\n"
|
|
23
61
|
fi
|
|
24
62
|
fi
|
|
25
63
|
done
|