dsh-paper-doc-adapter 0.2.8 → 0.2.9

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-es.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [English](README.md) · [简体中文](README-zh.md) · [Español](README-es.md) · [Português](README-pt.md) · [हिन्दी](README-hi.md)
4
4
 
5
5
  [![DSH Market](https://raw.githubusercontent.com/2BingLing/dsh-market/master/assets/readme/badge-listed-en.svg)](https://dsh.market/)
6
+ [![dshfind](https://dshfind.com/api/badge/PerryLink/dsh-paper-doc-adapter?metric=downloads)](https://dshfind.com/en/plugins/PerryLink/dsh-paper-doc-adapter?ref=badge)
6
7
 
7
8
  `dsh-paper-doc-adapter` lee un examen ya analizado —la cabecera del examen más una fila por pregunta— y comprueba la coherencia estructural interna de ese resultado: que cada pregunta registre su número y su enunciado, que haya una respuesta o una explicación, que la suma de las puntuaciones de las preguntas coincida con la puntuación total que indica la cabecera, que el tipo de pregunta provenga del vocabulario que usted configura, que el coeficiente de dificultad quede dentro de su rango, que los identificadores de pregunta estén presentes y no se repitan, que se registre un punto de conocimiento y que no quede ningún marcador de plantilla en el enunciado.
8
9
 
@@ -15,14 +16,47 @@ dsh --profile <name> --dump-config | grep 'dsh-paper-doc-adapter'
15
16
 
16
17
  ## Cómo se ve la salida
17
18
 
18
- ![Terminal demo of dsh-paper-doc-adapter: real output over its PD-006 fixture](https://raw.githubusercontent.com/PerryLink/dsh-paper-doc-adapter/main/docs/assets/dsh-paper-doc-adapter-hero.png)
19
+ ![Diagrama de flujo de dsh-paper-doc-adapter: llamada → plugin → resultado.](docs/assets/dsh-paper-doc-adapter-flow.svg)
20
+
21
+ *Resumen del flujo: llamada → plugin → resultado. Los ejemplos siguientes usan la superficie de comandos real.*
19
22
 
20
- ![Animated terminal demo of dsh-paper-doc-adapter](https://raw.githubusercontent.com/PerryLink/dsh-paper-doc-adapter/main/docs/assets/dsh-paper-doc-adapter-demo.gif)
21
23
 
22
24
  Salida real de este plugin sobre su propio fixture de prueba `PD-006` — no es un montaje. El paquete de reglas no inventa citas, así que cada hallazgo nombra la cláusula aplicada y advierte que su texto no se obtuvo.
23
25
 
24
26
  ## Qué responde
25
27
 
28
+ ### Ejemplos
29
+
30
+ La tabla siguiente es el conjunto de ejemplos: la primera fila es el caso detallado y las demás son casos breves.
31
+
32
+ #### Salida detallada
33
+
34
+ **Herramienta** `paper_doc_adapter`
35
+
36
+ **Entrada**
37
+
38
+ ~~~json
39
+ {"paperTitle":"某某科目 2026 年模拟试卷","subject":"某某科目","grade":"高二","totalScore":"3","rows":[{"序号":"1","题号":"","题型":"单选题","题干":"","答案":"B","分值":"3"}]}
40
+ ~~~
41
+
42
+ **Salida**
43
+
44
+ ~~~json
45
+ {
46
+ "id": "dsh-paper-doc-adapter.PD-001.de09b5a6",
47
+ "ruleId": "PD-001",
48
+ "severity": "warn",
49
+ "locator": {
50
+ "row": 1,
51
+ "field": "questionNo"
52
+ },
53
+ "found": "第 1 行 questionNo、stem 都为空",
54
+ "expected": "questionNo、stem 至少应填写一项"
55
+ }
56
+ ~~~
57
+
58
+ *Observado en `dsh-paper-doc-adapter/tests/fixtures/PD-001/PD-001-unsafe.json`*
59
+
26
60
  | Usted pregunta | Qué responde |
27
61
  |---|---|
28
62
  | En una fila están vacíos tanto el número como el enunciado, ¿se informa de algo? | Sí. `PD-001` informa de la fila cuyo `questionNo` y `stem` están ambos vacíos, porque pide que se rellene al menos uno de los dos. Comprueba que algo esté puesto, no si la pregunta está bien redactada o el enunciado es riguroso. |
@@ -122,6 +156,10 @@ node ../scripts/sync-shared.mjs dsh-paper-doc-adapter
122
156
 
123
157
  El último comando copia el kit compartido de `../_shared` a `src/shared/`; vuelva a ejecutarlo tras cada cambio compartido.
124
158
 
159
+ ## PerryLink DSH Plugin Family
160
+
161
+ Full family index: [choose a checker by material](https://perrylink.github.io/zh/checkers/choose/) and [all plugins](https://github.com/PerryLink). This repository is one of them.
162
+
125
163
  ## License
126
164
 
127
165
  [Apache License 2.0](LICENSE) © 2026 dsh-paper-doc-adapter contributors.
package/README-hi.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [English](README.md) · [简体中文](README-zh.md) · [Español](README-es.md) · [Português](README-pt.md) · [हिन्दी](README-hi.md)
4
4
 
5
5
  [![DSH Market](https://raw.githubusercontent.com/2BingLing/dsh-market/master/assets/readme/badge-listed-en.svg)](https://dsh.market/)
6
+ [![dshfind](https://dshfind.com/api/badge/PerryLink/dsh-paper-doc-adapter?metric=downloads)](https://dshfind.com/en/plugins/PerryLink/dsh-paper-doc-adapter?ref=badge)
6
7
 
7
8
  `dsh-paper-doc-adapter` एक विश्लेषित प्रश्नपत्र पढ़ता है — प्रश्नपत्र का हेडर और प्रत्येक प्रश्न की एक पंक्ति — और उसी विश्लेषण-परिणाम की आंतरिक संरचनात्मक संगति जाँचता है: क्या प्रत्येक प्रश्न में उसका क्रमांक और प्रश्न-कथन दर्ज है, क्या उत्तर या व्याख्या में से कम से कम एक दर्ज है, क्या सभी प्रश्नों के अंकों का जोड़ हेडर में लिखे कुल अंक के बराबर है, क्या प्रश्न-प्रकार आपके द्वारा कॉन्फ़िगर की गई सूची से आता है, क्या कठिनाई-गुणांक आपकी निर्धारित सीमा के भीतर है, क्या प्रश्न-पहचानकर्ता दर्ज और अद्वितीय हैं, क्या ज्ञान-बिंदु दर्ज है, और क्या प्रश्न-कथन में कोई टेम्पलेट प्लेसहोल्डर शेष नहीं है।
8
9
 
@@ -15,14 +16,47 @@ dsh --profile <name> --dump-config | grep 'dsh-paper-doc-adapter'
15
16
 
16
17
  ## आउटपुट कैसा दिखता है
17
18
 
18
- ![Terminal demo of dsh-paper-doc-adapter: real output over its PD-006 fixture](https://raw.githubusercontent.com/PerryLink/dsh-paper-doc-adapter/main/docs/assets/dsh-paper-doc-adapter-hero.png)
19
+ ![dsh-paper-doc-adapter कार्यप्रवाह आरेख: कॉल → प्लगइन → परिणाम।](docs/assets/dsh-paper-doc-adapter-flow.svg)
20
+
21
+ *कार्यप्रवाह: कॉल → प्लगइन → परिणाम। नीचे के उदाहरण वास्तविक कमांड सतह का उपयोग करते हैं।*
19
22
 
20
- ![Animated terminal demo of dsh-paper-doc-adapter](https://raw.githubusercontent.com/PerryLink/dsh-paper-doc-adapter/main/docs/assets/dsh-paper-doc-adapter-demo.gif)
21
23
 
22
24
  इस प्लगइन का अपने ही `PD-006` टेस्ट फ़िक्स्चर पर वास्तविक आउटपुट — कोई नकली चित्र नहीं। नियम-पैक उद्धरण नहीं गढ़ता, इसलिए हर निष्कर्ष लागू किए गए खंड का नाम और यह भी बताता है कि उसका मूल पाठ इस बार प्राप्त नहीं हुआ।
23
25
 
24
26
  ## यह किन सवालों का जवाब देता है
25
27
 
28
+ ### उदाहरण
29
+
30
+ नीचे दी गई तालिका उदाहरण-समुच्चय है: पहली पंक्ति विस्तृत केस है, बाकी संक्षिप्त केस हैं।
31
+
32
+ #### विस्तृत आउटपुट
33
+
34
+ **उपकरण** `paper_doc_adapter`
35
+
36
+ **इनपुट**
37
+
38
+ ~~~json
39
+ {"paperTitle":"某某科目 2026 年模拟试卷","subject":"某某科目","grade":"高二","totalScore":"3","rows":[{"序号":"1","题号":"","题型":"单选题","题干":"","答案":"B","分值":"3"}]}
40
+ ~~~
41
+
42
+ **आउटपुट**
43
+
44
+ ~~~json
45
+ {
46
+ "id": "dsh-paper-doc-adapter.PD-001.de09b5a6",
47
+ "ruleId": "PD-001",
48
+ "severity": "warn",
49
+ "locator": {
50
+ "row": 1,
51
+ "field": "questionNo"
52
+ },
53
+ "found": "第 1 行 questionNo、stem 都为空",
54
+ "expected": "questionNo、stem 至少应填写一项"
55
+ }
56
+ ~~~
57
+
58
+ *स्रोत `dsh-paper-doc-adapter/tests/fixtures/PD-001/PD-001-unsafe.json`*
59
+
26
60
  | आपका सवाल | इसका जवाब |
27
61
  |---|---|
28
62
  | किसी पंक्ति में प्रश्न-क्रमांक और प्रश्न-कथन दोनों खाली हैं — क्या कुछ बताया जाता है? | हाँ। `PD-001` उस पंक्ति को दर्ज करता है जिसमें `questionNo` और `stem` दोनों खाली हैं, क्योंकि वह दोनों में से कम से कम एक भरा होने की अपेक्षा करता है। यह देखता है कि कुछ भरा है, यह नहीं कि प्रश्न अच्छा है या कथन कठोर है। |
@@ -122,6 +156,10 @@ node ../scripts/sync-shared.mjs dsh-paper-doc-adapter
122
156
 
123
157
  अंतिम कमांड `../_shared` का साझा किट `src/shared/` में कॉपी करता है; हर साझा बदलाव के बाद इसे दोबारा चलाएँ।
124
158
 
159
+ ## PerryLink DSH Plugin Family
160
+
161
+ Full family index: [choose a checker by material](https://perrylink.github.io/zh/checkers/choose/) and [all plugins](https://github.com/PerryLink). This repository is one of them.
162
+
125
163
  ## License
126
164
 
127
165
  [Apache License 2.0](LICENSE) © 2026 dsh-paper-doc-adapter contributors.
package/README-pt.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [English](README.md) · [简体中文](README-zh.md) · [Español](README-es.md) · [Português](README-pt.md) · [हिन्दी](README-hi.md)
4
4
 
5
5
  [![DSH Market](https://raw.githubusercontent.com/2BingLing/dsh-market/master/assets/readme/badge-listed-en.svg)](https://dsh.market/)
6
+ [![dshfind](https://dshfind.com/api/badge/PerryLink/dsh-paper-doc-adapter?metric=downloads)](https://dshfind.com/en/plugins/PerryLink/dsh-paper-doc-adapter?ref=badge)
6
7
 
7
8
  `dsh-paper-doc-adapter` lê um exame já analisado —o cabeçalho do exame mais uma linha por questão— e verifica a coerência estrutural interna desse resultado: se cada questão regista o seu número e o seu enunciado, se há uma resposta ou uma explicação, se a soma das pontuações das questões coincide com a pontuação total indicada no cabeçalho, se o tipo de questão vem do vocabulário que você configura, se o coeficiente de dificuldade fica dentro do seu intervalo, se os identificadores de questão estão presentes e não se repetem, se um ponto de conhecimento está registado e se não resta nenhum marcador de modelo no enunciado.
8
9
 
@@ -15,14 +16,47 @@ dsh --profile <name> --dump-config | grep 'dsh-paper-doc-adapter'
15
16
 
16
17
  ## Como é a saída
17
18
 
18
- ![Terminal demo of dsh-paper-doc-adapter: real output over its PD-006 fixture](https://raw.githubusercontent.com/PerryLink/dsh-paper-doc-adapter/main/docs/assets/dsh-paper-doc-adapter-hero.png)
19
+ ![Diagrama de fluxo de dsh-paper-doc-adapter: chamada → plugin → resultado.](docs/assets/dsh-paper-doc-adapter-flow.svg)
20
+
21
+ *Visão geral do fluxo: chamada → plugin → resultado. Os exemplos abaixo usam a superfície real de comandos.*
19
22
 
20
- ![Animated terminal demo of dsh-paper-doc-adapter](https://raw.githubusercontent.com/PerryLink/dsh-paper-doc-adapter/main/docs/assets/dsh-paper-doc-adapter-demo.gif)
21
23
 
22
24
  Saída real deste plugin sobre o seu próprio fixture de teste `PD-006` — não é uma simulação. O pacote de regras não inventa citações, por isso cada achado nomeia a cláusula aplicada e avisa que o seu texto não foi obtido.
23
25
 
24
26
  ## O que ele responde
25
27
 
28
+ ### Exemplos
29
+
30
+ A tabela abaixo é o conjunto de exemplos: a primeira linha é o caso detalhado e as demais são casos curtos.
31
+
32
+ #### Saída detalhada
33
+
34
+ **Ferramenta** `paper_doc_adapter`
35
+
36
+ **Entrada**
37
+
38
+ ~~~json
39
+ {"paperTitle":"某某科目 2026 年模拟试卷","subject":"某某科目","grade":"高二","totalScore":"3","rows":[{"序号":"1","题号":"","题型":"单选题","题干":"","答案":"B","分值":"3"}]}
40
+ ~~~
41
+
42
+ **Saída**
43
+
44
+ ~~~json
45
+ {
46
+ "id": "dsh-paper-doc-adapter.PD-001.de09b5a6",
47
+ "ruleId": "PD-001",
48
+ "severity": "warn",
49
+ "locator": {
50
+ "row": 1,
51
+ "field": "questionNo"
52
+ },
53
+ "found": "第 1 行 questionNo、stem 都为空",
54
+ "expected": "questionNo、stem 至少应填写一项"
55
+ }
56
+ ~~~
57
+
58
+ *Observado em `dsh-paper-doc-adapter/tests/fixtures/PD-001/PD-001-unsafe.json`*
59
+
26
60
  | Você pergunta | O que ele responde |
27
61
  |---|---|
28
62
  | Numa linha estão vazios tanto o número como o enunciado — isso é reportado? | Sim. `PD-001` reporta a linha cujo `questionNo` e `stem` estão ambos vazios, porque exige que pelo menos um dos dois seja preenchido. Verifica que algo está preenchido, não se a questão está bem redigida ou o enunciado é rigoroso. |
@@ -122,6 +156,10 @@ node ../scripts/sync-shared.mjs dsh-paper-doc-adapter
122
156
 
123
157
  O último comando copia o kit compartilhado de `../_shared` para `src/shared/`; execute-o novamente após cada alteração compartilhada.
124
158
 
159
+ ## PerryLink DSH Plugin Family
160
+
161
+ Full family index: [choose a checker by material](https://perrylink.github.io/zh/checkers/choose/) and [all plugins](https://github.com/PerryLink). This repository is one of them.
162
+
125
163
  ## License
126
164
 
127
165
  [Apache License 2.0](LICENSE) © 2026 dsh-paper-doc-adapter contributors.
package/README-zh.md CHANGED
@@ -2,7 +2,17 @@
2
2
 
3
3
  [English](README.md) · [简体中文](README-zh.md) · [Español](README-es.md) · [Português](README-pt.md) · [हिन्दी](README-hi.md)
4
4
 
5
+ <!-- topblock:v1 -->
6
+ > **这是什么** 试卷解析结构核对。输出一份「哪一行、哪一栏、差什么」的清单。
7
+ > **给谁用** 教研、命题与阅卷管理;不用懂命令行。
8
+ > **你交什么** 这项核对用到的原始材料(表格、清单或文书);不改原件。Excel 可先转成 JSON/YAML,对话里也能代转。
9
+ > **它不做什么** 不判合规、不认定责任、不替代审核人;只列材料内部能逐条指认的差异。
10
+ > **怎么开始** 在 WorkBuddy / 扣子搜「职业文档核对全集」(总包,本检查是其中一项;上架以商城为准);或命令行:
11
+ > `dsh plugin --profile <name> add dsh-paper-doc-adapter`
12
+ <!-- /topblock:v1 -->
13
+
5
14
  [![DSH Market](https://raw.githubusercontent.com/2BingLing/dsh-market/master/assets/readme/badge-listed-en.svg)](https://dsh.market/)
15
+ [![dshfind](https://dshfind.com/api/badge/PerryLink/dsh-paper-doc-adapter?metric=downloads)](https://dshfind.com/en/plugins/PerryLink/dsh-paper-doc-adapter?ref=badge)
6
16
 
7
17
  `dsh-paper-doc-adapter` 读取一份试卷解析结果——试卷表头加每道题一行——核对这份解析结果自身的结构自洽:每道题是否填写了题号与题干、是否填写了答案或解析、各题分值合计是否等于表头写的试卷总分、题型取值是否出自你配置的口径、难度系数是否落在你配置的范围内、题目标识是否齐备且唯一、是否标注了知识点、题干栏是否残留模板占位符。
8
18
 
@@ -15,14 +25,47 @@ dsh --profile <name> --dump-config | grep 'dsh-paper-doc-adapter'
15
25
 
16
26
  ## 实际输出长什么样
17
27
 
18
- ![Terminal demo of dsh-paper-doc-adapter: real output over its PD-006 fixture](https://raw.githubusercontent.com/PerryLink/dsh-paper-doc-adapter/main/docs/assets/dsh-paper-doc-adapter-hero.png)
28
+ ![dsh-paper-doc-adapter 工作流图:调用 → 插件 → 结果。](docs/assets/dsh-paper-doc-adapter-flow.svg)
29
+
30
+ *工作流概览:调用 → 插件 → 结果。下面的示例使用实际命令面。*
19
31
 
20
- ![Animated terminal demo of dsh-paper-doc-adapter](https://raw.githubusercontent.com/PerryLink/dsh-paper-doc-adapter/main/docs/assets/dsh-paper-doc-adapter-demo.gif)
21
32
 
22
33
  本插件对自己 `PD-006` 测试夹具的**真实输出**,不是示意图。规则库不伪造引文,因此每条发现都会同时写明所引条款,以及该条款原文本次未取得。
23
34
 
24
35
  ## 它回答什么问题
25
36
 
37
+ ### 示例
38
+
39
+ 下表是示例集:第一行是详细走查,其余行是简短案例。
40
+
41
+ #### 详细输出
42
+
43
+ **工具** `paper_doc_adapter`
44
+
45
+ **输入**
46
+
47
+ ~~~json
48
+ {"paperTitle":"某某科目 2026 年模拟试卷","subject":"某某科目","grade":"高二","totalScore":"3","rows":[{"序号":"1","题号":"","题型":"单选题","题干":"","答案":"B","分值":"3"}]}
49
+ ~~~
50
+
51
+ **输出**
52
+
53
+ ~~~json
54
+ {
55
+ "id": "dsh-paper-doc-adapter.PD-001.de09b5a6",
56
+ "ruleId": "PD-001",
57
+ "severity": "warn",
58
+ "locator": {
59
+ "row": 1,
60
+ "field": "questionNo"
61
+ },
62
+ "found": "第 1 行 questionNo、stem 都为空",
63
+ "expected": "questionNo、stem 至少应填写一项"
64
+ }
65
+ ~~~
66
+
67
+ *来源 `dsh-paper-doc-adapter/tests/fixtures/PD-001/PD-001-unsafe.json`*
68
+
26
69
  | 你会问 | 它怎么答 |
27
70
  |---|---|
28
71
  | 某行的题号与题干都是空的,会被报出吗? | 会。`PD-001` 只要求 `questionNo` 与 `stem` 至少填一项,两项都空才报出该行。它只核对是否填写,不判断题目出得好不好、题干是否严谨。 |
@@ -40,32 +83,17 @@ dsh --profile <name> --dump-config | grep 'dsh-paper-doc-adapter'
40
83
  | 本机构题库与命题口径(本机构配置) | 无统一标准(本条依据为本机构配置的题型口径) | PD-004 |
41
84
  | 本机构题库与命题口径(本机构配置) | 无统一标准(本条依据为本机构配置的难度口径) | PD-005 |
42
85
 
43
- **Boundary:** this plugin checks a **试卷解析结果** for structural self-consistency — that each question records its
44
- number and stem, that an answer or an explanation is present, that the question scores total the paper's score,
45
- that the question type comes from your vocabulary, that the difficulty coefficient falls inside your range, that
46
- question identifiers are present and unique, that a knowledge point is recorded, and that no placeholder survives.
47
- It does **not** decide whether a question is well written, whether an answer is correct, whether the difficulty is
48
- appropriate, or whether the paper meets its assessment objectives.
86
+ **边界(中文译文,以英文原文为准):** 本插件核对一份 **试卷解析结果** 的结构自洽——每道题是否记录了题号与题干,是否填写了答案或解析,各题分值合计是否等于试卷总分,题型是否取自你的取值口径,难度系数是否落在你配置的范围内,题目标识是否齐备且唯一,是否标注了知识点,以及是否残留占位符。它**不**判定题目是否写得好、答案是否正确、难度是否恰当,或试卷是否达到其考查目标。
49
87
 
50
- > ### ⚠️ What this plugin deliberately does not do
88
+ > ### ⚠️ 这个插件刻意不做的事(以英文原文为准)
51
89
  >
52
- > **It treats the paper as a generic table and performs no question-type-specific checking.** So it **does not
53
- > verify that an answer letter falls within the options offered**, that a fill-in-the-blank has the right number of
54
- > blanks, or that a multiple-choice question has exactly one correct option. Those need the structure of each
55
- > question type parsed, which this adapter does not attempt. That boundary is stated in the pack's header and in
56
- > the troubleshooting section.
90
+ > **它把试卷当作一张通用表格处理,不执行任何针对题型的分项核对。** 因此它**不核对答案字母是否落在所给选项范围内**,不核对填空题的空数是否正确,也不核对选择题是否恰好只有一个正确选项。这些都需要解析每种题型自身的结构,而本适配器并不尝试这样做。这条边界写在规则库库头和排障一节中。
57
91
  >
58
- > **It never checks whether data is fit to import into a question bank beyond key presence and uniqueness.** A
59
- > duplicate identifier is the dangerous case — importing would silently overwrite an existing question — which is
60
- > why `PD-006` is `warn` and why it reports itself in `skipped` when no identifier column is present rather than
61
- > checking the wrong column.
92
+ > **除了键是否存在及其唯一性之外,它从不核对数据是否适合导入题库。** 重复的标识符是危险情形——导入会静默覆盖已有题目——这就是 `PD-006` 定为 `warn` 的原因,也是在没有标识符列时它会把自己记入 `skipped`、而不是去核对错误列的原因。
62
93
  >
63
- > **The difficulty range `0–1` is a local convention, not the only scale.** It is the common convention, larger
64
- > meaning easier; a unit using 1–5 or a percentage can change `min`/`max` or disable the rule.
94
+ > **难度区间 `0–1` 是一种本地约定,不是唯一的量表。** 它是常见约定,数值越大表示越容易;使用 1–5 或百分比的单位可以修改 `min`/`max`,或者停用该规则。
65
95
  >
66
- > **Every `excerpt` in the rule pack says, in so many words, that the clause text was not obtained** — the
67
- > verification pass retrieved neither JY/T 0606's text nor the yotta platform's field specification. When the
68
- > texts are in hand, replace each `excerpt` with the real clause and raise `kind` to `direct`.
96
+ > **规则库中的每一个 `excerpt` 都明文写着:条款原文本次未取得**——核验环节既没有取得 JY/T 0606 的原文,也没有取得 yotta 平台的字段规范。待取得原文后,请把每个 `excerpt` 换成真实条款,并把 `kind` 提到 `direct`。
69
97
 
70
98
  ## Compatibility
71
99
 
@@ -122,6 +150,10 @@ node ../scripts/sync-shared.mjs dsh-paper-doc-adapter
122
150
 
123
151
  第 4 项把 `../_shared` 的共享件同步进 `src/shared/`;每次改动共享件后都要重跑。
124
152
 
153
+ ## PerryLink DSH Plugin Family
154
+
155
+ 完整清单(62 个核查器 + 通用插件)见 [按材料选核查器](https://perrylink.github.io/zh/checkers/choose/);本仓只是其中一个。
156
+
125
157
  ## License
126
158
 
127
159
  [Apache License 2.0](LICENSE) © 2026 dsh-paper-doc-adapter contributors.
package/README.md CHANGED
@@ -2,7 +2,17 @@
2
2
 
3
3
  [English](README.md) · [简体中文](README-zh.md) · [Español](README-es.md) · [Português](README-pt.md) · [हिन्दी](README-hi.md)
4
4
 
5
+ <!-- topblock:v1 -->
6
+ > **What it is** — Parsed exam paper structural self-consistency check across question type, answer, score and yotta identifier. It returns a list of what is inconsistent, where, and what to fix.
7
+ > **Who it is for** — exam and teaching administrators; no command line required.
8
+ > **What you give it** — the source material the check works on (a table, register or document); the original is never modified. Excel can be converted to JSON/YAML first, in chat if the platform supports it.
9
+ > **What it does not do** — no compliance verdict, no liability finding, no replacement for the reviewer; differences only.
10
+ > **How to start** — search "Professional Document Check Suite" in WorkBuddy / Coze (the full set; this check is one part of it; availability as listed); or:
11
+ > `dsh plugin --profile <name> add dsh-paper-doc-adapter`
12
+ <!-- /topblock:v1 -->
13
+
5
14
  [![DSH Market](https://raw.githubusercontent.com/2BingLing/dsh-market/master/assets/readme/badge-listed-en.svg)](https://dsh.market/)
15
+ [![dshfind](https://dshfind.com/api/badge/PerryLink/dsh-paper-doc-adapter?metric=downloads)](https://dshfind.com/en/plugins/PerryLink/dsh-paper-doc-adapter?ref=badge)
6
16
 
7
17
  `dsh-paper-doc-adapter` reads one parsed exam paper — the paper header plus one row per question — and checks that parse result's own structural self-consistency: that each question records its number and stem, that an answer or an explanation is present, that the question scores total the paper score the header states, that the question type comes from the vocabulary you configure, that the difficulty coefficient falls inside your range, that question identifiers are present and unique, that a knowledge point is recorded, and that no template placeholder survives in the stem.
8
18
 
@@ -15,14 +25,46 @@ dsh --profile <name> --dump-config | grep 'dsh-paper-doc-adapter'
15
25
 
16
26
  ## What it looks like
17
27
 
18
- ![Terminal demo of dsh-paper-doc-adapter: real output over its PD-006 fixture](https://raw.githubusercontent.com/PerryLink/dsh-paper-doc-adapter/main/docs/assets/dsh-paper-doc-adapter-hero.png)
28
+ ![Workflow diagram for dsh-paper-doc-adapter: call → plugin → result.](docs/assets/dsh-paper-doc-adapter-flow.svg)
29
+
30
+ *Workflow overview: call → plugin → result. The examples below use the real command surface.*
19
31
 
20
- ![Animated terminal demo of dsh-paper-doc-adapter](https://raw.githubusercontent.com/PerryLink/dsh-paper-doc-adapter/main/docs/assets/dsh-paper-doc-adapter-demo.gif)
21
32
 
22
- Real output from this plugin over its own `PD-006` test fixture — not a mock-up. The rule pack ships no invented quotations, so a finding names both the clause it applied and the fact that the clause text was not obtained.
23
33
 
24
34
  ## What it answers
25
35
 
36
+ ### Examples
37
+
38
+ The table below is the example set: the first row is the detailed walkthrough, the remaining rows are short cases.
39
+
40
+ #### Detailed output
41
+
42
+ **Tool** `paper_doc_adapter`
43
+
44
+ **Input**
45
+
46
+ ~~~json
47
+ {"paperTitle":"某某科目 2026 年模拟试卷","subject":"某某科目","grade":"高二","totalScore":"3","rows":[{"序号":"1","题号":"","题型":"单选题","题干":"","答案":"B","分值":"3"}]}
48
+ ~~~
49
+
50
+ **Output**
51
+
52
+ ~~~json
53
+ {
54
+ "id": "dsh-paper-doc-adapter.PD-001.de09b5a6",
55
+ "ruleId": "PD-001",
56
+ "severity": "warn",
57
+ "locator": {
58
+ "row": 1,
59
+ "field": "questionNo"
60
+ },
61
+ "found": "第 1 行 questionNo、stem 都为空",
62
+ "expected": "questionNo、stem 至少应填写一项"
63
+ }
64
+ ~~~
65
+
66
+ *Observed from `dsh-paper-doc-adapter/tests/fixtures/PD-001/PD-001-unsafe.json`*
67
+
26
68
  | You ask | What it answers |
27
69
  |---|---|
28
70
  | Both the question number and the stem are blank on a row — does the check say anything? | Yes. `PD-001` reports a row whose `questionNo` and `stem` are both empty, because it asks for at least one of the two. It checks that something is filled, not whether the question is well written or the stem rigorous. |
@@ -172,6 +214,10 @@ node ../scripts/sync-shared.mjs dsh-paper-doc-adapter # refresh src/shared fro
172
214
  The plugin is **data-only**: `src/model.ts` declares the table shape, the shared kit supplies the reader and the
173
215
  check engine, and the rule pack declares every check.
174
216
 
217
+ ## PerryLink DSH Plugin Family
218
+
219
+ Full family index: [choose a checker by material](https://perrylink.github.io/zh/checkers/choose/) and [all plugins](https://github.com/PerryLink). This repository is one of them.
220
+
175
221
  ## License
176
222
 
177
223
  [Apache License 2.0](LICENSE) © 2026 dsh-paper-doc-adapter contributors.
package/lib/index.d.mts CHANGED
@@ -1,12 +1,11 @@
1
1
  import Schema from "@deepseek-ai/schemastery";
2
2
  import { Context } from "@deepseek-ai/cordis";
3
- //#region src/config.d.ts
4
3
  /**
5
4
  * Every tunable lives here so an operator can change behaviour from
6
5
  * `cordis.yml` without editing code (the family's "no hard-coded tunables"
7
6
  * redline). The rule pack itself is data as well and can be pointed elsewhere.
8
7
  */
9
- interface Config {
8
+ export interface Config {
10
9
  /** Rule-pack path relative to the plugin package root. */
11
10
  rulesFile: string;
12
11
  /** Rule ids disabled for this deployment. */
@@ -18,13 +17,11 @@ interface Config {
18
17
  /** Tool timeout budget in milliseconds. */
19
18
  timeoutMs: number;
20
19
  }
21
- declare const Config: Schema<Config>;
22
- //#endregion
23
- //#region src/index.d.ts
24
- declare const name = "dsh-paper-doc-adapter";
25
- declare const inject: string[];
20
+ export declare const Config: Schema<Config>;
21
+ export declare const name = "dsh-paper-doc-adapter";
22
+ export declare const inject: string[];
26
23
  /** Tool id exposed to the model, and the row id in `cordis.patch.yml`. */
27
- declare const TOOL_NAME = "paper_doc_adapter";
24
+ export declare const TOOL_NAME = "paper_doc_adapter";
28
25
  /**
29
26
  * Locate a package-owned file such as the rule pack.
30
27
  *
@@ -36,7 +33,7 @@ declare const TOOL_NAME = "paper_doc_adapter";
36
33
  * @returns the resolved absolute path.
37
34
  * @throws Error naming every location tried, when the file is absent.
38
35
  */
39
- declare function resolvePackageFile(relative: string): string;
36
+ export declare function resolvePackageFile(relative: string): string;
40
37
  /**
41
38
  * Register the checker tool.
42
39
  *
@@ -47,6 +44,4 @@ declare function resolvePackageFile(relative: string): string;
47
44
  * @param ctx - plugin context, with `tools` already available.
48
45
  * @param config - validated configuration.
49
46
  */
50
- declare function apply(ctx: Context, config: Config): () => void;
51
- //#endregion
52
- export { Config, TOOL_NAME, apply, inject, name, resolvePackageFile };
47
+ export declare function apply(ctx: Context, config: Config): () => void;
package/lib/index.mjs CHANGED
@@ -3,7 +3,7 @@ import { existsSync } from "node:fs";
3
3
  import { dirname, isAbsolute, resolve } from "node:path";
4
4
  import { defineTool } from "@deepseek-ai/dsh-tools";
5
5
  import Schema from "@deepseek-ai/schemastery";
6
- //#region src/config.ts
6
+ // src/config.ts
7
7
  const Config = Schema.object({
8
8
  rulesFile: Schema.string().default("rules/paper-doc-adapter.yaml").description("规则库文件路径(相对插件包根目录)。替换该文件即可切换规则集版本。"),
9
9
  disabledRules: Schema.array(Schema.string()).default([]).description("要停用的规则 id 列表;停用的规则会出现在报告的 skipped 中。"),
@@ -11,8 +11,7 @@ const Config = Schema.object({
11
11
  skipNotes: Schema.string().default("").description("附加到每条 skipped 说明后的备注,例如标注本机构实施细则。"),
12
12
  timeoutMs: Schema.number().default(12e4).description("工具协作式超时预算(毫秒)。")
13
13
  });
14
- //#endregion
15
- //#region src/shared/yaml.ts
14
+ // src/shared/yaml.ts
16
15
  /**
17
16
  * Minimal, dependency-free YAML reader for rule packs and check material.
18
17
  *
@@ -365,6 +364,10 @@ var Reader = class {
365
364
  if (!isSequenceItem(line.text)) break;
366
365
  this.index += 1;
367
366
  const rest = line.text === "-" ? "" : line.text.slice(2).trim();
367
+ if (rest.startsWith("{") || rest.startsWith("[")) {
368
+ items.push(parseScalar(rest, line.num));
369
+ continue;
370
+ }
368
371
  if ((rest === "" ? -1 : findKeySeparator(rest)) >= 0) {
369
372
  items.push(this.readMapping(indent + 2, {
370
373
  text: rest,
@@ -444,8 +447,7 @@ function requireString(source, key, where) {
444
447
  if (typeof value !== "string" || value.trim() === "") throw new YamlSubsetError(`${where}: missing required string field "${key}"`);
445
448
  return value;
446
449
  }
447
- //#endregion
448
- //#region src/shared/table.ts
450
+ // src/shared/table.ts
449
451
  /**
450
452
  * Generic reader for table-shaped check plugins.
451
453
  *
@@ -609,8 +611,7 @@ function canonicaliseRow(row, spec) {
609
611
  }
610
612
  return row;
611
613
  }
612
- //#endregion
613
- //#region src/shared/datetime.ts
614
+ // src/shared/datetime.ts
614
615
  const DATE_PATTERN = /^(\d{4})[-/.](\d{1,2})[-/.](\d{1,2})$/;
615
616
  const TIME_PATTERN = /^(\d{1,2}):(\d{2})(?::(\d{2}))?$/;
616
617
  function pad(value, width = 2) {
@@ -678,8 +679,7 @@ function instant(wall) {
678
679
  function diffMinutes(from, to) {
679
680
  return instant(to) - instant(from);
680
681
  }
681
- //#endregion
682
- //#region src/shared/report.ts
682
+ // src/shared/report.ts
683
683
  /** Locator fields that participate in the stable issue id, in fixed order. */
684
684
  const LOCATOR_ID_KEYS = [
685
685
  "file",
@@ -723,8 +723,7 @@ function sortValue(value) {
723
723
  }
724
724
  return target;
725
725
  }
726
- //#endregion
727
- //#region src/shared/rules.ts
726
+ // src/shared/rules.ts
728
727
  /**
729
728
  * Compose the one-line `basis` string rendered into reports.
730
729
  * @param basis - the rule's normative basis.
@@ -740,8 +739,7 @@ function formatBasis(basis, alsoBasis = []) {
740
739
  const parts = [render(basis), ...alsoBasis.map(render)];
741
740
  return parts.length === 1 ? parts[0] : `${parts[0]};另见 ${parts.slice(1).join(";另见 ")}`;
742
741
  }
743
- //#endregion
744
- //#region src/shared/rows.ts
742
+ // src/shared/rows.ts
745
743
  /**
746
744
  * The generic table-check engine.
747
745
  *
@@ -833,7 +831,7 @@ function optionalNumber(params, key) {
833
831
  function locatorOf(row, field) {
834
832
  const out = {};
835
833
  if (row !== void 0) out.row = row;
836
- if (field !== "") out.field = field;
834
+ if (field !== "") out.column = field;
837
835
  return out;
838
836
  }
839
837
  /**
@@ -1164,7 +1162,7 @@ function sumToConstant(ctx) {
1164
1162
  const total = parsed.reduce((sum, value) => sum + value, 0);
1165
1163
  const gap = Math.abs(total - target);
1166
1164
  if (gap <= tolerance) return;
1167
- ctx.add(locatorOf(void 0, field), `${parsed.length} 行的「${field}」合计 ${Number(total.toFixed(4))},与配置的目标值 ${target} 相差 ${Number(gap.toFixed(4))}`, `「${field}」的合计应为 ${target},允许偏差 ${tolerance}`, str(ctx.params, "fix", "核对是否有行遗漏或数值抄错;本条只做加法核对,不判断设置是否合规"));
1165
+ ctx.add(locatorOf(void 0, field), `${parsed.length} 行的「${field}」合计 ${Number(total.toFixed(4))},与配置的目标值 ${target} 相差 ${Number(gap.toFixed(4))}`, `「${field}」的合计应为 ${target},允许偏差 ${tolerance}`, str(ctx.params, "fix", "核对是否有行遗漏或数值抄错;本条只做加法核对,不评价分值设置本身"));
1168
1166
  }
1169
1167
  /** `countPerGroup` — each group value must appear at least N times. */
1170
1168
  function countPerGroup(ctx) {
@@ -2112,7 +2110,10 @@ function runChecks(input, ruleset, options) {
2112
2110
  const issues = [];
2113
2111
  const reasons = /* @__PURE__ */ new Map();
2114
2112
  const fired = /* @__PURE__ */ new Set();
2113
+ const disabled = /* @__PURE__ */ new Set([...ruleset.disabled, ...options.disabledRules]);
2114
+ const only = new Set(options.onlyRules);
2115
2115
  for (const rule of ruleset.rules) {
2116
+ if (disabled.has(rule.id) || only.size > 0 && !only.has(rule.id)) continue;
2116
2117
  const declaredCheck = typeof rule.params.check === "object" && rule.params.check !== null && !Array.isArray(rule.params.check) ? rule.params.check : {};
2117
2118
  const check = {
2118
2119
  ...rule.params,
@@ -2375,12 +2376,10 @@ function parseMaterial(source, target) {
2375
2376
  function runCheck(input, ruleset, options) {
2376
2377
  return runTableCheck(input, ruleset, options);
2377
2378
  }
2378
- //#endregion
2379
- //#region src/shared/wording.ts
2379
+ // src/shared/wording.ts
2380
2380
  /** Footer appended to every rendered report. */
2381
2381
  const DISCLAIMER = "免责声明:本报告由程序按声明的规则集自动生成,仅列出与所引条款之间的字面差异,供人工复核线索使用;不构成对任何事实、行为或文件的定性意见,也不替代主管人员、评审专家或监管机构的判断。规则集的时效性与适用范围以引用文件的最新有效版本为准。";
2382
- //#endregion
2383
- //#region src/view.ts
2382
+ // src/view.ts
2384
2383
  /**
2385
2384
  * Model-facing projection of a {@link Report}.
2386
2385
  *
@@ -2460,8 +2459,7 @@ function buildView(report) {
2460
2459
  reportJson: canonicalJson(report)
2461
2460
  };
2462
2461
  }
2463
- //#endregion
2464
- //#region src/shared/ruleset.ts
2462
+ // src/shared/ruleset.ts
2465
2463
  /**
2466
2464
  * Rule-pack loading and validation.
2467
2465
  *
@@ -2571,8 +2569,7 @@ function loadRuleset(source) {
2571
2569
  disabled
2572
2570
  };
2573
2571
  }
2574
- //#endregion
2575
- //#region src/shared/memo.ts
2572
+ // src/shared/memo.ts
2576
2573
  /**
2577
2574
  * Memoized loading of package-owned rule packs.
2578
2575
  *
@@ -2595,8 +2592,7 @@ function loadRulesetFile(path) {
2595
2592
  pending.catch(() => cache.delete(path));
2596
2593
  return pending;
2597
2594
  }
2598
- //#endregion
2599
- //#region src/index.ts
2595
+ // src/index.ts
2600
2596
  const name = "dsh-paper-doc-adapter";
2601
2597
  const inject = ["tools"];
2602
2598
  /** Tool id exposed to the model, and the row id in `cordis.patch.yml`. */
@@ -2733,5 +2729,4 @@ function apply(ctx, config) {
2733
2729
  }
2734
2730
  }));
2735
2731
  }
2736
- //#endregion
2737
2732
  export { Config, TOOL_NAME, apply, inject, name, resolvePackageFile };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-paper-doc-adapter",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "试卷解析结构核对(按题型、答案、分值与 yotta 标识核对试卷结构自洽,仅提示差异,不作出定性结论)",
5
5
  "type": "module",
6
6
  "main": "lib/index.mjs",
@@ -78,14 +78,14 @@
78
78
  "@deepseek-ai/schemastery": "^3.18.2"
79
79
  },
80
80
  "devDependencies": {
81
- "@deepseek-ai/cordis": "4.0.5-alpha.1",
82
- "@deepseek-ai/dsh-package-manifest": "0.2.1-rc.2",
81
+ "@deepseek-ai/cordis": "4.0.5",
82
+ "@deepseek-ai/dsh-package-manifest": "0.2.1-rc.3",
83
83
  "@deepseek-ai/dsh-tools": "0.2.1-rc.2",
84
- "@deepseek-ai/schemastery": "3.18.5-alpha.1",
84
+ "@deepseek-ai/schemastery": "3.18.5",
85
85
  "@types/node": "^22.20.1",
86
86
  "vitest": "^3.2.7",
87
87
  "@deepseek-ai/dsh-working-directory": "0.2.1-rc.2",
88
- "tsdown": "^0.22.14",
88
+ "tsdown": "^0.23.1",
89
89
  "typescript": "^5.9.3"
90
90
  },
91
91
  "dependencies": {}