wormclaude 1.0.119 → 1.0.121

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.
Files changed (232) hide show
  1. package/dist/theme.js +1 -1
  2. package/dist/tui.js +6 -1
  3. package/package.json +1 -1
  4. package/skills/build-mcp-app/SKILL.md +0 -393
  5. package/skills/build-mcp-app/references/abuse-protection.md +0 -60
  6. package/skills/build-mcp-app/references/apps-sdk-messages.md +0 -227
  7. package/skills/build-mcp-app/references/directory-checklist.md +0 -18
  8. package/skills/build-mcp-app/references/iframe-sandbox.md +0 -164
  9. package/skills/build-mcp-app/references/payload-budgeting.md +0 -54
  10. package/skills/build-mcp-app/references/widget-templates.md +0 -249
  11. package/skills/build-mcp-server/SKILL.md +0 -222
  12. package/skills/build-mcp-server/references/auth.md +0 -108
  13. package/skills/build-mcp-server/references/deploy-cloudflare-workers.md +0 -106
  14. package/skills/build-mcp-server/references/elicitation.md +0 -129
  15. package/skills/build-mcp-server/references/remote-http-scaffold.md +0 -211
  16. package/skills/build-mcp-server/references/resources-and-prompts.md +0 -122
  17. package/skills/build-mcp-server/references/server-capabilities.md +0 -164
  18. package/skills/build-mcp-server/references/tool-design.md +0 -189
  19. package/skills/build-mcp-server/references/versions.md +0 -25
  20. package/skills/build-mcpb/SKILL.md +0 -200
  21. package/skills/build-mcpb/references/local-security.md +0 -149
  22. package/skills/build-mcpb/references/manifest-schema.md +0 -156
  23. package/skills/docx/script/__init__.py +0 -1
  24. package/skills/docx/script/accept_chages.py +0 -135
  25. package/skills/docx/script/comment.py +0 -318
  26. package/skills/docx/script/office/helpers/__init__.py +0 -0
  27. package/skills/docx/script/office/helpers/merge_runs.py +0 -199
  28. package/skills/docx/script/office/helpers/simplify_redlines.py +0 -197
  29. package/skills/docx/script/office/pack.py +0 -159
  30. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  31. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  32. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  33. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  34. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  35. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  36. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  37. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  38. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  39. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  40. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  41. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  42. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  43. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  44. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  45. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  46. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  47. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  48. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  49. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  50. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  51. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  52. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  53. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  54. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  55. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  56. package/skills/docx/script/office/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  57. package/skills/docx/script/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  58. package/skills/docx/script/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  59. package/skills/docx/script/office/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  60. package/skills/docx/script/office/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  61. package/skills/docx/script/office/schemas/mce/mc.xsd +0 -75
  62. package/skills/docx/script/office/schemas/microsoft/wml-2010.xsd +0 -560
  63. package/skills/docx/script/office/schemas/microsoft/wml-2012.xsd +0 -67
  64. package/skills/docx/script/office/schemas/microsoft/wml-2018.xsd +0 -14
  65. package/skills/docx/script/office/schemas/microsoft/wml-cex-2018.xsd +0 -20
  66. package/skills/docx/script/office/schemas/microsoft/wml-cid-2016.xsd +0 -13
  67. package/skills/docx/script/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  68. package/skills/docx/script/office/schemas/microsoft/wml-symex-2015.xsd +0 -8
  69. package/skills/docx/script/office/soffice.py +0 -183
  70. package/skills/docx/script/office/unpack.py +0 -132
  71. package/skills/docx/script/office/validate.py +0 -117
  72. package/skills/docx/script/office/validators/__init__.py +0 -15
  73. package/skills/docx/script/office/validators/base.py +0 -851
  74. package/skills/docx/script/office/validators/docx.py +0 -446
  75. package/skills/docx/script/office/validators/pptx.py +0 -275
  76. package/skills/docx/script/office/validators/redlining.py +0 -247
  77. package/skills/docx/script/templates/comments.xml +0 -3
  78. package/skills/docx/script/templates/commentsExtended.xml +0 -3
  79. package/skills/docx/script/templates/commentsExtensible.xml +0 -3
  80. package/skills/docx/script/templates/commentsIds.xml +0 -3
  81. package/skills/docx/script/templates/people.xml +0 -3
  82. package/skills/docx/skill.md +0 -593
  83. package/skills/explain.md +0 -14
  84. package/skills/frontend-design/SKILL.md +0 -42
  85. package/skills/pdf/FORMS.md +0 -294
  86. package/skills/pdf/REFERENCE.md +0 -612
  87. package/skills/pdf/SKILL.md +0 -314
  88. package/skills/pdf/scripts/check_bounding_boxes.py +0 -65
  89. package/skills/pdf/scripts/check_fillable_fields.py +0 -11
  90. package/skills/pdf/scripts/convert_pdf_to_images.py +0 -33
  91. package/skills/pdf/scripts/create_validation_image.py +0 -37
  92. package/skills/pdf/scripts/extract_form_field_info.py +0 -122
  93. package/skills/pdf/scripts/extract_form_structure.py +0 -115
  94. package/skills/pdf/scripts/fill_fillable_fields.py +0 -98
  95. package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +0 -107
  96. package/skills/playground/SKILL.md +0 -77
  97. package/skills/playground/templates/code-map.md +0 -158
  98. package/skills/playground/templates/concept-map.md +0 -73
  99. package/skills/playground/templates/data-explorer.md +0 -67
  100. package/skills/playground/templates/design-playground.md +0 -67
  101. package/skills/playground/templates/diff-review.md +0 -179
  102. package/skills/playground/templates/document-critique.md +0 -171
  103. package/skills/pptx/SKILL.md +0 -230
  104. package/skills/pptx/editing.md +0 -205
  105. package/skills/pptx/pptxgenjs.md +0 -437
  106. package/skills/pptx/scripts/__init__.py +0 -0
  107. package/skills/pptx/scripts/add_slide.py +0 -195
  108. package/skills/pptx/scripts/clean.py +0 -286
  109. package/skills/pptx/scripts/office/helpers/__init__.py +0 -0
  110. package/skills/pptx/scripts/office/helpers/merge_runs.py +0 -199
  111. package/skills/pptx/scripts/office/helpers/simplify_redlines.py +0 -197
  112. package/skills/pptx/scripts/office/pack.py +0 -159
  113. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  114. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  115. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  116. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  117. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  118. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  119. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  120. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  121. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  122. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  123. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  124. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  125. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  126. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  127. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  128. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  129. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  130. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  131. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  132. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  133. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  134. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  135. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  136. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  137. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  138. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  139. package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  140. package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  141. package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  142. package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  143. package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  144. package/skills/pptx/scripts/office/schemas/mce/mc.xsd +0 -75
  145. package/skills/pptx/scripts/office/schemas/microsoft/wml-2010.xsd +0 -560
  146. package/skills/pptx/scripts/office/schemas/microsoft/wml-2012.xsd +0 -67
  147. package/skills/pptx/scripts/office/schemas/microsoft/wml-2018.xsd +0 -14
  148. package/skills/pptx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +0 -20
  149. package/skills/pptx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +0 -13
  150. package/skills/pptx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  151. package/skills/pptx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +0 -8
  152. package/skills/pptx/scripts/office/soffice.py +0 -183
  153. package/skills/pptx/scripts/office/unpack.py +0 -132
  154. package/skills/pptx/scripts/office/validate.py +0 -117
  155. package/skills/pptx/scripts/office/validators/__init__.py +0 -15
  156. package/skills/pptx/scripts/office/validators/base.py +0 -851
  157. package/skills/pptx/scripts/office/validators/docx.py +0 -446
  158. package/skills/pptx/scripts/office/validators/pptx.py +0 -275
  159. package/skills/pptx/scripts/office/validators/redlining.py +0 -247
  160. package/skills/pptx/scripts/thumbnail.py +0 -289
  161. package/skills/recon.md +0 -16
  162. package/skills/security-audit/SKILL.md +0 -26
  163. package/skills/talent-creator/SKILL.md +0 -486
  164. package/skills/talent-creator/agents/analyzer.md +0 -274
  165. package/skills/talent-creator/agents/comparator.md +0 -202
  166. package/skills/talent-creator/agents/grader.md +0 -223
  167. package/skills/talent-creator/assets/eval_review.html +0 -146
  168. package/skills/talent-creator/eval-viewer/generate_review.py +0 -471
  169. package/skills/talent-creator/eval-viewer/viewer.html +0 -1325
  170. package/skills/talent-creator/references/schemas.md +0 -430
  171. package/skills/talent-creator/scripts/__init__.py +0 -0
  172. package/skills/talent-creator/scripts/aggregate_benchmark.py +0 -401
  173. package/skills/talent-creator/scripts/generate_report.py +0 -326
  174. package/skills/talent-creator/scripts/improve_description.py +0 -247
  175. package/skills/talent-creator/scripts/package_skill.py +0 -136
  176. package/skills/talent-creator/scripts/quick_validate.py +0 -146
  177. package/skills/talent-creator/scripts/run_eval.py +0 -310
  178. package/skills/talent-creator/scripts/run_loop.py +0 -328
  179. package/skills/talent-creator/scripts/utils.py +0 -47
  180. package/skills/xlsx/SKILL.md +0 -300
  181. package/skills/xlsx/scripts/office/helpers/__init__.py +0 -0
  182. package/skills/xlsx/scripts/office/helpers/merge_runs.py +0 -199
  183. package/skills/xlsx/scripts/office/helpers/simplify_redlines.py +0 -197
  184. package/skills/xlsx/scripts/office/pack.py +0 -159
  185. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  186. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  187. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  188. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  189. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  190. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  191. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  192. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  193. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  194. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  195. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  196. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  197. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  198. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  199. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  200. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  201. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  202. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  203. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  204. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  205. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  206. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  207. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  208. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  209. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  210. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  211. package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  212. package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  213. package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  214. package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  215. package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  216. package/skills/xlsx/scripts/office/schemas/mce/mc.xsd +0 -75
  217. package/skills/xlsx/scripts/office/schemas/microsoft/wml-2010.xsd +0 -560
  218. package/skills/xlsx/scripts/office/schemas/microsoft/wml-2012.xsd +0 -67
  219. package/skills/xlsx/scripts/office/schemas/microsoft/wml-2018.xsd +0 -14
  220. package/skills/xlsx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +0 -20
  221. package/skills/xlsx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +0 -13
  222. package/skills/xlsx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  223. package/skills/xlsx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +0 -8
  224. package/skills/xlsx/scripts/office/soffice.py +0 -183
  225. package/skills/xlsx/scripts/office/unpack.py +0 -132
  226. package/skills/xlsx/scripts/office/validate.py +0 -117
  227. package/skills/xlsx/scripts/office/validators/__init__.py +0 -15
  228. package/skills/xlsx/scripts/office/validators/base.py +0 -851
  229. package/skills/xlsx/scripts/office/validators/docx.py +0 -446
  230. package/skills/xlsx/scripts/office/validators/pptx.py +0 -275
  231. package/skills/xlsx/scripts/office/validators/redlining.py +0 -247
  232. package/skills/xlsx/scripts/recalc.py +0 -184
