dsh-medrec-qc 0.2.11 → 0.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -2,14 +2,200 @@
2
2
  Version 2.0, January 2004
3
3
  http://www.apache.org/licenses/
4
4
 
5
- Licensed under the Apache License, Version 2.0 (the "License");
6
- you may not use this file except in compliance with the License.
7
- You may obtain a copy of the License at
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8
6
 
9
- http://www.apache.org/licenses/LICENSE-2.0
7
+ 1. Definitions.
10
8
 
11
- Unless required by applicable law or agreed to in writing, software
12
- distributed under the License is distributed on an "AS IS" BASIS,
13
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- See the License for the specific language governing permissions and
15
- limitations under the License.
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright 2026 PerryLink
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/README-es.md CHANGED
@@ -8,6 +8,7 @@ dsh plugin --profile <name> add dsh-medrec-qc
8
8
 
9
9
 
10
10
  [![DSH Market](https://raw.githubusercontent.com/2BingLing/dsh-market/master/assets/readme/badge-listed-en.svg)](https://dsh.market/)
11
+ [![dshfind](https://dshfind.com/api/badge/PerryLink/dsh-medrec-qc?metric=downloads)](https://dshfind.com/en/plugins/PerryLink/dsh-medrec-qc?ref=badge)
11
12
 
12
13
  `dsh-medrec-qc` lee una exportación de la portada del historial clínico de hospitalización (病案首页), una fila por alta, con el juego de columnas de la exportación de evaluación nacional, de la estadística sanitaria o de una exportación local del hospital, y comprueba la completitud formal, la aritmética interna y la forma de codificación de esa misma exportación: que cada columna obligatoria tenga contenido o el marcador `-`, que las horas de ingreso y de alta estén presentes, sean precisas al minuto y no estén invertidas, que la estancia declarada coincida con las dos fechas, que el nombre y el código del diagnóstico principal y los de la operación principal se rellenen juntos, que los códigos tengan la forma escrita que configura el paquete de reglas, que las tres columnas de firma reflejen la responsabilidad médica de tres niveles, que el modo de alta sea uno de los códigos definidos, que la edad y los pesos neonatales usen las formas prescritas, que el número de otros diagnósticos no supere el techo configurado, y que se señalen para revisión humana un diagnóstico incompatible con el sexo registrado o dos horas discordantes en un alta por fallecimiento.
13
14
 
@@ -20,14 +21,52 @@ dsh --profile <name> --dump-config | grep 'dsh-medrec-qc'
20
21
 
21
22
  ## Cómo se ve la salida
22
23
 
23
- ![Terminal demo of dsh-medrec-qc: real output over its MR-009 fixture](https://raw.githubusercontent.com/PerryLink/dsh-medrec-qc/main/docs/assets/dsh-medrec-qc-hero.png)
24
+ ![Diagrama de flujo de dsh-medrec-qc: llamada → plugin → resultado.](docs/assets/dsh-medrec-qc-flow.svg)
25
+
26
+ *Resumen del flujo: llamada → plugin → resultado. Los ejemplos siguientes usan la superficie de comandos real.*
24
27
 
25
- ![Animated terminal demo of dsh-medrec-qc](https://raw.githubusercontent.com/PerryLink/dsh-medrec-qc/main/docs/assets/dsh-medrec-qc-demo.gif)
26
28
 
27
29
  Salida real de este plugin sobre su propio fixture de prueba `MR-009` — 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.
28
30
 
29
31
  ## Qué responde
30
32
 
33
+ ### Ejemplos
34
+
35
+ La tabla siguiente es el conjunto de ejemplos: la primera fila es el caso detallado y las demás son casos breves.
36
+
37
+ #### Salida detallada
38
+
39
+ **Herramienta** `medrec_qc`
40
+
41
+ **Entrada**
42
+
43
+ ~~~yaml
44
+ target: 2026 年 3 月出院病案首页导出
45
+ cases:
46
+ - row: 1
47
+ 病案号: ""
48
+ 入院时间: "2026-03-01 08:30"
49
+ 出院时间: "2026-03-06 10:00"
50
+ ~~~
51
+
52
+ **Salida**
53
+
54
+ ~~~json
55
+ {
56
+ "id": "dsh-medrec-qc.MR-001.a58905f0",
57
+ "ruleId": "MR-001",
58
+ "severity": "error",
59
+ "locator": {
60
+ "row": 1,
61
+ "column": "病案号"
62
+ },
63
+ "found": "「病案号」为空",
64
+ "expected": "附件1 必填栏不能为空项,没有可填写内容时填写\"-\""
65
+ }
66
+ ~~~
67
+
68
+ *Observado en `dsh-medrec-qc/tests/fixtures/MR-001/MR-001-unsafe.yaml`*
69
+
31
70
  | Usted pregunta | Qué responde |
32
71
  |---|---|
33
72
  | Una columna obligatoria está vacía, pero escribí `-` en ella. ¿Se informa de eso? | No. `MR-001` considera un `-` aislado la marca de «no hay nada que registrar» e informa solo de las columnas realmente vacías. Comprueba que la columna obligatoria tenga contenido, no que el contenido sea correcto. Es un `error`: la nota al pie del anexo 1 del documento 24号文 se leyó literalmente el **2026-10-13** (el anexo **tiene capa de texto**: 328 páginas, 205 847 caracteres extraíbles, **sin OCR**), y dice 「注:必填栏不能为空项,没有可填写内容时填写“-”」. ⚠️ `www.nhc.gov.cn` devuelve **HTTP 412** a las peticiones automáticas, así que el texto se leyó de una **recopilación del Centro de Control de Calidad de Historias Clínicas de Henan** — la misma URL que el `source` de esta regla siempre ha llevado; véase `rules/evidence/clause-verification-homepage-attachment1.md`. Ese mismo `-` sigue contando como firma ausente en `MR-009`. |
@@ -108,6 +147,10 @@ node ../scripts/sync-shared.mjs dsh-medrec-qc
108
147
 
109
148
  El último comando copia el kit compartido de `../_shared` a `src/shared/`; vuelva a ejecutarlo tras cada cambio compartido.
110
149
 
150
+ ## PerryLink DSH Plugin Family
151
+
152
+ 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.
153
+
111
154
  ## License
112
155
 
113
156
  [Apache License 2.0](LICENSE) © 2026 dsh-medrec-qc contributors.
package/README-hi.md CHANGED
@@ -8,6 +8,7 @@ dsh plugin --profile <name> add dsh-medrec-qc
8
8
 
9
9
 
10
10
  [![DSH Market](https://raw.githubusercontent.com/2BingLing/dsh-market/master/assets/readme/badge-listed-en.svg)](https://dsh.market/)
11
+ [![dshfind](https://dshfind.com/api/badge/PerryLink/dsh-medrec-qc?metric=downloads)](https://dshfind.com/en/plugins/PerryLink/dsh-medrec-qc?ref=badge)
11
12
 
12
13
  `dsh-medrec-qc` भर्ती रोगी के मेडिकल रिकॉर्ड की फ्रंट शीट (病案首页) के एक्सपोर्ट को पढ़ता है, जिसमें प्रत्येक डिस्चार्ज की एक पंक्ति होती है और कॉलम-सेट राष्ट्रीय मूल्यांकन एक्सपोर्ट, स्वास्थ्य सांख्यिकी एक्सपोर्ट या अस्पताल के स्थानीय एक्सपोर्ट का हो सकता है, और उसी एक्सपोर्ट की रूप-पूर्णता, आंतरिक अंकगणित तथा कोडन-रूप की जाँच करता है: हर अनिवार्य कॉलम में सामग्री या `-` चिह्न हो, भर्ती और डिस्चार्ज का समय दर्ज हो, मिनट तक सटीक हो और उलटा न हो, दर्ज ठहराव-अवधि दोनों तारीख़ों से मेल खाए, मुख्य निदान का नाम और कोड तथा मुख्य ऑपरेशन का नाम और कोड साथ-साथ भरे गए हों, कोड उस लिखित रूप में हों जो नियम-पैक कॉन्फ़िगर करता है, तीन हस्ताक्षर कॉलम त्रि-स्तरीय चिकित्सक उत्तरदायित्व दर्शाते हों, डिस्चार्ज मोड निर्धारित कोड में से हो, आयु और नवजात का वज़न निर्धारित रूपों में हों, अन्य निदानों की संख्या कॉन्फ़िगर की गई सीमा के भीतर हो, और दर्ज लिंग से असंगत निदान अथवा मृत्यु-डिस्चार्ज में परस्पर भिन्न दो समय मानवीय समीक्षा के लिए सामने लाए जाएँ।
13
14
 
@@ -20,14 +21,52 @@ dsh --profile <name> --dump-config | grep 'dsh-medrec-qc'
20
21
 
21
22
  ## आउटपुट कैसा दिखता है
22
23
 
23
- ![Terminal demo of dsh-medrec-qc: real output over its MR-009 fixture](https://raw.githubusercontent.com/PerryLink/dsh-medrec-qc/main/docs/assets/dsh-medrec-qc-hero.png)
24
+ ![dsh-medrec-qc कार्यप्रवाह आरेख: कॉल → प्लगइन → परिणाम।](docs/assets/dsh-medrec-qc-flow.svg)
25
+
26
+ *कार्यप्रवाह: कॉल → प्लगइन → परिणाम। नीचे के उदाहरण वास्तविक कमांड सतह का उपयोग करते हैं।*
24
27
 
25
- ![Animated terminal demo of dsh-medrec-qc](https://raw.githubusercontent.com/PerryLink/dsh-medrec-qc/main/docs/assets/dsh-medrec-qc-demo.gif)
26
28
 
27
29
  इस प्लगइन का अपने ही `MR-009` टेस्ट फ़िक्स्चर पर वास्तविक आउटपुट — कोई नकली चित्र नहीं। नियम-पैक उद्धरण नहीं गढ़ता, इसलिए हर निष्कर्ष लागू किए गए खंड का नाम और यह भी बताता है कि उसका मूल पाठ इस बार प्राप्त नहीं हुआ।
28
30
 
29
31
  ## यह किन सवालों का जवाब देता है
30
32
 
33
+ ### उदाहरण
34
+
35
+ नीचे दी गई तालिका उदाहरण-समुच्चय है: पहली पंक्ति विस्तृत केस है, बाकी संक्षिप्त केस हैं।
36
+
37
+ #### विस्तृत आउटपुट
38
+
39
+ **उपकरण** `medrec_qc`
40
+
41
+ **इनपुट**
42
+
43
+ ~~~yaml
44
+ target: 2026 年 3 月出院病案首页导出
45
+ cases:
46
+ - row: 1
47
+ 病案号: ""
48
+ 入院时间: "2026-03-01 08:30"
49
+ 出院时间: "2026-03-06 10:00"
50
+ ~~~
51
+
52
+ **आउटपुट**
53
+
54
+ ~~~json
55
+ {
56
+ "id": "dsh-medrec-qc.MR-001.a58905f0",
57
+ "ruleId": "MR-001",
58
+ "severity": "error",
59
+ "locator": {
60
+ "row": 1,
61
+ "column": "病案号"
62
+ },
63
+ "found": "「病案号」为空",
64
+ "expected": "附件1 必填栏不能为空项,没有可填写内容时填写\"-\""
65
+ }
66
+ ~~~
67
+
68
+ *स्रोत `dsh-medrec-qc/tests/fixtures/MR-001/MR-001-unsafe.yaml`*
69
+
31
70
  | आपका सवाल | इसका जवाब |
32
71
  |---|---|
33
72
  | कोई अनिवार्य कॉलम खाली छूटा है, पर मैंने उसमें `-` लिखा है। क्या यह दर्ज होगा? | नहीं। `MR-001` अकेले `-` को «यहाँ दर्ज करने योग्य कुछ नहीं» का चिह्न मानता है और केवल सचमुच खाली छूटे कॉलम दर्ज करता है। यह देखता है कि अनिवार्य कॉलम में सामग्री है, यह नहीं कि सामग्री सही है। यह `error` है: 24号文 के अनुलग्नक 1 की अंतिम टिप्पणी **2026-10-13** को शब्दशः प्राप्त हुई (अनुलग्नक में **पाठ-परत है**: 328 पृष्ठ, 205,847 वर्ण निकाले जा सकते हैं, **OCR का प्रयोग नहीं**), और वह है 「注:必填栏不能为空项,没有可填写内容时填写“-”」。⚠️ `www.nhc.gov.cn` स्वचालित अनुरोधों पर **HTTP 412** लौटाता है, इसलिए पाठ **हेनान प्रांतीय मेडिकल रिकॉर्ड गुणवत्ता नियंत्रण केंद्र** के संकलन से पढ़ा गया — वही URL जो इस नियम के `source` में पहले से है; देखें `rules/evidence/clause-verification-homepage-attachment1.md`। वही `-` `MR-009` में हस्ताक्षर अनुपस्थित ही गिना जाता है। |
@@ -108,6 +147,10 @@ node ../scripts/sync-shared.mjs dsh-medrec-qc
108
147
 
109
148
  अंतिम कमांड `../_shared` का साझा किट `src/shared/` में कॉपी करता है; हर साझा बदलाव के बाद इसे दोबारा चलाएँ।
110
149
 
150
+ ## PerryLink DSH Plugin Family
151
+
152
+ 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.
153
+
111
154
  ## License
112
155
 
113
156
  [Apache License 2.0](LICENSE) © 2026 dsh-medrec-qc contributors.
package/README-pt.md CHANGED
@@ -8,6 +8,7 @@ dsh plugin --profile <name> add dsh-medrec-qc
8
8
 
9
9
 
10
10
  [![DSH Market](https://raw.githubusercontent.com/2BingLing/dsh-market/master/assets/readme/badge-listed-en.svg)](https://dsh.market/)
11
+ [![dshfind](https://dshfind.com/api/badge/PerryLink/dsh-medrec-qc?metric=downloads)](https://dshfind.com/en/plugins/PerryLink/dsh-medrec-qc?ref=badge)
11
12
 
12
13
  `dsh-medrec-qc` lê uma exportação da folha de rosto do registo clínico de internamento (病案首页), uma linha por alta, com o conjunto de colunas da exportação de avaliação nacional, da estatística sanitária ou de uma exportação local do hospital, e verifica a completude formal, a aritmética interna e a forma de codificação dessa mesma exportação: que cada coluna obrigatória tenha conteúdo ou o marcador `-`, que as horas de admissão e de alta estejam preenchidas, sejam precisas ao minuto e não estejam invertidas, que o tempo de internamento declarado coincida com as duas datas, que o nome e o código do diagnóstico principal e os da operação principal sejam preenchidos em conjunto, que os códigos tenham a forma escrita que o pacote de regras configura, que as três colunas de assinatura reflitam a responsabilidade médica de três níveis, que o modo de alta seja um dos códigos definidos, que a idade e os pesos neonatais usem as formas prescritas, que o número de outros diagnósticos não exceda o limite configurado, e que sejam assinalados para revisão humana um diagnóstico incompatível com o sexo registado ou duas horas discordantes numa alta por óbito.
13
14
 
@@ -20,14 +21,52 @@ dsh --profile <name> --dump-config | grep 'dsh-medrec-qc'
20
21
 
21
22
  ## Como é a saída
22
23
 
23
- ![Terminal demo of dsh-medrec-qc: real output over its MR-009 fixture](https://raw.githubusercontent.com/PerryLink/dsh-medrec-qc/main/docs/assets/dsh-medrec-qc-hero.png)
24
+ ![Diagrama de fluxo de dsh-medrec-qc: chamada → plugin → resultado.](docs/assets/dsh-medrec-qc-flow.svg)
25
+
26
+ *Visão geral do fluxo: chamada → plugin → resultado. Os exemplos abaixo usam a superfície real de comandos.*
24
27
 
25
- ![Animated terminal demo of dsh-medrec-qc](https://raw.githubusercontent.com/PerryLink/dsh-medrec-qc/main/docs/assets/dsh-medrec-qc-demo.gif)
26
28
 
27
29
  Saída real deste plugin sobre o seu próprio fixture de teste `MR-009` — 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.
28
30
 
29
31
  ## O que ele responde
30
32
 
33
+ ### Exemplos
34
+
35
+ A tabela abaixo é o conjunto de exemplos: a primeira linha é o caso detalhado e as demais são casos curtos.
36
+
37
+ #### Saída detalhada
38
+
39
+ **Ferramenta** `medrec_qc`
40
+
41
+ **Entrada**
42
+
43
+ ~~~yaml
44
+ target: 2026 年 3 月出院病案首页导出
45
+ cases:
46
+ - row: 1
47
+ 病案号: ""
48
+ 入院时间: "2026-03-01 08:30"
49
+ 出院时间: "2026-03-06 10:00"
50
+ ~~~
51
+
52
+ **Saída**
53
+
54
+ ~~~json
55
+ {
56
+ "id": "dsh-medrec-qc.MR-001.a58905f0",
57
+ "ruleId": "MR-001",
58
+ "severity": "error",
59
+ "locator": {
60
+ "row": 1,
61
+ "column": "病案号"
62
+ },
63
+ "found": "「病案号」为空",
64
+ "expected": "附件1 必填栏不能为空项,没有可填写内容时填写\"-\""
65
+ }
66
+ ~~~
67
+
68
+ *Observado em `dsh-medrec-qc/tests/fixtures/MR-001/MR-001-unsafe.yaml`*
69
+
31
70
  | Você pergunta | O que ele responde |
32
71
  |---|---|
33
72
  | Uma coluna obrigatória ficou vazia, mas escrevi `-` nela. Isso é reportado? | Não. `MR-001` considera um `-` isolado a marca de «não há nada a registar» e reporta apenas as colunas realmente vazias. Verifica que a coluna obrigatória tem conteúdo, não que o conteúdo está correto. É um `error`: a nota de rodapé do anexo 1 do documento 24号文 foi lida literalmente em **2026-10-13** (o anexo **tem camada de texto**: 328 páginas, 205 847 caracteres extraíveis, **sem OCR**), e diz 「注:必填栏不能为空项,没有可填写内容时填写“-”」. ⚠️ `www.nhc.gov.cn` devolve **HTTP 412** a pedidos automáticos, pelo que o texto foi lido de uma **compilação do Centro de Controlo de Qualidade de Processos Clínicos de Henan** — o próprio URL que o `source` desta regra sempre indicou; ver `rules/evidence/clause-verification-homepage-attachment1.md`. Esse mesmo `-` continua a contar como assinatura em falta em `MR-009`. |
@@ -108,6 +147,10 @@ node ../scripts/sync-shared.mjs dsh-medrec-qc
108
147
 
109
148
  O último comando copia o kit compartilhado de `../_shared` para `src/shared/`; execute-o novamente após cada alteração compartilhada.
110
149
 
150
+ ## PerryLink DSH Plugin Family
151
+
152
+ 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.
153
+
111
154
  ## License
112
155
 
113
156
  [Apache License 2.0](LICENSE) © 2026 dsh-medrec-qc contributors.
package/README-zh.md CHANGED
@@ -1,8 +1,27 @@
1
1
  # dsh-medrec-qc — 病案首页形式质控与逻辑矛盾提示
2
2
 
3
+ ### 快速试跑(1 分钟)
4
+
5
+ ```bash
6
+ node samples/quickstart/run.mjs --check
7
+ ```
8
+
9
+ 样例在 `samples/quickstart/input/`,期望输出在 `samples/quickstart/expected/result.json`;截图见 `docs/assets/quickstart.png`。
10
+
11
+
3
12
  [English](README.md) · [简体中文](README-zh.md) · [Español](README-es.md) · [Português](README-pt.md) · [हिन्दी](README-hi.md)
4
13
 
14
+ <!-- topblock:v1 -->
15
+ > **这是什么** 病案首页形式质控与逻辑矛盾提示。输出一份「哪一行、哪一栏、差什么」的清单。
16
+ > **给谁用** 病案室、质控科;不用懂命令行。
17
+ > **你交什么** 这项核对用到的原始材料(表格、清单或文书);不改原件。Excel 可先转成 JSON/YAML,对话里也能代转。
18
+ > **它不做什么** 不判合规、不认定责任、不替代审核人;只列材料内部能逐条指认的差异。
19
+ > **怎么开始** 在 WorkBuddy / 扣子搜「医疗文书质控包」(本检查是其中一项;上架以商城为准);或命令行:
20
+ > `dsh plugin --profile <name> add dsh-medrec-qc`
21
+ <!-- /topblock:v1 -->
22
+
5
23
  [![DSH Market](https://raw.githubusercontent.com/2BingLing/dsh-market/master/assets/readme/badge-listed-en.svg)](https://dsh.market/)
24
+ [![dshfind](https://dshfind.com/api/badge/PerryLink/dsh-medrec-qc?metric=downloads)](https://dshfind.com/en/plugins/PerryLink/dsh-medrec-qc?ref=badge)
6
25
 
7
26
  `dsh-medrec-qc` 读取一份住院病案首页导出表,每行一例出院病例,列名可以是国家绩效考核导出、卫生统计导出或医院本地导出的写法,核对这份材料自身的形式齐备、内部算术与编码形式:必填栏目是否有内容或按规范填写 `-`、入院时间与出院时间是否填写且精确到分钟且前后不倒置、填写的实际住院天数是否与两个日期一致、主要诊断的名称与编码以及主要手术的名称与编码是否同时填写、编码是否符合规则库配置的书写形式、三级医师签名栏是否齐全、离院方式是否为规定代码、年龄与新生儿体重是否使用规定形式、其他诊断条数是否在配置上限内,以及诊断与性别不相容、死亡病例两条时间不一致等需人工核实的情形是否被列出。
8
27
 
@@ -15,14 +34,52 @@ dsh --profile <name> --dump-config | grep 'dsh-medrec-qc'
15
34
 
16
35
  ## 实际输出长什么样
17
36
 
18
- ![Terminal demo of dsh-medrec-qc: real output over its MR-009 fixture](https://raw.githubusercontent.com/PerryLink/dsh-medrec-qc/main/docs/assets/dsh-medrec-qc-hero.png)
37
+ ![dsh-medrec-qc 工作流图:调用 → 插件 → 结果。](docs/assets/dsh-medrec-qc-flow.svg)
38
+
39
+ *工作流概览:调用 → 插件 → 结果。下面的示例使用实际命令面。*
19
40
 
20
- ![Animated terminal demo of dsh-medrec-qc](https://raw.githubusercontent.com/PerryLink/dsh-medrec-qc/main/docs/assets/dsh-medrec-qc-demo.gif)
21
41
 
22
42
  本插件对自己 `MR-009` 测试夹具的**真实输出**,不是示意图。规则库不伪造引文,因此每条发现都会同时写明所引条款,以及该条款原文本次未取得。
23
43
 
24
44
  ## 它回答什么问题
25
45
 
46
+ ### 示例
47
+
48
+ 下表是示例集:第一行是详细走查,其余行是简短案例。
49
+
50
+ #### 详细输出
51
+
52
+ **工具** `medrec_qc`
53
+
54
+ **输入**
55
+
56
+ ~~~yaml
57
+ target: 2026 年 3 月出院病案首页导出
58
+ cases:
59
+ - row: 1
60
+ 病案号: ""
61
+ 入院时间: "2026-03-01 08:30"
62
+ 出院时间: "2026-03-06 10:00"
63
+ ~~~
64
+
65
+ **输出**
66
+
67
+ ~~~json
68
+ {
69
+ "id": "dsh-medrec-qc.MR-001.a58905f0",
70
+ "ruleId": "MR-001",
71
+ "severity": "error",
72
+ "locator": {
73
+ "row": 1,
74
+ "column": "病案号"
75
+ },
76
+ "found": "「病案号」为空",
77
+ "expected": "附件1 必填栏不能为空项,没有可填写内容时填写\"-\""
78
+ }
79
+ ~~~
80
+
81
+ *来源 `dsh-medrec-qc/tests/fixtures/MR-001/MR-001-unsafe.yaml`*
82
+
26
83
  | 你会问 | 它怎么答 |
27
84
  |---|---|
28
85
  | 某个必填栏目是空的,但我填了 `-`,会被报出来吗? | 不会。`MR-001` 把单独一个 `-` 视为「没有可填写内容」的标注,只报真正留空的栏目。它核对的是必填栏目有没有内容,不判断内容填得对不对。本条为 `error`:24 号文附件1 的表末注释已于 **2026-10-13 逐字取得**(该附件**有文字层**,328 页、205,847 字符可提取,**未使用 OCR**),原文为「注:必填栏不能为空项,没有可填写内容时填写“-”」。⚠️ 发布机关 `www.nhc.gov.cn` 对自动访问返回 **HTTP 412**,本次采用的是**河南省病案质量控制中心的汇编件**——即本条 `source` 一直指向的那份文件;详见 `rules/evidence/clause-verification-homepage-attachment1.md`。同一个 `-` 在 `MR-009` 里仍然算签名缺失。 |
@@ -41,12 +98,7 @@ dsh --profile <name> --dump-config | grep 'dsh-medrec-qc'
41
98
  | 《卫生部关于修订住院病案首页的通知》 | 卫医政发〔2011〕84号 | MR-004, MR-009, MR-010, MR-011, MR-012 |
42
99
  | 国家医疗保障局"两库"知识点(诊断与患者性别不符) | 国家医疗保障局公告(第二十一批) | MR-014 |
43
100
 
44
- **Boundary:** this plugin checks the **front sheet of the inpatient medical record (病案首页)** — the
45
- one-page discharge summary coders and the national assessment system read — for form completeness,
46
- internal contradictions and coding form. It is not `dsh-nurse-record-check` (which checks nursing
47
- documentation timeliness), not `dsh-icd-rule-check` (which checks ICD coding rules and dagger/asterisk
48
- pairing), and it does not judge whether a diagnosis was clinically correct. It reads an export of the
49
- front sheet and reports literal mismatches against cited clauses.
101
+ **边界(中文译文,以英文原文为准):** 本插件核对**住院病案首页**——编码员与国家考核体系所阅读的那一页出院摘要——的表格完整性、内部矛盾与编码形态。它不是 `dsh-nurse-record-check`(后者核对护理文书的及时性),不是 `dsh-icd-rule-check`(后者核对 ICD 编码规则与剑号/星号配对),也不判定诊断在临床上是否正确。它读取病案首页的导出数据,并报出与所引条款之间的字面不符。
50
102
 
51
103
  ## Compatibility
52
104
 
@@ -103,6 +155,10 @@ node ../scripts/sync-shared.mjs dsh-medrec-qc
103
155
 
104
156
  第 4 项把 `../_shared` 的共享件同步进 `src/shared/`;每次改动共享件后都要重跑。
105
157
 
158
+ ## PerryLink DSH Plugin Family
159
+
160
+ 完整清单(62 个核查器 + 通用插件)见 [按材料选核查器](https://perrylink.github.io/zh/checkers/choose/);本仓只是其中一个。
161
+
106
162
  ## License
107
163
 
108
164
  [Apache License 2.0](LICENSE) © 2026 dsh-medrec-qc contributors.
package/README.md CHANGED
@@ -2,12 +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
- ```sh
6
- dsh plugin --profile <name> add dsh-medrec-qc
7
- ```
8
-
5
+ <!-- topblock:v1 -->
6
+ > **What it is** — Form check and logic-contradiction prompts for the inpatient medical record front sheet. It returns a list of what is inconsistent, where, and what to fix.
7
+ > **Who it is for** — medical records and quality control; 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 "Medical Record QC Suite" in WorkBuddy / Coze (this check is one part of it; availability as listed); or:
11
+ > `dsh plugin --profile <name> add dsh-medrec-qc`
12
+ <!-- /topblock:v1 -->
9
13
 
10
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-medrec-qc?metric=downloads)](https://dshfind.com/en/plugins/PerryLink/dsh-medrec-qc?ref=badge)
11
16
 
12
17
  `dsh-medrec-qc` reads an export of the inpatient medical record front sheet (病案首页), one row per discharge, in the column set of the national assessment export, the health statistics export or a hospital-local export, and checks that export's own form completeness, internal arithmetic and coding form: that each required column carries content or the `-` marker, that the admission and discharge times are present, precise to the minute and not in the wrong order, that the declared length of stay agrees with the two dates, that the primary diagnosis name and code and the primary operation name and code are filled together, that the codes have the written form the pack configures, that the three signature columns reflect three-level physician responsibility, that the discharge mode is one of the defined codes, that the age and the neonatal weights use the prescribed forms, that the count of other diagnoses stays within the configured ceiling, and that a diagnosis incompatible with the recorded sex or two disagreeing times in a death discharge are surfaced for human review.
13
18
 
@@ -20,14 +25,51 @@ dsh --profile <name> --dump-config | grep 'dsh-medrec-qc'
20
25
 
21
26
  ## What it looks like
22
27
 
23
- ![Terminal demo of dsh-medrec-qc: real output over its MR-009 fixture](https://raw.githubusercontent.com/PerryLink/dsh-medrec-qc/main/docs/assets/dsh-medrec-qc-hero.png)
28
+ ![Workflow diagram for dsh-medrec-qc: call → plugin → result.](docs/assets/dsh-medrec-qc-flow.svg)
29
+
30
+ *Workflow overview: call → plugin → result. The examples below use the real command surface.*
24
31
 
25
- ![Animated terminal demo of dsh-medrec-qc](https://raw.githubusercontent.com/PerryLink/dsh-medrec-qc/main/docs/assets/dsh-medrec-qc-demo.gif)
26
32
 
27
- Real output from this plugin over its own `MR-009` 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.
28
33
 
29
34
  ## What it answers
30
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** `medrec_qc`
43
+
44
+ **Input**
45
+
46
+ ~~~yaml
47
+ target: 2026 年 3 月出院病案首页导出
48
+ cases:
49
+ - row: 1
50
+ 病案号: ""
51
+ 入院时间: "2026-03-01 08:30"
52
+ 出院时间: "2026-03-06 10:00"
53
+ ~~~
54
+
55
+ **Output**
56
+
57
+ ~~~json
58
+ {
59
+ "id": "dsh-medrec-qc.MR-001.a58905f0",
60
+ "ruleId": "MR-001",
61
+ "severity": "error",
62
+ "locator": {
63
+ "row": 1,
64
+ "column": "病案号"
65
+ },
66
+ "found": "「病案号」为空",
67
+ "expected": "附件1 必填栏不能为空项,没有可填写内容时填写\"-\""
68
+ }
69
+ ~~~
70
+
71
+ *Observed from `dsh-medrec-qc/tests/fixtures/MR-001/MR-001-unsafe.yaml`*
72
+
31
73
  | You ask | What it answers |
32
74
  |---|---|
33
75
  | A required column is left empty, but I typed `-` in it. Is that reported? | No. `MR-001` treats a lone `-` as the marker for 'nothing to record here' and reports only the columns that are truly blank. It checks that a required column carries content, not that the content is correct. It is an `error` because 附件1's note now **has** been read verbatim (2026-10-13) — see the note below. The same `-` still counts as a missing signature under `MR-009`. |
@@ -230,6 +272,10 @@ pnpm run build # tsdown -> lib/index.mjs + lib/index.d.mts
230
272
  node ../scripts/sync-shared.mjs dsh-medrec-qc # refresh src/shared from ../_shared
231
273
  ```
232
274
 
275
+ ## PerryLink DSH Plugin Family
276
+
277
+ 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.
278
+
233
279
  ## License
234
280
 
235
281
  [Apache License 2.0](LICENSE) © 2026 dsh-medrec-qc contributors.
@@ -0,0 +1,34 @@
1
+ # Troubleshooting `dsh-medrec-qc`
2
+
3
+ ## The package is not found or refuses to install
4
+
5
+ - This checker targets DSH `>=0.2.1-0 <0.3.0` and Node `^22.19.0 || >=24.0.0`.
6
+ - Install it through the profile closure: `dsh plugin --profile <name> add dsh-medrec-qc`.
7
+ - If npm reports a peer conflict, check the host line first; do not force-install an older DSH core.
8
+
9
+ ## It installs, but I see no findings
10
+
11
+ - The checker only reports what it can decide from the document you pass to its tool.
12
+ - Confirm the tool ran and returned a result; an empty result is not the same as a skipped run.
13
+ - Check the document's required columns/fields against the checker's README table. Missing input is usually reported as `skipped`, not as a guessed finding.
14
+
15
+ ## A finding says the clause text was not obtained
16
+
17
+ - The rule pack follows a citation gate: it never invents clause text.
18
+ - When the exact text is unavailable, the finding stays at `warn`/`info` and says so in its `excerpt`.
19
+ - Treat that as a verification gap, not as proof that the document is compliant.
20
+
21
+ ## Everything is `warn` or `info`
22
+
23
+ - By design, this checker does not make a legal, medical, customs, or safety determination.
24
+ - It reports differences and gaps; a human owner decides what to do with them.
25
+
26
+ ## Reporting a bug
27
+
28
+ Open an issue at `https://github.com/PerryLink/dsh-medrec-qc/issues` with:
29
+
30
+ - the checker version and DSH host version;
31
+ - the command or tool call you used;
32
+ - a minimal, redacted input and the actual vs expected result.
33
+
34
+ Never paste credentials, tokens, personal data, or sealed evidence bytes into an issue.
@@ -0,0 +1,19 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1200" height="360" viewBox="0 0 1200 360" role="img" aria-label="dsh-medrec-qc workflow">
2
+ <title>dsh-medrec-qc workflow</title>
3
+ <rect width="1200" height="360" rx="18" fill="#0d1117"/>
4
+ <text x="60" y="58" fill="#f0f6fc" font-family="ui-sans-serif,system-ui,sans-serif" font-size="30" font-weight="700">dsh-medrec-qc</text>
5
+ <text x="60" y="92" fill="#8b949e" font-family="ui-monospace,monospace" font-size="16">DeepSeek Harness plugin</text>
6
+ <line x1="60" y1="118" x2="1140" y2="118" stroke="#30363d"/>
7
+ <rect x="120" y="150" width="240" height="140" rx="14" fill="#161b22" stroke="#2563eb" stroke-width="2"/>
8
+ <rect x="213" y="185" width="54" height="66" rx="8" fill="none" stroke="#2563eb" stroke-width="3"/><path d="M226 205h28M226 217h28M226 229h18" stroke="#2563eb" stroke-width="3" stroke-linecap="round"/>
9
+ <circle cx="330" cy="270" r="13" fill="#2563eb"/><text x="330" y="276" fill="#0d1117" text-anchor="middle" font-family="ui-monospace,monospace" font-size="14" font-weight="700">1</text>
10
+ <path d="M368 220h64" stroke="#2563eb" stroke-width="3"/><path d="M422 213l10 7-10 7" fill="none" stroke="#2563eb" stroke-width="3" stroke-linecap="round"/>
11
+ <rect x="480" y="150" width="240" height="140" rx="14" fill="#161b22" stroke="#2563eb" stroke-width="2"/>
12
+ <path d="M577 203h46M577 219h46M577 235h46" stroke="#2563eb" stroke-width="3" stroke-linecap="round"/><circle cx="591" cy="203" r="6" fill="#2563eb"/><circle cx="611" cy="219" r="6" fill="#2563eb"/><circle cx="597" cy="235" r="6" fill="#2563eb"/>
13
+ <circle cx="690" cy="270" r="13" fill="#2563eb"/><text x="690" y="276" fill="#0d1117" text-anchor="middle" font-family="ui-monospace,monospace" font-size="14" font-weight="700">2</text>
14
+ <path d="M728 220h64" stroke="#2563eb" stroke-width="3"/><path d="M782 213l10 7-10 7" fill="none" stroke="#2563eb" stroke-width="3" stroke-linecap="round"/>
15
+ <rect x="840" y="150" width="240" height="140" rx="14" fill="#161b22" stroke="#2563eb" stroke-width="2"/>
16
+ <circle cx="960" cy="218" r="28" fill="none" stroke="#2563eb" stroke-width="3"/><path d="M947 219l9 9 18-20" fill="none" stroke="#2563eb" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
17
+ <circle cx="1050" cy="270" r="13" fill="#2563eb"/><text x="1050" y="276" fill="#0d1117" text-anchor="middle" font-family="ui-monospace,monospace" font-size="14" font-weight="700">3</text>
18
+ <text x="60" y="332" fill="#8b949e" font-family="ui-monospace,monospace" font-size="14">PerryLink DSH plugin family · Apache-2.0</text>
19
+ </svg>
@@ -0,0 +1,3 @@
1
+ $ node samples/quickstart/run.mjs
2
+ medrec_qc: 1 issue(s) — error 1, warn 0, info 0
3
+ skipped: 14
Binary file
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-medrec-qc";
25
- declare const inject: string[];
20
+ export declare const Config: Schema<Config>;
21
+ export declare const name = "dsh-medrec-qc";
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 = "medrec_qc";
24
+ export declare const TOOL_NAME = "medrec_qc";
28
25
  /**
29
26
  * Locate a package-owned file such as the rule pack.
30
27
  *
@@ -36,7 +33,7 @@ declare const TOOL_NAME = "medrec_qc";
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/medrec-qc.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/datetime.ts
14
+ // src/shared/datetime.ts
16
15
  const DATE_PATTERN = /^(\d{4})[-/.](\d{1,2})[-/.](\d{1,2})$/;
17
16
  const TIME_PATTERN = /^(\d{1,2}):(\d{2})(?::(\d{2}))?$/;
18
17
  function pad(value, width = 2) {
@@ -72,8 +71,7 @@ function dayNumber(date) {
72
71
  function diffDays(from, to) {
73
72
  return dayNumber(to) - dayNumber(from);
74
73
  }
75
- //#endregion
76
- //#region src/shared/rules.ts
74
+ // src/shared/rules.ts
77
75
  /**
78
76
  * Compose the one-line `basis` string rendered into reports.
79
77
  * @param basis - the rule's normative basis.
@@ -103,8 +101,7 @@ function disabledAsSkipped(ruleset, disabledIds, reason) {
103
101
  reason
104
102
  }));
105
103
  }
106
- //#endregion
107
- //#region src/shared/yaml.ts
104
+ // src/shared/yaml.ts
108
105
  /**
109
106
  * Minimal, dependency-free YAML reader for rule packs and check material.
110
107
  *
@@ -457,6 +454,10 @@ var Reader = class {
457
454
  if (!isSequenceItem(line.text)) break;
458
455
  this.index += 1;
459
456
  const rest = line.text === "-" ? "" : line.text.slice(2).trim();
457
+ if (rest.startsWith("{") || rest.startsWith("[")) {
458
+ items.push(parseScalar(rest, line.num));
459
+ continue;
460
+ }
460
461
  if ((rest === "" ? -1 : findKeySeparator(rest)) >= 0) {
461
462
  items.push(this.readMapping(indent + 2, {
462
463
  text: rest,
@@ -536,8 +537,7 @@ function requireString(source, key, where) {
536
537
  if (typeof value !== "string" || value.trim() === "") throw new YamlSubsetError(`${where}: missing required string field "${key}"`);
537
538
  return value;
538
539
  }
539
- //#endregion
540
- //#region src/shared/ruleset.ts
540
+ // src/shared/ruleset.ts
541
541
  /**
542
542
  * Rule-pack loading and validation.
543
543
  *
@@ -667,8 +667,7 @@ function paramStrings(rule, key, fallback) {
667
667
  if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) throw new YamlSubsetError(`rule ${rule.id}: params.${key} must be a list of strings`);
668
668
  return value;
669
669
  }
670
- //#endregion
671
- //#region src/shared/report.ts
670
+ // src/shared/report.ts
672
671
  /** Locator fields that participate in the stable issue id, in fixed order. */
673
672
  const LOCATOR_ID_KEYS = [
674
673
  "file",
@@ -744,8 +743,7 @@ function sortValue(value) {
744
743
  }
745
744
  return target;
746
745
  }
747
- //#endregion
748
- //#region src/check.ts
746
+ // src/check.ts
749
747
  /**
750
748
  * Pure check core: `(input, ruleset, options) => Report`.
751
749
  *
@@ -1222,8 +1220,7 @@ function runCheck(input, ruleset, options) {
1222
1220
  skipped
1223
1221
  });
1224
1222
  }
1225
- //#endregion
1226
- //#region src/shared/dictionary.ts
1223
+ // src/shared/dictionary.ts
1227
1224
  /** Strip decoration that never carries meaning in a header cell. */
1228
1225
  function normalizeHeader(raw) {
1229
1226
  return raw.replace(/[\u3000\s]+/g, "").replace(/[**]/g, "").replace(/[((][^(())]*[))]/g, "").replace(/[::]/g, "").replace(/[【】\[\]]/g, "").toLowerCase();
@@ -1252,8 +1249,7 @@ function resolveHeaders(headers, fields) {
1252
1249
  return ranked.find((entry) => header.includes(entry.alias))?.key;
1253
1250
  });
1254
1251
  }
1255
- //#endregion
1256
- //#region src/parse.ts
1252
+ // src/parse.ts
1257
1253
  /**
1258
1254
  * Reader for the canonical front-sheet material, plus the column dictionary.
1259
1255
  *
@@ -1524,12 +1520,10 @@ function parseMaterial(source, target) {
1524
1520
  warnings
1525
1521
  };
1526
1522
  }
1527
- //#endregion
1528
- //#region src/shared/wording.ts
1523
+ // src/shared/wording.ts
1529
1524
  /** Footer appended to every rendered report. */
1530
1525
  const DISCLAIMER = "免责声明:本报告由程序按声明的规则集自动生成,仅列出与所引条款之间的字面差异,供人工复核线索使用;不构成对任何事实、行为或文件的定性意见,也不替代主管人员、评审专家或监管机构的判断。规则集的时效性与适用范围以引用文件的最新有效版本为准。";
1531
- //#endregion
1532
- //#region src/view.ts
1526
+ // src/view.ts
1533
1527
  /**
1534
1528
  * Model-facing projection of a {@link Report}.
1535
1529
  *
@@ -1609,8 +1603,7 @@ function buildView(report) {
1609
1603
  reportJson: canonicalJson(report)
1610
1604
  };
1611
1605
  }
1612
- //#endregion
1613
- //#region src/shared/memo.ts
1606
+ // src/shared/memo.ts
1614
1607
  /**
1615
1608
  * Memoized loading of package-owned rule packs.
1616
1609
  *
@@ -1633,8 +1626,7 @@ function loadRulesetFile(path) {
1633
1626
  pending.catch(() => cache.delete(path));
1634
1627
  return pending;
1635
1628
  }
1636
- //#endregion
1637
- //#region src/index.ts
1629
+ // src/index.ts
1638
1630
  const name = "dsh-medrec-qc";
1639
1631
  const inject = ["tools"];
1640
1632
  /** Tool id exposed to the model, and the row id in `cordis.patch.yml`. */
@@ -1771,5 +1763,4 @@ function apply(ctx, config) {
1771
1763
  }
1772
1764
  }));
1773
1765
  }
1774
- //#endregion
1775
1766
  export { Config, TOOL_NAME, apply, inject, name, resolvePackageFile };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-medrec-qc",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
4
4
  "description": "病案首页形式质控与逻辑矛盾提示(依据国卫办医发〔2016〕24号等公开文件,仅提示差异,不作出定性结论)",
5
5
  "type": "module",
6
6
  "main": "lib/index.mjs",
@@ -25,7 +25,11 @@
25
25
  "icon.svg",
26
26
  "rules",
27
27
  "CHANGELOG.md",
28
- "SECURITY.md"
28
+ "SECURITY.md",
29
+ "docs/assets/*",
30
+ "samples",
31
+ "TROUBLESHOOTING.md",
32
+ "screenshots.json"
29
33
  ],
30
34
  "scripts": {
31
35
  "build": "tsdown",
@@ -42,7 +46,23 @@
42
46
  "manifestVersion": 1,
43
47
  "bundle": {
44
48
  "patch": "./cordis.patch.yml"
45
- }
49
+ },
50
+ "demo": {
51
+ "sample": "samples/quickstart/input/MR-001-unsafe.yaml",
52
+ "prompt": "用自带样例跑一次这项检查,告诉我发现了几条问题、分别是什么级别。",
53
+ "expect": "samples/quickstart/expected/result.json",
54
+ "screenshot": "docs/assets/quickstart.png",
55
+ "reads": [
56
+ "用户指定的材料文件"
57
+ ],
58
+ "writes": [],
59
+ "network": false,
60
+ "external": []
61
+ },
62
+ "capabilities": [
63
+ "tools:register"
64
+ ],
65
+ "labels": []
46
66
  },
47
67
  "keywords": [
48
68
  "deepseek-harness",
@@ -77,14 +97,14 @@
77
97
  "@deepseek-ai/schemastery": "^3.18.2"
78
98
  },
79
99
  "devDependencies": {
80
- "@deepseek-ai/cordis": "4.0.5-alpha.1",
81
- "@deepseek-ai/dsh-package-manifest": "0.2.1-rc.2",
100
+ "@deepseek-ai/cordis": "4.0.5",
101
+ "@deepseek-ai/dsh-package-manifest": "0.2.1-rc.3",
82
102
  "@deepseek-ai/dsh-tools": "0.2.1-rc.2",
83
- "@deepseek-ai/schemastery": "3.18.5-alpha.1",
103
+ "@deepseek-ai/schemastery": "3.18.5",
84
104
  "@types/node": "^22.20.1",
85
105
  "vitest": "^3.2.7",
86
106
  "@deepseek-ai/dsh-working-directory": "0.2.1-rc.2",
87
- "tsdown": "^0.22.14",
107
+ "tsdown": "^0.23.1",
88
108
  "typescript": "^5.9.3"
89
109
  },
90
110
  "dependencies": {}
@@ -0,0 +1,10 @@
1
+ {
2
+ "tool": "medrec_qc",
3
+ "issueCount": 1,
4
+ "summary": {
5
+ "error": 1,
6
+ "warn": 0,
7
+ "info": 0
8
+ },
9
+ "skippedCount": 14
10
+ }
@@ -0,0 +1,23 @@
1
+ target: 2026 年 3 月出院病案首页导出
2
+ cases:
3
+ - row: 1
4
+ 病案号: ""
5
+ 入院时间: "2026-03-01 08:30"
6
+ 出院时间: "2026-03-06 10:00"
7
+ 实际住院天数: "5"
8
+ 性别: "1"
9
+ 出生日期: "1972-05-04"
10
+ 年龄: "53"
11
+ 离院方式: "1"
12
+ 科主任: "赵主任"
13
+ 主任医师: "钱主任医师"
14
+ 主治医师: "孙主治"
15
+ 住院医师: "李医师"
16
+ 责任护士: "周护士"
17
+ 编码员: "吴编码"
18
+ 主要诊断名称: "2型糖尿病"
19
+ 主要诊断编码: "E11.900"
20
+ 其他诊断: "高血压;慢性肾功能不全"
21
+ 主要手术名称: "腹腔镜胆囊切除术"
22
+ 主要手术编码: "51.2300"
23
+ 有手术操作: "1"
@@ -0,0 +1,27 @@
1
+ import { readFile } from 'node:fs/promises'
2
+ import { dirname, join } from 'node:path'
3
+ import { fileURLToPath } from 'node:url'
4
+ import * as plugin from '../../lib/index.mjs'
5
+
6
+ const here = dirname(fileURLToPath(import.meta.url))
7
+ const material = await readFile(join(here, 'input', "MR-001-unsafe.yaml"), 'utf8')
8
+
9
+ const registered = []
10
+ const ctx = { tools: { register: (tool) => { registered.push(tool); return () => {} } } }
11
+ plugin.apply(ctx, plugin.Config ? plugin.Config({}) : {})
12
+ const tool = registered.find((t) => t.name === plugin.TOOL_NAME)
13
+ if (!tool) throw new Error('tool not registered: ' + plugin.TOOL_NAME)
14
+
15
+ const result = await tool.execute({ material }, { signal: new AbortController().signal })
16
+ const summary = {
17
+ tool: tool.name,
18
+ issueCount: result.issueCount,
19
+ summary: result.summary,
20
+ skippedCount: result.skippedCount,
21
+ }
22
+ if (process.argv.includes('--json')) console.log(JSON.stringify(summary, null, 2))
23
+ else {
24
+ console.log('$ node samples/quickstart/run.mjs')
25
+ console.log(tool.name + ': ' + summary.issueCount + ' issue(s) — error ' + summary.summary.error + ', warn ' + summary.summary.warn + ', info ' + summary.summary.info)
26
+ console.log('skipped: ' + summary.skippedCount)
27
+ }
@@ -0,0 +1,14 @@
1
+ [
2
+ {
3
+ "path": "docs/assets/dsh-medrec-qc-hero.png",
4
+ "kind": "hero",
5
+ "alt": "dsh-medrec-qc terminal output",
6
+ "caption": "Real dsh-medrec-qc checker output; 33 tests passed."
7
+ },
8
+ {
9
+ "path": "docs/assets/dsh-medrec-qc-demo.gif",
10
+ "kind": "demo",
11
+ "alt": "Animated dsh-medrec-qc terminal session",
12
+ "caption": "The same run, assembled line by line."
13
+ }
14
+ ]