ite-agent 0.0.23__tar.gz

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 (285) hide show
  1. ite_agent-0.0.23/.agents/skills/docx/SKILL.md +107 -0
  2. ite_agent-0.0.23/.agents/skills/docx/references/document-recipes.md +12 -0
  3. ite_agent-0.0.23/.agents/skills/docx/references/ooxml-notes.md +10 -0
  4. ite_agent-0.0.23/.agents/skills/docx/scripts/__init__.py +1 -0
  5. ite_agent-0.0.23/.agents/skills/docx/scripts/_docx_core.py +223 -0
  6. ite_agent-0.0.23/.agents/skills/docx/scripts/extract_docx.py +40 -0
  7. ite_agent-0.0.23/.agents/skills/docx/scripts/inspect_docx.py +20 -0
  8. ite_agent-0.0.23/.agents/skills/docx/scripts/pack_docx.py +21 -0
  9. ite_agent-0.0.23/.agents/skills/docx/scripts/render_docx.py +70 -0
  10. ite_agent-0.0.23/.agents/skills/docx/scripts/replace_text.py +39 -0
  11. ite_agent-0.0.23/.agents/skills/docx/scripts/unpack_docx.py +21 -0
  12. ite_agent-0.0.23/.agents/skills/docx/scripts/validate_docx.py +24 -0
  13. ite_agent-0.0.23/.agents/skills/docx/scripts/write_docx.py +40 -0
  14. ite_agent-0.0.23/.agents/skills/docx/templates/letter.md +11 -0
  15. ite_agent-0.0.23/.agents/skills/docx/templates/memo.md +13 -0
  16. ite_agent-0.0.23/.agents/skills/frontend-design/SKILL.md +292 -0
  17. ite_agent-0.0.23/.agents/skills/frontend-design/agents/openai.yaml +4 -0
  18. ite_agent-0.0.23/.agents/skills/frontend-design/references/color-and-contrast.md +132 -0
  19. ite_agent-0.0.23/.agents/skills/frontend-design/references/interaction-design.md +123 -0
  20. ite_agent-0.0.23/.agents/skills/frontend-design/references/motion-design.md +99 -0
  21. ite_agent-0.0.23/.agents/skills/frontend-design/references/responsive-design.md +114 -0
  22. ite_agent-0.0.23/.agents/skills/frontend-design/references/spatial-design.md +100 -0
  23. ite_agent-0.0.23/.agents/skills/frontend-design/references/typography.md +133 -0
  24. ite_agent-0.0.23/.agents/skills/frontend-design/references/ux-writing.md +107 -0
  25. ite_agent-0.0.23/.agents/skills/pdf/LICENSE.txt +201 -0
  26. ite_agent-0.0.23/.agents/skills/pdf/SKILL.md +78 -0
  27. ite_agent-0.0.23/.agents/skills/pdf/references/layout-review.md +13 -0
  28. ite_agent-0.0.23/.agents/skills/pdf/scripts/__init__.py +1 -0
  29. ite_agent-0.0.23/.agents/skills/pdf/scripts/_pdf_core.py +113 -0
  30. ite_agent-0.0.23/.agents/skills/pdf/scripts/extract_pdf_text.py +24 -0
  31. ite_agent-0.0.23/.agents/skills/pdf/scripts/inspect_pdf.py +20 -0
  32. ite_agent-0.0.23/.agents/skills/pdf/scripts/render_pdf.py +33 -0
  33. ite_agent-0.0.23/.agents/skills/pdf/scripts/validate_pdf.py +24 -0
  34. ite_agent-0.0.23/.agents/skills/pdf/scripts/write_pdf.py +26 -0
  35. ite_agent-0.0.23/.agents/skills/pdf/templates/report.txt +13 -0
  36. ite_agent-0.0.23/.agents/skills/repo-audit/SKILL.md +111 -0
  37. ite_agent-0.0.23/.agents/skills/repo-audit/agents/openai.yaml +4 -0
  38. ite_agent-0.0.23/.agents/skills/repo-audit/references/common_bug_patterns.md +342 -0
  39. ite_agent-0.0.23/.agents/skills/repo-audit/references/security_patterns.md +250 -0
  40. ite_agent-0.0.23/.agents/skills/repo-audit/references/test_guidelines.md +394 -0
  41. ite_agent-0.0.23/.agents/skills/repo-audit/scripts/audit_test_coverage.py +155 -0
  42. ite_agent-0.0.23/.agents/skills/repo-audit/scripts/find_common_bugs.py +304 -0
  43. ite_agent-0.0.23/.agents/skills/skill-creator/LICENSE.txt +202 -0
  44. ite_agent-0.0.23/.agents/skills/skill-creator/SKILL.md +519 -0
  45. ite_agent-0.0.23/.agents/skills/skill-creator/agents/openai.yaml +4 -0
  46. ite_agent-0.0.23/.agents/skills/skill-creator/references/openai_yaml.md +43 -0
  47. ite_agent-0.0.23/.agents/skills/skill-creator/scripts/generate_openai_yaml.py +225 -0
  48. ite_agent-0.0.23/.agents/skills/skill-creator/scripts/init_skill.py +397 -0
  49. ite_agent-0.0.23/.agents/skills/skill-creator/scripts/quick_validate.py +101 -0
  50. ite_agent-0.0.23/.gitignore +51 -0
  51. ite_agent-0.0.23/DESIGN.md +719 -0
  52. ite_agent-0.0.23/INSTALLATION.md +93 -0
  53. ite_agent-0.0.23/OVERVIEW.md +352 -0
  54. ite_agent-0.0.23/PKG-INFO +250 -0
  55. ite_agent-0.0.23/README.md +215 -0
  56. ite_agent-0.0.23/docs/BYOK_QUICKSTART.md +71 -0
  57. ite_agent-0.0.23/docs/CONTINUATION_HARDENING_PLAN_2026-04-16.md +263 -0
  58. ite_agent-0.0.23/docs/PRODUCTION_DEPLOYMENT.md +145 -0
  59. ite_agent-0.0.23/docs/PROD_LAUNCH_BYOK.md +136 -0
  60. ite_agent-0.0.23/docs/RELEASE_BUMP_WORKFLOW.md +202 -0
  61. ite_agent-0.0.23/docs/SHELL_AND_WEB_CAPABILITIES.md +111 -0
  62. ite_agent-0.0.23/docs/SHIP_TODAY_PLAN_2026-04-16.md +231 -0
  63. ite_agent-0.0.23/docs/SKILLS.md +133 -0
  64. ite_agent-0.0.23/docs/SUBAGENT_PRODUCTION_READINESS.md +244 -0
  65. ite_agent-0.0.23/docs/TOOLS.md +386 -0
  66. ite_agent-0.0.23/docs/WORK_LOG_2026-04-14.md +40 -0
  67. ite_agent-0.0.23/docs/architecture/context-runtime-roadmap.md +256 -0
  68. ite_agent-0.0.23/docs/architecture/csrc-vs-ite-runtime-handoff.md +243 -0
  69. ite_agent-0.0.23/docs/bugs/interrupt-clears-content.md +107 -0
  70. ite_agent-0.0.23/docs/fix_idb.py +36 -0
  71. ite_agent-0.0.23/docs/fix_ios_simulator_mcp.md +74 -0
  72. ite_agent-0.0.23/docs/launch-real-life-eval.md +482 -0
  73. ite_agent-0.0.23/docs/live-memory-and-context-eval-pass.md +374 -0
  74. ite_agent-0.0.23/docs/manual-context-runtime-live-tests.md +214 -0
  75. ite_agent-0.0.23/docs/manual-git-tool-tests.md +290 -0
  76. ite_agent-0.0.23/docs/manual-skills-test-plan.md +618 -0
  77. ite_agent-0.0.23/docs/manual-verification-json-tool-tests.md +473 -0
  78. ite_agent-0.0.23/docs/poem.txt +21 -0
  79. ite_agent-0.0.23/docs/reup-inchat-reactive-cards.md +96 -0
  80. ite_agent-0.0.23/docs/reup-live-test-runbook.md +219 -0
  81. ite_agent-0.0.23/docs/reup-modal-click-note.md +54 -0
  82. ite_agent-0.0.23/docs/tool-implementation-plan.md +430 -0
  83. ite_agent-0.0.23/docs/tool-parallel-execution-plan.md +135 -0
  84. ite_agent-0.0.23/docs/tool-research.md +459 -0
  85. ite_agent-0.0.23/landing-site/README.md +30 -0
  86. ite_agent-0.0.23/landing-site/favicon.svg +5 -0
  87. ite_agent-0.0.23/landing-site/index.html +143 -0
  88. ite_agent-0.0.23/landing-site/ite-prev.png +0 -0
  89. ite_agent-0.0.23/landing-site/ite-preview.png +0 -0
  90. ite_agent-0.0.23/landing-site/ite.css +842 -0
  91. ite_agent-0.0.23/landing-site/ite.js +138 -0
  92. ite_agent-0.0.23/landing-site/netlify/functions/waitlist.mjs +56 -0
  93. ite_agent-0.0.23/landing-site/netlify.toml +6 -0
  94. ite_agent-0.0.23/landing-site/package.json +12 -0
  95. ite_agent-0.0.23/landing-site/server/waitlist-core.mjs +196 -0
  96. ite_agent-0.0.23/pyproject.toml +31 -0
  97. ite_agent-0.0.23/src/ite/__init__.py +0 -0
  98. ite_agent-0.0.23/src/ite/agent/__init__.py +0 -0
  99. ite_agent-0.0.23/src/ite/agent/agent.py +2345 -0
  100. ite_agent-0.0.23/src/ite/agent/change_history.py +315 -0
  101. ite_agent-0.0.23/src/ite/agent/events.py +202 -0
  102. ite_agent-0.0.23/src/ite/agent/session.py +753 -0
  103. ite_agent-0.0.23/src/ite/agent/session_manager.py +411 -0
  104. ite_agent-0.0.23/src/ite/agent/subagent_runtime.py +606 -0
  105. ite_agent-0.0.23/src/ite/attachment_refs.py +313 -0
  106. ite_agent-0.0.23/src/ite/attachments.py +241 -0
  107. ite_agent-0.0.23/src/ite/client/__init__.py +0 -0
  108. ite_agent-0.0.23/src/ite/client/llm_client.py +780 -0
  109. ite_agent-0.0.23/src/ite/client/response.py +89 -0
  110. ite_agent-0.0.23/src/ite/cloud/__init__.py +11 -0
  111. ite_agent-0.0.23/src/ite/cloud/auth.py +437 -0
  112. ite_agent-0.0.23/src/ite/commands/__init__.py +107 -0
  113. ite_agent-0.0.23/src/ite/commands/aside.py +138 -0
  114. ite_agent-0.0.23/src/ite/commands/attach.py +182 -0
  115. ite_agent-0.0.23/src/ite/commands/branch.py +191 -0
  116. ite_agent-0.0.23/src/ite/commands/cloud.py +162 -0
  117. ite_agent-0.0.23/src/ite/commands/csv2json.py +139 -0
  118. ite_agent-0.0.23/src/ite/commands/general.py +220 -0
  119. ite_agent-0.0.23/src/ite/commands/history.py +133 -0
  120. ite_agent-0.0.23/src/ite/commands/info.py +1202 -0
  121. ite_agent-0.0.23/src/ite/commands/model.py +335 -0
  122. ite_agent-0.0.23/src/ite/commands/plan.py +146 -0
  123. ite_agent-0.0.23/src/ite/commands/publish.py +73 -0
  124. ite_agent-0.0.23/src/ite/commands/sandbox.py +160 -0
  125. ite_agent-0.0.23/src/ite/commands/session.py +675 -0
  126. ite_agent-0.0.23/src/ite/commands/skills.py +149 -0
  127. ite_agent-0.0.23/src/ite/commands/subagent.py +151 -0
  128. ite_agent-0.0.23/src/ite/commands/todos.py +112 -0
  129. ite_agent-0.0.23/src/ite/config/__init__.py +0 -0
  130. ite_agent-0.0.23/src/ite/config/config.py +313 -0
  131. ite_agent-0.0.23/src/ite/config/loader.py +869 -0
  132. ite_agent-0.0.23/src/ite/config/setup.py +134 -0
  133. ite_agent-0.0.23/src/ite/context/__init__.py +0 -0
  134. ite_agent-0.0.23/src/ite/context/compact_artifacts.py +47 -0
  135. ite_agent-0.0.23/src/ite/context/compaction.py +117 -0
  136. ite_agent-0.0.23/src/ite/context/loop_detector.py +103 -0
  137. ite_agent-0.0.23/src/ite/context/manager.py +768 -0
  138. ite_agent-0.0.23/src/ite/context/transcript.py +140 -0
  139. ite_agent-0.0.23/src/ite/git/__init__.py +2 -0
  140. ite_agent-0.0.23/src/ite/git/branches.py +116 -0
  141. ite_agent-0.0.23/src/ite/git/remotes.py +121 -0
  142. ite_agent-0.0.23/src/ite/git/working_tree.py +604 -0
  143. ite_agent-0.0.23/src/ite/hooks/__init__.py +0 -0
  144. ite_agent-0.0.23/src/ite/hooks/hook_system.py +140 -0
  145. ite_agent-0.0.23/src/ite/main.py +1440 -0
  146. ite_agent-0.0.23/src/ite/memory/__init__.py +29 -0
  147. ite_agent-0.0.23/src/ite/memory/intent.py +261 -0
  148. ite_agent-0.0.23/src/ite/memory/manager.py +1030 -0
  149. ite_agent-0.0.23/src/ite/memory/response_intent.py +307 -0
  150. ite_agent-0.0.23/src/ite/memory/session_memory.py +258 -0
  151. ite_agent-0.0.23/src/ite/prompts/__init__.py +0 -0
  152. ite_agent-0.0.23/src/ite/prompts/system.py +780 -0
  153. ite_agent-0.0.23/src/ite/safety/__init__.py +0 -0
  154. ite_agent-0.0.23/src/ite/safety/approval.py +333 -0
  155. ite_agent-0.0.23/src/ite/safety/git_sandbox.py +310 -0
  156. ite_agent-0.0.23/src/ite/safety/sandbox.py +71 -0
  157. ite_agent-0.0.23/src/ite/skills/__init__.py +23 -0
  158. ite_agent-0.0.23/src/ite/skills/installer.py +144 -0
  159. ite_agent-0.0.23/src/ite/skills/manager.py +304 -0
  160. ite_agent-0.0.23/src/ite/skills/rendering.py +386 -0
  161. ite_agent-0.0.23/src/ite/skills/trust.py +47 -0
  162. ite_agent-0.0.23/src/ite/tools/__init__.py +0 -0
  163. ite_agent-0.0.23/src/ite/tools/base.py +282 -0
  164. ite_agent-0.0.23/src/ite/tools/builtin/__init__.py +146 -0
  165. ite_agent-0.0.23/src/ite/tools/builtin/apply_patch.py +385 -0
  166. ite_agent-0.0.23/src/ite/tools/builtin/archive_tools.py +113 -0
  167. ite_agent-0.0.23/src/ite/tools/builtin/config_tools.py +783 -0
  168. ite_agent-0.0.23/src/ite/tools/builtin/edit_file.py +252 -0
  169. ite_agent-0.0.23/src/ite/tools/builtin/git_tools.py +793 -0
  170. ite_agent-0.0.23/src/ite/tools/builtin/glob.py +91 -0
  171. ite_agent-0.0.23/src/ite/tools/builtin/grep.py +146 -0
  172. ite_agent-0.0.23/src/ite/tools/builtin/http_tools.py +172 -0
  173. ite_agent-0.0.23/src/ite/tools/builtin/json_tools.py +302 -0
  174. ite_agent-0.0.23/src/ite/tools/builtin/list_dir.py +75 -0
  175. ite_agent-0.0.23/src/ite/tools/builtin/media_tools.py +407 -0
  176. ite_agent-0.0.23/src/ite/tools/builtin/memory.py +312 -0
  177. ite_agent-0.0.23/src/ite/tools/builtin/plan_question.py +79 -0
  178. ite_agent-0.0.23/src/ite/tools/builtin/read_file.py +144 -0
  179. ite_agent-0.0.23/src/ite/tools/builtin/shell.py +1055 -0
  180. ite_agent-0.0.23/src/ite/tools/builtin/skills.py +182 -0
  181. ite_agent-0.0.23/src/ite/tools/builtin/subagent_runtime_tools.py +366 -0
  182. ite_agent-0.0.23/src/ite/tools/builtin/todo.py +353 -0
  183. ite_agent-0.0.23/src/ite/tools/builtin/verification_tools.py +323 -0
  184. ite_agent-0.0.23/src/ite/tools/builtin/web_fetch.py +154 -0
  185. ite_agent-0.0.23/src/ite/tools/builtin/web_search.py +88 -0
  186. ite_agent-0.0.23/src/ite/tools/builtin/write_file.py +121 -0
  187. ite_agent-0.0.23/src/ite/tools/discovery.py +74 -0
  188. ite_agent-0.0.23/src/ite/tools/mcp/__init__.py +0 -0
  189. ite_agent-0.0.23/src/ite/tools/mcp/client.py +382 -0
  190. ite_agent-0.0.23/src/ite/tools/mcp/mcp_manager.py +256 -0
  191. ite_agent-0.0.23/src/ite/tools/mcp/mcp_tool.py +364 -0
  192. ite_agent-0.0.23/src/ite/tools/mcp/oauth.py +206 -0
  193. ite_agent-0.0.23/src/ite/tools/policy.py +208 -0
  194. ite_agent-0.0.23/src/ite/tools/registry.py +753 -0
  195. ite_agent-0.0.23/src/ite/tools/subagent.py +822 -0
  196. ite_agent-0.0.23/src/ite/tools/subagent_loader.py +64 -0
  197. ite_agent-0.0.23/src/ite/ui/__init__.py +0 -0
  198. ite_agent-0.0.23/src/ite/ui/assets/ite_image.png +0 -0
  199. ite_agent-0.0.23/src/ite/ui/gui/MIGRATION.md +53 -0
  200. ite_agent-0.0.23/src/ite/ui/gui/__init__.py +6 -0
  201. ite_agent-0.0.23/src/ite/ui/gui/adapters/registry.py +17 -0
  202. ite_agent-0.0.23/src/ite/ui/gui/app.py +2365 -0
  203. ite_agent-0.0.23/src/ite/ui/gui/builders/layout.py +933 -0
  204. ite_agent-0.0.23/src/ite/ui/gui/builders/messages.py +1467 -0
  205. ite_agent-0.0.23/src/ite/ui/gui/controllers/agent_events.py +328 -0
  206. ite_agent-0.0.23/src/ite/ui/gui/controllers/approval.py +204 -0
  207. ite_agent-0.0.23/src/ite/ui/gui/controllers/branch.py +313 -0
  208. ite_agent-0.0.23/src/ite/ui/gui/controllers/commands.py +474 -0
  209. ite_agent-0.0.23/src/ite/ui/gui/controllers/scroll.py +51 -0
  210. ite_agent-0.0.23/src/ite/ui/gui/controllers/sessions.py +407 -0
  211. ite_agent-0.0.23/src/ite/ui/gui/controllers/workspace.py +350 -0
  212. ite_agent-0.0.23/src/ite/ui/gui/state.py +279 -0
  213. ite_agent-0.0.23/src/ite/ui/gui/tokens.py +73 -0
  214. ite_agent-0.0.23/src/ite/ui/gui/types.py +7 -0
  215. ite_agent-0.0.23/src/ite/ui/gui.py +5 -0
  216. ite_agent-0.0.23/src/ite/ui/reup/__init__.py +15 -0
  217. ite_agent-0.0.23/src/ite/ui/reup/adapters/__init__.py +1 -0
  218. ite_agent-0.0.23/src/ite/ui/reup/adapters/registry.py +52 -0
  219. ite_agent-0.0.23/src/ite/ui/reup/app.py +8250 -0
  220. ite_agent-0.0.23/src/ite/ui/reup/change_tree.py +88 -0
  221. ite_agent-0.0.23/src/ite/ui/reup/change_views.py +67 -0
  222. ite_agent-0.0.23/src/ite/ui/reup/command_views.py +521 -0
  223. ite_agent-0.0.23/src/ite/ui/reup/composer_views.py +479 -0
  224. ite_agent-0.0.23/src/ite/ui/reup/markdown_widget.py +137 -0
  225. ite_agent-0.0.23/src/ite/ui/reup/modals.py +2353 -0
  226. ite_agent-0.0.23/src/ite/ui/reup/reup.tcss +2541 -0
  227. ite_agent-0.0.23/src/ite/ui/reup/tool_views.py +1688 -0
  228. ite_agent-0.0.23/src/ite/ui/tool_narrative.py +948 -0
  229. ite_agent-0.0.23/src/ite/ui/tui.py +1652 -0
  230. ite_agent-0.0.23/src/ite/utils/__init__.py +0 -0
  231. ite_agent-0.0.23/src/ite/utils/errors.py +236 -0
  232. ite_agent-0.0.23/src/ite/utils/paths.py +43 -0
  233. ite_agent-0.0.23/src/ite/utils/text.py +87 -0
  234. ite_agent-0.0.23/tests/test_agent_continuation.py +457 -0
  235. ite_agent-0.0.23/tests/test_agent_tool_recovery.py +820 -0
  236. ite_agent-0.0.23/tests/test_aside_command.py +164 -0
  237. ite_agent-0.0.23/tests/test_attachment_refs.py +101 -0
  238. ite_agent-0.0.23/tests/test_attachments.py +96 -0
  239. ite_agent-0.0.23/tests/test_bundled_docx_skill.py +106 -0
  240. ite_agent-0.0.23/tests/test_bundled_pdf_skill.py +98 -0
  241. ite_agent-0.0.23/tests/test_bundled_skill_creator.py +25 -0
  242. ite_agent-0.0.23/tests/test_change_history.py +108 -0
  243. ite_agent-0.0.23/tests/test_cli_modes.py +256 -0
  244. ite_agent-0.0.23/tests/test_cli_prompt.py +60 -0
  245. ite_agent-0.0.23/tests/test_cloud_auth.py +124 -0
  246. ite_agent-0.0.23/tests/test_compaction.py +77 -0
  247. ite_agent-0.0.23/tests/test_config_setup_requirements.py +32 -0
  248. ite_agent-0.0.23/tests/test_config_tools.py +141 -0
  249. ite_agent-0.0.23/tests/test_execution_todo_progress.py +66 -0
  250. ite_agent-0.0.23/tests/test_git_tools.py +347 -0
  251. ite_agent-0.0.23/tests/test_gui_state_store.py +52 -0
  252. ite_agent-0.0.23/tests/test_http_archive_tools.py +130 -0
  253. ite_agent-0.0.23/tests/test_info_commands.py +110 -0
  254. ite_agent-0.0.23/tests/test_json_tools.py +86 -0
  255. ite_agent-0.0.23/tests/test_llm_client.py +361 -0
  256. ite_agent-0.0.23/tests/test_loop_detector.py +52 -0
  257. ite_agent-0.0.23/tests/test_mcp.py +1165 -0
  258. ite_agent-0.0.23/tests/test_media_tools.py +233 -0
  259. ite_agent-0.0.23/tests/test_memory_behavior.py +414 -0
  260. ite_agent-0.0.23/tests/test_memory_eval_matrix.py +336 -0
  261. ite_agent-0.0.23/tests/test_memory_lifecycle.py +1047 -0
  262. ite_agent-0.0.23/tests/test_memory_manager.py +958 -0
  263. ite_agent-0.0.23/tests/test_provider_error_formatting.py +89 -0
  264. ite_agent-0.0.23/tests/test_publish_command.py +87 -0
  265. ite_agent-0.0.23/tests/test_release_bump_skill.py +41 -0
  266. ite_agent-0.0.23/tests/test_reup_command_palette.py +2331 -0
  267. ite_agent-0.0.23/tests/test_reup_modals.py +194 -0
  268. ite_agent-0.0.23/tests/test_reup_startup.py +452 -0
  269. ite_agent-0.0.23/tests/test_reup_theme_guards.py +67 -0
  270. ite_agent-0.0.23/tests/test_reup_tool_views.py +255 -0
  271. ite_agent-0.0.23/tests/test_saved_custom_provider.py +96 -0
  272. ite_agent-0.0.23/tests/test_session_commands.py +75 -0
  273. ite_agent-0.0.23/tests/test_session_manager.py +297 -0
  274. ite_agent-0.0.23/tests/test_session_naming.py +53 -0
  275. ite_agent-0.0.23/tests/test_setup_modal.py +515 -0
  276. ite_agent-0.0.23/tests/test_shell_web_capabilities.py +697 -0
  277. ite_agent-0.0.23/tests/test_skills.py +561 -0
  278. ite_agent-0.0.23/tests/test_subagent_runtime.py +777 -0
  279. ite_agent-0.0.23/tests/test_system_prompt.py +116 -0
  280. ite_agent-0.0.23/tests/test_text_utils.py +24 -0
  281. ite_agent-0.0.23/tests/test_todos_scoped.py +160 -0
  282. ite_agent-0.0.23/tests/test_tool_narrative.py +317 -0
  283. ite_agent-0.0.23/tests/test_tool_param_normalization.py +152 -0
  284. ite_agent-0.0.23/tests/test_tooling_v01.py +1091 -0
  285. ite_agent-0.0.23/tests/test_verification_tools.py +101 -0
