@kortix/sandbox 0.4.1

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 (246) hide show
  1. package/config/customize.sh +143 -0
  2. package/config/kortix-env-setup.sh +25 -0
  3. package/kortix-master/package.json +22 -0
  4. package/kortix-master/src/config.ts +22 -0
  5. package/kortix-master/src/index.ts +44 -0
  6. package/kortix-master/src/routes/env.ts +65 -0
  7. package/kortix-master/src/routes/proxy.ts +108 -0
  8. package/kortix-master/src/routes/update.ts +185 -0
  9. package/kortix-master/src/services/proxy.ts +43 -0
  10. package/kortix-master/src/services/secret-store.ts +156 -0
  11. package/kortix-master/tsconfig.json +14 -0
  12. package/opencode/agents/kortix-browser.md +142 -0
  13. package/opencode/agents/kortix-build.md +62 -0
  14. package/opencode/agents/kortix-explore.md +66 -0
  15. package/opencode/agents/kortix-image-gen.md +33 -0
  16. package/opencode/agents/kortix-main.md +450 -0
  17. package/opencode/agents/kortix-plan.md +100 -0
  18. package/opencode/agents/kortix-research.md +84 -0
  19. package/opencode/agents/kortix-sheets.md +61 -0
  20. package/opencode/agents/kortix-slides.md +64 -0
  21. package/opencode/agents/kortix-web-dev.md +572 -0
  22. package/opencode/commands/email.md +36 -0
  23. package/opencode/commands/init.md +43 -0
  24. package/opencode/commands/journal.md +44 -0
  25. package/opencode/commands/memory-init.md +81 -0
  26. package/opencode/commands/memory-search.md +50 -0
  27. package/opencode/commands/memory-status.md +56 -0
  28. package/opencode/commands/research.md +36 -0
  29. package/opencode/commands/search.md +38 -0
  30. package/opencode/commands/slides.md +32 -0
  31. package/opencode/commands/spreadsheet.md +30 -0
  32. package/opencode/memory.json +37 -0
  33. package/opencode/ocx.jsonc +10 -0
  34. package/opencode/opencode.jsonc +103 -0
  35. package/opencode/package.json +25 -0
  36. package/opencode/patches/apply.sh +19 -0
  37. package/opencode/patches/opencode-pty-spawn.txt +49 -0
  38. package/opencode/plugin/background-agents.ts.disabled +483 -0
  39. package/opencode/plugin/kdco-primitives/get-project-id.ts +172 -0
  40. package/opencode/plugin/kdco-primitives/index.ts +26 -0
  41. package/opencode/plugin/kdco-primitives/log-warn.ts +51 -0
  42. package/opencode/plugin/kdco-primitives/mutex.ts +122 -0
  43. package/opencode/plugin/kdco-primitives/shell.ts +138 -0
  44. package/opencode/plugin/kdco-primitives/temp.ts +36 -0
  45. package/opencode/plugin/kdco-primitives/terminal-detect.ts +34 -0
  46. package/opencode/plugin/kdco-primitives/types.ts +13 -0
  47. package/opencode/plugin/kdco-primitives/with-timeout.ts +84 -0
  48. package/opencode/plugin/memory.ts +306 -0
  49. package/opencode/plugin/worktree/state.ts +412 -0
  50. package/opencode/plugin/worktree/terminal.ts +1002 -0
  51. package/opencode/plugin/worktree.ts +861 -0
  52. package/opencode/skills/KORTIX-browser/SKILL.md +478 -0
  53. package/opencode/skills/KORTIX-cron-triggers/SKILL.md +173 -0
  54. package/opencode/skills/KORTIX-deep-research/SKILL.md +278 -0
  55. package/opencode/skills/KORTIX-docx/SKILL.md +398 -0
  56. package/opencode/skills/KORTIX-docx/scripts/__init__.py +1 -0
  57. package/opencode/skills/KORTIX-docx/scripts/accept_changes.py +104 -0
  58. package/opencode/skills/KORTIX-docx/scripts/comment.py +244 -0
  59. package/opencode/skills/KORTIX-docx/scripts/office/helpers/__init__.py +0 -0
  60. package/opencode/skills/KORTIX-docx/scripts/office/helpers/merge_runs.py +199 -0
  61. package/opencode/skills/KORTIX-docx/scripts/office/helpers/simplify_redlines.py +197 -0
  62. package/opencode/skills/KORTIX-docx/scripts/office/pack.py +159 -0
  63. package/opencode/skills/KORTIX-docx/scripts/office/soffice.py +183 -0
  64. package/opencode/skills/KORTIX-docx/scripts/office/unpack.py +132 -0
  65. package/opencode/skills/KORTIX-docx/scripts/office/validate.py +111 -0
  66. package/opencode/skills/KORTIX-docx/scripts/office/validators/__init__.py +15 -0
  67. package/opencode/skills/KORTIX-docx/scripts/office/validators/base.py +847 -0
  68. package/opencode/skills/KORTIX-docx/scripts/office/validators/docx.py +446 -0
  69. package/opencode/skills/KORTIX-docx/scripts/office/validators/pptx.py +275 -0
  70. package/opencode/skills/KORTIX-docx/scripts/office/validators/redlining.py +247 -0
  71. package/opencode/skills/KORTIX-docx/scripts/render_docx.py +179 -0
  72. package/opencode/skills/KORTIX-docx/scripts/templates/comments.xml +3 -0
  73. package/opencode/skills/KORTIX-docx/scripts/templates/commentsExtended.xml +3 -0
  74. package/opencode/skills/KORTIX-docx/scripts/templates/commentsExtensible.xml +3 -0
  75. package/opencode/skills/KORTIX-docx/scripts/templates/commentsIds.xml +3 -0
  76. package/opencode/skills/KORTIX-docx/scripts/templates/people.xml +3 -0
  77. package/opencode/skills/KORTIX-domain-research/SKILL.md +96 -0
  78. package/opencode/skills/KORTIX-domain-research/scripts/domain-lookup.py +810 -0
  79. package/opencode/skills/KORTIX-elevenlabs/SKILL.md +230 -0
  80. package/opencode/skills/KORTIX-elevenlabs/scripts/tts.py +389 -0
  81. package/opencode/skills/KORTIX-email/SKILL.md +145 -0
  82. package/opencode/skills/KORTIX-legal-writer/SKILL.md +409 -0
  83. package/opencode/skills/KORTIX-legal-writer/references/bluebook.md +152 -0
  84. package/opencode/skills/KORTIX-legal-writer/references/document-types.md +416 -0
  85. package/opencode/skills/KORTIX-legal-writer/scripts/courtlistener.py +291 -0
  86. package/opencode/skills/KORTIX-legal-writer/scripts/ecfr_lookup.py +299 -0
  87. package/opencode/skills/KORTIX-legal-writer/scripts/verify-legal.py +507 -0
  88. package/opencode/skills/KORTIX-logo-creator/SKILL.md +293 -0
  89. package/opencode/skills/KORTIX-logo-creator/references/prompt-patterns.md +134 -0
  90. package/opencode/skills/KORTIX-logo-creator/scripts/compose_logo.py +406 -0
  91. package/opencode/skills/KORTIX-logo-creator/scripts/create_logo_sheet.py +258 -0
  92. package/opencode/skills/KORTIX-logo-creator/scripts/remove_bg.py +96 -0
  93. package/opencode/skills/KORTIX-memory/SKILL.md +261 -0
  94. package/opencode/skills/KORTIX-memory/scripts/export-sessions.py +409 -0
  95. package/opencode/skills/KORTIX-paper-creator/SKILL.md +549 -0
  96. package/opencode/skills/KORTIX-paper-creator/assets/template.tex +101 -0
  97. package/opencode/skills/KORTIX-paper-creator/scripts/compile.sh +177 -0
  98. package/opencode/skills/KORTIX-paper-creator/scripts/openalex_to_bibtex.py +220 -0
  99. package/opencode/skills/KORTIX-paper-creator/scripts/verify.sh +354 -0
  100. package/opencode/skills/KORTIX-paper-search/SKILL.md +418 -0
  101. package/opencode/skills/KORTIX-pdf/SKILL.md +232 -0
  102. package/opencode/skills/KORTIX-pdf/forms.md +36 -0
  103. package/opencode/skills/KORTIX-pdf/reference.md +105 -0
  104. package/opencode/skills/KORTIX-pdf/scripts/check_bounding_boxes.py +65 -0
  105. package/opencode/skills/KORTIX-pdf/scripts/check_fillable_fields.py +11 -0
  106. package/opencode/skills/KORTIX-pdf/scripts/convert_pdf_to_images.py +33 -0
  107. package/opencode/skills/KORTIX-pdf/scripts/create_validation_image.py +37 -0
  108. package/opencode/skills/KORTIX-pdf/scripts/extract_form_field_info.py +122 -0
  109. package/opencode/skills/KORTIX-pdf/scripts/extract_form_structure.py +115 -0
  110. package/opencode/skills/KORTIX-pdf/scripts/fill_fillable_fields.py +98 -0
  111. package/opencode/skills/KORTIX-pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
  112. package/opencode/skills/KORTIX-plan/SKILL.md +228 -0
  113. package/opencode/skills/KORTIX-presentation-viewer/SKILL.md +87 -0
  114. package/opencode/skills/KORTIX-presentation-viewer/serve.ts +136 -0
  115. package/opencode/skills/KORTIX-presentation-viewer/viewer.html +559 -0
  116. package/opencode/skills/KORTIX-presentations/SKILL.md +344 -0
  117. package/opencode/skills/KORTIX-remotion/SKILL.md +56 -0
  118. package/opencode/skills/KORTIX-remotion/rules/3d.md +86 -0
  119. package/opencode/skills/KORTIX-remotion/rules/animations.md +29 -0
  120. package/opencode/skills/KORTIX-remotion/rules/assets.md +78 -0
  121. package/opencode/skills/KORTIX-remotion/rules/audio-visualization.md +198 -0
  122. package/opencode/skills/KORTIX-remotion/rules/audio.md +169 -0
  123. package/opencode/skills/KORTIX-remotion/rules/calculate-metadata.md +104 -0
  124. package/opencode/skills/KORTIX-remotion/rules/can-decode.md +75 -0
  125. package/opencode/skills/KORTIX-remotion/rules/charts.md +120 -0
  126. package/opencode/skills/KORTIX-remotion/rules/compositions.md +141 -0
  127. package/opencode/skills/KORTIX-remotion/rules/display-captions.md +184 -0
  128. package/opencode/skills/KORTIX-remotion/rules/extract-frames.md +229 -0
  129. package/opencode/skills/KORTIX-remotion/rules/ffmpeg.md +38 -0
  130. package/opencode/skills/KORTIX-remotion/rules/fonts.md +152 -0
  131. package/opencode/skills/KORTIX-remotion/rules/get-audio-duration.md +58 -0
  132. package/opencode/skills/KORTIX-remotion/rules/get-video-dimensions.md +68 -0
  133. package/opencode/skills/KORTIX-remotion/rules/get-video-duration.md +58 -0
  134. package/opencode/skills/KORTIX-remotion/rules/gifs.md +141 -0
  135. package/opencode/skills/KORTIX-remotion/rules/images.md +130 -0
  136. package/opencode/skills/KORTIX-remotion/rules/import-srt-captions.md +69 -0
  137. package/opencode/skills/KORTIX-remotion/rules/light-leaks.md +73 -0
  138. package/opencode/skills/KORTIX-remotion/rules/lottie.md +68 -0
  139. package/opencode/skills/KORTIX-remotion/rules/maps.md +401 -0
  140. package/opencode/skills/KORTIX-remotion/rules/measuring-dom-nodes.md +35 -0
  141. package/opencode/skills/KORTIX-remotion/rules/measuring-text.md +143 -0
  142. package/opencode/skills/KORTIX-remotion/rules/parameters.md +98 -0
  143. package/opencode/skills/KORTIX-remotion/rules/sequencing.md +118 -0
  144. package/opencode/skills/KORTIX-remotion/rules/subtitles.md +36 -0
  145. package/opencode/skills/KORTIX-remotion/rules/tailwind.md +11 -0
  146. package/opencode/skills/KORTIX-remotion/rules/text-animations.md +20 -0
  147. package/opencode/skills/KORTIX-remotion/rules/timing.md +179 -0
  148. package/opencode/skills/KORTIX-remotion/rules/transcribe-captions.md +70 -0
  149. package/opencode/skills/KORTIX-remotion/rules/transitions.md +197 -0
  150. package/opencode/skills/KORTIX-remotion/rules/transparent-videos.md +106 -0
  151. package/opencode/skills/KORTIX-remotion/rules/trimming.md +53 -0
  152. package/opencode/skills/KORTIX-remotion/rules/videos.md +171 -0
  153. package/opencode/skills/KORTIX-secrets/SKILL.md +280 -0
  154. package/opencode/skills/KORTIX-semantic-search/SKILL.md +213 -0
  155. package/opencode/skills/KORTIX-session-search/SKILL.md +807 -0
  156. package/opencode/skills/KORTIX-session-search/Untitled +1 -0
  157. package/opencode/skills/KORTIX-skill-creator/SKILL.md +163 -0
  158. package/opencode/skills/KORTIX-web-research/SKILL.md +69 -0
  159. package/opencode/skills/KORTIX-xlsx/LICENSE.txt +30 -0
  160. package/opencode/skills/KORTIX-xlsx/SKILL.md +549 -0
  161. package/opencode/skills/KORTIX-xlsx/scripts/office/helpers/__init__.py +0 -0
  162. package/opencode/skills/KORTIX-xlsx/scripts/office/helpers/merge_runs.py +199 -0
  163. package/opencode/skills/KORTIX-xlsx/scripts/office/helpers/simplify_redlines.py +197 -0
  164. package/opencode/skills/KORTIX-xlsx/scripts/office/pack.py +159 -0
  165. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  166. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  167. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  168. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  169. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  170. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  171. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  172. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  173. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  174. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  175. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  176. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  177. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  178. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  179. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  180. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  181. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  182. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  183. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  184. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  185. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  186. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  187. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  188. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  189. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  190. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  191. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  192. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  193. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  194. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  195. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  196. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/mce/mc.xsd +75 -0
  197. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  198. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  199. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  200. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  201. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  202. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  203. package/opencode/skills/KORTIX-xlsx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  204. package/opencode/skills/KORTIX-xlsx/scripts/office/soffice.py +183 -0
  205. package/opencode/skills/KORTIX-xlsx/scripts/office/unpack.py +132 -0
  206. package/opencode/skills/KORTIX-xlsx/scripts/office/validate.py +111 -0
  207. package/opencode/skills/KORTIX-xlsx/scripts/office/validators/__init__.py +15 -0
  208. package/opencode/skills/KORTIX-xlsx/scripts/office/validators/base.py +847 -0
  209. package/opencode/skills/KORTIX-xlsx/scripts/office/validators/docx.py +446 -0
  210. package/opencode/skills/KORTIX-xlsx/scripts/office/validators/pptx.py +275 -0
  211. package/opencode/skills/KORTIX-xlsx/scripts/office/validators/redlining.py +247 -0
  212. package/opencode/skills/KORTIX-xlsx/scripts/recalc.py +184 -0
  213. package/opencode/tools/image-gen.ts +342 -0
  214. package/opencode/tools/image-search.ts +190 -0
  215. package/opencode/tools/memory-get.ts +168 -0
  216. package/opencode/tools/memory-search.ts +247 -0
  217. package/opencode/tools/presentation-gen.ts +723 -0
  218. package/opencode/tools/scrape-webpage.ts +115 -0
  219. package/opencode/tools/scripts/.python-version +1 -0
  220. package/opencode/tools/scripts/convert_pdf.py +184 -0
  221. package/opencode/tools/scripts/convert_pptx.py +562 -0
  222. package/opencode/tools/scripts/pyproject.toml +11 -0
  223. package/opencode/tools/scripts/uv.lock +287 -0
  224. package/opencode/tools/scripts/validate_slide.py +74 -0
  225. package/opencode/tools/show-user.ts +217 -0
  226. package/opencode/tools/tests/e2e-presentation-fix.ts +277 -0
  227. package/opencode/tools/tests/image-gen.test.ts +215 -0
  228. package/opencode/tools/tests/image-search.test.ts +125 -0
  229. package/opencode/tools/tests/memory-system-benchmark.ts +1076 -0
  230. package/opencode/tools/tests/presentation-gen.test.ts +389 -0
  231. package/opencode/tools/tests/scrape-webpage.test.ts +74 -0
  232. package/opencode/tools/tests/show-user.test.ts +241 -0
  233. package/opencode/tools/tests/video-gen.test.ts +110 -0
  234. package/opencode/tools/tests/web-search.test.ts +106 -0
  235. package/opencode/tools/video-gen.ts +200 -0
  236. package/opencode/tools/web-search.ts +153 -0
  237. package/opencode/tsconfig.json +29 -0
  238. package/package.json +36 -0
  239. package/patch-agent-browser.js +100 -0
  240. package/postinstall.sh +88 -0
  241. package/services/KORTIX-presentation-viewer/run +37 -0
  242. package/services/agent-browser-viewer/run +48 -0
  243. package/services/kortix-master/run +16 -0
  244. package/services/lss-sync/run +22 -0
  245. package/services/opencode-serve/run +25 -0
  246. package/services/opencode-web/run +21 -0
