@kolbo/kolbo-code-linux-arm64-musl 1.1.73 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/bin/kolbo +0 -0
  2. package/package.json +1 -1
  3. package/skills/brainstorming/SKILL.md +164 -0
  4. package/skills/brainstorming/scripts/frame-template.html +214 -0
  5. package/skills/brainstorming/scripts/helper.js +88 -0
  6. package/skills/brainstorming/scripts/server.cjs +354 -0
  7. package/skills/brainstorming/scripts/start-server.sh +148 -0
  8. package/skills/brainstorming/scripts/stop-server.sh +56 -0
  9. package/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
  10. package/skills/brainstorming/visual-companion.md +287 -0
  11. package/skills/dispatching-parallel-agents/SKILL.md +182 -0
  12. package/skills/docx/.skillfish.json +10 -0
  13. package/skills/docx/SKILL.md +196 -0
  14. package/skills/docx/docx-js.md +350 -0
  15. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  16. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  17. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  18. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  19. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  20. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  21. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  22. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  23. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  24. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  25. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  26. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  27. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  28. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  29. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  30. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  31. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  32. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  33. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  34. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  35. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  36. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  37. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  38. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  39. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  40. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  41. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  42. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  43. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  44. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  45. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  46. package/skills/docx/ooxml/schemas/mce/mc.xsd +75 -0
  47. package/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  48. package/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  49. package/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  50. package/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  51. package/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  52. package/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  53. package/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  54. package/skills/docx/ooxml/scripts/pack.py +159 -0
  55. package/skills/docx/ooxml/scripts/unpack.py +29 -0
  56. package/skills/docx/ooxml/scripts/validate.py +69 -0
  57. package/skills/docx/ooxml/scripts/validation/__init__.py +15 -0
  58. package/skills/docx/ooxml/scripts/validation/base.py +951 -0
  59. package/skills/docx/ooxml/scripts/validation/docx.py +274 -0
  60. package/skills/docx/ooxml/scripts/validation/pptx.py +315 -0
  61. package/skills/docx/ooxml/scripts/validation/redlining.py +279 -0
  62. package/skills/docx/ooxml.md +599 -0
  63. package/skills/docx/scripts/__init__.py +1 -0
  64. package/skills/docx/scripts/document.py +1272 -0
  65. package/skills/docx/scripts/templates/comments.xml +3 -0
  66. package/skills/docx/scripts/templates/commentsExtended.xml +3 -0
  67. package/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
  68. package/skills/docx/scripts/templates/commentsIds.xml +3 -0
  69. package/skills/docx/scripts/templates/people.xml +3 -0
  70. package/skills/docx/scripts/utilities.py +374 -0
  71. package/skills/executing-plans/SKILL.md +70 -0
  72. package/skills/finishing-a-development-branch/SKILL.md +200 -0
  73. package/skills/fullstack-app/SKILL.md +621 -0
  74. package/skills/kolbo/SKILL.md +19 -263
  75. package/skills/ollama-vision/SKILL.md +105 -0
  76. package/skills/pdf/.skillfish.json +10 -0
  77. package/skills/pdf/FORMS.md +205 -0
  78. package/skills/pdf/REFERENCE.md +612 -0
  79. package/skills/pdf/SKILL.md +293 -0
  80. package/skills/pdf/scripts/check_bounding_boxes.py +70 -0
  81. package/skills/pdf/scripts/check_bounding_boxes_test.py +226 -0
  82. package/skills/pdf/scripts/check_fillable_fields.py +12 -0
  83. package/skills/pdf/scripts/convert_pdf_to_images.py +35 -0
  84. package/skills/pdf/scripts/create_validation_image.py +41 -0
  85. package/skills/pdf/scripts/extract_form_field_info.py +152 -0
  86. package/skills/pdf/scripts/fill_fillable_fields.py +114 -0
  87. package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
  88. package/skills/photo-studio/SKILL.md +122 -0
  89. package/skills/pptx/.skillfish.json +10 -0
  90. package/skills/pptx/SKILL.md +483 -0
  91. package/skills/pptx/html2pptx.md +626 -0
  92. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  93. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  94. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  95. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  96. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  97. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  98. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  99. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  100. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  101. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  102. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  103. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  104. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  105. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  106. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  107. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  108. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  109. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  110. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  111. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  112. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  113. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  114. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  115. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  116. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  117. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  118. package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  119. package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  120. package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  121. package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  122. package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  123. package/skills/pptx/ooxml/schemas/mce/mc.xsd +75 -0
  124. package/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
  125. package/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
  126. package/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
  127. package/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
  128. package/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
  129. package/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  130. package/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
  131. package/skills/pptx/ooxml/scripts/pack.py +159 -0
  132. package/skills/pptx/ooxml/scripts/unpack.py +29 -0
  133. package/skills/pptx/ooxml/scripts/validate.py +69 -0
  134. package/skills/pptx/ooxml/scripts/validation/__init__.py +15 -0
  135. package/skills/pptx/ooxml/scripts/validation/base.py +951 -0
  136. package/skills/pptx/ooxml/scripts/validation/docx.py +274 -0
  137. package/skills/pptx/ooxml/scripts/validation/pptx.py +315 -0
  138. package/skills/pptx/ooxml/scripts/validation/redlining.py +279 -0
  139. package/skills/pptx/ooxml.md +427 -0
  140. package/skills/pptx/scripts/html2pptx.js +995 -0
  141. package/skills/pptx/scripts/inventory.py +1020 -0
  142. package/skills/pptx/scripts/rearrange.py +231 -0
  143. package/skills/pptx/scripts/replace.py +385 -0
  144. package/skills/pptx/scripts/thumbnail.py +450 -0
  145. package/skills/receiving-code-review/SKILL.md +213 -0
  146. package/skills/requesting-code-review/SKILL.md +105 -0
  147. package/skills/requesting-code-review/code-reviewer.md +146 -0
  148. package/skills/subagent-driven-development/SKILL.md +277 -0
  149. package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -0
  150. package/skills/subagent-driven-development/implementer-prompt.md +113 -0
  151. package/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
  152. package/skills/supabase/.skillfish.json +10 -0
  153. package/skills/supabase/SKILL.md +106 -0
  154. package/skills/supabase/assets/feedback-issue-template.md +17 -0
  155. package/skills/supabase/references/skill-feedback.md +17 -0
  156. package/skills/supabase-postgres-best-practices/.skillfish.json +10 -0
  157. package/skills/supabase-postgres-best-practices/SKILL.md +64 -0
  158. package/skills/supabase-postgres-best-practices/references/_contributing.md +170 -0
  159. package/skills/supabase-postgres-best-practices/references/_sections.md +39 -0
  160. package/skills/supabase-postgres-best-practices/references/_template.md +34 -0
  161. package/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -0
  162. package/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -0
  163. package/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -0
  164. package/skills/supabase-postgres-best-practices/references/conn-limits.md +44 -0
  165. package/skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -0
  166. package/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -0
  167. package/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -0
  168. package/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -0
  169. package/skills/supabase-postgres-best-practices/references/data-pagination.md +50 -0
  170. package/skills/supabase-postgres-best-practices/references/data-upsert.md +50 -0
  171. package/skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -0
  172. package/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -0
  173. package/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -0
  174. package/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -0
  175. package/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -0
  176. package/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -0
  177. package/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -0
  178. package/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -0
  179. package/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -0
  180. package/skills/supabase-postgres-best-practices/references/query-index-types.md +48 -0
  181. package/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -0
  182. package/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -0
  183. package/skills/supabase-postgres-best-practices/references/schema-constraints.md +80 -0
  184. package/skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -0
  185. package/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -0
  186. package/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -0
  187. package/skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -0
  188. package/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -0
  189. package/skills/supabase-postgres-best-practices/references/security-privileges.md +54 -0
  190. package/skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -0
  191. package/skills/supabase-postgres-best-practices/references/security-rls-performance.md +57 -0
  192. package/skills/supabase-quickstart/SKILL.md +400 -0
  193. package/skills/systematic-debugging/CREATION-LOG.md +119 -0
  194. package/skills/systematic-debugging/SKILL.md +296 -0
  195. package/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
  196. package/skills/systematic-debugging/condition-based-waiting.md +115 -0
  197. package/skills/systematic-debugging/defense-in-depth.md +122 -0
  198. package/skills/systematic-debugging/find-polluter.sh +63 -0
  199. package/skills/systematic-debugging/root-cause-tracing.md +169 -0
  200. package/skills/systematic-debugging/test-academic.md +14 -0
  201. package/skills/systematic-debugging/test-pressure-1.md +58 -0
  202. package/skills/systematic-debugging/test-pressure-2.md +68 -0
  203. package/skills/systematic-debugging/test-pressure-3.md +69 -0
  204. package/skills/test-driven-development/SKILL.md +371 -0
  205. package/skills/test-driven-development/testing-anti-patterns.md +299 -0
  206. package/skills/using-git-worktrees/SKILL.md +218 -0
  207. package/skills/using-superpowers/SKILL.md +115 -0
  208. package/skills/using-superpowers/references/codex-tools.md +100 -0
  209. package/skills/using-superpowers/references/gemini-tools.md +33 -0
  210. package/skills/verification-before-completion/SKILL.md +139 -0
  211. package/skills/video-production/SKILL.md +8 -7
  212. package/skills/writing-plans/SKILL.md +152 -0
  213. package/skills/writing-plans/plan-document-reviewer-prompt.md +49 -0
  214. package/skills/writing-skills/SKILL.md +655 -0
  215. package/skills/writing-skills/anthropic-best-practices.md +1150 -0
  216. package/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  217. package/skills/writing-skills/graphviz-conventions.dot +172 -0
  218. package/skills/writing-skills/persuasion-principles.md +187 -0
  219. package/skills/writing-skills/render-graphs.js +168 -0
  220. package/skills/writing-skills/testing-skills-with-subagents.md +384 -0
  221. package/skills/xlsx/.skillfish.json +10 -0
  222. package/skills/xlsx/SKILL.md +288 -0
  223. package/skills/xlsx/recalc.py +178 -0
  224. package/skills/color-grading/SKILL.md +0 -152
  225. package/skills/ffmpeg-patterns/SKILL.md +0 -240
  226. package/skills/image-prompting-guide/SKILL.md +0 -143
  227. package/skills/music-prompting/SKILL.md +0 -146
  228. package/skills/production-review/SKILL.md +0 -152
  229. package/skills/short-form-video/SKILL.md +0 -168
  230. package/skills/sound-design/SKILL.md +0 -154
  231. package/skills/storytelling/SKILL.md +0 -139
  232. package/skills/subtitle-production/SKILL.md +0 -244
  233. package/skills/subtitle-production/reference/burn_to_video.py +0 -222
  234. package/skills/subtitle-production/reference/export_srts.py +0 -127
  235. package/skills/subtitle-production/reference/gen_srt.py +0 -42
  236. package/skills/typography-video/SKILL.md +0 -182
  237. package/skills/typography-video/reference/KineticTitleScene.tsx +0 -345
  238. package/skills/video-editing/SKILL.md +0 -128
  239. package/skills/video-prompting-guide/SKILL.md +0 -268
