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,195 +0,0 @@
1
- """Add a new slide to an unpacked PPTX directory.
2
-
3
- Usage: python add_slide.py <unpacked_dir> <source>
4
-
5
- The source can be:
6
- - A slide file (e.g., slide2.xml) - duplicates the slide
7
- - A layout file (e.g., slideLayout2.xml) - creates from layout
8
-
9
- Examples:
10
- python add_slide.py unpacked/ slide2.xml
11
- # Duplicates slide2, creates slide5.xml
12
-
13
- python add_slide.py unpacked/ slideLayout2.xml
14
- # Creates slide5.xml from slideLayout2.xml
15
-
16
- To see available layouts: ls unpacked/ppt/slideLayouts/
17
-
18
- Prints the <p:sldId> element to add to presentation.xml.
19
- """
20
-
21
- import re
22
- import shutil
23
- import sys
24
- from pathlib import Path
25
-
26
-
27
- def get_next_slide_number(slides_dir: Path) -> int:
28
- existing = [int(m.group(1)) for f in slides_dir.glob("slide*.xml")
29
- if (m := re.match(r"slide(\d+)\.xml", f.name))]
30
- return max(existing) + 1 if existing else 1
31
-
32
-
33
- def create_slide_from_layout(unpacked_dir: Path, layout_file: str) -> None:
34
- slides_dir = unpacked_dir / "ppt" / "slides"
35
- rels_dir = slides_dir / "_rels"
36
- layouts_dir = unpacked_dir / "ppt" / "slideLayouts"
37
-
38
- layout_path = layouts_dir / layout_file
39
- if not layout_path.exists():
40
- print(f"Error: {layout_path} not found", file=sys.stderr)
41
- sys.exit(1)
42
-
43
- next_num = get_next_slide_number(slides_dir)
44
- dest = f"slide{next_num}.xml"
45
- dest_slide = slides_dir / dest
46
- dest_rels = rels_dir / f"{dest}.rels"
47
-
48
- slide_xml = '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
49
- <p:sld xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
50
- <p:cSld>
51
- <p:spTree>
52
- <p:nvGrpSpPr>
53
- <p:cNvPr id="1" name=""/>
54
- <p:cNvGrpSpPr/>
55
- <p:nvPr/>
56
- </p:nvGrpSpPr>
57
- <p:grpSpPr>
58
- <a:xfrm>
59
- <a:off x="0" y="0"/>
60
- <a:ext cx="0" cy="0"/>
61
- <a:chOff x="0" y="0"/>
62
- <a:chExt cx="0" cy="0"/>
63
- </a:xfrm>
64
- </p:grpSpPr>
65
- </p:spTree>
66
- </p:cSld>
67
- <p:clrMapOvr>
68
- <a:masterClrMapping/>
69
- </p:clrMapOvr>
70
- </p:sld>'''
71
- dest_slide.write_text(slide_xml, encoding="utf-8")
72
-
73
- rels_dir.mkdir(exist_ok=True)
74
- rels_xml = f'''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
75
- <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
76
- <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/{layout_file}"/>
77
- </Relationships>'''
78
- dest_rels.write_text(rels_xml, encoding="utf-8")
79
-
80
- _add_to_content_types(unpacked_dir, dest)
81
-
82
- rid = _add_to_presentation_rels(unpacked_dir, dest)
83
-
84
- next_slide_id = _get_next_slide_id(unpacked_dir)
85
-
86
- print(f"Created {dest} from {layout_file}")
87
- print(f'Add to presentation.xml <p:sldIdLst>: <p:sldId id="{next_slide_id}" r:id="{rid}"/>')
88
-
89
-
90
- def duplicate_slide(unpacked_dir: Path, source: str) -> None:
91
- slides_dir = unpacked_dir / "ppt" / "slides"
92
- rels_dir = slides_dir / "_rels"
93
-
94
- source_slide = slides_dir / source
95
-
96
- if not source_slide.exists():
97
- print(f"Error: {source_slide} not found", file=sys.stderr)
98
- sys.exit(1)
99
-
100
- next_num = get_next_slide_number(slides_dir)
101
- dest = f"slide{next_num}.xml"
102
- dest_slide = slides_dir / dest
103
-
104
- source_rels = rels_dir / f"{source}.rels"
105
- dest_rels = rels_dir / f"{dest}.rels"
106
-
107
- shutil.copy2(source_slide, dest_slide)
108
-
109
- if source_rels.exists():
110
- shutil.copy2(source_rels, dest_rels)
111
-
112
- rels_content = dest_rels.read_text(encoding="utf-8")
113
- rels_content = re.sub(
114
- r'\s*<Relationship[^>]*Type="[^"]*notesSlide"[^>]*/>\s*',
115
- "\n",
116
- rels_content,
117
- )
118
- dest_rels.write_text(rels_content, encoding="utf-8")
119
-
120
- _add_to_content_types(unpacked_dir, dest)
121
-
122
- rid = _add_to_presentation_rels(unpacked_dir, dest)
123
-
124
- next_slide_id = _get_next_slide_id(unpacked_dir)
125
-
126
- print(f"Created {dest} from {source}")
127
- print(f'Add to presentation.xml <p:sldIdLst>: <p:sldId id="{next_slide_id}" r:id="{rid}"/>')
128
-
129
-
130
- def _add_to_content_types(unpacked_dir: Path, dest: str) -> None:
131
- content_types_path = unpacked_dir / "[Content_Types].xml"
132
- content_types = content_types_path.read_text(encoding="utf-8")
133
-
134
- new_override = f'<Override PartName="/ppt/slides/{dest}" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slide+xml"/>'
135
-
136
- if f"/ppt/slides/{dest}" not in content_types:
137
- content_types = content_types.replace("</Types>", f" {new_override}\n</Types>")
138
- content_types_path.write_text(content_types, encoding="utf-8")
139
-
140
-
141
- def _add_to_presentation_rels(unpacked_dir: Path, dest: str) -> str:
142
- pres_rels_path = unpacked_dir / "ppt" / "_rels" / "presentation.xml.rels"
143
- pres_rels = pres_rels_path.read_text(encoding="utf-8")
144
-
145
- rids = [int(m) for m in re.findall(r'Id="rId(\d+)"', pres_rels)]
146
- next_rid = max(rids) + 1 if rids else 1
147
- rid = f"rId{next_rid}"
148
-
149
- new_rel = f'<Relationship Id="{rid}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" Target="slides/{dest}"/>'
150
-
151
- if f"slides/{dest}" not in pres_rels:
152
- pres_rels = pres_rels.replace("</Relationships>", f" {new_rel}\n</Relationships>")
153
- pres_rels_path.write_text(pres_rels, encoding="utf-8")
154
-
155
- return rid
156
-
157
-
158
- def _get_next_slide_id(unpacked_dir: Path) -> int:
159
- pres_path = unpacked_dir / "ppt" / "presentation.xml"
160
- pres_content = pres_path.read_text(encoding="utf-8")
161
- slide_ids = [int(m) for m in re.findall(r'<p:sldId[^>]*id="(\d+)"', pres_content)]
162
- return max(slide_ids) + 1 if slide_ids else 256
163
-
164
-
165
- def parse_source(source: str) -> tuple[str, str | None]:
166
- if source.startswith("slideLayout") and source.endswith(".xml"):
167
- return ("layout", source)
168
-
169
- return ("slide", None)
170
-
171
-
172
- if __name__ == "__main__":
173
- if len(sys.argv) != 3:
174
- print("Usage: python add_slide.py <unpacked_dir> <source>", file=sys.stderr)
175
- print("", file=sys.stderr)
176
- print("Source can be:", file=sys.stderr)
177
- print(" slide2.xml - duplicate an existing slide", file=sys.stderr)
178
- print(" slideLayout2.xml - create from a layout template", file=sys.stderr)
179
- print("", file=sys.stderr)
180
- print("To see available layouts: ls <unpacked_dir>/ppt/slideLayouts/", file=sys.stderr)
181
- sys.exit(1)
182
-
183
- unpacked_dir = Path(sys.argv[1])
184
- source = sys.argv[2]
185
-
186
- if not unpacked_dir.exists():
187
- print(f"Error: {unpacked_dir} not found", file=sys.stderr)
188
- sys.exit(1)
189
-
190
- source_type, layout_file = parse_source(source)
191
-
192
- if source_type == "layout" and layout_file is not None:
193
- create_slide_from_layout(unpacked_dir, layout_file)
194
- else:
195
- duplicate_slide(unpacked_dir, source)
@@ -1,286 +0,0 @@
1
- """Remove unreferenced files from an unpacked PPTX directory.
2
-
3
- Usage: python clean.py <unpacked_dir>
4
-
5
- Example:
6
- python clean.py unpacked/
7
-
8
- This script removes:
9
- - Orphaned slides (not in sldIdLst) and their relationships
10
- - [trash] directory (unreferenced files)
11
- - Orphaned .rels files for deleted resources
12
- - Unreferenced media, embeddings, charts, diagrams, drawings, ink files
13
- - Unreferenced theme files
14
- - Unreferenced notes slides
15
- - Content-Type overrides for deleted files
16
- """
17
-
18
- import sys
19
- from pathlib import Path
20
-
21
- import defusedxml.minidom
22
-
23
-
24
- import re
25
-
26
-
27
- def get_slides_in_sldidlst(unpacked_dir: Path) -> set[str]:
28
- pres_path = unpacked_dir / "ppt" / "presentation.xml"
29
- pres_rels_path = unpacked_dir / "ppt" / "_rels" / "presentation.xml.rels"
30
-
31
- if not pres_path.exists() or not pres_rels_path.exists():
32
- return set()
33
-
34
- rels_dom = defusedxml.minidom.parse(str(pres_rels_path))
35
- rid_to_slide = {}
36
- for rel in rels_dom.getElementsByTagName("Relationship"):
37
- rid = rel.getAttribute("Id")
38
- target = rel.getAttribute("Target")
39
- rel_type = rel.getAttribute("Type")
40
- if "slide" in rel_type and target.startswith("slides/"):
41
- rid_to_slide[rid] = target.replace("slides/", "")
42
-
43
- pres_content = pres_path.read_text(encoding="utf-8")
44
- referenced_rids = set(re.findall(r'<p:sldId[^>]*r:id="([^"]+)"', pres_content))
45
-
46
- return {rid_to_slide[rid] for rid in referenced_rids if rid in rid_to_slide}
47
-
48
-
49
- def remove_orphaned_slides(unpacked_dir: Path) -> list[str]:
50
- slides_dir = unpacked_dir / "ppt" / "slides"
51
- slides_rels_dir = slides_dir / "_rels"
52
- pres_rels_path = unpacked_dir / "ppt" / "_rels" / "presentation.xml.rels"
53
-
54
- if not slides_dir.exists():
55
- return []
56
-
57
- referenced_slides = get_slides_in_sldidlst(unpacked_dir)
58
- removed = []
59
-
60
- for slide_file in slides_dir.glob("slide*.xml"):
61
- if slide_file.name not in referenced_slides:
62
- rel_path = slide_file.relative_to(unpacked_dir)
63
- slide_file.unlink()
64
- removed.append(str(rel_path))
65
-
66
- rels_file = slides_rels_dir / f"{slide_file.name}.rels"
67
- if rels_file.exists():
68
- rels_file.unlink()
69
- removed.append(str(rels_file.relative_to(unpacked_dir)))
70
-
71
- if removed and pres_rels_path.exists():
72
- rels_dom = defusedxml.minidom.parse(str(pres_rels_path))
73
- changed = False
74
-
75
- for rel in list(rels_dom.getElementsByTagName("Relationship")):
76
- target = rel.getAttribute("Target")
77
- if target.startswith("slides/"):
78
- slide_name = target.replace("slides/", "")
79
- if slide_name not in referenced_slides:
80
- if rel.parentNode:
81
- rel.parentNode.removeChild(rel)
82
- changed = True
83
-
84
- if changed:
85
- with open(pres_rels_path, "wb") as f:
86
- f.write(rels_dom.toxml(encoding="utf-8"))
87
-
88
- return removed
89
-
90
-
91
- def remove_trash_directory(unpacked_dir: Path) -> list[str]:
92
- trash_dir = unpacked_dir / "[trash]"
93
- removed = []
94
-
95
- if trash_dir.exists() and trash_dir.is_dir():
96
- for file_path in trash_dir.iterdir():
97
- if file_path.is_file():
98
- rel_path = file_path.relative_to(unpacked_dir)
99
- removed.append(str(rel_path))
100
- file_path.unlink()
101
- trash_dir.rmdir()
102
-
103
- return removed
104
-
105
-
106
- def get_slide_referenced_files(unpacked_dir: Path) -> set:
107
- referenced = set()
108
- slides_rels_dir = unpacked_dir / "ppt" / "slides" / "_rels"
109
-
110
- if not slides_rels_dir.exists():
111
- return referenced
112
-
113
- for rels_file in slides_rels_dir.glob("*.rels"):
114
- dom = defusedxml.minidom.parse(str(rels_file))
115
- for rel in dom.getElementsByTagName("Relationship"):
116
- target = rel.getAttribute("Target")
117
- if not target:
118
- continue
119
- target_path = (rels_file.parent.parent / target).resolve()
120
- try:
121
- referenced.add(target_path.relative_to(unpacked_dir.resolve()))
122
- except ValueError:
123
- pass
124
-
125
- return referenced
126
-
127
-
128
- def remove_orphaned_rels_files(unpacked_dir: Path) -> list[str]:
129
- resource_dirs = ["charts", "diagrams", "drawings"]
130
- removed = []
131
- slide_referenced = get_slide_referenced_files(unpacked_dir)
132
-
133
- for dir_name in resource_dirs:
134
- rels_dir = unpacked_dir / "ppt" / dir_name / "_rels"
135
- if not rels_dir.exists():
136
- continue
137
-
138
- for rels_file in rels_dir.glob("*.rels"):
139
- resource_file = rels_dir.parent / rels_file.name.replace(".rels", "")
140
- try:
141
- resource_rel_path = resource_file.resolve().relative_to(unpacked_dir.resolve())
142
- except ValueError:
143
- continue
144
-
145
- if not resource_file.exists() or resource_rel_path not in slide_referenced:
146
- rels_file.unlink()
147
- rel_path = rels_file.relative_to(unpacked_dir)
148
- removed.append(str(rel_path))
149
-
150
- return removed
151
-
152
-
153
- def get_referenced_files(unpacked_dir: Path) -> set:
154
- referenced = set()
155
-
156
- for rels_file in unpacked_dir.rglob("*.rels"):
157
- dom = defusedxml.minidom.parse(str(rels_file))
158
- for rel in dom.getElementsByTagName("Relationship"):
159
- target = rel.getAttribute("Target")
160
- if not target:
161
- continue
162
- target_path = (rels_file.parent.parent / target).resolve()
163
- try:
164
- referenced.add(target_path.relative_to(unpacked_dir.resolve()))
165
- except ValueError:
166
- pass
167
-
168
- return referenced
169
-
170
-
171
- def remove_orphaned_files(unpacked_dir: Path, referenced: set) -> list[str]:
172
- resource_dirs = ["media", "embeddings", "charts", "diagrams", "tags", "drawings", "ink"]
173
- removed = []
174
-
175
- for dir_name in resource_dirs:
176
- dir_path = unpacked_dir / "ppt" / dir_name
177
- if not dir_path.exists():
178
- continue
179
-
180
- for file_path in dir_path.glob("*"):
181
- if not file_path.is_file():
182
- continue
183
- rel_path = file_path.relative_to(unpacked_dir)
184
- if rel_path not in referenced:
185
- file_path.unlink()
186
- removed.append(str(rel_path))
187
-
188
- theme_dir = unpacked_dir / "ppt" / "theme"
189
- if theme_dir.exists():
190
- for file_path in theme_dir.glob("theme*.xml"):
191
- rel_path = file_path.relative_to(unpacked_dir)
192
- if rel_path not in referenced:
193
- file_path.unlink()
194
- removed.append(str(rel_path))
195
- theme_rels = theme_dir / "_rels" / f"{file_path.name}.rels"
196
- if theme_rels.exists():
197
- theme_rels.unlink()
198
- removed.append(str(theme_rels.relative_to(unpacked_dir)))
199
-
200
- notes_dir = unpacked_dir / "ppt" / "notesSlides"
201
- if notes_dir.exists():
202
- for file_path in notes_dir.glob("*.xml"):
203
- if not file_path.is_file():
204
- continue
205
- rel_path = file_path.relative_to(unpacked_dir)
206
- if rel_path not in referenced:
207
- file_path.unlink()
208
- removed.append(str(rel_path))
209
-
210
- notes_rels_dir = notes_dir / "_rels"
211
- if notes_rels_dir.exists():
212
- for file_path in notes_rels_dir.glob("*.rels"):
213
- notes_file = notes_dir / file_path.name.replace(".rels", "")
214
- if not notes_file.exists():
215
- file_path.unlink()
216
- removed.append(str(file_path.relative_to(unpacked_dir)))
217
-
218
- return removed
219
-
220
-
221
- def update_content_types(unpacked_dir: Path, removed_files: list[str]) -> None:
222
- ct_path = unpacked_dir / "[Content_Types].xml"
223
- if not ct_path.exists():
224
- return
225
-
226
- dom = defusedxml.minidom.parse(str(ct_path))
227
- changed = False
228
-
229
- for override in list(dom.getElementsByTagName("Override")):
230
- part_name = override.getAttribute("PartName").lstrip("/")
231
- if part_name in removed_files:
232
- if override.parentNode:
233
- override.parentNode.removeChild(override)
234
- changed = True
235
-
236
- if changed:
237
- with open(ct_path, "wb") as f:
238
- f.write(dom.toxml(encoding="utf-8"))
239
-
240
-
241
- def clean_unused_files(unpacked_dir: Path) -> list[str]:
242
- all_removed = []
243
-
244
- slides_removed = remove_orphaned_slides(unpacked_dir)
245
- all_removed.extend(slides_removed)
246
-
247
- trash_removed = remove_trash_directory(unpacked_dir)
248
- all_removed.extend(trash_removed)
249
-
250
- while True:
251
- removed_rels = remove_orphaned_rels_files(unpacked_dir)
252
- referenced = get_referenced_files(unpacked_dir)
253
- removed_files = remove_orphaned_files(unpacked_dir, referenced)
254
-
255
- total_removed = removed_rels + removed_files
256
- if not total_removed:
257
- break
258
-
259
- all_removed.extend(total_removed)
260
-
261
- if all_removed:
262
- update_content_types(unpacked_dir, all_removed)
263
-
264
- return all_removed
265
-
266
-
267
- if __name__ == "__main__":
268
- if len(sys.argv) != 2:
269
- print("Usage: python clean.py <unpacked_dir>", file=sys.stderr)
270
- print("Example: python clean.py unpacked/", file=sys.stderr)
271
- sys.exit(1)
272
-
273
- unpacked_dir = Path(sys.argv[1])
274
-
275
- if not unpacked_dir.exists():
276
- print(f"Error: {unpacked_dir} not found", file=sys.stderr)
277
- sys.exit(1)
278
-
279
- removed = clean_unused_files(unpacked_dir)
280
-
281
- if removed:
282
- print(f"Removed {len(removed)} unreferenced files:")
283
- for f in removed:
284
- print(f" {f}")
285
- else:
286
- print("No unreferenced files found")
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)