@@ -0,0 +1,20 @@
1
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" xmlns:w16="http://schemas.microsoft.com/office/word/2018/wordml" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2018/wordml/cex" targetNamespace="http://schemas.microsoft.com/office/word/2018/wordml/cex">
2
+ <xsd:import id="w16" namespace="http://schemas.microsoft.com/office/word/2018/wordml" schemaLocation="wml-2018.xsd"/>
3
+ <xsd:import id="w" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
4
+ <xsd:import id="s" namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" schemaLocation="../ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd"/>
5
+ <xsd:complexType name="CT_CommentsExtensible">
6
+ <xsd:sequence>
7
+ <xsd:element name="commentExtensible" type="CT_CommentExtensible" minOccurs="0" maxOccurs="unbounded"/>
8
+ <xsd:element name="extLst" type="w16:CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
9
+ </xsd:sequence>
10
+ </xsd:complexType>
11
+ <xsd:complexType name="CT_CommentExtensible">
12
+ <xsd:sequence>
13
+ <xsd:element name="extLst" type="w16:CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
14
+ </xsd:sequence>
15
+ <xsd:attribute name="durableId" type="w:ST_LongHexNumber" use="required"/>
16
+ <xsd:attribute name="dateUtc" type="w:ST_DateTime" use="optional"/>
17
+ <xsd:attribute name="intelligentPlaceholder" type="s:ST_OnOff" use="optional"/>
18
+ </xsd:complexType>
19
+ <xsd:element name="commentsExtensible" type="CT_CommentsExtensible"/>
20
+ </xsd:schema>
@@ -0,0 +1,13 @@
1
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2016/wordml/cid" targetNamespace="http://schemas.microsoft.com/office/word/2016/wordml/cid">
2
+ <xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
3
+ <xsd:complexType name="CT_CommentsIds">
4
+ <xsd:sequence>
5
+ <xsd:element name="commentId" type="CT_CommentId" minOccurs="0" maxOccurs="unbounded"/>
6
+ </xsd:sequence>
7
+ </xsd:complexType>
8
+ <xsd:complexType name="CT_CommentId">
9
+ <xsd:attribute name="paraId" type="w12:ST_LongHexNumber" use="required"/>
10
+ <xsd:attribute name="durableId" type="w12:ST_LongHexNumber" use="required"/>
11
+ </xsd:complexType>
12
+ <xsd:element name="commentsIds" type="CT_CommentsIds"/>
13
+ </xsd:schema>
@@ -0,0 +1,4 @@
1
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" targetNamespace="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash">
2
+ <xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
3
+ <xsd:attribute name="storeItemChecksum" type="w12:ST_String"/>
4
+ </xsd:schema>
@@ -0,0 +1,8 @@
1
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2015/wordml/symex" targetNamespace="http://schemas.microsoft.com/office/word/2015/wordml/symex">
2
+ <xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
3
+ <xsd:complexType name="CT_SymEx">
4
+ <xsd:attribute name="font" type="w12:ST_String"/>
5
+ <xsd:attribute name="char" type="w12:ST_LongHexNumber"/>
6
+ </xsd:complexType>
7
+ <xsd:element name="symEx" type="CT_SymEx"/>
8
+ </xsd:schema>
@@ -0,0 +1,183 @@
1
+ """
2
+ Helper for running LibreOffice (soffice) in environments where AF_UNIX
3
+ sockets may be blocked (e.g., sandboxed VMs). Detects the restriction
4
+ at runtime and applies an LD_PRELOAD shim if needed.
5
+
6
+ Usage:
7
+ from office.soffice import run_soffice, get_soffice_env
8
+
9
+ # Option 1 – run soffice directly
10
+ result = run_soffice(["--headless", "--convert-to", "pdf", "input.docx"])
11
+
12
+ # Option 2 – get env dict for your own subprocess calls
13
+ env = get_soffice_env()
14
+ subprocess.run(["soffice", ...], env=env)
15
+ """
16
+
17
+ import os
18
+ import socket
19
+ import subprocess
20
+ import tempfile
21
+ from pathlib import Path
22
+
23
+
24
+ def get_soffice_env() -> dict:
25
+ env = os.environ.copy()
26
+ env["SAL_USE_VCLPLUGIN"] = "svp"
27
+
28
+ if _needs_shim():
29
+ shim = _ensure_shim()
30
+ env["LD_PRELOAD"] = str(shim)
31
+
32
+ return env
33
+
34
+
35
+ def run_soffice(args: list[str], **kwargs) -> subprocess.CompletedProcess:
36
+ env = get_soffice_env()
37
+ return subprocess.run(["soffice"] + args, env=env, **kwargs)
38
+
39
+
40
+
41
+ _SHIM_SO = Path(tempfile.gettempdir()) / "lo_socket_shim.so"
42
+
43
+
44
+ def _needs_shim() -> bool:
45
+ try:
46
+ s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
47
+ s.close()
48
+ return False
49
+ except OSError:
50
+ return True
51
+
52
+
53
+ def _ensure_shim() -> Path:
54
+ if _SHIM_SO.exists():
55
+ return _SHIM_SO
56
+
57
+ src = Path(tempfile.gettempdir()) / "lo_socket_shim.c"
58
+ src.write_text(_SHIM_SOURCE)
59
+ subprocess.run(
60
+ ["gcc", "-shared", "-fPIC", "-o", str(_SHIM_SO), str(src), "-ldl"],
61
+ check=True,
62
+ capture_output=True,
63
+ )
64
+ src.unlink()
65
+ return _SHIM_SO
66
+
67
+
68
+
69
+ _SHIM_SOURCE = r"""
70
+ #define _GNU_SOURCE
71
+ #include <dlfcn.h>
72
+ #include <errno.h>
73
+ #include <signal.h>
74
+ #include <stdio.h>
75
+ #include <stdlib.h>
76
+ #include <sys/socket.h>
77
+ #include <unistd.h>
78
+
79
+ static int (*real_socket)(int, int, int);
80
+ static int (*real_socketpair)(int, int, int, int[2]);
81
+ static int (*real_listen)(int, int);
82
+ static int (*real_accept)(int, struct sockaddr *, socklen_t *);
83
+ static int (*real_close)(int);
84
+ static int (*real_read)(int, void *, size_t);
85
+
86
+ /* Per-FD bookkeeping (FDs >= 1024 are passed through unshimmed). */
87
+ static int is_shimmed[1024];
88
+ static int peer_of[1024];
89
+ static int wake_r[1024]; /* accept() blocks reading this */
90
+ static int wake_w[1024]; /* close() writes to this */
91
+ static int listener_fd = -1; /* FD that received listen() */
92
+
93
+ __attribute__((constructor))
94
+ static void init(void) {
95
+ real_socket = dlsym(RTLD_NEXT, "socket");
96
+ real_socketpair = dlsym(RTLD_NEXT, "socketpair");
97
+ real_listen = dlsym(RTLD_NEXT, "listen");
98
+ real_accept = dlsym(RTLD_NEXT, "accept");
99
+ real_close = dlsym(RTLD_NEXT, "close");
100
+ real_read = dlsym(RTLD_NEXT, "read");
101
+ for (int i = 0; i < 1024; i++) {
102
+ peer_of[i] = -1;
103
+ wake_r[i] = -1;
104
+ wake_w[i] = -1;
105
+ }
106
+ }
107
+
108
+ /* ---- socket ---------------------------------------------------------- */
109
+ int socket(int domain, int type, int protocol) {
110
+ if (domain == AF_UNIX) {
111
+ int fd = real_socket(domain, type, protocol);
112
+ if (fd >= 0) return fd;
113
+ /* socket(AF_UNIX) blocked – fall back to socketpair(). */
114
+ int sv[2];
115
+ if (real_socketpair(domain, type, protocol, sv) == 0) {
116
+ if (sv[0] >= 0 && sv[0] < 1024) {
117
+ is_shimmed[sv[0]] = 1;
118
+ peer_of[sv[0]] = sv[1];
119
+ int wp[2];
120
+ if (pipe(wp) == 0) {
121
+ wake_r[sv[0]] = wp[0];
122
+ wake_w[sv[0]] = wp[1];
123
+ }
124
+ }
125
+ return sv[0];
126
+ }
127
+ errno = EPERM;
128
+ return -1;
129
+ }
130
+ return real_socket(domain, type, protocol);
131
+ }
132
+
133
+ /* ---- listen ---------------------------------------------------------- */
134
+ int listen(int sockfd, int backlog) {
135
+ if (sockfd >= 0 && sockfd < 1024 && is_shimmed[sockfd]) {
136
+ listener_fd = sockfd;
137
+ return 0;
138
+ }
139
+ return real_listen(sockfd, backlog);
140
+ }
141
+
142
+ /* ---- accept ---------------------------------------------------------- */
143
+ int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
144
+ if (sockfd >= 0 && sockfd < 1024 && is_shimmed[sockfd]) {
145
+ /* Block until close() writes to the wake pipe. */
146
+ if (wake_r[sockfd] >= 0) {
147
+ char buf;
148
+ real_read(wake_r[sockfd], &buf, 1);
149
+ }
150
+ errno = ECONNABORTED;
151
+ return -1;
152
+ }
153
+ return real_accept(sockfd, addr, addrlen);
154
+ }
155
+
156
+ /* ---- close ----------------------------------------------------------- */
157
+ int close(int fd) {
158
+ if (fd >= 0 && fd < 1024 && is_shimmed[fd]) {
159
+ int was_listener = (fd == listener_fd);
160
+ is_shimmed[fd] = 0;
161
+
162
+ if (wake_w[fd] >= 0) { /* unblock accept() */
163
+ char c = 0;
164
+ write(wake_w[fd], &c, 1);
165
+ real_close(wake_w[fd]);
166
+ wake_w[fd] = -1;
167
+ }
168
+ if (wake_r[fd] >= 0) { real_close(wake_r[fd]); wake_r[fd] = -1; }
169
+ if (peer_of[fd] >= 0) { real_close(peer_of[fd]); peer_of[fd] = -1; }
170
+
171
+ if (was_listener)
172
+ _exit(0); /* conversion done – exit */
173
+ }
174
+ return real_close(fd);
175
+ }
176
+ """
177
+
178
+
179
+
180
+ if __name__ == "__main__":
181
+ import sys
182
+ result = run_soffice(sys.argv[1:])
183
+ sys.exit(result.returncode)
@@ -0,0 +1,132 @@
1
+ """Unpack Office files (DOCX, PPTX, XLSX) for editing.
2
+
3
+ Extracts the ZIP archive, pretty-prints XML files, and optionally:
4
+ - Merges adjacent runs with identical formatting (DOCX only)
5
+ - Simplifies adjacent tracked changes from same author (DOCX only)
6
+
7
+ Usage:
8
+ python unpack.py <office_file> <output_dir> [options]
9
+
10
+ Examples:
11
+ python unpack.py document.docx unpacked/
12
+ python unpack.py presentation.pptx unpacked/
13
+ python unpack.py document.docx unpacked/ --merge-runs false
14
+ """
15
+
16
+ import argparse
17
+ import sys
18
+ import zipfile
19
+ from pathlib import Path
20
+
21
+ import defusedxml.minidom
22
+
23
+ from helpers.merge_runs import merge_runs as do_merge_runs
24
+ from helpers.simplify_redlines import simplify_redlines as do_simplify_redlines
25
+
26
+ SMART_QUOTE_REPLACEMENTS = {
27
+ "\u201c": "&#x201C;",
28
+ "\u201d": "&#x201D;",
29
+ "\u2018": "&#x2018;",
30
+ "\u2019": "&#x2019;",
31
+ }
32
+
33
+
34
+ def unpack(
35
+ input_file: str,
36
+ output_directory: str,
37
+ merge_runs: bool = True,
38
+ simplify_redlines: bool = True,
39
+ ) -> tuple[None, str]:
40
+ input_path = Path(input_file)
41
+ output_path = Path(output_directory)
42
+ suffix = input_path.suffix.lower()
43
+
44
+ if not input_path.exists():
45
+ return None, f"Error: {input_file} does not exist"
46
+
47
+ if suffix not in {".docx", ".pptx", ".xlsx"}:
48
+ return None, f"Error: {input_file} must be a .docx, .pptx, or .xlsx file"
49
+
50
+ try:
51
+ output_path.mkdir(parents=True, exist_ok=True)
52
+
53
+ with zipfile.ZipFile(input_path, "r") as zf:
54
+ zf.extractall(output_path)
55
+
56
+ xml_files = list(output_path.rglob("*.xml")) + list(output_path.rglob("*.rels"))
57
+ for xml_file in xml_files:
58
+ _pretty_print_xml(xml_file)
59
+
60
+ message = f"Unpacked {input_file} ({len(xml_files)} XML files)"
61
+
62
+ if suffix == ".docx":
63
+ if simplify_redlines:
64
+ simplify_count, _ = do_simplify_redlines(str(output_path))
65
+ message += f", simplified {simplify_count} tracked changes"
66
+
67
+ if merge_runs:
68
+ merge_count, _ = do_merge_runs(str(output_path))
69
+ message += f", merged {merge_count} runs"
70
+
71
+ for xml_file in xml_files:
72
+ _escape_smart_quotes(xml_file)
73
+
74
+ return None, message
75
+
76
+ except zipfile.BadZipFile:
77
+ return None, f"Error: {input_file} is not a valid Office file"
78
+ except Exception as e:
79
+ return None, f"Error unpacking: {e}"
80
+
81
+
82
+ def _pretty_print_xml(xml_file: Path) -> None:
83
+ try:
84
+ content = xml_file.read_text(encoding="utf-8")
85
+ dom = defusedxml.minidom.parseString(content)
86
+ xml_file.write_bytes(dom.toprettyxml(indent=" ", encoding="utf-8"))
87
+ except Exception:
88
+ pass
89
+
90
+
91
+ def _escape_smart_quotes(xml_file: Path) -> None:
92
+ try:
93
+ content = xml_file.read_text(encoding="utf-8")
94
+ for char, entity in SMART_QUOTE_REPLACEMENTS.items():
95
+ content = content.replace(char, entity)
96
+ xml_file.write_text(content, encoding="utf-8")
97
+ except Exception:
98
+ pass
99
+
100
+
101
+ if __name__ == "__main__":
102
+ parser = argparse.ArgumentParser(
103
+ description="Unpack an Office file (DOCX, PPTX, XLSX) for editing"
104
+ )
105
+ parser.add_argument("input_file", help="Office file to unpack")
106
+ parser.add_argument("output_directory", help="Output directory")
107
+ parser.add_argument(
108
+ "--merge-runs",
109
+ type=lambda x: x.lower() == "true",
110
+ default=True,
111
+ metavar="true|false",
112
+ help="Merge adjacent runs with identical formatting (DOCX only, default: true)",
113
+ )
114
+ parser.add_argument(
115
+ "--simplify-redlines",
116
+ type=lambda x: x.lower() == "true",
117
+ default=True,
118
+ metavar="true|false",
119
+ help="Merge adjacent tracked changes from same author (DOCX only, default: true)",
120
+ )
121
+ args = parser.parse_args()
122
+
123
+ _, message = unpack(
124
+ args.input_file,
125
+ args.output_directory,
126
+ merge_runs=args.merge_runs,
127
+ simplify_redlines=args.simplify_redlines,
128
+ )
129
+ print(message)
130
+
131
+ if "Error" in message:
132
+ sys.exit(1)
@@ -0,0 +1,111 @@
1
+ """
2
+ Command line tool to validate Office document XML files against XSD schemas and tracked changes.
3
+
4
+ Usage:
5
+ python validate.py <path> [--original <original_file>] [--auto-repair] [--author NAME]
6
+
7
+ The first argument can be either:
8
+ - An unpacked directory containing the Office document XML files
9
+ - A packed Office file (.docx/.pptx/.xlsx) which will be unpacked to a temp directory
10
+
11
+ Auto-repair fixes:
12
+ - paraId/durableId values that exceed OOXML limits
13
+ - Missing xml:space="preserve" on w:t elements with whitespace
14
+ """
15
+
16
+ import argparse
17
+ import sys
18
+ import tempfile
19
+ import zipfile
20
+ from pathlib import Path
21
+
22
+ from validators import DOCXSchemaValidator, PPTXSchemaValidator, RedliningValidator
23
+
24
+
25
+ def main():
26
+ parser = argparse.ArgumentParser(description="Validate Office document XML files")
27
+ parser.add_argument(
28
+ "path",
29
+ help="Path to unpacked directory or packed Office file (.docx/.pptx/.xlsx)",
30
+ )
31
+ parser.add_argument(
32
+ "--original",
33
+ required=False,
34
+ default=None,
35
+ help="Path to original file (.docx/.pptx/.xlsx). If omitted, all XSD errors are reported and redlining validation is skipped.",
36
+ )
37
+ parser.add_argument(
38
+ "-v",
39
+ "--verbose",
40
+ action="store_true",
41
+ help="Enable verbose output",
42
+ )
43
+ parser.add_argument(
44
+ "--auto-repair",
45
+ action="store_true",
46
+ help="Automatically repair common issues (hex IDs, whitespace preservation)",
47
+ )
48
+ parser.add_argument(
49
+ "--author",
50
+ default="Claude",
51
+ help="Author name for redlining validation (default: Claude)",
52
+ )
53
+ args = parser.parse_args()
54
+
55
+ path = Path(args.path)
56
+ assert path.exists(), f"Error: {path} does not exist"
57
+
58
+ original_file = None
59
+ if args.original:
60
+ original_file = Path(args.original)
61
+ assert original_file.is_file(), f"Error: {original_file} is not a file"
62
+ assert original_file.suffix.lower() in [".docx", ".pptx", ".xlsx"], (
63
+ f"Error: {original_file} must be a .docx, .pptx, or .xlsx file"
64
+ )
65
+
66
+ file_extension = (original_file or path).suffix.lower()
67
+ assert file_extension in [".docx", ".pptx", ".xlsx"], (
68
+ f"Error: Cannot determine file type from {path}. Use --original or provide a .docx/.pptx/.xlsx file."
69
+ )
70
+
71
+ if path.is_file() and path.suffix.lower() in [".docx", ".pptx", ".xlsx"]:
72
+ temp_dir = tempfile.mkdtemp()
73
+ with zipfile.ZipFile(path, "r") as zf:
74
+ zf.extractall(temp_dir)
75
+ unpacked_dir = Path(temp_dir)
76
+ else:
77
+ assert path.is_dir(), f"Error: {path} is not a directory or Office file"
78
+ unpacked_dir = path
79
+
80
+ match file_extension:
81
+ case ".docx":
82
+ validators = [
83
+ DOCXSchemaValidator(unpacked_dir, original_file, verbose=args.verbose),
84
+ ]
85
+ if original_file:
86
+ validators.append(
87
+ RedliningValidator(unpacked_dir, original_file, verbose=args.verbose, author=args.author)
88
+ )
89
+ case ".pptx":
90
+ validators = [
91
+ PPTXSchemaValidator(unpacked_dir, original_file, verbose=args.verbose),
92
+ ]
93
+ case _:
94
+ print(f"Error: Validation not supported for file type {file_extension}")
95
+ sys.exit(1)
96
+
97
+ if args.auto_repair:
98
+ total_repairs = sum(v.repair() for v in validators)
99
+ if total_repairs:
100
+ print(f"Auto-repaired {total_repairs} issue(s)")
101
+
102
+ success = all(v.validate() for v in validators)
103
+
104
+ if success:
105
+ print("All validations PASSED!")
106
+
107
+ sys.exit(0 if success else 1)
108
+
109
+
110
+ if __name__ == "__main__":
111
+ main()
@@ -0,0 +1,15 @@
1
+ """
2
+ Validation modules for Word document processing.
3
+ """
4
+
5
+ from .base import BaseSchemaValidator
6
+ from .docx import DOCXSchemaValidator
7
+ from .pptx import PPTXSchemaValidator
8
+ from .redlining import RedliningValidator
9
+
10
+ __all__ = [
11
+ "BaseSchemaValidator",
12
+ "DOCXSchemaValidator",
13
+ "PPTXSchemaValidator",
14
+ "RedliningValidator",
15
+ ]