@@ -0,0 +1,599 @@
1
+ # Office Open XML Technical Reference
2
+
3
+ **Important: Read this entire document before starting.** This document covers:
4
+ - [Technical Guidelines](#technical-guidelines) - Schema compliance rules and validation requirements
5
+ - [Document Content Patterns](#document-content-patterns) - XML patterns for headings, lists, tables, formatting, etc.
6
+ - [Document Library (Python)](#document-library-python) - Recommended approach for OOXML manipulation with automatic infrastructure setup
7
+ - [Tracked Changes (Redlining)](#tracked-changes-redlining) - XML patterns for implementing tracked changes
8
+
9
+ ## Technical Guidelines
10
+
11
+ ### Schema Compliance
12
+ - **Element ordering in `<w:pPr>`**: `<w:pStyle>`, `<w:numPr>`, `<w:spacing>`, `<w:ind>`, `<w:jc>`
13
+ - **Whitespace**: Add `xml:space='preserve'` to `<w:t>` elements with leading/trailing spaces
14
+ - **Unicode**: Escape characters in ASCII content: `"` becomes `&#8220;`
15
+ - **Character encoding reference**: Curly quotes `""` become `&#8220;&#8221;`, apostrophe `'` becomes `&#8217;`, em-dash `—` becomes `&#8212;`
16
+ - **Tracked changes**: Use `<w:del>` and `<w:ins>` tags with `w:author="Claude"` outside `<w:r>` elements
17
+ - **Critical**: `<w:ins>` closes with `</w:ins>`, `<w:del>` closes with `</w:del>` - never mix
18
+ - **RSIDs must be 8-digit hex**: Use values like `00AB1234` (only 0-9, A-F characters)
19
+ - **trackRevisions placement**: Add `<w:trackRevisions/>` after `<w:proofState>` in settings.xml
20
+ - **Images**: Add to `word/media/`, reference in `document.xml`, set dimensions to prevent overflow
21
+
22
+ ## Document Content Patterns
23
+
24
+ ### Basic Structure
25
+ ```xml
26
+ <w:p>
27
+ <w:r><w:t>Text content</w:t></w:r>
28
+ </w:p>
29
+ ```
30
+
31
+ ### Headings and Styles
32
+ ```xml
33
+ <w:p>
34
+ <w:pPr>
35
+ <w:pStyle w:val="Title"/>
36
+ <w:jc w:val="center"/>
37
+ </w:pPr>
38
+ <w:r><w:t>Document Title</w:t></w:r>
39
+ </w:p>
40
+
41
+ <w:p>
42
+ <w:pPr><w:pStyle w:val="Heading2"/></w:pPr>
43
+ <w:r><w:t>Section Heading</w:t></w:r>
44
+ </w:p>
45
+ ```
46
+
47
+ ### Text Formatting
48
+ ```xml
49
+ <!-- Bold -->
50
+ <w:r><w:rPr><w:b/><w:bCs/></w:rPr><w:t>Bold</w:t></w:r>
51
+ <!-- Italic -->
52
+ <w:r><w:rPr><w:i/><w:iCs/></w:rPr><w:t>Italic</w:t></w:r>
53
+ <!-- Underline -->
54
+ <w:r><w:rPr><w:u w:val="single"/></w:rPr><w:t>Underlined</w:t></w:r>
55
+ <!-- Highlight -->
56
+ <w:r><w:rPr><w:highlight w:val="yellow"/></w:rPr><w:t>Highlighted</w:t></w:r>
57
+ ```
58
+
59
+ ### Lists
60
+ ```xml
61
+ <!-- Numbered list -->
62
+ <w:p>
63
+ <w:pPr>
64
+ <w:pStyle w:val="ListParagraph"/>
65
+ <w:numPr><w:ilvl w:val="0"/><w:numId w:val="1"/></w:numPr>
66
+ <w:spacing w:before="240"/>
67
+ </w:pPr>
68
+ <w:r><w:t>First item</w:t></w:r>
69
+ </w:p>
70
+
71
+ <!-- Restart numbered list at 1 - use different numId -->
72
+ <w:p>
73
+ <w:pPr>
74
+ <w:pStyle w:val="ListParagraph"/>
75
+ <w:numPr><w:ilvl w:val="0"/><w:numId w:val="2"/></w:numPr>
76
+ <w:spacing w:before="240"/>
77
+ </w:pPr>
78
+ <w:r><w:t>New list item 1</w:t></w:r>
79
+ </w:p>
80
+
81
+ <!-- Bullet list (level 2) -->
82
+ <w:p>
83
+ <w:pPr>
84
+ <w:pStyle w:val="ListParagraph"/>
85
+ <w:numPr><w:ilvl w:val="1"/><w:numId w:val="1"/></w:numPr>
86
+ <w:spacing w:before="240"/>
87
+ <w:ind w:left="900"/>
88
+ </w:pPr>
89
+ <w:r><w:t>Bullet item</w:t></w:r>
90
+ </w:p>
91
+ ```
92
+
93
+ ### Tables
94
+ ```xml
95
+ <w:tbl>
96
+ <w:tblPr>
97
+ <w:tblStyle w:val="TableGrid"/>
98
+ <w:tblW w:w="0" w:type="auto"/>
99
+ </w:tblPr>
100
+ <w:tblGrid>
101
+ <w:gridCol w:w="4675"/><w:gridCol w:w="4675"/>
102
+ </w:tblGrid>
103
+ <w:tr>
104
+ <w:tc>
105
+ <w:tcPr><w:tcW w:w="4675" w:type="dxa"/></w:tcPr>
106
+ <w:p><w:r><w:t>Cell 1</w:t></w:r></w:p>
107
+ </w:tc>
108
+ <w:tc>
109
+ <w:tcPr><w:tcW w:w="4675" w:type="dxa"/></w:tcPr>
110
+ <w:p><w:r><w:t>Cell 2</w:t></w:r></w:p>
111
+ </w:tc>
112
+ </w:tr>
113
+ </w:tbl>
114
+ ```
115
+
116
+ ### Layout
117
+ ```xml
118
+ <!-- Page break before new section (common pattern) -->
119
+ <w:p>
120
+ <w:r>
121
+ <w:br w:type="page"/>
122
+ </w:r>
123
+ </w:p>
124
+ <w:p>
125
+ <w:pPr>
126
+ <w:pStyle w:val="Heading1"/>
127
+ </w:pPr>
128
+ <w:r>
129
+ <w:t>New Section Title</w:t>
130
+ </w:r>
131
+ </w:p>
132
+
133
+ <!-- Centered paragraph -->
134
+ <w:p>
135
+ <w:pPr>
136
+ <w:spacing w:before="240" w:after="0"/>
137
+ <w:jc w:val="center"/>
138
+ </w:pPr>
139
+ <w:r><w:t>Centered text</w:t></w:r>
140
+ </w:p>
141
+
142
+ <!-- Font change - paragraph level (applies to all runs) -->
143
+ <w:p>
144
+ <w:pPr>
145
+ <w:rPr><w:rFonts w:ascii="Courier New" w:hAnsi="Courier New"/></w:rPr>
146
+ </w:pPr>
147
+ <w:r><w:t>Monospace text</w:t></w:r>
148
+ </w:p>
149
+
150
+ <!-- Font change - run level (specific to this text) -->
151
+ <w:p>
152
+ <w:r>
153
+ <w:rPr><w:rFonts w:ascii="Courier New" w:hAnsi="Courier New"/></w:rPr>
154
+ <w:t>This text is Courier New</w:t>
155
+ </w:r>
156
+ <w:r><w:t> and this text uses default font</w:t></w:r>
157
+ </w:p>
158
+ ```
159
+
160
+ ## File Updates
161
+
162
+ When adding content, update these files:
163
+
164
+ **`word/_rels/document.xml.rels`:**
165
+ ```xml
166
+ <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering" Target="numbering.xml"/>
167
+ <Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image1.png"/>
168
+ ```
169
+
170
+ **`[Content_Types].xml`:**
171
+ ```xml
172
+ <Default Extension="png" ContentType="image/png"/>
173
+ <Override PartName="/word/numbering.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"/>
174
+ ```
175
+
176
+ ### Images
177
+ **CRITICAL**: Calculate dimensions to prevent page overflow and maintain aspect ratio.
178
+
179
+ ```xml
180
+ <!-- Minimal required structure -->
181
+ <w:p>
182
+ <w:r>
183
+ <w:drawing>
184
+ <wp:inline>
185
+ <wp:extent cx="2743200" cy="1828800"/>
186
+ <wp:docPr id="1" name="Picture 1"/>
187
+ <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
188
+ <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
189
+ <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
190
+ <pic:nvPicPr>
191
+ <pic:cNvPr id="0" name="image1.png"/>
192
+ <pic:cNvPicPr/>
193
+ </pic:nvPicPr>
194
+ <pic:blipFill>
195
+ <a:blip r:embed="rId5"/>
196
+ <!-- Add for stretch fill with aspect ratio preservation -->
197
+ <a:stretch>
198
+ <a:fillRect/>
199
+ </a:stretch>
200
+ </pic:blipFill>
201
+ <pic:spPr>
202
+ <a:xfrm>
203
+ <a:ext cx="2743200" cy="1828800"/>
204
+ </a:xfrm>
205
+ <a:prstGeom prst="rect"/>
206
+ </pic:spPr>
207
+ </pic:pic>
208
+ </a:graphicData>
209
+ </a:graphic>
210
+ </wp:inline>
211
+ </w:drawing>
212
+ </w:r>
213
+ </w:p>
214
+ ```
215
+
216
+ ### Links (Hyperlinks)
217
+
218
+ **IMPORTANT**: All hyperlinks (both internal and external) require the Hyperlink style to be defined in styles.xml. Without this style, links will look like regular text instead of blue underlined clickable links.
219
+
220
+ **External Links:**
221
+ ```xml
222
+ <!-- In document.xml -->
223
+ <w:hyperlink r:id="rId5">
224
+ <w:r>
225
+ <w:rPr><w:rStyle w:val="Hyperlink"/></w:rPr>
226
+ <w:t>Link Text</w:t>
227
+ </w:r>
228
+ </w:hyperlink>
229
+
230
+ <!-- In word/_rels/document.xml.rels -->
231
+ <Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
232
+ Target="https://www.example.com/" TargetMode="External"/>
233
+ ```
234
+
235
+ **Internal Links:**
236
+
237
+ ```xml
238
+ <!-- Link to bookmark -->
239
+ <w:hyperlink w:anchor="myBookmark">
240
+ <w:r>
241
+ <w:rPr><w:rStyle w:val="Hyperlink"/></w:rPr>
242
+ <w:t>Link Text</w:t>
243
+ </w:r>
244
+ </w:hyperlink>
245
+
246
+ <!-- Bookmark target -->
247
+ <w:bookmarkStart w:id="0" w:name="myBookmark"/>
248
+ <w:r><w:t>Target content</w:t></w:r>
249
+ <w:bookmarkEnd w:id="0"/>
250
+ ```
251
+
252
+ **Hyperlink Style (required in styles.xml):**
253
+ ```xml
254
+ <w:style w:type="character" w:styleId="Hyperlink">
255
+ <w:name w:val="Hyperlink"/>
256
+ <w:basedOn w:val="DefaultParagraphFont"/>
257
+ <w:uiPriority w:val="99"/>
258
+ <w:unhideWhenUsed/>
259
+ <w:rPr>
260
+ <w:color w:val="467886" w:themeColor="hyperlink"/>
261
+ <w:u w:val="single"/>
262
+ </w:rPr>
263
+ </w:style>
264
+ ```
265
+
266
+ ## Document Library (Python)
267
+
268
+ Use the Document class from `scripts/document.py` for all tracked changes and comments. It automatically handles infrastructure setup (people.xml, RSIDs, settings.xml, comment files, relationships, content types). Only use direct XML manipulation for complex scenarios not supported by the library.
269
+
270
+ **Working with Unicode and Entities:**
271
+ - **Searching**: Both entity notation and Unicode characters work - `contains="&#8220;Company"` and `contains="\u201cCompany"` find the same text
272
+ - **Replacing**: Use either entities (`&#8220;`) or Unicode (`\u201c`) - both work and will be converted appropriately based on the file's encoding (ascii → entities, utf-8 → Unicode)
273
+
274
+ ### Initialization
275
+
276
+ **Critical**: Before importing `Document`, search for `document.py` using `find` to locate the correct module path, then adjust the import statement accordingly. Alternatively, set `PYTHONPATH` to the project root.
277
+
278
+ ```python
279
+ # Adjust import path or run with: PYTHONPATH=/path/to/skill python script.py
280
+ # e.g: from skills.docx.scripts.document import Document, DocxXMLEditor
281
+ from ... import Document, DocxXMLEditor
282
+
283
+ # Basic initialization (automatically creates temp copy and sets up infrastructure)
284
+ doc = Document('unpacked')
285
+
286
+ # Customize author and initials
287
+ doc = Document('unpacked', author="John Doe", initials="JD")
288
+
289
+ # Enable track revisions mode
290
+ doc = Document('unpacked', track_revisions=True)
291
+
292
+ # Specify custom RSID (auto-generated if not provided)
293
+ doc = Document('unpacked', rsid="07DC5ECB")
294
+ ```
295
+
296
+ ### Creating Tracked Changes
297
+
298
+ **CRITICAL**: Only mark text that actually changes. Keep ALL unchanged text outside `<w:del>`/`<w:ins>` tags. Marking unchanged text makes edits unprofessional and harder to review.
299
+
300
+ **Attribute Handling**: The Document class auto-injects attributes (w:id, w:date, w:rsidR, w:rsidDel, w16du:dateUtc, xml:space) into new elements. When preserving unchanged text from the original document, copy the original `<w:r>` element with its existing attributes to maintain document integrity.
301
+
302
+ **Method Selection Guide**:
303
+ - **Adding your own changes to regular text**: Use `replace_node()` with `<w:del>`/`<w:ins>` tags, or `suggest_deletion()` for removing entire `<w:r>` or `<w:p>` elements
304
+ - **Partially modifying another author's tracked change**: Use `replace_node()` to nest your changes inside their `<w:ins>`/`<w:del>`
305
+ - **Completely rejecting another author's insertion**: Use `revert_insertion()` on the `<w:ins>` element (NOT `suggest_deletion()`)
306
+ - **Completely rejecting another author's deletion**: Use `revert_deletion()` on the `<w:del>` element to restore deleted content using tracked changes
307
+
308
+ ```python
309
+ # Minimal edit - change one word: "The report is monthly" → "The report is quarterly"
310
+ # Original: <w:r w:rsidR="00AB12CD"><w:rPr><w:rFonts w:ascii="Calibri"/></w:rPr><w:t>The report is monthly</w:t></w:r>
311
+ node = doc["word/document.xml"].get_node(tag="w:r", contains="The report is monthly")
312
+ rpr = tags[0].toxml() if (tags := node.getElementsByTagName("w:rPr")) else ""
313
+ replacement = f'<w:r w:rsidR="00AB12CD">{rpr}<w:t>The report is </w:t></w:r><w:del><w:r>{rpr}<w:delText>monthly</w:delText></w:r></w:del><w:ins><w:r>{rpr}<w:t>quarterly</w:t></w:r></w:ins>'
314
+ doc["word/document.xml"].replace_node(node, replacement)
315
+
316
+ # Minimal edit - change number: "within 30 days" → "within 45 days"
317
+ # Original: <w:r w:rsidR="00XYZ789"><w:rPr><w:rFonts w:ascii="Calibri"/></w:rPr><w:t>within 30 days</w:t></w:r>
318
+ node = doc["word/document.xml"].get_node(tag="w:r", contains="within 30 days")
319
+ rpr = tags[0].toxml() if (tags := node.getElementsByTagName("w:rPr")) else ""
320
+ replacement = f'<w:r w:rsidR="00XYZ789">{rpr}<w:t>within </w:t></w:r><w:del><w:r>{rpr}<w:delText>30</w:delText></w:r></w:del><w:ins><w:r>{rpr}<w:t>45</w:t></w:r></w:ins><w:r w:rsidR="00XYZ789">{rpr}<w:t> days</w:t></w:r>'
321
+ doc["word/document.xml"].replace_node(node, replacement)
322
+
323
+ # Complete replacement - preserve formatting even when replacing all text
324
+ node = doc["word/document.xml"].get_node(tag="w:r", contains="apple")
325
+ rpr = tags[0].toxml() if (tags := node.getElementsByTagName("w:rPr")) else ""
326
+ replacement = f'<w:del><w:r>{rpr}<w:delText>apple</w:delText></w:r></w:del><w:ins><w:r>{rpr}<w:t>banana orange</w:t></w:r></w:ins>'
327
+ doc["word/document.xml"].replace_node(node, replacement)
328
+
329
+ # Insert new content (no attributes needed - auto-injected)
330
+ node = doc["word/document.xml"].get_node(tag="w:r", contains="existing text")
331
+ doc["word/document.xml"].insert_after(node, '<w:ins><w:r><w:t>new text</w:t></w:r></w:ins>')
332
+
333
+ # Partially delete another author's insertion
334
+ # Original: <w:ins w:author="Jane Smith" w:date="..."><w:r><w:t>quarterly financial report</w:t></w:r></w:ins>
335
+ # Goal: Delete only "financial" to make it "quarterly report"
336
+ node = doc["word/document.xml"].get_node(tag="w:ins", attrs={"w:id": "5"})
337
+ # IMPORTANT: Preserve w:author="Jane Smith" on the outer <w:ins> to maintain authorship
338
+ replacement = '''<w:ins w:author="Jane Smith" w:date="2025-01-15T10:00:00Z">
339
+ <w:r><w:t>quarterly </w:t></w:r>
340
+ <w:del><w:r><w:delText>financial </w:delText></w:r></w:del>
341
+ <w:r><w:t>report</w:t></w:r>
342
+ </w:ins>'''
343
+ doc["word/document.xml"].replace_node(node, replacement)
344
+
345
+ # Change part of another author's insertion
346
+ # Original: <w:ins w:author="Jane Smith"><w:r><w:t>in silence, safe and sound</w:t></w:r></w:ins>
347
+ # Goal: Change "safe and sound" to "soft and unbound"
348
+ node = doc["word/document.xml"].get_node(tag="w:ins", attrs={"w:id": "8"})
349
+ replacement = f'''<w:ins w:author="Jane Smith" w:date="2025-01-15T10:00:00Z">
350
+ <w:r><w:t>in silence, </w:t></w:r>
351
+ </w:ins>
352
+ <w:ins>
353
+ <w:r><w:t>soft and unbound</w:t></w:r>
354
+ </w:ins>
355
+ <w:ins w:author="Jane Smith" w:date="2025-01-15T10:00:00Z">
356
+ <w:del><w:r><w:delText>safe and sound</w:delText></w:r></w:del>
357
+ </w:ins>'''
358
+ doc["word/document.xml"].replace_node(node, replacement)
359
+
360
+ # Delete entire run (use only when deleting all content; use replace_node for partial deletions)
361
+ node = doc["word/document.xml"].get_node(tag="w:r", contains="text to delete")
362
+ doc["word/document.xml"].suggest_deletion(node)
363
+
364
+ # Delete entire paragraph (in-place, handles both regular and numbered list paragraphs)
365
+ para = doc["word/document.xml"].get_node(tag="w:p", contains="paragraph to delete")
366
+ doc["word/document.xml"].suggest_deletion(para)
367
+
368
+ # Add new numbered list item
369
+ target_para = doc["word/document.xml"].get_node(tag="w:p", contains="existing list item")
370
+ pPr = tags[0].toxml() if (tags := target_para.getElementsByTagName("w:pPr")) else ""
371
+ new_item = f'<w:p>{pPr}<w:r><w:t>New item</w:t></w:r></w:p>'
372
+ tracked_para = DocxXMLEditor.suggest_paragraph(new_item)
373
+ doc["word/document.xml"].insert_after(target_para, tracked_para)
374
+ # Optional: add spacing paragraph before content for better visual separation
375
+ # spacing = DocxXMLEditor.suggest_paragraph('<w:p><w:pPr><w:pStyle w:val="ListParagraph"/></w:pPr></w:p>')
376
+ # doc["word/document.xml"].insert_after(target_para, spacing + tracked_para)
377
+ ```
378
+
379
+ ### Adding Comments
380
+
381
+ ```python
382
+ # Add comment spanning two existing tracked changes
383
+ # Note: w:id is auto-generated. Only search by w:id if you know it from XML inspection
384
+ start_node = doc["word/document.xml"].get_node(tag="w:del", attrs={"w:id": "1"})
385
+ end_node = doc["word/document.xml"].get_node(tag="w:ins", attrs={"w:id": "2"})
386
+ doc.add_comment(start=start_node, end=end_node, text="Explanation of this change")
387
+
388
+ # Add comment on a paragraph
389
+ para = doc["word/document.xml"].get_node(tag="w:p", contains="paragraph text")
390
+ doc.add_comment(start=para, end=para, text="Comment on this paragraph")
391
+
392
+ # Add comment on newly created tracked change
393
+ # First create the tracked change
394
+ node = doc["word/document.xml"].get_node(tag="w:r", contains="old")
395
+ new_nodes = doc["word/document.xml"].replace_node(
396
+ node,
397
+ '<w:del><w:r><w:delText>old</w:delText></w:r></w:del><w:ins><w:r><w:t>new</w:t></w:r></w:ins>'
398
+ )
399
+ # Then add comment on the newly created elements
400
+ # new_nodes[0] is the <w:del>, new_nodes[1] is the <w:ins>
401
+ doc.add_comment(start=new_nodes[0], end=new_nodes[1], text="Changed old to new per requirements")
402
+
403
+ # Reply to existing comment
404
+ doc.reply_to_comment(parent_comment_id=0, text="I agree with this change")
405
+ ```
406
+
407
+ ### Rejecting Tracked Changes
408
+
409
+ **IMPORTANT**: Use `revert_insertion()` to reject insertions and `revert_deletion()` to restore deletions using tracked changes. Use `suggest_deletion()` only for regular unmarked content.
410
+
411
+ ```python
412
+ # Reject insertion (wraps it in deletion)
413
+ # Use this when another author inserted text that you want to delete
414
+ ins = doc["word/document.xml"].get_node(tag="w:ins", attrs={"w:id": "5"})
415
+ nodes = doc["word/document.xml"].revert_insertion(ins) # Returns [ins]
416
+
417
+ # Reject deletion (creates insertion to restore deleted content)
418
+ # Use this when another author deleted text that you want to restore
419
+ del_elem = doc["word/document.xml"].get_node(tag="w:del", attrs={"w:id": "3"})
420
+ nodes = doc["word/document.xml"].revert_deletion(del_elem) # Returns [del_elem, new_ins]
421
+
422
+ # Reject all insertions in a paragraph
423
+ para = doc["word/document.xml"].get_node(tag="w:p", contains="paragraph text")
424
+ nodes = doc["word/document.xml"].revert_insertion(para) # Returns [para]
425
+
426
+ # Reject all deletions in a paragraph
427
+ para = doc["word/document.xml"].get_node(tag="w:p", contains="paragraph text")
428
+ nodes = doc["word/document.xml"].revert_deletion(para) # Returns [para]
429
+ ```
430
+
431
+ ### Inserting Images
432
+
433
+ **CRITICAL**: The Document class works with a temporary copy at `doc.unpacked_path`. Always copy images to this temp directory, not the original unpacked folder.
434
+
435
+ ```python
436
+ from PIL import Image
437
+ import shutil, os
438
+
439
+ # Initialize document first
440
+ doc = Document('unpacked')
441
+
442
+ # Copy image and calculate full-width dimensions with aspect ratio
443
+ media_dir = os.path.join(doc.unpacked_path, 'word/media')
444
+ os.makedirs(media_dir, exist_ok=True)
445
+ shutil.copy('image.png', os.path.join(media_dir, 'image1.png'))
446
+ img = Image.open(os.path.join(media_dir, 'image1.png'))
447
+ width_emus = int(6.5 * 914400) # 6.5" usable width, 914400 EMUs/inch
448
+ height_emus = int(width_emus * img.size[1] / img.size[0])
449
+
450
+ # Add relationship and content type
451
+ rels_editor = doc['word/_rels/document.xml.rels']
452
+ next_rid = rels_editor.get_next_rid()
453
+ rels_editor.append_to(rels_editor.dom.documentElement,
454
+ f'<Relationship Id="{next_rid}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image1.png"/>')
455
+ doc['[Content_Types].xml'].append_to(doc['[Content_Types].xml'].dom.documentElement,
456
+ '<Default Extension="png" ContentType="image/png"/>')
457
+
458
+ # Insert image
459
+ node = doc["word/document.xml"].get_node(tag="w:p", line_number=100)
460
+ doc["word/document.xml"].insert_after(node, f'''<w:p>
461
+ <w:r>
462
+ <w:drawing>
463
+ <wp:inline distT="0" distB="0" distL="0" distR="0">
464
+ <wp:extent cx="{width_emus}" cy="{height_emus}"/>
465
+ <wp:docPr id="1" name="Picture 1"/>
466
+ <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
467
+ <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
468
+ <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
469
+ <pic:nvPicPr><pic:cNvPr id="1" name="image1.png"/><pic:cNvPicPr/></pic:nvPicPr>
470
+ <pic:blipFill><a:blip r:embed="{next_rid}"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill>
471
+ <pic:spPr><a:xfrm><a:ext cx="{width_emus}" cy="{height_emus}"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr>
472
+ </pic:pic>
473
+ </a:graphicData>
474
+ </a:graphic>
475
+ </wp:inline>
476
+ </w:drawing>
477
+ </w:r>
478
+ </w:p>''')
479
+ ```
480
+
481
+ ### Getting Nodes
482
+
483
+ ```python
484
+ # By text content
485
+ node = doc["word/document.xml"].get_node(tag="w:p", contains="specific text")
486
+
487
+ # By line range
488
+ para = doc["word/document.xml"].get_node(tag="w:p", line_number=range(100, 150))
489
+
490
+ # By attributes
491
+ node = doc["word/document.xml"].get_node(tag="w:del", attrs={"w:id": "1"})
492
+
493
+ # By exact line number (must be line number where tag opens)
494
+ para = doc["word/document.xml"].get_node(tag="w:p", line_number=42)
495
+
496
+ # Combine filters
497
+ node = doc["word/document.xml"].get_node(tag="w:r", line_number=range(40, 60), contains="text")
498
+
499
+ # Disambiguate when text appears multiple times - add line_number range
500
+ node = doc["word/document.xml"].get_node(tag="w:r", contains="Section", line_number=range(2400, 2500))
501
+ ```
502
+
503
+ ### Saving
504
+
505
+ ```python
506
+ # Save with automatic validation (copies back to original directory)
507
+ doc.save() # Validates by default, raises error if validation fails
508
+
509
+ # Save to different location
510
+ doc.save('modified-unpacked')
511
+
512
+ # Skip validation (debugging only - needing this in production indicates XML issues)
513
+ doc.save(validate=False)
514
+ ```
515
+
516
+ ### Direct DOM Manipulation
517
+
518
+ For complex scenarios not covered by the library:
519
+
520
+ ```python
521
+ # Access any XML file
522
+ editor = doc["word/document.xml"]
523
+ editor = doc["word/comments.xml"]
524
+
525
+ # Direct DOM access (defusedxml.minidom.Document)
526
+ node = doc["word/document.xml"].get_node(tag="w:p", line_number=5)
527
+ parent = node.parentNode
528
+ parent.removeChild(node)
529
+ parent.appendChild(node) # Move to end
530
+
531
+ # General document manipulation (without tracked changes)
532
+ old_node = doc["word/document.xml"].get_node(tag="w:p", contains="original text")
533
+ doc["word/document.xml"].replace_node(old_node, "<w:p><w:r><w:t>replacement text</w:t></w:r></w:p>")
534
+
535
+ # Multiple insertions - use return value to maintain order
536
+ node = doc["word/document.xml"].get_node(tag="w:r", line_number=100)
537
+ nodes = doc["word/document.xml"].insert_after(node, "<w:r><w:t>A</w:t></w:r>")
538
+ nodes = doc["word/document.xml"].insert_after(nodes[-1], "<w:r><w:t>B</w:t></w:r>")
539
+ nodes = doc["word/document.xml"].insert_after(nodes[-1], "<w:r><w:t>C</w:t></w:r>")
540
+ # Results in: original_node, A, B, C
541
+ ```
542
+
543
+ ## Tracked Changes (Redlining)
544
+
545
+ **Use the Document class above for all tracked changes.** The patterns below are for reference when constructing replacement XML strings.
546
+
547
+ ### Validation Rules
548
+ The validator checks that the document text matches the original after reverting Claude's changes. This means:
549
+ - **NEVER modify text inside another author's `<w:ins>` or `<w:del>` tags**
550
+ - **ALWAYS use nested deletions** to remove another author's insertions
551
+ - **Every edit must be properly tracked** with `<w:ins>` or `<w:del>` tags
552
+
553
+ ### Tracked Change Patterns
554
+
555
+ **CRITICAL RULES**:
556
+ 1. Never modify the content inside another author's tracked changes. Always use nested deletions.
557
+ 2. **XML Structure**: Always place `<w:del>` and `<w:ins>` at paragraph level containing complete `<w:r>` elements. Never nest inside `<w:r>` elements - this creates invalid XML that breaks document processing.
558
+
559
+ **Text Insertion:**
560
+ ```xml
561
+ <w:ins w:id="1" w:author="Claude" w:date="2025-07-30T23:05:00Z" w16du:dateUtc="2025-07-31T06:05:00Z">
562
+ <w:r w:rsidR="00792858">
563
+ <w:t>inserted text</w:t>
564
+ </w:r>
565
+ </w:ins>
566
+ ```
567
+
568
+ **Text Deletion:**
569
+ ```xml
570
+ <w:del w:id="2" w:author="Claude" w:date="2025-07-30T23:05:00Z" w16du:dateUtc="2025-07-31T06:05:00Z">
571
+ <w:r w:rsidDel="00792858">
572
+ <w:delText>deleted text</w:delText>
573
+ </w:r>
574
+ </w:del>
575
+ ```
576
+
577
+ **Deleting Another Author's Insertion (MUST use nested structure):**
578
+ ```xml
579
+ <!-- Nest deletion inside the original insertion -->
580
+ <w:ins w:author="Jane Smith" w:id="16">
581
+ <w:del w:author="Claude" w:id="40">
582
+ <w:r><w:delText>monthly</w:delText></w:r>
583
+ </w:del>
584
+ </w:ins>
585
+ <w:ins w:author="Claude" w:id="41">
586
+ <w:r><w:t>weekly</w:t></w:r>
587
+ </w:ins>
588
+ ```
589
+
590
+ **Restoring Another Author's Deletion:**
591
+ ```xml
592
+ <!-- Leave their deletion unchanged, add new insertion after it -->
593
+ <w:del w:author="Jane Smith" w:id="50">
594
+ <w:r><w:delText>within 30 days</w:delText></w:r>
595
+ </w:del>
596
+ <w:ins w:author="Claude" w:id="51">
597
+ <w:r><w:t>within 30 days</w:t></w:r>
598
+ </w:ins>
599
+ ```
@@ -0,0 +1 @@
1
+ # Make scripts directory a package for relative imports in tests