@@ -0,0 +1,107 @@
1
+ ---
2
+ name: docx
3
+ description: Create, inspect, edit, and validate Microsoft Word .docx documents. Use for reading .docx content, generating reports, memos, or letters as Word files, editing existing documents, and converting Word documents into structured text or a new polished .docx.
4
+ tags:
5
+ - office
6
+ - documents
7
+ - word
8
+ author: ite
9
+ argument-hint: "[INPUT=<path>] [OUTPUT=<path>]"
10
+ ---
11
+
12
+ # DOCX workflow
13
+
14
+ Use this skill whenever the user is working with a `.docx` file or explicitly wants a Word document as output.
15
+
16
+ ## Core rules
17
+
18
+ - Do not use `read_file` directly on `.docx`; it is a packaged binary file.
19
+ - Resolve all script paths relative to this skill directory.
20
+ - Prefer a workspace-local scratch directory such as `./.ite/tmp/docx/<job-id>/` over `/tmp/`.
21
+ - Keep the source document intact unless the user explicitly asks to overwrite it.
22
+ - Validate any newly created or repacked `.docx` before presenting it as finished.
23
+ - If LibreOffice and Poppler are available, render pages for visual review before final delivery.
24
+
25
+ ## Default workflows
26
+
27
+ ### Inspect or extract text
28
+
29
+ Inspect first when the goal is to understand the file quickly:
30
+
31
+ ```bash
32
+ python <skill_dir>/scripts/inspect_docx.py input.docx
33
+ ```
34
+
35
+ Then use the extractor when you need readable content:
36
+
37
+ ```bash
38
+ python <skill_dir>/scripts/extract_docx.py input.docx --format markdown --output extracted.md
39
+ ```
40
+
41
+ Use `--format text` for a plain transcript or `--format json` for machine-readable sections.
42
+
43
+ ### Unpack for structured editing
44
+
45
+ ```bash
46
+ python <skill_dir>/scripts/unpack_docx.py input.docx ./.ite/tmp/docx/job-123/unpacked
47
+ ```
48
+
49
+ Edit the unpacked XML only when a simple text replacement is not enough.
50
+
51
+ ### Simple text replacement
52
+
53
+ For straightforward content changes inside `word/document.xml`, use:
54
+
55
+ ```bash
56
+ python <skill_dir>/scripts/replace_text.py input.docx output.docx --replace "Old text" "New text"
57
+ ```
58
+
59
+ This is for direct text substitutions, not layout-heavy edits.
60
+
61
+ ### Create a new document
62
+
63
+ For letters, memos, and simple reports, start from a markdown or text draft:
64
+
65
+ ```bash
66
+ python <skill_dir>/scripts/write_docx.py draft.md output.docx --title "Quarterly Update"
67
+ ```
68
+
69
+ Templates in `templates/` are starter content, not strict requirements.
70
+
71
+ ```bash
72
+ python <skill_dir>/scripts/write_docx.py output.docx --template memo --title "Quarterly Update"
73
+ ```
74
+
75
+ ### Visual review
76
+
77
+ When layout matters, render the document to page images:
78
+
79
+ ```bash
80
+ python <skill_dir>/scripts/render_docx.py input.docx --output_dir ./.ite/tmp/docx/job-123/rendered
81
+ ```
82
+
83
+ If the required system tools are unavailable, say so clearly and call out layout risk.
84
+
85
+ ### Repack and validate
86
+
87
+ ```bash
88
+ python <skill_dir>/scripts/pack_docx.py ./.ite/tmp/docx/job-123/unpacked output.docx
89
+ python <skill_dir>/scripts/validate_docx.py output.docx
90
+ ```
91
+
92
+ Validation is required before presenting the result as complete.
93
+
94
+ ## Choosing the path
95
+
96
+ - Need to read or summarize a `.docx`: extract text.
97
+ - Need a polished new `.docx`: write a new document from structured content.
98
+ - Need a small wording change: replace text.
99
+ - Need deeper changes: unpack, edit carefully, repack, validate.
100
+ - Need to check pagination, tables, or spacing: render the pages and inspect them.
101
+
102
+ ## Output expectations
103
+
104
+ - Tell the user what file was created or updated.
105
+ - Summarize the structural approach used.
106
+ - Mention validation status.
107
+ - If a limitation blocks the requested formatting, say so explicitly instead of silently improvising.
@@ -0,0 +1,12 @@
1
+ # DOCX recipes
2
+
3
+ Use the bundled scripts for these common jobs:
4
+
5
+ - Inspect a document: `extract_docx.py`
6
+ - Unpack for XML edits: `unpack_docx.py`
7
+ - Repack the edited package: `pack_docx.py`
8
+ - Validate a generated file: `validate_docx.py`
9
+ - Create a simple memo or report from a text draft: `write_docx.py`
10
+ - Apply direct wording swaps: `replace_text.py`
11
+
12
+ Prefer a workspace-local scratch directory under `./.ite/tmp/docx/` so shell commands remain inside the project sandbox.
@@ -0,0 +1,10 @@
1
+ # OOXML notes
2
+
3
+ A `.docx` file is a ZIP package. The most important members for this skill are:
4
+
5
+ - `[Content_Types].xml`
6
+ - `_rels/.rels`
7
+ - `word/document.xml`
8
+
9
+ The first-party `ite` docx skill only guarantees safe handling of plain paragraph content in `word/document.xml`.
10
+ If the user needs advanced layout, section, comment, or tracked-change behavior, say that the request exceeds the current bundled workflow and avoid fabricating support.
@@ -0,0 +1 @@
1
+ """Helper scripts for the bundled ite docx skill."""
@@ -0,0 +1,223 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from zipfile import ZIP_DEFLATED
5
+ from zipfile import ZipFile
6
+ import shutil
7
+ import tempfile
8
+ import xml.etree.ElementTree as ET
9
+ import json
10
+
11
+ W_NS = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
12
+ NS = {"w": W_NS}
13
+ ET.register_namespace("w", W_NS)
14
+
15
+ REQUIRED_MEMBERS = {
16
+ "[Content_Types].xml",
17
+ "_rels/.rels",
18
+ "word/document.xml",
19
+ }
20
+
21
+
22
+ def load_document_tree(docx_path: Path) -> ET.ElementTree:
23
+ with ZipFile(docx_path) as archive:
24
+ with archive.open("word/document.xml") as handle:
25
+ return ET.parse(handle)
26
+
27
+
28
+ def write_document_tree(source_docx: Path, output_docx: Path, tree: ET.ElementTree) -> None:
29
+ with tempfile.TemporaryDirectory(prefix="ite-docx-") as temp_dir:
30
+ temp_root = Path(temp_dir)
31
+ unpack_to_directory(source_docx, temp_root)
32
+ document_path = temp_root / "word" / "document.xml"
33
+ tree.write(document_path, encoding="utf-8", xml_declaration=True)
34
+ pack_directory(temp_root, output_docx)
35
+
36
+
37
+ def unpack_to_directory(docx_path: Path, output_dir: Path) -> None:
38
+ output_dir.mkdir(parents=True, exist_ok=True)
39
+ with ZipFile(docx_path) as archive:
40
+ archive.extractall(output_dir)
41
+
42
+
43
+ def pack_directory(source_dir: Path, output_docx: Path) -> None:
44
+ output_docx.parent.mkdir(parents=True, exist_ok=True)
45
+ temp_output = output_docx.with_suffix(output_docx.suffix + ".tmp")
46
+ if temp_output.exists():
47
+ temp_output.unlink()
48
+ with ZipFile(temp_output, "w", compression=ZIP_DEFLATED) as archive:
49
+ for path in sorted(source_dir.rglob("*")):
50
+ if path.is_dir():
51
+ continue
52
+ archive.write(path, path.relative_to(source_dir).as_posix())
53
+ shutil.move(str(temp_output), str(output_docx))
54
+
55
+
56
+ def paragraph_texts(tree: ET.ElementTree) -> list[str]:
57
+ paragraphs: list[str] = []
58
+ for paragraph in tree.findall(".//w:body/w:p", NS):
59
+ texts = [node.text or "" for node in paragraph.findall(".//w:t", NS)]
60
+ line = "".join(texts).strip()
61
+ if line:
62
+ paragraphs.append(line)
63
+ return paragraphs
64
+
65
+
66
+ def inspect_docx(path: Path) -> dict[str, object]:
67
+ tree = load_document_tree(path)
68
+ paragraphs = paragraph_texts(tree)
69
+ preview = paragraphs[:5]
70
+ return {
71
+ "path": str(path.resolve()),
72
+ "size_bytes": path.stat().st_size,
73
+ "paragraph_count": len(paragraphs),
74
+ "preview": preview,
75
+ "validation_errors": validate_docx(path),
76
+ }
77
+
78
+
79
+ def set_paragraphs(tree: ET.ElementTree, paragraphs: list[str]) -> ET.ElementTree:
80
+ root = tree.getroot()
81
+ body = root.find("w:body", NS)
82
+ if body is None:
83
+ raise ValueError("word/document.xml does not contain w:body")
84
+
85
+ sect_pr = body.find("w:sectPr", NS)
86
+ for child in list(body):
87
+ body.remove(child)
88
+
89
+ for text in paragraphs:
90
+ body.append(_paragraph_element(text))
91
+
92
+ if sect_pr is not None:
93
+ body.append(sect_pr)
94
+ return tree
95
+
96
+
97
+ def replace_in_paragraphs(
98
+ paragraphs: list[str],
99
+ replacements: list[tuple[str, str]],
100
+ ) -> tuple[list[str], int]:
101
+ updated = list(paragraphs)
102
+ total_replacements = 0
103
+ for old, new in replacements:
104
+ next_paragraphs: list[str] = []
105
+ for paragraph in updated:
106
+ occurrences = paragraph.count(old)
107
+ if occurrences:
108
+ total_replacements += occurrences
109
+ next_paragraphs.append(paragraph.replace(old, new))
110
+ updated = next_paragraphs
111
+ return updated, total_replacements
112
+
113
+
114
+ def json_dump(payload: dict[str, object]) -> str:
115
+ return json.dumps(payload, indent=2)
116
+
117
+
118
+ def build_simple_document(paragraphs: list[str], title: str | None = None) -> bytes:
119
+ document = ET.Element(f"{{{W_NS}}}document")
120
+ body = ET.SubElement(document, f"{{{W_NS}}}body")
121
+ all_paragraphs = list(paragraphs)
122
+ if title:
123
+ all_paragraphs.insert(0, title.strip())
124
+ for paragraph in all_paragraphs:
125
+ body.append(_paragraph_element(paragraph))
126
+ sect_pr = ET.SubElement(body, f"{{{W_NS}}}sectPr")
127
+ pg_sz = ET.SubElement(sect_pr, f"{{{W_NS}}}pgSz")
128
+ pg_sz.set(f"{{{W_NS}}}w", "12240")
129
+ pg_sz.set(f"{{{W_NS}}}h", "15840")
130
+ pg_mar = ET.SubElement(sect_pr, f"{{{W_NS}}}pgMar")
131
+ for key, value in {
132
+ "top": "1440",
133
+ "right": "1440",
134
+ "bottom": "1440",
135
+ "left": "1440",
136
+ "header": "720",
137
+ "footer": "720",
138
+ "gutter": "0",
139
+ }.items():
140
+ pg_mar.set(f"{{{W_NS}}}{key}", value)
141
+
142
+ document_xml = ET.tostring(document, encoding="utf-8", xml_declaration=True)
143
+ return _package_document_xml(document_xml)
144
+
145
+
146
+ def _package_document_xml(document_xml: bytes) -> bytes:
147
+ with tempfile.TemporaryDirectory(prefix="ite-docx-build-") as temp_dir:
148
+ root = Path(temp_dir)
149
+ (root / "_rels").mkdir(parents=True, exist_ok=True)
150
+ (root / "word").mkdir(parents=True, exist_ok=True)
151
+ (root / "[Content_Types].xml").write_text(
152
+ """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
153
+ <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
154
+ <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
155
+ <Default Extension="xml" ContentType="application/xml"/>
156
+ <Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
157
+ <Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>
158
+ <Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>
159
+ </Types>
160
+ """,
161
+ encoding="utf-8",
162
+ )
163
+ (root / "_rels" / ".rels").write_text(
164
+ """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
165
+ <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
166
+ <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
167
+ <Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
168
+ <Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
169
+ </Relationships>
170
+ """,
171
+ encoding="utf-8",
172
+ )
173
+ (root / "word" / "document.xml").write_bytes(document_xml)
174
+ (root / "docProps").mkdir(parents=True, exist_ok=True)
175
+ (root / "docProps" / "core.xml").write_text(
176
+ """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
177
+ <cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
178
+ <dc:title>ite document</dc:title>
179
+ <dc:creator>ite</dc:creator>
180
+ </cp:coreProperties>
181
+ """,
182
+ encoding="utf-8",
183
+ )
184
+ (root / "docProps" / "app.xml").write_text(
185
+ """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
186
+ <Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">
187
+ <Application>ite</Application>
188
+ </Properties>
189
+ """,
190
+ encoding="utf-8",
191
+ )
192
+ output = root / "out.docx"
193
+ pack_directory(root, output)
194
+ return output.read_bytes()
195
+
196
+
197
+ def validate_docx(path: Path) -> list[str]:
198
+ errors: list[str] = []
199
+ try:
200
+ with ZipFile(path) as archive:
201
+ members = set(archive.namelist())
202
+ missing = REQUIRED_MEMBERS - members
203
+ if missing:
204
+ errors.append(f"missing required members: {', '.join(sorted(missing))}")
205
+ for member in sorted(REQUIRED_MEMBERS & members):
206
+ with archive.open(member) as handle:
207
+ try:
208
+ ET.parse(handle)
209
+ except ET.ParseError as exc:
210
+ errors.append(f"{member}: invalid XML ({exc})")
211
+ except Exception as exc:
212
+ errors.append(str(exc))
213
+ return errors
214
+
215
+
216
+ def _paragraph_element(text: str) -> ET.Element:
217
+ paragraph = ET.Element(f"{{{W_NS}}}p")
218
+ run = ET.SubElement(paragraph, f"{{{W_NS}}}r")
219
+ text_node = ET.SubElement(run, f"{{{W_NS}}}t")
220
+ if text.startswith(" ") or text.endswith(" "):
221
+ text_node.set("{http://www.w3.org/XML/1998/namespace}space", "preserve")
222
+ text_node.text = text
223
+ return paragraph
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ from pathlib import Path
6
+
7
+ from _docx_core import load_document_tree
8
+ from _docx_core import paragraph_texts
9
+
10
+
11
+ def main() -> int:
12
+ parser = argparse.ArgumentParser(description="Extract readable content from a .docx file.")
13
+ parser.add_argument("input", type=Path, help="Path to the source .docx file")
14
+ parser.add_argument(
15
+ "--format",
16
+ choices=("text", "markdown", "json"),
17
+ default="text",
18
+ help="Output format",
19
+ )
20
+ parser.add_argument("--output", type=Path, help="Optional file to write extracted content to")
21
+ args = parser.parse_args()
22
+
23
+ tree = load_document_tree(args.input)
24
+ paragraphs = paragraph_texts(tree)
25
+ if args.format == "json":
26
+ content = json.dumps({"paragraphs": paragraphs}, indent=2)
27
+ elif args.format == "markdown":
28
+ content = "\n\n".join(paragraphs)
29
+ else:
30
+ content = "\n".join(paragraphs)
31
+
32
+ if args.output:
33
+ args.output.write_text(content, encoding="utf-8")
34
+ else:
35
+ print(content)
36
+ return 0
37
+
38
+
39
+ if __name__ == "__main__":
40
+ raise SystemExit(main())
@@ -0,0 +1,20 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+
6
+ from _docx_core import inspect_docx
7
+ from _docx_core import json_dump
8
+
9
+
10
+ def main() -> int:
11
+ parser = argparse.ArgumentParser(description="Inspect a .docx file and report basic metadata.")
12
+ parser.add_argument("input", type=Path, help="Path to the source .docx file")
13
+ args = parser.parse_args()
14
+
15
+ print(json_dump(inspect_docx(args.input)))
16
+ return 0
17
+
18
+
19
+ if __name__ == "__main__":
20
+ raise SystemExit(main())
@@ -0,0 +1,21 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+
6
+ from _docx_core import pack_directory
7
+
8
+
9
+ def main() -> int:
10
+ parser = argparse.ArgumentParser(description="Pack an unpacked OOXML directory into a .docx file.")
11
+ parser.add_argument("input_dir", type=Path, help="Directory containing the unpacked document")
12
+ parser.add_argument("output", type=Path, help="Output .docx file")
13
+ args = parser.parse_args()
14
+
15
+ pack_directory(args.input_dir, args.output)
16
+ print(args.output.resolve())
17
+ return 0
18
+
19
+
20
+ if __name__ == "__main__":
21
+ raise SystemExit(main())
@@ -0,0 +1,70 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+ import shutil
6
+ import subprocess
7
+ import tempfile
8
+
9
+
10
+ def main() -> int:
11
+ parser = argparse.ArgumentParser(description="Render a DOCX file to page PNGs using LibreOffice and Poppler.")
12
+ parser.add_argument("input", type=Path, help="Source .docx file")
13
+ parser.add_argument("--output_dir", type=Path, required=True, help="Directory for rendered page images")
14
+ parser.add_argument("--dpi", type=int, default=144, help="Rasterization DPI")
15
+ args = parser.parse_args()
16
+
17
+ for tool in ("soffice", "pdftoppm"):
18
+ if shutil.which(tool) is None:
19
+ raise SystemExit(f"missing required system tool: {tool}")
20
+
21
+ args.output_dir.mkdir(parents=True, exist_ok=True)
22
+ with tempfile.TemporaryDirectory(prefix="ite-docx-render-") as temp_dir:
23
+ temp_root = Path(temp_dir)
24
+ pdf_dir = temp_root / "pdf"
25
+ pdf_dir.mkdir(parents=True, exist_ok=True)
26
+ profile_dir = temp_root / "profile"
27
+ profile_dir.mkdir(parents=True, exist_ok=True)
28
+
29
+ subprocess.run(
30
+ [
31
+ "soffice",
32
+ f"-env:UserInstallation=file://{profile_dir}",
33
+ "--headless",
34
+ "--convert-to",
35
+ "pdf",
36
+ "--outdir",
37
+ str(pdf_dir),
38
+ str(args.input),
39
+ ],
40
+ check=True,
41
+ capture_output=True,
42
+ text=True,
43
+ )
44
+
45
+ pdf_path = pdf_dir / f"{args.input.stem}.pdf"
46
+ if not pdf_path.is_file():
47
+ raise SystemExit("failed to produce an intermediate PDF")
48
+
49
+ prefix = args.output_dir / "page"
50
+ subprocess.run(
51
+ [
52
+ "pdftoppm",
53
+ "-png",
54
+ "-r",
55
+ str(args.dpi),
56
+ str(pdf_path),
57
+ str(prefix),
58
+ ],
59
+ check=True,
60
+ capture_output=True,
61
+ text=True,
62
+ )
63
+
64
+ for path in sorted(args.output_dir.glob("page-*.png")):
65
+ print(path.resolve())
66
+ return 0
67
+
68
+
69
+ if __name__ == "__main__":
70
+ raise SystemExit(main())
@@ -0,0 +1,39 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+
6
+ from _docx_core import load_document_tree
7
+ from _docx_core import paragraph_texts
8
+ from _docx_core import replace_in_paragraphs
9
+ from _docx_core import set_paragraphs
10
+ from _docx_core import write_document_tree
11
+
12
+
13
+ def main() -> int:
14
+ parser = argparse.ArgumentParser(description="Apply direct string replacements inside a .docx document.")
15
+ parser.add_argument("input", type=Path, help="Source .docx file")
16
+ parser.add_argument("output", type=Path, help="Output .docx file")
17
+ parser.add_argument(
18
+ "--replace",
19
+ nargs=2,
20
+ metavar=("OLD", "NEW"),
21
+ action="append",
22
+ required=True,
23
+ help="Pair of strings to replace in order",
24
+ )
25
+ args = parser.parse_args()
26
+
27
+ tree = load_document_tree(args.input)
28
+ paragraphs = paragraph_texts(tree)
29
+ updated, replacement_count = replace_in_paragraphs(paragraphs, args.replace)
30
+ if replacement_count == 0:
31
+ raise SystemExit("no matching text was found for replacement")
32
+ set_paragraphs(tree, updated)
33
+ write_document_tree(args.input, args.output, tree)
34
+ print(f"{args.output.resolve()} ({replacement_count} replacements)")
35
+ return 0
36
+
37
+
38
+ if __name__ == "__main__":
39
+ raise SystemExit(main())
@@ -0,0 +1,21 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+
6
+ from _docx_core import unpack_to_directory
7
+
8
+
9
+ def main() -> int:
10
+ parser = argparse.ArgumentParser(description="Unpack a .docx file into a directory.")
11
+ parser.add_argument("input", type=Path, help="Path to the source .docx file")
12
+ parser.add_argument("output_dir", type=Path, help="Directory to receive the unpacked package")
13
+ args = parser.parse_args()
14
+
15
+ unpack_to_directory(args.input, args.output_dir)
16
+ print(args.output_dir.resolve())
17
+ return 0
18
+
19
+
20
+ if __name__ == "__main__":
21
+ raise SystemExit(main())
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+
6
+ from _docx_core import validate_docx
7
+
8
+
9
+ def main() -> int:
10
+ parser = argparse.ArgumentParser(description="Validate the basic shape of a .docx file.")
11
+ parser.add_argument("input", type=Path, help="Path to the .docx file")
12
+ args = parser.parse_args()
13
+
14
+ errors = validate_docx(args.input)
15
+ if errors:
16
+ for error in errors:
17
+ print(error)
18
+ return 1
19
+ print("ok")
20
+ return 0
21
+
22
+
23
+ if __name__ == "__main__":
24
+ raise SystemExit(main())
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+
6
+ from _docx_core import build_simple_document
7
+
8
+
9
+ def main() -> int:
10
+ parser = argparse.ArgumentParser(description="Create a simple .docx file from text or markdown.")
11
+ parser.add_argument("input", type=Path, nargs="?", help="Source text or markdown file")
12
+ parser.add_argument("output", type=Path, help="Output .docx path")
13
+ parser.add_argument("--title", help="Optional document title inserted as the first paragraph")
14
+ parser.add_argument(
15
+ "--template",
16
+ choices=("memo", "letter"),
17
+ help="Use a bundled starter template when no input file is provided",
18
+ )
19
+ args = parser.parse_args()
20
+
21
+ if args.input is None and args.template is None:
22
+ raise SystemExit("provide either an input file or --template")
23
+
24
+ source_path = args.input
25
+ if source_path is None:
26
+ source_path = Path(__file__).resolve().parent.parent / "templates" / f"{args.template}.md"
27
+
28
+ source = source_path.read_text(encoding="utf-8")
29
+ paragraphs = [line.strip() for line in source.splitlines() if line.strip()]
30
+ if not paragraphs:
31
+ raise SystemExit("input did not contain any non-empty lines")
32
+ payload = build_simple_document(paragraphs, title=args.title)
33
+ args.output.parent.mkdir(parents=True, exist_ok=True)
34
+ args.output.write_bytes(payload)
35
+ print(args.output.resolve())
36
+ return 0
37
+
38
+
39
+ if __name__ == "__main__":
40
+ raise SystemExit(main())
@@ -0,0 +1,11 @@
1
+ Letter Title
2
+
3
+ Recipient
4
+
5
+ Opening
6
+
7
+ Body paragraph one.
8
+
9
+ Body paragraph two.
10
+
11
+ Closing
@@ -0,0 +1,13 @@
1
+ Team Memo
2
+
3
+ Summary
4
+
5
+ Add the short executive summary here.
6
+
7
+ Details
8
+
9
+ Add the supporting details here.
10
+
11
+ Next steps
12
+
13
+ List the follow-up actions here.