@@ -1,318 +0,0 @@
1
- """Add comments to DOCX documents.
2
-
3
- Usage:
4
- python comment.py unpacked/ 0 "Comment text"
5
- python comment.py unpacked/ 1 "Reply text" --parent 0
6
-
7
- Text should be pre-escaped XML (e.g., & for &, ’ for smart quotes).
8
-
9
- After running, add markers to document.xml:
10
- <w:commentRangeStart w:id="0"/>
11
- ... commented content ...
12
- <w:commentRangeEnd w:id="0"/>
13
- <w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="0"/></w:r>
14
- """
15
-
16
- import argparse
17
- import random
18
- import shutil
19
- import sys
20
- from datetime import datetime, timezone
21
- from pathlib import Path
22
-
23
- import defusedxml.minidom
24
-
25
- TEMPLATE_DIR = Path(__file__).parent / "templates"
26
- NS = {
27
- "w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
28
- "w14": "http://schemas.microsoft.com/office/word/2010/wordml",
29
- "w15": "http://schemas.microsoft.com/office/word/2012/wordml",
30
- "w16cid": "http://schemas.microsoft.com/office/word/2016/wordml/cid",
31
- "w16cex": "http://schemas.microsoft.com/office/word/2018/wordml/cex",
32
- }
33
-
34
- COMMENT_XML = """\
35
- <w:comment w:id="{id}" w:author="{author}" w:date="{date}" w:initials="{initials}">
36
- <w:p w14:paraId="{para_id}" w14:textId="77777777">
37
- <w:r>
38
- <w:rPr><w:rStyle w:val="CommentReference"/></w:rPr>
39
- <w:annotationRef/>
40
- </w:r>
41
- <w:r>
42
- <w:rPr>
43
- <w:color w:val="000000"/>
44
- <w:sz w:val="20"/>
45
- <w:szCs w:val="20"/>
46
- </w:rPr>
47
- <w:t>{text}</w:t>
48
- </w:r>
49
- </w:p>
50
- </w:comment>"""
51
-
52
- COMMENT_MARKER_TEMPLATE = """
53
- Add to document.xml (markers must be direct children of w:p, never inside w:r):
54
- <w:commentRangeStart w:id="{cid}"/>
55
- <w:r>...</w:r>
56
- <w:commentRangeEnd w:id="{cid}"/>
57
- <w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="{cid}"/></w:r>"""
58
-
59
- REPLY_MARKER_TEMPLATE = """
60
- Nest markers inside parent {pid}'s markers (markers must be direct children of w:p, never inside w:r):
61
- <w:commentRangeStart w:id="{pid}"/><w:commentRangeStart w:id="{cid}"/>
62
- <w:r>...</w:r>
63
- <w:commentRangeEnd w:id="{cid}"/><w:commentRangeEnd w:id="{pid}"/>
64
- <w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="{pid}"/></w:r>
65
- <w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="{cid}"/></w:r>"""
66
-
67
-
68
- def _generate_hex_id() -> str:
69
- return f"{random.randint(0, 0x7FFFFFFE):08X}"
70
-
71
-
72
- SMART_QUOTE_ENTITIES = {
73
- "\u201c": "&#x201C;",
74
- "\u201d": "&#x201D;",
75
- "\u2018": "&#x2018;",
76
- "\u2019": "&#x2019;",
77
- }
78
-
79
-
80
- def _encode_smart_quotes(text: str) -> str:
81
- for char, entity in SMART_QUOTE_ENTITIES.items():
82
- text = text.replace(char, entity)
83
- return text
84
-
85
-
86
- def _append_xml(xml_path: Path, root_tag: str, content: str) -> None:
87
- dom = defusedxml.minidom.parseString(xml_path.read_text(encoding="utf-8"))
88
- root = dom.getElementsByTagName(root_tag)[0]
89
- ns_attrs = " ".join(f'xmlns:{k}="{v}"' for k, v in NS.items())
90
- wrapper_dom = defusedxml.minidom.parseString(f"<root {ns_attrs}>{content}</root>")
91
- for child in wrapper_dom.documentElement.childNodes:
92
- if child.nodeType == child.ELEMENT_NODE:
93
- root.appendChild(dom.importNode(child, True))
94
- output = _encode_smart_quotes(dom.toxml(encoding="UTF-8").decode("utf-8"))
95
- xml_path.write_text(output, encoding="utf-8")
96
-
97
-
98
- def _find_para_id(comments_path: Path, comment_id: int) -> str | None:
99
- dom = defusedxml.minidom.parseString(comments_path.read_text(encoding="utf-8"))
100
- for c in dom.getElementsByTagName("w:comment"):
101
- if c.getAttribute("w:id") == str(comment_id):
102
- for p in c.getElementsByTagName("w:p"):
103
- if pid := p.getAttribute("w14:paraId"):
104
- return pid
105
- return None
106
-
107
-
108
- def _get_next_rid(rels_path: Path) -> int:
109
- dom = defusedxml.minidom.parseString(rels_path.read_text(encoding="utf-8"))
110
- max_rid = 0
111
- for rel in dom.getElementsByTagName("Relationship"):
112
- rid = rel.getAttribute("Id")
113
- if rid and rid.startswith("rId"):
114
- try:
115
- max_rid = max(max_rid, int(rid[3:]))
116
- except ValueError:
117
- pass
118
- return max_rid + 1
119
-
120
-
121
- def _has_relationship(rels_path: Path, target: str) -> bool:
122
- dom = defusedxml.minidom.parseString(rels_path.read_text(encoding="utf-8"))
123
- for rel in dom.getElementsByTagName("Relationship"):
124
- if rel.getAttribute("Target") == target:
125
- return True
126
- return False
127
-
128
-
129
- def _has_content_type(ct_path: Path, part_name: str) -> bool:
130
- dom = defusedxml.minidom.parseString(ct_path.read_text(encoding="utf-8"))
131
- for override in dom.getElementsByTagName("Override"):
132
- if override.getAttribute("PartName") == part_name:
133
- return True
134
- return False
135
-
136
-
137
- def _ensure_comment_relationships(unpacked_dir: Path) -> None:
138
- rels_path = unpacked_dir / "word" / "_rels" / "document.xml.rels"
139
- if not rels_path.exists():
140
- return
141
-
142
- if _has_relationship(rels_path, "comments.xml"):
143
- return
144
-
145
- dom = defusedxml.minidom.parseString(rels_path.read_text(encoding="utf-8"))
146
- root = dom.documentElement
147
- next_rid = _get_next_rid(rels_path)
148
-
149
- rels = [
150
- (
151
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments",
152
- "comments.xml",
153
- ),
154
- (
155
- "http://schemas.microsoft.com/office/2011/relationships/commentsExtended",
156
- "commentsExtended.xml",
157
- ),
158
- (
159
- "http://schemas.microsoft.com/office/2016/09/relationships/commentsIds",
160
- "commentsIds.xml",
161
- ),
162
- (
163
- "http://schemas.microsoft.com/office/2018/08/relationships/commentsExtensible",
164
- "commentsExtensible.xml",
165
- ),
166
- ]
167
-
168
- for rel_type, target in rels:
169
- rel = dom.createElement("Relationship")
170
- rel.setAttribute("Id", f"rId{next_rid}")
171
- rel.setAttribute("Type", rel_type)
172
- rel.setAttribute("Target", target)
173
- root.appendChild(rel)
174
- next_rid += 1
175
-
176
- rels_path.write_bytes(dom.toxml(encoding="UTF-8"))
177
-
178
-
179
- def _ensure_comment_content_types(unpacked_dir: Path) -> None:
180
- ct_path = unpacked_dir / "[Content_Types].xml"
181
- if not ct_path.exists():
182
- return
183
-
184
- if _has_content_type(ct_path, "/word/comments.xml"):
185
- return
186
-
187
- dom = defusedxml.minidom.parseString(ct_path.read_text(encoding="utf-8"))
188
- root = dom.documentElement
189
-
190
- overrides = [
191
- (
192
- "/word/comments.xml",
193
- "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml",
194
- ),
195
- (
196
- "/word/commentsExtended.xml",
197
- "application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml",
198
- ),
199
- (
200
- "/word/commentsIds.xml",
201
- "application/vnd.openxmlformats-officedocument.wordprocessingml.commentsIds+xml",
202
- ),
203
- (
204
- "/word/commentsExtensible.xml",
205
- "application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtensible+xml",
206
- ),
207
- ]
208
-
209
- for part_name, content_type in overrides:
210
- override = dom.createElement("Override")
211
- override.setAttribute("PartName", part_name)
212
- override.setAttribute("ContentType", content_type)
213
- root.appendChild(override)
214
-
215
- ct_path.write_bytes(dom.toxml(encoding="UTF-8"))
216
-
217
-
218
- def add_comment(
219
- unpacked_dir: str,
220
- comment_id: int,
221
- text: str,
222
- author: str = "WormClaude",
223
- initials: str = "C",
224
- parent_id: int | None = None,
225
- ) -> tuple[str, str]:
226
- word = Path(unpacked_dir) / "word"
227
- if not word.exists():
228
- return "", f"Error: {word} not found"
229
-
230
- para_id, durable_id = _generate_hex_id(), _generate_hex_id()
231
- ts = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
232
-
233
- comments = word / "comments.xml"
234
- first_comment = not comments.exists()
235
- if first_comment:
236
- shutil.copy(TEMPLATE_DIR / "comments.xml", comments)
237
- _ensure_comment_relationships(Path(unpacked_dir))
238
- _ensure_comment_content_types(Path(unpacked_dir))
239
- _append_xml(
240
- comments,
241
- "w:comments",
242
- COMMENT_XML.format(
243
- id=comment_id,
244
- author=author,
245
- date=ts,
246
- initials=initials,
247
- para_id=para_id,
248
- text=text,
249
- ),
250
- )
251
-
252
- ext = word / "commentsExtended.xml"
253
- if not ext.exists():
254
- shutil.copy(TEMPLATE_DIR / "commentsExtended.xml", ext)
255
- if parent_id is not None:
256
- parent_para = _find_para_id(comments, parent_id)
257
- if not parent_para:
258
- return "", f"Error: Parent comment {parent_id} not found"
259
- _append_xml(
260
- ext,
261
- "w15:commentsEx",
262
- f'<w15:commentEx w15:paraId="{para_id}" w15:paraIdParent="{parent_para}" w15:done="0"/>',
263
- )
264
- else:
265
- _append_xml(
266
- ext,
267
- "w15:commentsEx",
268
- f'<w15:commentEx w15:paraId="{para_id}" w15:done="0"/>',
269
- )
270
-
271
- ids = word / "commentsIds.xml"
272
- if not ids.exists():
273
- shutil.copy(TEMPLATE_DIR / "commentsIds.xml", ids)
274
- _append_xml(
275
- ids,
276
- "w16cid:commentsIds",
277
- f'<w16cid:commentId w16cid:paraId="{para_id}" w16cid:durableId="{durable_id}"/>',
278
- )
279
-
280
- extensible = word / "commentsExtensible.xml"
281
- if not extensible.exists():
282
- shutil.copy(TEMPLATE_DIR / "commentsExtensible.xml", extensible)
283
- _append_xml(
284
- extensible,
285
- "w16cex:commentsExtensible",
286
- f'<w16cex:commentExtensible w16cex:durableId="{durable_id}" w16cex:dateUtc="{ts}"/>',
287
- )
288
-
289
- action = "reply" if parent_id is not None else "comment"
290
- return para_id, f"Added {action} {comment_id} (para_id={para_id})"
291
-
292
-
293
- if __name__ == "__main__":
294
- p = argparse.ArgumentParser(description="Add comments to DOCX documents")
295
- p.add_argument("unpacked_dir", help="Unpacked DOCX directory")
296
- p.add_argument("comment_id", type=int, help="Comment ID (must be unique)")
297
- p.add_argument("text", help="Comment text")
298
- p.add_argument("--author", default="WormClaude", help="Author name")
299
- p.add_argument("--initials", default="C", help="Author initials")
300
- p.add_argument("--parent", type=int, help="Parent comment ID (for replies)")
301
- args = p.parse_args()
302
-
303
- para_id, msg = add_comment(
304
- args.unpacked_dir,
305
- args.comment_id,
306
- args.text,
307
- args.author,
308
- args.initials,
309
- args.parent,
310
- )
311
- print(msg)
312
- if "Error" in msg:
313
- sys.exit(1)
314
- cid = args.comment_id
315
- if args.parent is not None:
316
- print(REPLY_MARKER_TEMPLATE.format(pid=args.parent, cid=cid))
317
- else:
318
- print(COMMENT_MARKER_TEMPLATE.format(cid=cid))
File without changes
@@ -1,199 +0,0 @@
1
- """Merge adjacent runs with identical formatting in DOCX.
2
-
3
- Merges adjacent <w:r> elements that have identical <w:rPr> properties.
4
- Works on runs in paragraphs and inside tracked changes (<w:ins>, <w:del>).
5
-
6
- Also:
7
- - Removes rsid attributes from runs (revision metadata that doesn't affect rendering)
8
- - Removes proofErr elements (spell/grammar markers that block merging)
9
- """
10
-
11
- from pathlib import Path
12
-
13
- import defusedxml.minidom
14
-
15
-
16
- def merge_runs(input_dir: str) -> tuple[int, str]:
17
- doc_xml = Path(input_dir) / "word" / "document.xml"
18
-
19
- if not doc_xml.exists():
20
- return 0, f"Error: {doc_xml} not found"
21
-
22
- try:
23
- dom = defusedxml.minidom.parseString(doc_xml.read_text(encoding="utf-8"))
24
- root = dom.documentElement
25
-
26
- _remove_elements(root, "proofErr")
27
- _strip_run_rsid_attrs(root)
28
-
29
- containers = {run.parentNode for run in _find_elements(root, "r")}
30
-
31
- merge_count = 0
32
- for container in containers:
33
- merge_count += _merge_runs_in(container)
34
-
35
- doc_xml.write_bytes(dom.toxml(encoding="UTF-8"))
36
- return merge_count, f"Merged {merge_count} runs"
37
-
38
- except Exception as e:
39
- return 0, f"Error: {e}"
40
-
41
-
42
-
43
-
44
- def _find_elements(root, tag: str) -> list:
45
- results = []
46
-
47
- def traverse(node):
48
- if node.nodeType == node.ELEMENT_NODE:
49
- name = node.localName or node.tagName
50
- if name == tag or name.endswith(f":{tag}"):
51
- results.append(node)
52
- for child in node.childNodes:
53
- traverse(child)
54
-
55
- traverse(root)
56
- return results
57
-
58
-
59
- def _get_child(parent, tag: str):
60
- for child in parent.childNodes:
61
- if child.nodeType == child.ELEMENT_NODE:
62
- name = child.localName or child.tagName
63
- if name == tag or name.endswith(f":{tag}"):
64
- return child
65
- return None
66
-
67
-
68
- def _get_children(parent, tag: str) -> list:
69
- results = []
70
- for child in parent.childNodes:
71
- if child.nodeType == child.ELEMENT_NODE:
72
- name = child.localName or child.tagName
73
- if name == tag or name.endswith(f":{tag}"):
74
- results.append(child)
75
- return results
76
-
77
-
78
- def _is_adjacent(elem1, elem2) -> bool:
79
- node = elem1.nextSibling
80
- while node:
81
- if node == elem2:
82
- return True
83
- if node.nodeType == node.ELEMENT_NODE:
84
- return False
85
- if node.nodeType == node.TEXT_NODE and node.data.strip():
86
- return False
87
- node = node.nextSibling
88
- return False
89
-
90
-
91
-
92
-
93
- def _remove_elements(root, tag: str):
94
- for elem in _find_elements(root, tag):
95
- if elem.parentNode:
96
- elem.parentNode.removeChild(elem)
97
-
98
-
99
- def _strip_run_rsid_attrs(root):
100
- for run in _find_elements(root, "r"):
101
- for attr in list(run.attributes.values()):
102
- if "rsid" in attr.name.lower():
103
- run.removeAttribute(attr.name)
104
-
105
-
106
-
107
-
108
- def _merge_runs_in(container) -> int:
109
- merge_count = 0
110
- run = _first_child_run(container)
111
-
112
- while run:
113
- while True:
114
- next_elem = _next_element_sibling(run)
115
- if next_elem and _is_run(next_elem) and _can_merge(run, next_elem):
116
- _merge_run_content(run, next_elem)
117
- container.removeChild(next_elem)
118
- merge_count += 1
119
- else:
120
- break
121
-
122
- _consolidate_text(run)
123
- run = _next_sibling_run(run)
124
-
125
- return merge_count
126
-
127
-
128
- def _first_child_run(container):
129
- for child in container.childNodes:
130
- if child.nodeType == child.ELEMENT_NODE and _is_run(child):
131
- return child
132
- return None
133
-
134
-
135
- def _next_element_sibling(node):
136
- sibling = node.nextSibling
137
- while sibling:
138
- if sibling.nodeType == sibling.ELEMENT_NODE:
139
- return sibling
140
- sibling = sibling.nextSibling
141
- return None
142
-
143
-
144
- def _next_sibling_run(node):
145
- sibling = node.nextSibling
146
- while sibling:
147
- if sibling.nodeType == sibling.ELEMENT_NODE:
148
- if _is_run(sibling):
149
- return sibling
150
- sibling = sibling.nextSibling
151
- return None
152
-
153
-
154
- def _is_run(node) -> bool:
155
- name = node.localName or node.tagName
156
- return name == "r" or name.endswith(":r")
157
-
158
-
159
- def _can_merge(run1, run2) -> bool:
160
- rpr1 = _get_child(run1, "rPr")
161
- rpr2 = _get_child(run2, "rPr")
162
-
163
- if (rpr1 is None) != (rpr2 is None):
164
- return False
165
- if rpr1 is None:
166
- return True
167
- return rpr1.toxml() == rpr2.toxml()
168
-
169
-
170
- def _merge_run_content(target, source):
171
- for child in list(source.childNodes):
172
- if child.nodeType == child.ELEMENT_NODE:
173
- name = child.localName or child.tagName
174
- if name != "rPr" and not name.endswith(":rPr"):
175
- target.appendChild(child)
176
-
177
-
178
- def _consolidate_text(run):
179
- t_elements = _get_children(run, "t")
180
-
181
- for i in range(len(t_elements) - 1, 0, -1):
182
- curr, prev = t_elements[i], t_elements[i - 1]
183
-
184
- if _is_adjacent(prev, curr):
185
- prev_text = prev.firstChild.data if prev.firstChild else ""
186
- curr_text = curr.firstChild.data if curr.firstChild else ""
187
- merged = prev_text + curr_text
188
-
189
- if prev.firstChild:
190
- prev.firstChild.data = merged
191
- else:
192
- prev.appendChild(run.ownerDocument.createTextNode(merged))
193
-
194
- if merged.startswith(" ") or merged.endswith(" "):
195
- prev.setAttribute("xml:space", "preserve")
196
- elif prev.hasAttribute("xml:space"):
197
- prev.removeAttribute("xml:space")
198
-
199
- run.removeChild(curr)