master-skill 0.5.0 → 0.8.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/ETHICS.md +4 -4
- package/README.md +105 -51
- package/README_EN.md +105 -53
- package/SKILL.md +65 -308
- package/bin/cli.mjs +29 -8
- package/gemini-extension.json +2 -2
- package/hooks/session-start +40 -2
- package/hooks/tests/test_session_start.sh +149 -0
- package/package.json +7 -3
- package/prebuilt/compare/SKILL.md +44 -44
- package/prebuilt/compare/tests/fidelity.jsonl +13 -0
- package/prebuilt/{ajahn-chah → master-ajahn-chah}/SKILL.md +1 -1
- package/prebuilt/{ajahn-chah → master-ajahn-chah}/meta.json +17 -1
- package/prebuilt/{atisha → master-atisha}/SKILL.md +1 -1
- package/prebuilt/{atisha → master-atisha}/meta.json +17 -1
- package/prebuilt/{buddhaghosa → master-buddhaghosa}/SKILL.md +1 -1
- package/prebuilt/{buddhaghosa → 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/{fazang → master-fazang}/SKILL.md +1 -1
- package/prebuilt/{fazang → master-fazang}/meta.json +25 -0
- package/prebuilt/{huineng → master-huineng}/SKILL.md +1 -1
- package/prebuilt/master-huineng/meta.json +128 -0
- package/prebuilt/{huineng → master-huineng}/references/teaching.md +1 -1
- package/prebuilt/{huineng → master-huineng}/sources/INDEX.md +1 -1
- package/prebuilt/{huineng → master-huineng}/sources/tanjing-excerpts.md +17 -1
- package/prebuilt/{kumarajiva → master-kumarajiva}/SKILL.md +1 -1
- package/prebuilt/{kumarajiva → master-kumarajiva}/meta.json +16 -0
- package/prebuilt/{kumarajiva → master-kumarajiva}/references/teaching.md +2 -2
- package/prebuilt/{mahasi-sayadaw → master-mahasi-sayadaw}/SKILL.md +1 -1
- package/prebuilt/{mahasi-sayadaw → master-mahasi-sayadaw}/meta.json +17 -1
- package/prebuilt/{milarepa → master-milarepa}/SKILL.md +1 -1
- package/prebuilt/{milarepa → master-milarepa}/meta.json +26 -1
- package/prebuilt/{ouyi → master-ouyi}/SKILL.md +1 -1
- package/prebuilt/{ouyi → master-ouyi}/meta.json +17 -0
- package/prebuilt/{ouyi → master-ouyi}/references/teaching.md +4 -4
- package/prebuilt/{ouyi → master-ouyi}/sources/INDEX.md +1 -1
- package/prebuilt/{ouyi → master-ouyi}/sources/jiaoguan-gangzong-excerpts.md +3 -3
- package/prebuilt/{tsongkhapa → master-tsongkhapa}/SKILL.md +1 -1
- package/prebuilt/{tsongkhapa → master-tsongkhapa}/meta.json +18 -1
- package/prebuilt/{xuanzang → master-xuanzang}/SKILL.md +1 -1
- package/prebuilt/{xuanzang → master-xuanzang}/meta.json +16 -0
- package/prebuilt/{xuanzang → master-xuanzang}/references/teaching.md +5 -5
- package/prebuilt/{xuanzang → master-xuanzang}/references/voice.md +1 -1
- package/prebuilt/{xuyun → master-xuyun}/SKILL.md +1 -1
- package/prebuilt/{xuyun → master-xuyun}/meta.json +39 -0
- package/prebuilt/{yinguang → master-yinguang}/SKILL.md +2 -2
- package/prebuilt/{yinguang → master-yinguang}/meta.json +17 -0
- package/prebuilt/{yinguang → master-yinguang}/references/teaching.md +7 -7
- package/prebuilt/{yinguang → master-yinguang}/references/voice.md +1 -1
- package/prebuilt/{yinguang → master-yinguang}/sources/INDEX.md +3 -3
- package/prebuilt/{yinguang → master-yinguang}/sources/wenchao-excerpts.md +4 -4
- package/prebuilt/{yinguang → master-yinguang}/sources/yihanbianfu-excerpts.md +3 -3
- package/prebuilt/{zhiyi → master-zhiyi}/SKILL.md +1 -1
- package/prebuilt/{zhiyi → master-zhiyi}/meta.json +28 -0
- package/prebuilt/{zhiyi → master-zhiyi}/references/teaching.md +2 -2
- package/scripts/check-manifest-versions.py +142 -0
- package/scripts/cite.py +1 -1
- package/scripts/query.py +1 -1
- package/scripts/test-fidelity.py +4 -4
- package/scripts/tests/test_check_manifest_versions.py +217 -0
- package/scripts/tests/test_debate_protocol.py +159 -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 +213 -5
- package/prebuilt/huineng/meta.json +0 -91
- /package/prebuilt/{ajahn-chah → master-ajahn-chah}/references/teaching.md +0 -0
- /package/prebuilt/{ajahn-chah → master-ajahn-chah}/references/voice.md +0 -0
- /package/prebuilt/{ajahn-chah → master-ajahn-chah}/sources/INDEX.md +0 -0
- /package/prebuilt/{ajahn-chah → master-ajahn-chah}/sources/sutta-excerpts.md +0 -0
- /package/prebuilt/{ajahn-chah → master-ajahn-chah}/sources/teachings-excerpts.md +0 -0
- /package/prebuilt/{ajahn-chah → master-ajahn-chah}/tests/fidelity.jsonl +0 -0
- /package/prebuilt/{atisha → master-atisha}/references/teaching.md +0 -0
- /package/prebuilt/{atisha → master-atisha}/references/voice.md +0 -0
- /package/prebuilt/{atisha → master-atisha}/sources/INDEX.md +0 -0
- /package/prebuilt/{atisha → master-atisha}/sources/bodhipathapradipa-excerpts.md +0 -0
- /package/prebuilt/{atisha → master-atisha}/tests/fidelity.jsonl +0 -0
- /package/prebuilt/{buddhaghosa → master-buddhaghosa}/references/teaching.md +0 -0
- /package/prebuilt/{buddhaghosa → master-buddhaghosa}/references/voice.md +0 -0
- /package/prebuilt/{buddhaghosa → master-buddhaghosa}/sources/INDEX.md +0 -0
- /package/prebuilt/{buddhaghosa → master-buddhaghosa}/sources/visuddhimagga-excerpts.md +0 -0
- /package/prebuilt/{buddhaghosa → master-buddhaghosa}/tests/fidelity.jsonl +0 -0
- /package/prebuilt/{fazang → master-fazang}/references/teaching.md +0 -0
- /package/prebuilt/{fazang → master-fazang}/references/voice.md +0 -0
- /package/prebuilt/{fazang → master-fazang}/sources/INDEX.md +0 -0
- /package/prebuilt/{fazang → master-fazang}/sources/jinshizi-excerpts.md +0 -0
- /package/prebuilt/{fazang → master-fazang}/sources/wujiao-zhang-excerpts.md +0 -0
- /package/prebuilt/{fazang → master-fazang}/tests/fidelity.jsonl +0 -0
- /package/prebuilt/{huineng → master-huineng}/references/voice.md +0 -0
- /package/prebuilt/{huineng → master-huineng}/sources/jingang-excerpts.md +0 -0
- /package/prebuilt/{huineng → master-huineng}/tests/fidelity.jsonl +0 -0
- /package/prebuilt/{kumarajiva → master-kumarajiva}/references/voice.md +0 -0
- /package/prebuilt/{kumarajiva → master-kumarajiva}/sources/INDEX.md +0 -0
- /package/prebuilt/{kumarajiva → master-kumarajiva}/sources/fahua-excerpts.md +0 -0
- /package/prebuilt/{kumarajiva → master-kumarajiva}/sources/jingang-bore-excerpts.md +0 -0
- /package/prebuilt/{kumarajiva → master-kumarajiva}/sources/zhonglun-excerpts.md +0 -0
- /package/prebuilt/{kumarajiva → master-kumarajiva}/tests/fidelity.jsonl +0 -0
- /package/prebuilt/{mahasi-sayadaw → master-mahasi-sayadaw}/references/teaching.md +0 -0
- /package/prebuilt/{mahasi-sayadaw → master-mahasi-sayadaw}/references/voice.md +0 -0
- /package/prebuilt/{mahasi-sayadaw → master-mahasi-sayadaw}/sources/INDEX.md +0 -0
- /package/prebuilt/{mahasi-sayadaw → master-mahasi-sayadaw}/sources/teachings-excerpts.md +0 -0
- /package/prebuilt/{mahasi-sayadaw → master-mahasi-sayadaw}/tests/fidelity.jsonl +0 -0
- /package/prebuilt/{milarepa → master-milarepa}/references/teaching.md +0 -0
- /package/prebuilt/{milarepa → master-milarepa}/references/voice.md +0 -0
- /package/prebuilt/{milarepa → master-milarepa}/sources/INDEX.md +0 -0
- /package/prebuilt/{milarepa → master-milarepa}/sources/grubum-excerpts.md +0 -0
- /package/prebuilt/{milarepa → master-milarepa}/sources/namthar-excerpts.md +0 -0
- /package/prebuilt/{milarepa → master-milarepa}/tests/fidelity.jsonl +0 -0
- /package/prebuilt/{ouyi → master-ouyi}/references/voice.md +0 -0
- /package/prebuilt/{ouyi → master-ouyi}/sources/mituo-yaojie-excerpts.md +0 -0
- /package/prebuilt/{ouyi → master-ouyi}/tests/fidelity.jsonl +0 -0
- /package/prebuilt/{tsongkhapa → master-tsongkhapa}/references/teaching.md +0 -0
- /package/prebuilt/{tsongkhapa → master-tsongkhapa}/references/voice.md +0 -0
- /package/prebuilt/{tsongkhapa → master-tsongkhapa}/sources/INDEX.md +0 -0
- /package/prebuilt/{tsongkhapa → master-tsongkhapa}/sources/lamrim-excerpts.md +0 -0
- /package/prebuilt/{tsongkhapa → master-tsongkhapa}/tests/fidelity.jsonl +0 -0
- /package/prebuilt/{xuanzang → master-xuanzang}/sources/INDEX.md +0 -0
- /package/prebuilt/{xuanzang → master-xuanzang}/sources/chengweishi-excerpts.md +0 -0
- /package/prebuilt/{xuanzang → master-xuanzang}/sources/xinjing-excerpts.md +0 -0
- /package/prebuilt/{xuanzang → master-xuanzang}/tests/fidelity.jsonl +0 -0
- /package/prebuilt/{xuyun → master-xuyun}/references/teaching.md +0 -0
- /package/prebuilt/{xuyun → master-xuyun}/references/voice.md +0 -0
- /package/prebuilt/{xuyun → master-xuyun}/sources/INDEX.md +0 -0
- /package/prebuilt/{xuyun → master-xuyun}/sources/lengyanjing-excerpts.md +0 -0
- /package/prebuilt/{xuyun → master-xuyun}/sources/tanjing-excerpts.md +0 -0
- /package/prebuilt/{xuyun → master-xuyun}/tests/fidelity.jsonl +0 -0
- /package/prebuilt/{yinguang → master-yinguang}/sources/jingtu-sanjing-excerpts.md +0 -0
- /package/prebuilt/{yinguang → master-yinguang}/tests/fidelity.jsonl +0 -0
- /package/prebuilt/{zhiyi → master-zhiyi}/references/voice.md +0 -0
- /package/prebuilt/{zhiyi → master-zhiyi}/sources/INDEX.md +0 -0
- /package/prebuilt/{zhiyi → master-zhiyi}/sources/fahua-xuanyi-excerpts.md +0 -0
- /package/prebuilt/{zhiyi → master-zhiyi}/sources/mohezhiguan-excerpts.md +0 -0
- /package/prebuilt/{zhiyi → master-zhiyi}/tests/fidelity.jsonl +0 -0
|
@@ -14,31 +14,31 @@
|
|
|
14
14
|
|
|
15
15
|
净土法门以信、愿、行为往生三要。信者,信阿弥陀佛四十八愿摄受众生,信极乐世界真实不虚;愿者,厌离娑婆,欣求极乐,发愿往生;行者,执持名号,一心念佛。三者缺一不可,而信愿尤为重要,为净土法门之纲领。
|
|
16
16
|
|
|
17
|
-
> 出处:【《印光法师文钞正编》卷一·与大兴善寺体安和尚书】→ https://fojin.app/texts/
|
|
17
|
+
> 出处:【《印光法师文钞正编》卷一·与大兴善寺体安和尚书】→ https://fojin.app/texts/12977
|
|
18
18
|
|
|
19
19
|
### 2. 仗佛慈力,带业往生
|
|
20
20
|
|
|
21
21
|
末法时期众生根钝障深,唯依净土法门,仗阿弥陀佛愿力加持,虽未断惑,亦可带业往生。此为净土法门殊胜之处——横超三界,不同竖出之难。
|
|
22
22
|
|
|
23
|
-
> 出处:【《印光法师文钞正编》卷一·复邓伯诚居士书一】→ https://fojin.app/texts/
|
|
23
|
+
> 出处:【《印光法师文钞正编》卷一·复邓伯诚居士书一】→ https://fojin.app/texts/12977
|
|
24
24
|
|
|
25
25
|
### 3. 敦伦尽分,闲邪存诚
|
|
26
26
|
|
|
27
27
|
学佛之人,首须敦伦尽分,闲邪存诚。即在世间尽好自己的本分——孝亲、尊师、忠国、爱人,以儒家伦理为基,佛法为归。不可借修行之名,废弃人伦职责。
|
|
28
28
|
|
|
29
|
-
> 出处:【《印光法师文钞续编》卷上·一函遍复】→ https://fojin.app/texts/
|
|
29
|
+
> 出处:【《印光法师文钞续编》卷上·一函遍复】→ https://fojin.app/texts/12978
|
|
30
30
|
|
|
31
31
|
### 4. 因果为入道之基
|
|
32
32
|
|
|
33
33
|
因果之理,为佛法入门之基础。不信因果,则一切善法无从建立。印光大师一生极力提倡因果教育,认为若人人深信因果,则天下太平,人心向善。
|
|
34
34
|
|
|
35
|
-
> 出处:【《印光法师文钞正编》卷四·挽回劫运护国救民正本清源论】→ https://fojin.app/texts/
|
|
35
|
+
> 出处:【《印光法师文钞正编》卷四·挽回劫运护国救民正本清源论】→ https://fojin.app/texts/12977
|
|
36
36
|
|
|
37
37
|
### 5. 老实念佛,莫换题目
|
|
38
38
|
|
|
39
39
|
修行当老实念佛,不可今日参禅、明日学密、后日又习教观,心无定主,终无所成。应择定净土一门,信愿坚固,一门深入,长时熏修。
|
|
40
40
|
|
|
41
|
-
> 出处:【《印光法师文钞续编》卷上·复王子立居士书】→ https://fojin.app/texts/
|
|
41
|
+
> 出处:【《印光法师文钞续编》卷上·复王子立居士书】→ https://fojin.app/texts/12978
|
|
42
42
|
|
|
43
43
|
## 精通经典
|
|
44
44
|
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
| 《佛说观无量寿佛经》 | 净土三经之一,十六观法与九品往生 | [阅读原文](https://fojin.app/texts/19) |
|
|
49
49
|
| 《佛说无量寿经》 | 净土三经之一,阿弥陀佛四十八愿 | [阅读原文](https://fojin.app/texts/18) |
|
|
50
50
|
| 《大势至菩萨念佛圆通章》 | 楞严经二十五圆通之一,都摄六根念佛法 | [阅读原文](https://fojin.app/texts/65) |
|
|
51
|
-
| 《往生论注》(昙鸾) | 天亲菩萨《往生论》之注释,净土五经一论 | [阅读原文](https://fojin.app/texts/
|
|
52
|
-
| 《印光法师文钞正编》 | 书信体弘法著作,涵盖净土教理与修行指导 | [阅读原文](https://fojin.app/texts/
|
|
51
|
+
| 《往生论注》(昙鸾) | 天亲菩萨《往生论》之注释,净土五经一论 | [阅读原文](https://fojin.app/texts/7991) |
|
|
52
|
+
| 《印光法师文钞正编》 | 书信体弘法著作,涵盖净土教理与修行指导 | [阅读原文](https://fojin.app/texts/12977) |
|
|
53
53
|
|
|
54
54
|
## 修行方法
|
|
55
55
|
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
|
|
91
91
|
### 推荐进一步学习
|
|
92
92
|
|
|
93
|
-
- "建议阅读《印光法师文钞》中相关书信 → [FoJin 原文](https://fojin.app/texts/
|
|
93
|
+
- "建议阅读《印光法师文钞》中相关书信 → [FoJin 原文](https://fojin.app/texts/12977)"
|
|
94
94
|
- "可参考《佛说阿弥陀经》了解极乐世界依正庄严 → [FoJin 原文](https://fojin.app/texts/20)"
|
|
95
95
|
- "关于念佛方法,可详阅《大势至菩萨念佛圆通章》"
|
|
96
96
|
- "可在 FoJin 词典中查阅相关佛学术语的详解"
|
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
|
|
7
7
|
| 文件 | 来源经典 | CBETA | FoJin | 覆盖主题 |
|
|
8
8
|
|---|---|---|---|---|
|
|
9
|
-
| `wenchao-excerpts.md` | 《印光法師文鈔》 | X62n1182/X62n1183 | [X62n1182](https://fojin.app/texts/
|
|
10
|
-
| `yihanbianfu-excerpts.md` | 《一函遍復》 | X62n1183 | [X62n1183](https://fojin.app/texts/
|
|
9
|
+
| `wenchao-excerpts.md` | 《印光法師文鈔》 | X62n1182/X62n1183 | [X62n1182](https://fojin.app/texts/12977) | 信愿行三资粮、摄耳谛听念佛、带业往生横超 |
|
|
10
|
+
| `yihanbianfu-excerpts.md` | 《一函遍復》 | X62n1183 | [X62n1183](https://fojin.app/texts/12978) | 敦伦尽分、闲邪存诚、因果教育 |
|
|
11
11
|
| `jingtu-sanjing-excerpts.md` | 净土三经 | T12n0366/T12n0360 | [20](https://fojin.app/texts/20) / [18](https://fojin.app/texts/18) | 持名念佛、第十八愿、一心不乱 |
|
|
12
12
|
|
|
13
13
|
## 引用规范
|
|
14
14
|
|
|
15
15
|
- 格式:`【《经名》卷N,CBETA_ID】→ https://fojin.app/texts/{fojin_text_id}`
|
|
16
|
-
- 示例:`【《印光法師文鈔正編》卷一,X62n1182】→ https://fojin.app/texts/
|
|
16
|
+
- 示例:`【《印光法師文鈔正編》卷一,X62n1182】→ https://fojin.app/texts/12977`
|
|
17
17
|
|
|
18
18
|
## 说明
|
|
19
19
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 《印光法師文鈔》关键片段
|
|
2
2
|
|
|
3
|
-
> 印光大师著。CBETA ID: X62n1182 (正编), X62n1183 (续编)。FoJin: https://fojin.app/texts/
|
|
3
|
+
> 印光大师著。CBETA ID: X62n1182 (正编), X62n1183 (续编)。FoJin: https://fojin.app/texts/12977
|
|
4
4
|
> 本文件为教学引用用,节选自 CBETA 公开资料。完整经文请访问 FoJin 或 CBETA。
|
|
5
5
|
|
|
6
6
|
## 信愿行三资粮
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
> 念佛法门,以信愿行三法为宗。信则信我此世界是苦,信极乐世界是乐,信我是业力凡夫决定不能仗自力断惑证真了生脱死,信阿弥陀佛有大誓愿若众生念佛求生净土必垂慈接引。愿则厌离娑婆欣求极乐。行则至诚恳切常念南无阿弥陀佛,时刻不忘,朝暮定课,闲忙不废。
|
|
11
11
|
|
|
12
|
-
**引用格式:**【《印光法師文鈔正編》卷一,X62n1182】→ https://fojin.app/texts/
|
|
12
|
+
**引用格式:**【《印光法師文鈔正編》卷一,X62n1182】→ https://fojin.app/texts/12977
|
|
13
13
|
|
|
14
14
|
**教义要点:**
|
|
15
15
|
- 信愿行为净土法门三资粮,缺一不可
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
> 念佛之法,各随所好。或小声念,或默念。除多人同念用引磬外,但宜心念,不宜口念。无论声念默念,皆须念从心起,声从口出,音从耳入。心口念得清清楚楚,耳根听得清清楚楚。如是摄心,妄念自息。
|
|
27
27
|
|
|
28
|
-
**引用格式:**【《印光法師文鈔正編》卷一,X62n1182】→ https://fojin.app/texts/
|
|
28
|
+
**引用格式:**【《印光法師文鈔正編》卷一,X62n1182】→ https://fojin.app/texts/12977
|
|
29
29
|
|
|
30
30
|
**教义要点:**
|
|
31
31
|
- 念从心起、声从口出、音从耳入
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
> 净土法门,乃如来一代时教中之特别法门。末法众生根钝障深,仗自力断惑证真,比登天还难。仗佛慈力,带业往生,则如风帆扬于顺水,更加橹棹之功,不离当念即登彼岸。
|
|
43
43
|
|
|
44
|
-
**引用格式:**【《印光法師文鈔正編》卷一,X62n1182】→ https://fojin.app/texts/
|
|
44
|
+
**引用格式:**【《印光法師文鈔正編》卷一,X62n1182】→ https://fojin.app/texts/12977
|
|
45
45
|
|
|
46
46
|
**教义要点:**
|
|
47
47
|
- 净土为特别法门,异于通途法门
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 《一函遍復》关键片段
|
|
2
2
|
|
|
3
|
-
> 印光大师著,出自《印光法師文鈔續編》。CBETA ID: X62n1183。FoJin: https://fojin.app/texts/
|
|
3
|
+
> 印光大师著,出自《印光法師文鈔續編》。CBETA ID: X62n1183。FoJin: https://fojin.app/texts/12978
|
|
4
4
|
> 本文件为教学引用用,节选自 CBETA 公开资料。完整经文请访问 FoJin 或 CBETA。
|
|
5
5
|
|
|
6
6
|
## 敦伦尽分、闲邪存诚
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
> 敦伦尽分,闲邪存诚,诸恶莫作,众善奉行。正心诚意,以立人道之本。然后以此回向净土,求生西方。在家人第一须尽各人本分。如父慈子孝,兄友弟恭,夫和妇顺。
|
|
11
11
|
|
|
12
|
-
**引用格式:**【《印光法師文鈔續編》·一函遍復,X62n1183】→ https://fojin.app/texts/
|
|
12
|
+
**引用格式:**【《印光法師文鈔續編》·一函遍復,X62n1183】→ https://fojin.app/texts/12978
|
|
13
13
|
|
|
14
14
|
**教义要点:**
|
|
15
15
|
- 学佛首须敦伦尽分——尽好世间本分
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
> 因果者,圣人治天下、佛度众生之大权也。若人人深信因果,则人心自善,风俗自淳,唐虞之治不难复见。
|
|
27
27
|
|
|
28
|
-
**引用格式:**【《印光法師文鈔續編》·一函遍復,X62n1183】→ https://fojin.app/texts/
|
|
28
|
+
**引用格式:**【《印光法師文鈔續編》·一函遍復,X62n1183】→ https://fojin.app/texts/12978
|
|
29
29
|
|
|
30
30
|
**教义要点:**
|
|
31
31
|
- 因果为佛法入门之基础
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: zhiyi
|
|
2
|
+
name: master-zhiyi
|
|
3
3
|
description: Use when user asks about 天台宗, 止观, 一念三千, 三谛圆融, 五时八教, 摩诃止观, 法华经, or wants teaching in 智者大师 Zhiyi's voice. Triggers include phrases like "天台"、"智者大师"、"止观怎么修"、"三谛"、"法华"、"一心三观"、"判教"、"圆教"、"四种三昧" — invoke whenever user's question touches Tiantai doctrine, even without explicit request.
|
|
4
4
|
version: 0.3.0
|
|
5
5
|
license: MIT
|
|
@@ -100,5 +100,33 @@
|
|
|
100
100
|
"q": "《法华经·方便品》说'唯有一佛乘',但前面又说三乘,这是否矛盾?",
|
|
101
101
|
"why": "天台以'开权显实'化解此矛盾,是其核心方法论"
|
|
102
102
|
}
|
|
103
|
+
],
|
|
104
|
+
"signature_phrases": [
|
|
105
|
+
"一念三千",
|
|
106
|
+
"一心三观",
|
|
107
|
+
"三谛圆融",
|
|
108
|
+
"五时八教",
|
|
109
|
+
"圆顿止观",
|
|
110
|
+
"性具善恶"
|
|
111
|
+
],
|
|
112
|
+
"style": {
|
|
113
|
+
"all": "系统论述体,层次分明,逻辑严密;以判教思维统摄诸说,先分后合,义理与实修并重不空谈。",
|
|
114
|
+
"qa": "先以判教定位所问属何教何理,次分十乘十境之纲,末归一念三千之实,绝不孤悬一边。",
|
|
115
|
+
"monologue": "上堂依五时八教纲领开列,举一念心具十法界十如三世间,归结於圆顿止观一心三观之实修。"
|
|
116
|
+
},
|
|
117
|
+
"lore_triggers": [
|
|
118
|
+
{
|
|
119
|
+
"keys": ["一念三千", "三千", "性具"],
|
|
120
|
+
"content": "夫一心具十法界,一法界又具十法界、百法界;一界具三十种世间,百法界即具三千种世间。此三千在一念心,若无心而已,介尔有心即具三千。亦不言一心在前,一切法在後;亦不言一切法在前,一心在後。",
|
|
121
|
+
"source_ref": "T46n1911#卷五上"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"keys": ["一心三观", "三谛", "空假中"],
|
|
125
|
+
"content": "一空一切空,无假无中而不空,总空观也;一假一切假,无空无中而不假,总假观也;一中一切中,无空无假而不中,总中观也。即中论所说不可思议一心三观。於一念心同时观空假中三谛,非次第而修。",
|
|
126
|
+
"source_ref": "T46n1911#卷五上"
|
|
127
|
+
}
|
|
128
|
+
],
|
|
129
|
+
"cross_critique": [
|
|
130
|
+
{ "target_master": "huineng", "position": "对禅宗顿悟:顿悟一念固是事;须知一念三千、性具善恶,理观事造皆备方为圆顿;离开教相判摄,恐落孤山顿悟。", "citation": "T46n1911" }
|
|
103
131
|
]
|
|
104
132
|
}
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
佛性本具善恶,不但九界众生性具善恶,即佛界亦性具善恶。但佛界虽性具恶,而不起恶用;九界众生虽性具善,而善用未显。此义为天台独有之说,区别于他宗之"缘起善恶"或"性唯善"说。
|
|
40
40
|
|
|
41
|
-
> 出处:【《观音玄义》卷上】→ https://fojin.app/texts/
|
|
41
|
+
> 出处:【《观音玄义》卷上】→ https://fojin.app/texts/7898
|
|
42
42
|
|
|
43
43
|
## 精通经典
|
|
44
44
|
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
| 《妙法莲华经玄义》 | 天台三大部之一,法华经深义之系统阐发 | [阅读原文](https://fojin.app/texts/52) |
|
|
50
50
|
| 《妙法莲华经文句》 | 天台三大部之一,法华经逐句注释 | [阅读原文](https://fojin.app/texts/52) |
|
|
51
51
|
| 《修习止观坐禅法要》(小止观) | 止观入门之作,初学必读 | [阅读原文](https://fojin.app/texts/8085) |
|
|
52
|
-
| 《观音玄义》 | 天台五小部之一,性具善恶之重要出处 | [阅读原文](https://fojin.app/texts/
|
|
52
|
+
| 《观音玄义》 | 天台五小部之一,性具善恶之重要出处 | [阅读原文](https://fojin.app/texts/7898) |
|
|
53
53
|
|
|
54
54
|
## 修行方法
|
|
55
55
|
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Check that the version field is consistent across all platform manifests.
|
|
3
|
+
|
|
4
|
+
Master-skill ships to 5 ecosystems and each carries its own manifest with a
|
|
5
|
+
`version` field. PR #26 (post-mortem) showed that the manifests can drift
|
|
6
|
+
silently when only some are bumped — users on Cursor would get a stale
|
|
7
|
+
version while npm users got the new one. This script is a hard CI gate to
|
|
8
|
+
catch drift before a release goes out.
|
|
9
|
+
|
|
10
|
+
Files checked (all relative to repo root):
|
|
11
|
+
|
|
12
|
+
- package.json (canonical npm version)
|
|
13
|
+
- .claude-plugin/plugin.json (Claude Code plugin)
|
|
14
|
+
- .claude-plugin/marketplace.json (Claude Code marketplace — nested
|
|
15
|
+
`plugins[*].version`)
|
|
16
|
+
- .cursor-plugin/plugin.json (Cursor)
|
|
17
|
+
- gemini-extension.json (Gemini CLI)
|
|
18
|
+
|
|
19
|
+
Any *.json under .codex/ or .opencode/ that carries a `version` field is
|
|
20
|
+
also picked up (currently those directories ship INSTALL.md only, but
|
|
21
|
+
this future-proofs the check).
|
|
22
|
+
|
|
23
|
+
Files without a `version` field are skipped.
|
|
24
|
+
|
|
25
|
+
Usage
|
|
26
|
+
-----
|
|
27
|
+
python scripts/check-manifest-versions.py # exit 1 on drift
|
|
28
|
+
python scripts/check-manifest-versions.py --json
|
|
29
|
+
"""
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
import argparse
|
|
33
|
+
import json
|
|
34
|
+
import sys
|
|
35
|
+
from pathlib import Path
|
|
36
|
+
|
|
37
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _read_json(p: Path) -> dict | None:
|
|
41
|
+
try:
|
|
42
|
+
return json.loads(p.read_text(encoding="utf-8"))
|
|
43
|
+
except (json.JSONDecodeError, OSError):
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def collect_versions(root: Path = ROOT) -> dict[str, str]:
|
|
48
|
+
"""Return {relative_path: version_string} for every manifest with one."""
|
|
49
|
+
versions: dict[str, str] = {}
|
|
50
|
+
|
|
51
|
+
# Canonical: package.json
|
|
52
|
+
pkg = _read_json(root / "package.json")
|
|
53
|
+
if pkg and "version" in pkg:
|
|
54
|
+
versions["package.json"] = pkg["version"]
|
|
55
|
+
|
|
56
|
+
# Flat single-version manifests
|
|
57
|
+
flat_paths = [
|
|
58
|
+
root / ".claude-plugin" / "plugin.json",
|
|
59
|
+
root / ".cursor-plugin" / "plugin.json",
|
|
60
|
+
root / "gemini-extension.json",
|
|
61
|
+
]
|
|
62
|
+
for p in flat_paths:
|
|
63
|
+
if not p.exists():
|
|
64
|
+
continue
|
|
65
|
+
data = _read_json(p)
|
|
66
|
+
if data is None:
|
|
67
|
+
continue
|
|
68
|
+
v = data.get("version")
|
|
69
|
+
if isinstance(v, str):
|
|
70
|
+
versions[str(p.relative_to(root))] = v
|
|
71
|
+
|
|
72
|
+
# Marketplace manifest: nested plugins[*].version
|
|
73
|
+
mp = root / ".claude-plugin" / "marketplace.json"
|
|
74
|
+
if mp.exists():
|
|
75
|
+
data = _read_json(mp)
|
|
76
|
+
if data:
|
|
77
|
+
plugins = data.get("plugins", []) or []
|
|
78
|
+
for i, plugin in enumerate(plugins):
|
|
79
|
+
if isinstance(plugin, dict) and "version" in plugin:
|
|
80
|
+
rel = f"{mp.relative_to(root)}::plugins[{i}]"
|
|
81
|
+
versions[rel] = plugin["version"]
|
|
82
|
+
|
|
83
|
+
# Codex / OpenCode future-proofing — pick up any *.json with version
|
|
84
|
+
for sub in (".codex", ".opencode"):
|
|
85
|
+
d = root / sub
|
|
86
|
+
if not d.exists():
|
|
87
|
+
continue
|
|
88
|
+
for p in sorted(d.glob("*.json")):
|
|
89
|
+
data = _read_json(p)
|
|
90
|
+
if data is None:
|
|
91
|
+
continue
|
|
92
|
+
v = data.get("version")
|
|
93
|
+
if isinstance(v, str):
|
|
94
|
+
versions[str(p.relative_to(root))] = v
|
|
95
|
+
|
|
96
|
+
return versions
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def main() -> int:
|
|
100
|
+
parser = argparse.ArgumentParser(
|
|
101
|
+
description="Check version consistency across platform manifests"
|
|
102
|
+
)
|
|
103
|
+
parser.add_argument("--json", action="store_true", help="JSON output")
|
|
104
|
+
args = parser.parse_args()
|
|
105
|
+
|
|
106
|
+
versions = collect_versions()
|
|
107
|
+
if not versions:
|
|
108
|
+
print("No version fields found in any manifest — nothing to check.")
|
|
109
|
+
return 0
|
|
110
|
+
|
|
111
|
+
unique = set(versions.values())
|
|
112
|
+
|
|
113
|
+
if args.json:
|
|
114
|
+
out = {
|
|
115
|
+
"versions": versions,
|
|
116
|
+
"consistent": len(unique) == 1,
|
|
117
|
+
"unique_count": len(unique),
|
|
118
|
+
}
|
|
119
|
+
print(json.dumps(out, indent=2, ensure_ascii=False))
|
|
120
|
+
else:
|
|
121
|
+
if len(unique) > 1:
|
|
122
|
+
print("Manifest version drift detected:")
|
|
123
|
+
for path, v in sorted(versions.items()):
|
|
124
|
+
print(f" {path}: {v}")
|
|
125
|
+
print()
|
|
126
|
+
print(
|
|
127
|
+
f"Found {len(unique)} distinct versions across "
|
|
128
|
+
f"{len(versions)} manifests — they must all match."
|
|
129
|
+
)
|
|
130
|
+
else:
|
|
131
|
+
v = next(iter(unique))
|
|
132
|
+
print(
|
|
133
|
+
f"All {len(versions)} manifest version fields agree on {v}."
|
|
134
|
+
)
|
|
135
|
+
for path in sorted(versions):
|
|
136
|
+
print(f" {path}: {versions[path]}")
|
|
137
|
+
|
|
138
|
+
return 0 if len(unique) == 1 else 1
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
if __name__ == "__main__":
|
|
142
|
+
sys.exit(main())
|
package/scripts/cite.py
CHANGED
|
@@ -52,7 +52,7 @@ def find_citations(master, text):
|
|
|
52
52
|
|
|
53
53
|
def main():
|
|
54
54
|
parser = argparse.ArgumentParser(description="在 master 的 sources 中查找关键词并输出 CBETA 引用")
|
|
55
|
-
parser.add_argument("--master", required=True, help="大师 ID,如 zhiyi")
|
|
55
|
+
parser.add_argument("--master", required=True, help="大师 ID,如 master-zhiyi")
|
|
56
56
|
parser.add_argument("--text", required=True, help="搜索关键词")
|
|
57
57
|
parser.add_argument("--json", action="store_true", dest="as_json", help="JSON 格式输出")
|
|
58
58
|
args = parser.parse_args()
|
package/scripts/query.py
CHANGED
|
@@ -54,7 +54,7 @@ def search(master, query, brief=False):
|
|
|
54
54
|
|
|
55
55
|
def main():
|
|
56
56
|
parser = argparse.ArgumentParser(description="离线检索 master 的 sources 和 references")
|
|
57
|
-
parser.add_argument("--master", required=True, help="大师 ID,如 zhiyi")
|
|
57
|
+
parser.add_argument("--master", required=True, help="大师 ID,如 master-zhiyi")
|
|
58
58
|
parser.add_argument("--q", required=True, help="搜索关键词(空格分隔,OR 匹配)")
|
|
59
59
|
parser.add_argument("--json", action="store_true", dest="as_json", help="JSON 格式输出")
|
|
60
60
|
parser.add_argument("--brief", action="store_true", help="仅输出段标题和文件路径")
|
package/scripts/test-fidelity.py
CHANGED
|
@@ -6,10 +6,10 @@ with the master's SKILL.md loaded as system prompt, and checks responses for
|
|
|
6
6
|
expected citations and keywords.
|
|
7
7
|
|
|
8
8
|
Usage:
|
|
9
|
-
python scripts/test-fidelity.py --master zhiyi # test one master
|
|
10
|
-
python scripts/test-fidelity.py --master zhiyi --dry-run # show test cases without calling API
|
|
11
|
-
python scripts/test-fidelity.py --all
|
|
12
|
-
python scripts/test-fidelity.py --master zhiyi --model claude-sonnet-4-6 # specific model
|
|
9
|
+
python scripts/test-fidelity.py --master master-zhiyi # test one master
|
|
10
|
+
python scripts/test-fidelity.py --master master-zhiyi --dry-run # show test cases without calling API
|
|
11
|
+
python scripts/test-fidelity.py --all # test all masters
|
|
12
|
+
python scripts/test-fidelity.py --master master-zhiyi --model claude-sonnet-4-6 # specific model
|
|
13
13
|
|
|
14
14
|
Requires:
|
|
15
15
|
- ANTHROPIC_API_KEY environment variable
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"""Tests for check-manifest-versions.py.
|
|
2
|
+
|
|
3
|
+
Covers:
|
|
4
|
+
- collect_versions returns all 5 platform manifests when present
|
|
5
|
+
- drift between manifests is detected (returns mismatched dict)
|
|
6
|
+
- manifest with no `version` field is skipped silently
|
|
7
|
+
- marketplace.json plugins[].version is picked up
|
|
8
|
+
- main() exits 0 when consistent, 1 when drift
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import importlib.util
|
|
13
|
+
import json
|
|
14
|
+
import subprocess
|
|
15
|
+
import sys
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _load_module():
|
|
20
|
+
spec_path = (
|
|
21
|
+
Path(__file__).resolve().parents[1] / "check-manifest-versions.py"
|
|
22
|
+
)
|
|
23
|
+
spec = importlib.util.spec_from_file_location("cmv", spec_path)
|
|
24
|
+
mod = importlib.util.module_from_spec(spec)
|
|
25
|
+
sys.modules["cmv"] = mod
|
|
26
|
+
spec.loader.exec_module(mod)
|
|
27
|
+
return mod
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _make_repo(tmp: Path, versions: dict[str, str | None]) -> Path:
|
|
31
|
+
"""Build a fake repo. versions keys: package, claude, marketplace,
|
|
32
|
+
cursor, gemini. Value None means: do not write that file at all.
|
|
33
|
+
A version string of '' means: write the file without a version field.
|
|
34
|
+
"""
|
|
35
|
+
root = tmp / "repo"
|
|
36
|
+
root.mkdir(parents=True)
|
|
37
|
+
(root / ".claude-plugin").mkdir()
|
|
38
|
+
(root / ".cursor-plugin").mkdir()
|
|
39
|
+
|
|
40
|
+
if "package" in versions and versions["package"] is not None:
|
|
41
|
+
body = {"name": "x"}
|
|
42
|
+
if versions["package"]:
|
|
43
|
+
body["version"] = versions["package"]
|
|
44
|
+
(root / "package.json").write_text(json.dumps(body), encoding="utf-8")
|
|
45
|
+
|
|
46
|
+
if "claude" in versions and versions["claude"] is not None:
|
|
47
|
+
body = {"name": "x"}
|
|
48
|
+
if versions["claude"]:
|
|
49
|
+
body["version"] = versions["claude"]
|
|
50
|
+
(root / ".claude-plugin" / "plugin.json").write_text(
|
|
51
|
+
json.dumps(body), encoding="utf-8"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if "marketplace" in versions and versions["marketplace"] is not None:
|
|
55
|
+
body = {"name": "x", "plugins": []}
|
|
56
|
+
if versions["marketplace"]:
|
|
57
|
+
body["plugins"] = [
|
|
58
|
+
{"name": "x", "version": versions["marketplace"]}
|
|
59
|
+
]
|
|
60
|
+
(root / ".claude-plugin" / "marketplace.json").write_text(
|
|
61
|
+
json.dumps(body), encoding="utf-8"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
if "cursor" in versions and versions["cursor"] is not None:
|
|
65
|
+
body = {"name": "x"}
|
|
66
|
+
if versions["cursor"]:
|
|
67
|
+
body["version"] = versions["cursor"]
|
|
68
|
+
(root / ".cursor-plugin" / "plugin.json").write_text(
|
|
69
|
+
json.dumps(body), encoding="utf-8"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
if "gemini" in versions and versions["gemini"] is not None:
|
|
73
|
+
body = {"name": "x"}
|
|
74
|
+
if versions["gemini"]:
|
|
75
|
+
body["version"] = versions["gemini"]
|
|
76
|
+
(root / "gemini-extension.json").write_text(
|
|
77
|
+
json.dumps(body), encoding="utf-8"
|
|
78
|
+
)
|
|
79
|
+
return root
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# ---------- happy path ----------
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def test_all_manifests_consistent(tmp_path):
|
|
86
|
+
m = _load_module()
|
|
87
|
+
root = _make_repo(
|
|
88
|
+
tmp_path,
|
|
89
|
+
{
|
|
90
|
+
"package": "1.2.3",
|
|
91
|
+
"claude": "1.2.3",
|
|
92
|
+
"marketplace": "1.2.3",
|
|
93
|
+
"cursor": "1.2.3",
|
|
94
|
+
"gemini": "1.2.3",
|
|
95
|
+
},
|
|
96
|
+
)
|
|
97
|
+
out = m.collect_versions(root)
|
|
98
|
+
assert set(out.values()) == {"1.2.3"}
|
|
99
|
+
assert len(out) == 5
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def test_drift_detected(tmp_path):
|
|
103
|
+
m = _load_module()
|
|
104
|
+
root = _make_repo(
|
|
105
|
+
tmp_path,
|
|
106
|
+
{
|
|
107
|
+
"package": "1.2.3",
|
|
108
|
+
"claude": "1.2.3",
|
|
109
|
+
"marketplace": "1.2.2", # drift
|
|
110
|
+
"cursor": "1.2.3",
|
|
111
|
+
"gemini": "1.2.3",
|
|
112
|
+
},
|
|
113
|
+
)
|
|
114
|
+
out = m.collect_versions(root)
|
|
115
|
+
assert "1.2.2" in out.values()
|
|
116
|
+
assert "1.2.3" in out.values()
|
|
117
|
+
assert len(set(out.values())) == 2
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# ---------- skip files without version ----------
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def test_manifest_without_version_is_skipped(tmp_path):
|
|
124
|
+
m = _load_module()
|
|
125
|
+
# gemini has no version key
|
|
126
|
+
root = _make_repo(
|
|
127
|
+
tmp_path,
|
|
128
|
+
{
|
|
129
|
+
"package": "1.2.3",
|
|
130
|
+
"claude": "1.2.3",
|
|
131
|
+
"marketplace": "1.2.3",
|
|
132
|
+
"cursor": "1.2.3",
|
|
133
|
+
"gemini": "", # write file but no version field
|
|
134
|
+
},
|
|
135
|
+
)
|
|
136
|
+
out = m.collect_versions(root)
|
|
137
|
+
assert "gemini-extension.json" not in out
|
|
138
|
+
assert len(out) == 4
|
|
139
|
+
assert set(out.values()) == {"1.2.3"}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def test_marketplace_with_empty_plugins_is_skipped(tmp_path):
|
|
143
|
+
m = _load_module()
|
|
144
|
+
root = _make_repo(
|
|
145
|
+
tmp_path,
|
|
146
|
+
{
|
|
147
|
+
"package": "1.2.3",
|
|
148
|
+
"claude": "1.2.3",
|
|
149
|
+
"marketplace": "", # write file with no plugin entries
|
|
150
|
+
"cursor": "1.2.3",
|
|
151
|
+
"gemini": "1.2.3",
|
|
152
|
+
},
|
|
153
|
+
)
|
|
154
|
+
out = m.collect_versions(root)
|
|
155
|
+
assert ".claude-plugin/marketplace.json::plugins[0]" not in out
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def test_codex_opencode_picked_up_when_versioned(tmp_path):
|
|
159
|
+
m = _load_module()
|
|
160
|
+
root = _make_repo(
|
|
161
|
+
tmp_path,
|
|
162
|
+
{"package": "9.0.0"},
|
|
163
|
+
)
|
|
164
|
+
# Stash a future .codex/<name>.json with a version
|
|
165
|
+
(root / ".codex").mkdir()
|
|
166
|
+
(root / ".codex" / "agents.json").write_text(
|
|
167
|
+
json.dumps({"name": "x", "version": "9.0.0"}), encoding="utf-8"
|
|
168
|
+
)
|
|
169
|
+
(root / ".opencode").mkdir()
|
|
170
|
+
(root / ".opencode" / "plugin.json").write_text(
|
|
171
|
+
json.dumps({"name": "x", "version": "9.0.0"}), encoding="utf-8"
|
|
172
|
+
)
|
|
173
|
+
out = m.collect_versions(root)
|
|
174
|
+
assert ".codex/agents.json" in out
|
|
175
|
+
assert ".opencode/plugin.json" in out
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def test_codex_opencode_install_md_only_no_false_positive(tmp_path):
|
|
179
|
+
m = _load_module()
|
|
180
|
+
# The real repo today: .codex/INSTALL.md only — no JSON.
|
|
181
|
+
root = _make_repo(tmp_path, {"package": "1.0.0"})
|
|
182
|
+
(root / ".codex").mkdir()
|
|
183
|
+
(root / ".codex" / "INSTALL.md").write_text("# install", encoding="utf-8")
|
|
184
|
+
out = m.collect_versions(root)
|
|
185
|
+
assert all(not k.startswith(".codex/") for k in out)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
# ---------- CLI exit codes ----------
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _run_cli(args: list[str], cwd: Path) -> subprocess.CompletedProcess:
|
|
192
|
+
script = (
|
|
193
|
+
Path(__file__).resolve().parents[1] / "check-manifest-versions.py"
|
|
194
|
+
)
|
|
195
|
+
return subprocess.run(
|
|
196
|
+
[sys.executable, str(script), *args],
|
|
197
|
+
capture_output=True,
|
|
198
|
+
text=True,
|
|
199
|
+
cwd=cwd,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def test_cli_exits_zero_on_real_repo():
|
|
204
|
+
"""Live repo manifests must be consistent or the check fails."""
|
|
205
|
+
repo_root = Path(__file__).resolve().parents[2]
|
|
206
|
+
proc = _run_cli([], cwd=repo_root)
|
|
207
|
+
assert proc.returncode == 0, proc.stdout + proc.stderr
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def test_cli_json_output_shape():
|
|
211
|
+
repo_root = Path(__file__).resolve().parents[2]
|
|
212
|
+
proc = _run_cli(["--json"], cwd=repo_root)
|
|
213
|
+
assert proc.returncode == 0
|
|
214
|
+
data = json.loads(proc.stdout)
|
|
215
|
+
assert "versions" in data
|
|
216
|
+
assert "consistent" in data
|
|
217
|
+
assert data["consistent"] is True
|