patch-chat 0.1.0__tar.gz → 0.2.0__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 (324) hide show
  1. {patch_chat-0.1.0 → patch_chat-0.2.0}/.agents/setup +4 -1
  2. patch_chat-0.2.0/.github/workflows/packaging.yml +103 -0
  3. {patch_chat-0.1.0 → patch_chat-0.2.0}/.github/workflows/pre-commit.yml +10 -0
  4. {patch_chat-0.1.0 → patch_chat-0.2.0}/.github/workflows/ubuntu-tests.yml +9 -4
  5. {patch_chat-0.1.0 → patch_chat-0.2.0}/.github/workflows/windows-tests.yml +5 -3
  6. {patch_chat-0.1.0 → patch_chat-0.2.0}/.gitignore +3 -0
  7. patch_chat-0.2.0/AGENTS.md +138 -0
  8. patch_chat-0.2.0/AUDIT_PROMPT.md +314 -0
  9. patch_chat-0.2.0/AUDIT_REPORT.md +3610 -0
  10. patch_chat-0.2.0/CHANGELOG.md +624 -0
  11. {patch_chat-0.1.0 → patch_chat-0.2.0}/CONTRIBUTING.md +289 -226
  12. {patch_chat-0.1.0/patch_chat.egg-info → patch_chat-0.2.0}/PKG-INFO +51 -22
  13. {patch_chat-0.1.0 → patch_chat-0.2.0}/README.md +47 -8
  14. {patch_chat-0.1.0 → patch_chat-0.2.0}/docker/Dockerfile +10 -7
  15. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/__init__.py +20 -20
  16. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/_version.py +3 -3
  17. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/analytics.py +1 -13
  18. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/args.py +12 -3
  19. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/args_formatter.py +226 -228
  20. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/__init__.py +53 -32
  21. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/base_coder.py +331 -215
  22. patch_chat-0.2.0/patch/coders/chat_state.py +92 -0
  23. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/editblock_coder.py +25 -11
  24. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/editblock_fenced_coder.py +9 -10
  25. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/editblock_func_coder.py +1 -2
  26. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/patch_coder.py +10 -3
  27. patch_chat-0.2.0/patch/coders/search_replace.py +309 -0
  28. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/single_wholefile_func_coder.py +1 -1
  29. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/udiff_coder.py +31 -8
  30. patch_chat-0.2.0/patch/coders/usage.py +186 -0
  31. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/wholefile_coder.py +1 -2
  32. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/wholefile_func_coder.py +133 -134
  33. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/commands.py +58 -22
  34. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/copypaste.py +71 -70
  35. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/diffs.py +4 -4
  36. patch_chat-0.2.0/patch/dump.py +33 -0
  37. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/editor.py +16 -5
  38. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/exceptions.py +43 -12
  39. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/history.py +1 -23
  40. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/io.py +1318 -1209
  41. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/linter.py +25 -8
  42. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/llm.py +7 -6
  43. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/main.py +433 -537
  44. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/mdstream.py +241 -243
  45. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/models.py +44 -10
  46. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/onboarding.py +72 -22
  47. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/reasoning_tags.py +80 -82
  48. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/repo.py +28 -43
  49. patch_chat-0.2.0/patch/repo_trust.py +580 -0
  50. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/repomap.py +38 -14
  51. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/report.py +57 -4
  52. patch_chat-0.2.0/patch/run_cmd.py +338 -0
  53. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/scrape.py +332 -316
  54. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/sendchat.py +60 -61
  55. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/utils.py +12 -11
  56. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/versioncheck.py +112 -113
  57. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/voice.py +198 -200
  58. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/waiting.py +2 -1
  59. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/watch.py +6 -41
  60. {patch_chat-0.1.0 → patch_chat-0.2.0/patch_chat.egg-info}/PKG-INFO +51 -22
  61. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch_chat.egg-info/SOURCES.txt +5 -1
  62. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch_chat.egg-info/requires.txt +4 -16
  63. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch_chat.egg-info/scm_file_list.json +5 -1
  64. patch_chat-0.2.0/patch_chat.egg-info/scm_version.json +8 -0
  65. patch_chat-0.2.0/pyproject.toml +133 -0
  66. {patch_chat-0.1.0 → patch_chat-0.2.0}/requirements/common-constraints.txt +504 -535
  67. {patch_chat-0.1.0 → patch_chat-0.2.0}/requirements/requirements-browser.txt +169 -169
  68. {patch_chat-0.1.0 → patch_chat-0.2.0}/requirements/requirements-dev.in +20 -21
  69. {patch_chat-0.1.0 → patch_chat-0.2.0}/requirements/requirements-dev.txt +359 -398
  70. {patch_chat-0.1.0 → patch_chat-0.2.0}/requirements/requirements-playwright.txt +18 -18
  71. {patch_chat-0.1.0 → patch_chat-0.2.0}/requirements/requirements.in +47 -53
  72. {patch_chat-0.1.0 → patch_chat-0.2.0}/requirements/tree-sitter.in +2 -3
  73. {patch_chat-0.1.0 → patch_chat-0.2.0}/requirements.txt +464 -477
  74. {patch_chat-0.1.0 → patch_chat-0.2.0}/scripts/pip-compile.sh +46 -46
  75. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_analytics.py +0 -5
  76. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_aws_credentials.py +120 -169
  77. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_coder.py +1671 -1573
  78. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_commands.py +2297 -2226
  79. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_editblock.py +50 -0
  80. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_editor.py +23 -1
  81. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_history.py +68 -0
  82. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_io.py +236 -0
  83. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_linter.py +47 -3
  84. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_main.py +26 -2
  85. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_models.py +733 -668
  86. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_onboarding.py +56 -0
  87. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_path_containment.py +450 -286
  88. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_repo.py +726 -716
  89. patch_chat-0.2.0/tests/basic/test_repo_config_trust.py +680 -0
  90. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_repomap.py +71 -1
  91. patch_chat-0.2.0/tests/basic/test_run_cmd.py +207 -0
  92. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_udiff.py +241 -167
  93. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/browser/test_browser.py +36 -36
  94. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/conftest.py +94 -59
  95. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/scrape/test_scrape.py +56 -0
  96. patch_chat-0.1.0/AGENTS.md +0 -92
  97. patch_chat-0.1.0/AUDIT_REPORT.md +0 -1133
  98. patch_chat-0.1.0/CHANGELOG.md +0 -178
  99. patch_chat-0.1.0/patch/coders/search_replace.py +0 -757
  100. patch_chat-0.1.0/patch/dump.py +0 -29
  101. patch_chat-0.1.0/patch/run_cmd.py +0 -146
  102. patch_chat-0.1.0/patch_chat.egg-info/scm_version.json +0 -8
  103. patch_chat-0.1.0/pyproject.toml +0 -74
  104. patch_chat-0.1.0/scripts/versionbump.py +0 -175
  105. patch_chat-0.1.0/tests/basic/test_repo_config_trust.py +0 -216
  106. patch_chat-0.1.0/tests/basic/test_run_cmd.py +0 -45
  107. {patch_chat-0.1.0 → patch_chat-0.2.0}/.agents/resume +0 -0
  108. {patch_chat-0.1.0 → patch_chat-0.2.0}/.dockerignore +0 -0
  109. {patch_chat-0.1.0 → patch_chat-0.2.0}/.flake8 +0 -0
  110. {patch_chat-0.1.0 → patch_chat-0.2.0}/.github/ISSUE_TEMPLATE/issue.yml +0 -0
  111. {patch_chat-0.1.0 → patch_chat-0.2.0}/.pre-commit-config.yaml +0 -0
  112. {patch_chat-0.1.0 → patch_chat-0.2.0}/LICENSE.txt +0 -0
  113. {patch_chat-0.1.0 → patch_chat-0.2.0}/MANIFEST.in +0 -0
  114. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/Dockerfile +0 -0
  115. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/README.md +0 -0
  116. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/__init__.py +0 -0
  117. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/benchmark.py +0 -0
  118. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/clone-exercism.sh +0 -0
  119. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/cpp-test.sh +0 -0
  120. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/docker.sh +0 -0
  121. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/docker_build.sh +0 -0
  122. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/install-docker-ubuntu.sh +0 -0
  123. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/npm-test.sh +0 -0
  124. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/plot.sh +0 -0
  125. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/plots.py +0 -0
  126. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/prompts.py +0 -0
  127. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/refactor_tools.py +0 -0
  128. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/rsync.sh +0 -0
  129. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/rungrid.py +0 -0
  130. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/swe-bench-lite.txt +0 -0
  131. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/swe-bench.txt +0 -0
  132. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/swe_bench.py +0 -0
  133. {patch_chat-0.1.0 → patch_chat-0.2.0}/benchmark/test_benchmark.py +0 -0
  134. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/__main__.py +0 -0
  135. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/architect_coder.py +0 -0
  136. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/architect_prompts.py +0 -0
  137. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/ask_coder.py +0 -0
  138. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/ask_prompts.py +0 -0
  139. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/base_prompts.py +0 -0
  140. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/chat_chunks.py +0 -0
  141. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/context_coder.py +0 -0
  142. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/context_prompts.py +0 -0
  143. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/edit_apply.py +0 -0
  144. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/editblock_fenced_prompts.py +0 -0
  145. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/editblock_func_prompts.py +0 -0
  146. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/editblock_prompts.py +0 -0
  147. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/editor_diff_fenced_coder.py +0 -0
  148. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/editor_diff_fenced_prompts.py +0 -0
  149. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/editor_editblock_coder.py +0 -0
  150. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/editor_editblock_prompts.py +0 -0
  151. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/editor_whole_coder.py +0 -0
  152. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/editor_whole_prompts.py +0 -0
  153. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/patch_prompts.py +0 -0
  154. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/shell.py +0 -0
  155. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/single_wholefile_func_prompts.py +0 -0
  156. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/udiff_prompts.py +0 -0
  157. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/udiff_simple.py +0 -0
  158. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/udiff_simple_prompts.py +0 -0
  159. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/wholefile_func_prompts.py +0 -0
  160. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/coders/wholefile_prompts.py +0 -0
  161. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/deprecated.py +0 -0
  162. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/format_settings.py +0 -0
  163. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/gui.py +0 -0
  164. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/openrouter.py +0 -0
  165. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/prompts.py +0 -0
  166. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/README.md +0 -0
  167. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/arduino-tags.scm +0 -0
  168. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/bash-tags.scm +0 -0
  169. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/c-tags.scm +0 -0
  170. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/chatito-tags.scm +0 -0
  171. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/clojure-tags.scm +0 -0
  172. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/commonlisp-tags.scm +0 -0
  173. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/cpp-tags.scm +0 -0
  174. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/csharp-tags.scm +0 -0
  175. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/d-tags.scm +0 -0
  176. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/dart-tags.scm +0 -0
  177. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/elisp-tags.scm +0 -0
  178. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/elixir-tags.scm +0 -0
  179. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/elm-tags.scm +0 -0
  180. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/gleam-tags.scm +0 -0
  181. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/go-tags.scm +0 -0
  182. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/java-tags.scm +0 -0
  183. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/javascript-tags.scm +0 -0
  184. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/lua-tags.scm +0 -0
  185. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/matlab-tags.scm +0 -0
  186. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/ocaml-tags.scm +0 -0
  187. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +0 -0
  188. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/pony-tags.scm +0 -0
  189. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/properties-tags.scm +0 -0
  190. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/python-tags.scm +0 -0
  191. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/r-tags.scm +0 -0
  192. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/racket-tags.scm +0 -0
  193. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/ruby-tags.scm +0 -0
  194. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/rust-tags.scm +0 -0
  195. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/solidity-tags.scm +0 -0
  196. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/swift-tags.scm +0 -0
  197. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-language-pack/udev-tags.scm +0 -0
  198. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/README.md +0 -0
  199. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/bash-tags.scm +0 -0
  200. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/c-tags.scm +0 -0
  201. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/c_sharp-tags.scm +0 -0
  202. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/cpp-tags.scm +0 -0
  203. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/dart-tags.scm +0 -0
  204. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/elisp-tags.scm +0 -0
  205. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/elixir-tags.scm +0 -0
  206. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/elm-tags.scm +0 -0
  207. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/fortran-tags.scm +0 -0
  208. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/go-tags.scm +0 -0
  209. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/haskell-tags.scm +0 -0
  210. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/hcl-tags.scm +0 -0
  211. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/java-tags.scm +0 -0
  212. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/javascript-tags.scm +0 -0
  213. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/julia-tags.scm +0 -0
  214. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/kotlin-tags.scm +0 -0
  215. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/matlab-tags.scm +0 -0
  216. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/ocaml-tags.scm +0 -0
  217. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/ocaml_interface-tags.scm +0 -0
  218. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/php-tags.scm +0 -0
  219. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/python-tags.scm +0 -0
  220. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/ql-tags.scm +0 -0
  221. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/ruby-tags.scm +0 -0
  222. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/rust-tags.scm +0 -0
  223. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/scala-tags.scm +0 -0
  224. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/typescript-tags.scm +0 -0
  225. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/queries/tree-sitter-languages/zig-tags.scm +0 -0
  226. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/resources/__init__.py +0 -0
  227. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/resources/model-metadata.json +0 -0
  228. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/resources/model-settings.yml +0 -0
  229. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/special.py +0 -0
  230. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/urls.py +0 -0
  231. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch/watch_prompts.py +0 -0
  232. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch_chat.egg-info/dependency_links.txt +0 -0
  233. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch_chat.egg-info/entry_points.txt +0 -0
  234. {patch_chat-0.1.0 → patch_chat-0.2.0}/patch_chat.egg-info/top_level.txt +0 -0
  235. {patch_chat-0.1.0 → patch_chat-0.2.0}/pytest.ini +0 -0
  236. {patch_chat-0.1.0 → patch_chat-0.2.0}/requirements/pydub.in +0 -0
  237. {patch_chat-0.1.0 → patch_chat-0.2.0}/requirements/python-compat.in +0 -0
  238. {patch_chat-0.1.0 → patch_chat-0.2.0}/requirements/requirements-browser.in +0 -0
  239. {patch_chat-0.1.0 → patch_chat-0.2.0}/requirements/requirements-playwright.in +0 -0
  240. {patch_chat-0.1.0 → patch_chat-0.2.0}/scripts/__init__.py +0 -0
  241. {patch_chat-0.1.0 → patch_chat-0.2.0}/scripts/blame.py +0 -0
  242. {patch_chat-0.1.0 → patch_chat-0.2.0}/scripts/clean_metadata.py +0 -0
  243. {patch_chat-0.1.0 → patch_chat-0.2.0}/scripts/issues.py +0 -0
  244. {patch_chat-0.1.0 → patch_chat-0.2.0}/scripts/my_models.py +0 -0
  245. {patch_chat-0.1.0 → patch_chat-0.2.0}/scripts/redact-cast.py +0 -0
  246. {patch_chat-0.1.0 → patch_chat-0.2.0}/scripts/tmux_record.sh +0 -0
  247. {patch_chat-0.1.0 → patch_chat-0.2.0}/scripts/tsl_pack_langs.py +0 -0
  248. {patch_chat-0.1.0 → patch_chat-0.2.0}/scripts/yank-old-versions.py +0 -0
  249. {patch_chat-0.1.0 → patch_chat-0.2.0}/setup.cfg +0 -0
  250. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/__init__.py +0 -0
  251. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/__init__.py +0 -0
  252. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_copypaste.py +0 -0
  253. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_deprecated.py +0 -0
  254. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_edit_apply.py +0 -0
  255. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_exceptions.py +0 -0
  256. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_find_or_blocks.py +0 -0
  257. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_format_settings.py +0 -0
  258. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_model_info_manager.py +0 -0
  259. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_openrouter.py +0 -0
  260. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_patch_coder.py +0 -0
  261. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_reasoning.py +0 -0
  262. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_report.py +0 -0
  263. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_sanity_check_repo.py +0 -0
  264. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_scripting.py +0 -0
  265. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_sendchat.py +0 -0
  266. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_special.py +0 -0
  267. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_ssl_verification.py +0 -0
  268. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_urls.py +0 -0
  269. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_utils.py +0 -0
  270. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_versioncheck.py +0 -0
  271. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_voice.py +0 -0
  272. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_waiting.py +0 -0
  273. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_watch.py +0 -0
  274. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/basic/test_wholefile.py +0 -0
  275. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/chat-history-search-replace-gold.txt +0 -0
  276. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/chat-history.md +0 -0
  277. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/arduino/test.ino +0 -0
  278. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/bash/test.sh +0 -0
  279. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/c/test.c +0 -0
  280. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/chatito/test.chatito +0 -0
  281. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/clojure/test.clj +0 -0
  282. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/commonlisp/test.lisp +0 -0
  283. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/cpp/test.cpp +0 -0
  284. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/csharp/test.cs +0 -0
  285. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/d/test.d +0 -0
  286. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/dart/test.dart +0 -0
  287. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/elisp/test.el +0 -0
  288. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/elixir/test.ex +0 -0
  289. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/elm/test.elm +0 -0
  290. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/gleam/test.gleam +0 -0
  291. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/go/test.go +0 -0
  292. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/haskell/test.hs +0 -0
  293. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/hcl/test.tf +0 -0
  294. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/java/test.java +0 -0
  295. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/javascript/test.js +0 -0
  296. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/kotlin/test.kt +0 -0
  297. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/lua/test.lua +0 -0
  298. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/matlab/test.m +0 -0
  299. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/ocaml/test.ml +0 -0
  300. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/ocaml_interface/test.mli +0 -0
  301. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/php/test.php +0 -0
  302. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/pony/test.pony +0 -0
  303. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/properties/test.properties +0 -0
  304. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/python/test.py +0 -0
  305. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/ql/test.ql +0 -0
  306. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/r/test.r +0 -0
  307. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/racket/test.rkt +0 -0
  308. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/ruby/test.rb +0 -0
  309. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/rust/test.rs +0 -0
  310. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/scala/test.scala +0 -0
  311. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/solidity/test.sol +0 -0
  312. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/swift/test.swift +0 -0
  313. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/tsx/test.tsx +0 -0
  314. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/typescript/test.ts +0 -0
  315. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/udev/test.rules +0 -0
  316. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/languages/zig/test.zig +0 -0
  317. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/sample-code-base/sample.js +0 -0
  318. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/sample-code-base/sample.py +0 -0
  319. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/sample-code-base-repo-map.txt +0 -0
  320. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/watch.js +0 -0
  321. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/watch.lisp +0 -0
  322. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/watch.py +0 -0
  323. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/fixtures/watch_question.js +0 -0
  324. {patch_chat-0.1.0 → patch_chat-0.2.0}/tests/scrape/test_playwright_disable.py +0 -0
@@ -20,8 +20,11 @@ if ((${#missing_packages[@]})); then
20
20
  fi
21
21
 
22
22
  step "Installing Python project and development dependencies"
23
+ # No --extra-index-url: it resolves each name across both indexes and takes the
24
+ # highest version, rather than replacing the index as --index-url does. Nothing
25
+ # in the pinned locks needs the torch index; docker/Dockerfile uses --index-url
26
+ # where it genuinely does.
23
27
  python3 -m pip install --editable . \
24
- --extra-index-url https://download.pytorch.org/whl/cpu \
25
28
  --requirement requirements/requirements-dev.txt \
26
29
  --requirement requirements/requirements-browser.txt \
27
30
  --requirement requirements/requirements-playwright.txt
@@ -0,0 +1,103 @@
1
+ name: Packaging
2
+
3
+ # The test suite runs from the repository root, where `tests/__init__.py` puts the
4
+ # working tree on sys.path -- so `import patch` resolves to ./patch and the suite
5
+ # never sees the artifact users install. This job closes that gap: it builds a
6
+ # wheel with no .git present (the same context docker/Dockerfile gets, since
7
+ # .dockerignore excludes .git), installs it into a clean environment, and imports
8
+ # it from another directory.
9
+ #
10
+ # Without .git, setuptools-scm's file finder is unavailable and only the files
11
+ # enumerated in [tool.setuptools.package-data] survive. That is how
12
+ # patch/resources/model-settings.yml went missing once already; models.py opens it
13
+ # at import time, so the wheel raised FileNotFoundError on every invocation while
14
+ # passing the whole test suite.
15
+
16
+ on:
17
+ push:
18
+ branches:
19
+ - main
20
+ pull_request:
21
+ branches:
22
+ - main
23
+
24
+ jobs:
25
+ installed-wheel:
26
+ runs-on: ubuntu-latest
27
+
28
+ steps:
29
+ - name: Check out repository
30
+ uses: actions/checkout@v4
31
+ with:
32
+ fetch-depth: 0
33
+
34
+ - name: Set up Python
35
+ uses: actions/setup-python@v5
36
+ with:
37
+ python-version: "3.10"
38
+
39
+ - name: Build a wheel from a source tree with no .git
40
+ run: |
41
+ python -m pip install --upgrade pip build
42
+ mkdir -p /tmp/nogit
43
+ # Deliberately not `git archive`: this must mirror `COPY . /tmp/patch`,
44
+ # i.e. the working tree minus the directories .dockerignore excludes.
45
+ tar --exclude=.git --exclude='*.egg-info' --exclude=dist --exclude=build \
46
+ -cf - . | tar -C /tmp/nogit -xf -
47
+ test ! -e /tmp/nogit/.git
48
+ cd /tmp/nogit && python -m build --wheel --outdir /tmp/dist .
49
+
50
+ - name: Install the wheel into a clean environment
51
+ run: |
52
+ python -m venv /tmp/venv
53
+ /tmp/venv/bin/python -m pip install --upgrade pip
54
+ /tmp/venv/bin/python -m pip install /tmp/dist/*.whl
55
+
56
+ - name: Import it from another directory
57
+ run: |
58
+ mkdir -p /tmp/elsewhere
59
+ cd /tmp/elsewhere
60
+ # Must not resolve to a source checkout.
61
+ /tmp/venv/bin/python -c "
62
+ import patch, patch.main, patch.models
63
+ assert 'site-packages' in patch.__file__, patch.__file__
64
+ assert patch.models.MODEL_SETTINGS, 'model-settings.yml did not load'
65
+ print('imported', patch.__file__)
66
+ print('model settings:', len(patch.models.MODEL_SETTINGS))
67
+ "
68
+
69
+ - name: Check the console script is wired up
70
+ run: |
71
+ cd /tmp/elsewhere
72
+ /tmp/venv/bin/patch --version
73
+
74
+ - name: Verify wheel metadata and declared package data
75
+ run: |
76
+ python - <<'EOF'
77
+ from email.parser import BytesParser
78
+ import glob
79
+ from pathlib import Path
80
+ import zipfile
81
+
82
+ with zipfile.ZipFile(glob.glob("/tmp/dist/*.whl")[0]) as wheel:
83
+ names = wheel.namelist()
84
+ metadata_name = next(n for n in names if n.endswith(".dist-info/METADATA"))
85
+ metadata = BytesParser().parsebytes(wheel.read(metadata_name))
86
+
87
+ assert metadata["License-Expression"] == "Apache-2.0"
88
+ assert metadata["Requires-Python"] == "<3.15,>=3.10"
89
+ assert any(n.endswith(".dist-info/licenses/LICENSE.txt") for n in names)
90
+
91
+ required = [
92
+ "patch/resources/model-settings.yml",
93
+ "patch/resources/model-metadata.json",
94
+ ]
95
+ missing = [r for r in required if r not in names]
96
+ assert not missing, f"missing from the wheel: {missing}"
97
+ assert any(n.endswith(".scm") for n in names), "no tree-sitter queries in the wheel"
98
+ assert any(n.startswith("patch/coders/") for n in names), "patch.coders missing"
99
+
100
+ readme = Path("README.md").read_text()
101
+ assert "supports Python 3.10 through 3.14" in readme
102
+ print(f"wheel contains {len(names)} entries; metadata and required files verified")
103
+ EOF
@@ -14,6 +14,16 @@ jobs:
14
14
  - run: sudo apt-get update && sudo apt-get install cppcheck uncrustify
15
15
  if: false
16
16
  - uses: actions/checkout@v4
17
+ # Pin the interpreter. Without this every hook environment -- including
18
+ # mypy, which pyproject.toml configures for python_version = "3.10" -- is
19
+ # built against whatever ubuntu-latest currently ships, so the type gate
20
+ # drifts silently when the runner image changes. It also populates
21
+ # env.pythonLocation, which the cache keys below interpolate: unset, they
22
+ # collapse to `pre-commit-4||<hash>` and restore hook virtualenvs built
23
+ # against a different Python.
24
+ - uses: actions/setup-python@v5
25
+ with:
26
+ python-version: "3.10"
17
27
  - run: python -m pip install pre-commit
18
28
  - uses: actions/cache/restore@v4
19
29
  with:
@@ -32,7 +32,6 @@ jobs:
32
32
  cache: pip
33
33
  cache-dependency-path: |
34
34
  requirements.txt
35
- requirements/requirements-dev.txt
36
35
 
37
36
  - name: Install system dependencies
38
37
  run: |
@@ -42,11 +41,17 @@ jobs:
42
41
  - name: Install dependencies
43
42
  run: |
44
43
  python -m pip install --upgrade pip
45
- pip install pytest pytest-env
46
- pip install .
44
+ pip install pytest pytest-env pytest-cov
45
+ # pytest.ini collects tests/browser and tests/scrape, so the optional
46
+ # extras those exercise have to be present -- and installing them is the
47
+ # only thing that checks the extras are declared correctly at all.
48
+ pip install .[browser,playwright]
47
49
 
48
50
  - name: Run tests
49
51
  env:
50
52
  PATCH_ANALYTICS: false
53
+ # Coverage is reported, not gated: a threshold now would either be set so
54
+ # low it asserts nothing or would fail the build on unrelated changes.
55
+ # Making the number visible is the point.
51
56
  run: |
52
- pytest
57
+ pytest --cov=patch --cov-report=term-missing
@@ -32,13 +32,15 @@ jobs:
32
32
  cache: pip
33
33
  cache-dependency-path: |
34
34
  requirements.txt
35
- requirements/requirements-dev.txt
36
35
 
37
36
  - name: Install dependencies
38
37
  run: |
39
38
  python -m pip install --upgrade pip
40
- pip install pytest pytest-env
41
- pip install .
39
+ pip install pytest pytest-env pytest-cov
40
+ # pytest.ini collects tests/browser and tests/scrape, so the optional
41
+ # extras those exercise have to be present -- and installing them is the
42
+ # only thing that checks the extras are declared correctly at all.
43
+ pip install .[browser,playwright]
42
44
 
43
45
  - name: Run tests
44
46
  env:
@@ -20,3 +20,6 @@ patch/_version.py
20
20
  tmp.benchmarks/
21
21
  .docker_bash_history
22
22
  .amp/portals/*
23
+ .coverage
24
+ htmlcov/
25
+ .coverage.*
@@ -0,0 +1,138 @@
1
+ # AGENTS.md
2
+
3
+ Guidance for AI coding agents working in this repository.
4
+
5
+ ## What this project is
6
+
7
+ Patch is an AI pair-programming tool that runs in the terminal. The Python distribution is
8
+ [`patch-chat`](https://pypi.org/project/patch-chat/), the module is `patch/`, and the CLI entry
9
+ point is `patch` (`patch.main:main`). Release history lives in [CHANGELOG.md](CHANGELOG.md).
10
+
11
+ Versions come from git tags via setuptools-scm; the fork's own history starts at `0.1.0` and does
12
+ not continue upstream aider's `0.86.x` numbering.
13
+
14
+ ## Setup
15
+
16
+ Python 3.10 through 3.14 (`requires-python = ">=3.10,<3.15"`).
17
+
18
+ ```
19
+ pip install -e .
20
+ pip install -r requirements.txt
21
+ pip install -r requirements/requirements-dev.txt
22
+ ```
23
+
24
+ ## Testing
25
+
26
+ ```
27
+ pytest # full suite
28
+ pytest tests/basic/test_coder.py # one file
29
+ pytest -k test_repomap # one pattern
30
+ ```
31
+
32
+ `pytest.ini` sets `testpaths` to `tests/basic`, `tests/browser` and `tests/scrape`, and forces
33
+ `PATCH_ANALYTICS=false`. The bulk of the suite is
34
+ the 30+ files in `tests/basic/`. `benchmark/` is excluded from collection and is
35
+ not part of normal development.
36
+
37
+ ## Linting and formatting
38
+
39
+ The project uses pre-commit. Run it before finishing any code change:
40
+
41
+ ```
42
+ pre-commit run --all-files
43
+ ```
44
+
45
+ Five hooks, all of which CI enforces:
46
+
47
+ - **black**, line length 100, with `--preview`
48
+ - **isort**, black profile
49
+ - **flake8**, max line length 100, ignoring `E203` and `W503`
50
+ - **mypy**, over the configured high-value module boundaries
51
+ - **codespell**
52
+
53
+ The line length is 100, not black's default 88. Match it.
54
+
55
+ ## Repository layout
56
+
57
+ - `patch/coders/` — the heart of the project. Each edit format is a
58
+ `*_coder.py` paired with a `*_prompts.py` holding its system prompts.
59
+ `base_coder.py` (~2.6k lines) is the shared chat loop that all of them
60
+ subclass. `coders/usage.py` (token and cost accounting) and
61
+ `coders/chat_state.py` (the transcript and its background summariser)
62
+ hold state extracted from it. New edit formats are registered in `patch/coders/__init__.py`.
63
+ - `patch/main.py` — CLI entry, argument wiring, startup.
64
+ - `patch/models.py` — model definitions, aliases, and metadata. Adding support
65
+ for a new LLM usually means editing this file and nothing else.
66
+ - `patch/commands.py` — the in-chat `/slash` commands.
67
+ - `patch/repo.py`, `patch/repomap.py` — git integration and the tree-sitter
68
+ repository map.
69
+ - `patch/repo_trust.py` — the repository-trust boundary. The repo under edit is
70
+ untrusted input, and every rule about what its config files may set lives
71
+ here, applied in an enforced order. Adding an argument that names a file or a
72
+ command means recording a decision about it in this module, or a test fails.
73
+ - `tests/` — mirrors the module layout under `tests/basic/`.
74
+
75
+ Two root-level documents cover the audit history:
76
+
77
+ - `AUDIT_REPORT.md` — three completed audits (F-1 – F-97) and their remediation.
78
+ - `AUDIT_PROMPT.md` — the reusable brief for running another one. It carries the
79
+ evidence bar, the recurring defect shape worth searching for, and a list of
80
+ candidates already investigated and rejected, so a new round does not
81
+ re-derive them.
82
+
83
+ ## Things not to edit
84
+
85
+ - `patch/_version.py` — generated by setuptools_scm, gitignored.
86
+ - `requirements/*.txt` — compiled from the matching `.in` files by
87
+ `./scripts/pip-compile.sh`. Edit the `.in` file and re-run the script; never
88
+ hand-edit the `.txt`.
89
+
90
+ ## CI
91
+
92
+ Four workflows, all in `.github/workflows/`:
93
+
94
+ - `ubuntu-tests.yml` — pytest on Python 3.10 through 3.14
95
+ - `windows-tests.yml` — pytest on Python 3.10, 3.13
96
+ - `pre-commit.yml` — the hooks above
97
+ - `packaging.yml` — builds a wheel from a `.git`-less tree, installs it into a clean venv and
98
+ imports it from another directory. `pytest` runs from the repository root and therefore tests
99
+ the working tree, never the built artifact; this is the only job that does. Any new data file
100
+ must be added to `[tool.setuptools.package-data]` or it will fail here.
101
+
102
+ Publishing and deployment workflows are intentionally absent. Do not add them without the
103
+ required Patch-owned registries, infrastructure and secrets.
104
+
105
+ ## Workflow
106
+
107
+ Finish each task completely before starting the next one. A task is not done when the
108
+ code works — it is done when the docs match and the work is committed.
109
+
110
+ 1. Make the change and get the tests passing (`pytest`).
111
+ 2. Run `pre-commit run --all-files`. All five hooks must pass.
112
+ 3. Update every doc the change touches, in the same pass — not as a follow-up:
113
+ - `CHANGELOG.md` under `## [Unreleased]`, in the right subsection (`Added`,
114
+ `Changed`, `Fixed`, `Removed`, `Security`). This file records doc-only changes
115
+ too, so a docs commit still gets an entry. Describe what changed for the reader,
116
+ not which files were edited.
117
+ - `README.md` when installation, usage, security boundaries, or supported
118
+ versions change.
119
+ - `CONTRIBUTING.md` when setup, testing, dependencies, or the release process change.
120
+ - This file when the layout, tooling, or conventions change.
121
+ A released `## [X.Y.Z]` section is not a scratchpad: its text is mirrored in the annotated
122
+ git tag and the GitHub release, so do not reword or restructure it. Adding an entry for
123
+ something that genuinely shipped in that release is the one allowed edit — correcting an
124
+ omission is not rewriting history — and it comes with updating that release's body on
125
+ GitHub (`gh release edit`) in the same task. Leave the tag message alone; re-tagging a
126
+ published tag is worse than a tag message that trails the file.
127
+ 4. Commit the code and its doc updates together, in one commit per task. Do not
128
+ batch several tasks into one commit, and do not leave a task's docs for later.
129
+
130
+ ## Conventions
131
+
132
+ - Match the surrounding style rather than importing a new one. The codebase is
133
+ plain Python with light comments and no type annotations in most modules.
134
+ - Tests are a mix of `unittest.TestCase` classes (about half the files in
135
+ `tests/basic/`) and plain pytest functions. Follow whichever style the file
136
+ you are editing already uses.
137
+ - Commits follow Conventional Commits (`feat:`, `fix:`, `docs:`, `chore:`), as
138
+ seen in recent history.
@@ -0,0 +1,314 @@
1
+ # Full Codebase Audit — Prompt
2
+
3
+ The reusable brief for a full-repository audit of Patch. Three have been run
4
+ ([`AUDIT_REPORT.md`](AUDIT_REPORT.md)); this file exists so the fourth starts from what the first
5
+ three learned rather than from a blank page.
6
+
7
+ Read [Before you start](#before-you-start) and [Already disproved](#already-disproved) first. They
8
+ are the difference between a useful round and one that re-derives what is already known.
9
+
10
+ ---
11
+
12
+ ## The brief
13
+
14
+ You are a senior Python engineer performing a comprehensive audit of this entire codebase.
15
+
16
+ Identify real problems: correctness bugs, architectural weaknesses, maintainability issues, security
17
+ risks, performance problems, and opportunities to delete complexity.
18
+
19
+ **Do not modify the repository during the audit.** Inspect, understand, and report. Remediation is a
20
+ separate pass with its own commits.
21
+
22
+ ---
23
+
24
+ ## Before you start
25
+
26
+ Five rules, each of which came from a specific failure in an earlier round.
27
+
28
+ ### 1. Trace callers before reporting anything
29
+
30
+ Round three nearly reported `git_cherry_pick_osr_onto_o` as a thread-safety hazard — it calls
31
+ `os.chdir` process-wide during edit application, with watcher threads live. It is unreachable:
32
+ `udiff_coder.py` builds its own strategy list and never uses the table that references it. The
33
+ finding would have been wrong, and confidently so.
34
+
35
+ Before writing a finding: find the callers, confirm the path is reachable, and check whether a guard
36
+ already exists somewhere you have not looked.
37
+
38
+ ### 2. Verify by execution, not by reading
39
+
40
+ Anything you would call Critical or High should be reproduced by running the tree's own code in a
41
+ scratch directory **outside** the repository. Quote the output in the finding.
42
+
43
+ The three top findings of round three each had a probe:
44
+
45
+ ```
46
+ args.env_file = ./evil.env
47
+ OPENAI_API_BASE = https://attacker.example
48
+ args.test_cmd = touch /tmp/pwned
49
+ after sanitize_repo_config:
50
+ args.test_cmd = touch /tmp/pwned <-- not stripped
51
+ ```
52
+
53
+ Mark such findings **verified**. Findings you are confident about but did not execute are
54
+ **confirmed by reading** — say which.
55
+
56
+ ### 3. Look for the recurring shape
57
+
58
+ Every Critical finding across three audits has been the same thing: **a guard that exists, is right,
59
+ and is missing from one call site.**
60
+
61
+ | Round | Policy | Was missing at |
62
+ | --- | --- | --- |
63
+ | 2 | Repository config is untrusted | `.patch.model.settings.yml` |
64
+ | 2 | Redirect vars are denied | the yaml layer's `set-env` |
65
+ | 2 | `--dry-run` performs no side effects | `dirty_commit` |
66
+ | 2 | Writes stay inside the root | read-only paths |
67
+ | 3 | Repository config is untrusted | `env-file` |
68
+ | 3 | Home is distinguishable from the repo | the project's own Docker image |
69
+ | 3 | Writes stay inside the root | `/add` under `--no-auto-commits` |
70
+ | 3 | A failure is not a result | `apply_updates`' `OSError` branch, `summarize_worker` |
71
+
72
+ So: for each policy the code claims to enforce, enumerate *every* place it should apply and check
73
+ each one. That is a more productive search than reading files in order.
74
+
75
+ Several of these now have enforcement — `patch/repo_trust.py` is a chokepoint with a test that
76
+ enumerates the argument parser, and `Coder.write_edited_file` is the single write gate. **Test those
77
+ mechanisms rather than trusting them.** Each was written in response to a finding and has not yet
78
+ survived an audit it did not author.
79
+
80
+ ### 4. Distrust green gates
81
+
82
+ Four round-two findings were behaviours the suite actively reported as working. One test passed only
83
+ because it first set the global that hid the bug.
84
+
85
+ Ask what each gate does *not* cover:
86
+
87
+ - `pytest` runs from the repository root, so `import patch` resolves to the working tree. Only
88
+ `packaging.yml` exercises the built artifact.
89
+ - mypy covers 29 of 81 modules. `commands.py` and every coder are outside it.
90
+ - Gate results are per-platform. The fourth round recorded a green run while the
91
+ Windows job was red: `pexpect.spawn` does not exist there, and nothing in a
92
+ Linux-only run says so. Check the CI matrix, not just your own machine.
93
+ - `check_untyped_defs` is on, with three named exceptions (`base_coder.py`, `models.py`, `io.py`).
94
+ - Coverage is reported, not gated.
95
+
96
+ ### 5. Record what you disprove
97
+
98
+ Add to [Already disproved](#already-disproved) below. A candidate you investigated and rejected is
99
+ worth as much to the next round as one you confirmed, and costs nothing to write down.
100
+
101
+ ---
102
+
103
+ ## Scope
104
+
105
+ Everything: source, tests, `pyproject.toml`, the four lock files, `docker/Dockerfile`, the four
106
+ GitHub workflows, `.pre-commit-config.yaml`, `scripts/`, `benchmark/`, and the docs.
107
+
108
+ Trace the main execution path rather than reading files in isolation:
109
+
110
+ ```
111
+ main() → build_config() → RepoTrust layers → setup_model()
112
+ → Coder.create() → Coder.run() → send_message()
113
+ → get_edits() → allowed_to_edit() → apply_edits() → write_edited_file()
114
+ → lint → test → auto_commit
115
+ ```
116
+
117
+ `AGENTS.md` has the module layout. Determine what the application does, its module boundaries, how
118
+ configuration and secrets are handled, and how it is built, tested, typed, packaged and deployed.
119
+
120
+ ### What to look for
121
+
122
+ **Correctness** — logic errors, broken edge cases, swallowed exceptions, mutable default arguments,
123
+ shared mutable state, resource leaks, incorrect context-manager use, races, thread-safety, deadlocks,
124
+ timeout and retry behaviour, datetime/timezone handling, encoding, path handling, platform
125
+ assumptions, `None` handling, generator exhaustion, identity-vs-equality, object lifetime and caching.
126
+
127
+ **Python quality** — functions and classes doing too much, unnecessary abstraction, circular or
128
+ dynamic imports, excessive `Any`, misleading annotations, dataclass and property misuse, fragile
129
+ monkey-patching, incorrect dunders, deep nesting, duplication, dead code, compatibility shims that
130
+ have outlived their Python version.
131
+
132
+ **Architecture** — separation of concerns, coupling, hidden dependencies, leaky abstractions, god
133
+ objects, business logic mixed with transport, configuration mixed with runtime, dependency
134
+ direction, duplicated domain concepts, missing abstractions where duplication is real. Do not
135
+ recommend enterprise-style abstractions without a concrete benefit.
136
+
137
+ **Reliability** — exception boundaries and types, retries, timeouts, cleanup, partial failures,
138
+ transaction boundaries, idempotency, graceful shutdown, startup failures, recovery. Flag anywhere an
139
+ error is logged and execution continues in an invalid state, and anywhere a failure is
140
+ indistinguishable from a result.
141
+
142
+ **Security** — hardcoded secrets, committed credentials, unsafe environment handling, command and
143
+ SQL injection, path traversal, unsafe temp files and archive extraction, SSRF, auth mistakes,
144
+ missing permission checks, cryptographic misuse, unsafe deserialization, `pickle` and `yaml.load`
145
+ with untrusted input, `eval`/`exec`, insecure subprocess use, missing TLS verification, secrets in
146
+ logs, dependency risk. **Distinguish exploitable from theoretical.**
147
+
148
+ **Dependencies and packaging** — unused, duplicate, or heavyweight dependencies, poor pinning,
149
+ version conflicts, misplaced dev dependencies, deprecated APIs, Python-version compatibility,
150
+ packaging mistakes, imports that only work from the repository root. Note where a dependency could
151
+ be replaced by the standard library *if that would materially simplify things*.
152
+
153
+ **Performance** — accidental quadratic behaviour, repeated expensive work, repeated I/O, loading
154
+ whole datasets needlessly, poor data structures, blocking calls in concurrency-sensitive paths,
155
+ unbounded queues, caches and accumulation, excessive logging in hot paths. Measure before claiming;
156
+ do not report micro-optimisations.
157
+
158
+ **Typing** — incorrect or inconsistent annotations, excessive `Any`, wrong optionality, unsafe
159
+ casts, `# type: ignore` hiding defects, poor protocol boundaries, models that permit invalid states.
160
+ Assess whether the gate is *useful*, not merely present.
161
+
162
+ **Tests** — what is actually covered, which behaviour has none, whether failure paths are exercised,
163
+ determinism, order dependence, mocks hiding integration problems, tests asserting implementation
164
+ details rather than behaviour, fixture leakage, isolation of external services. Identify the
165
+ **highest-value missing tests** — ranked by the blast radius of what would break undetected, not by
166
+ coverage percentage.
167
+
168
+ **Observability** — log levels, structure, failure context, secrets in logs, repeated errors,
169
+ failures that cannot be diagnosed from what is emitted.
170
+
171
+ **Configuration** — precedence, defaults, validation, dev-vs-production behaviour, missing or
172
+ malformed handling. Configuration errors should fail early with a useful message.
173
+
174
+ **CI/CD** — tests that do not actually run, missing Python versions, caching, reproducibility,
175
+ deployment despite failed checks, secrets exposure, missing gates, CI-vs-production drift.
176
+
177
+ ---
178
+
179
+ ## Output
180
+
181
+ ### The report
182
+
183
+ Append a new section to `AUDIT_REPORT.md`, matching the existing structure:
184
+
185
+ - `# Nth Audit — commit <sha>`, with the tree state (LOC, test count, gate results)
186
+ - Remediation status tables — severity summary, then per-finding
187
+ - Audit scope and method
188
+ - Executive summary: the biggest risks, the systemic theme if there is one, what to fix first
189
+ - Findings, grouped `CRITICAL` / `HIGH` / `MEDIUM` / `LOW`
190
+ - Prioritised remediation plan: fix immediately / soon / refactor when convenient / optional
191
+ - Highest-value missing tests
192
+ - Positive findings
193
+ - **Disproved during this audit**
194
+ - Ratings
195
+
196
+ Update the table at the top of the file and add a row for the round.
197
+
198
+ ### Finding format
199
+
200
+ Continue the `F-N` sequence (three audits have used F-1 – F-97). Each finding:
201
+
202
+ ```markdown
203
+ #### F-98 · One-line statement of the defect
204
+
205
+ **Severity:** Critical | High | Medium | Low · **Category:** Security · **Confidence:** verified
206
+ **Location:** `patch/main.py:302-340`, `:787-796`
207
+
208
+ **Problem.** What is wrong.
209
+
210
+ **Evidence.** The code, and the probe output if you ran one.
211
+
212
+ **Impact.** What can happen because of it.
213
+
214
+ **Recommendation.** The smallest sensible fix.
215
+ ```
216
+
217
+ **Do not report an issue unless you can explain why it matters.** Line numbers go stale — cite the
218
+ commit you audited.
219
+
220
+ ### Issues
221
+
222
+ Open one GitHub issue per finding, matching the existing convention (see #80–#111):
223
+
224
+ - Title: `Severity: short description`
225
+ - Body: `**Severity:** X · **Audit ref:** F-N` then `## Problem` / `## Evidence` (or
226
+ `## Reproduction`) / `## Impact` / `## Fix`, plus `## Test` where the missing test is the actual
227
+ root cause
228
+ - Labels: `bug` (or `enhancement`), `security` where applicable, and the severity label
229
+
230
+ ### Ratings
231
+
232
+ Rate 1–10, with one sentence of reasoning each: Correctness, Security, Architecture,
233
+ Maintainability, Test quality, Type safety, Performance, Production readiness. Then an overall score.
234
+
235
+ Compare against the previous round's column. **If a dimension did not move, say so and why** — an
236
+ unchanged rating with an honest reason is more useful than a rounded-up one.
237
+
238
+ ---
239
+
240
+ ## Rules
241
+
242
+ - Do not modify the repository during the audit.
243
+ - Do not assume something is broken because it looks unusual.
244
+ - Trace callers and confirm reachability before reporting.
245
+ - Search for existing safeguards before claiming one is missing.
246
+ - Distinguish confirmed bugs from potential risks.
247
+ - Consolidate findings with a common root cause; do not produce dozens of duplicates.
248
+ - Avoid generic style complaints and cosmetic preferences.
249
+ - Prefer deleting complexity over adding abstraction.
250
+ - Do not recommend large rewrites without strong justification.
251
+ - Be skeptical of your own findings and try to disprove them before including them.
252
+
253
+ ---
254
+
255
+ ## Baseline at `5d6ad03b6`
256
+
257
+ What a clean run looks like today. If any of these has regressed, that is itself a finding.
258
+
259
+ | | |
260
+ | --- | --- |
261
+ | Source | 81 modules, 21,292 lines |
262
+ | Tests | 50 files, 15,209 lines — **674 passed**, 2 skipped on POSIX / 3 on Windows |
263
+ | `flake8` | clean over `patch tests scripts benchmark` |
264
+ | `mypy` | clean over 29 of 81 modules, `check_untyped_defs` on with 3 exceptions |
265
+ | `black` / `isort` / `codespell` | clean |
266
+ | Coverage | 67% overall |
267
+ | Findings | F-1 – F-106 across four rounds, all resolved |
268
+
269
+ Coverage is weakest where it matters most: `report.py` 40%, `linter.py` 43%, `utils.py` 46%,
270
+ `commands.py` 60%. `utils.py` contains `path_is_within`, the containment primitive the entire write
271
+ gate rests on.
272
+
273
+ Run the gates yourself before starting — do not trust this table.
274
+
275
+ ```bash
276
+ pytest -q
277
+ pre-commit run --all-files
278
+ pytest -q --cov=patch --cov-report=term
279
+ ```
280
+
281
+ ---
282
+
283
+ ## Already disproved
284
+
285
+ Investigated in an earlier round and rejected. Re-check if the code has changed, but do not re-derive
286
+ these from scratch.
287
+
288
+ | Candidate | Why it is not a finding |
289
+ | --- | --- |
290
+ | The 120s command timeout | **Was open, now fixed.** It applied to `/run`, `/test` and `--test-cmd` with no way to raise it, and this repository's own suite takes ~150s -- so `patch --test-cmd pytest` here was killed at 120s, and `--auto-test` reported the timeout to the model as a test failure to fix. `--command-timeout SECONDS` now raises it and `0` removes it. Kept here as the shape to look for: a safety limit with no escape hatch. |
291
+ | `Coder.commit_before_message` as shared class state | Declared `list[str] = []` at class level, but rebound in `__init__`, so the class attribute is never mutated. |
292
+ | `git_cherry_pick_*` chdir-ing the process during edit application | `GitTemporaryDirectory` does `os.chdir`, which would be a real race against the watcher threads — but the strategy tables referencing it were unreachable, and are now deleted. |
293
+ | `diff-match-patch` as an unused dependency | Reached only from dead functions at three sites, but live `diff_lines` uses it. |
294
+ | `RepoMap.token_count` dividing by zero | `lines[::step]` always includes `lines[0]`, so the sample is never empty. |
295
+ | `cmd_add`'s "Directory X is not in git" branch as unreachable | Reachable for a plain existing directory whose glob matches nothing. |
296
+ | `scrape_with_httpx` missing a timeout | `httpx.Client` applies its own 5s default. |
297
+ | The `F824` in `onboarding.py` as a live CI failure | The pinned flake8 did not flag it; only a newer one did. Since fixed. |
298
+
299
+ ---
300
+
301
+ ## Where the previous rounds landed
302
+
303
+ Context for judging whether a theme is recurring or resolved.
304
+
305
+ | Round | Commit | Findings | Overall |
306
+ | --- | --- | --- | --- |
307
+ | First | `425cb623c` | F-1 – F-41 | 8.3 after remediation |
308
+ | Second | `d6146ea7c` | F-42 – F-76 | 5.0 at audit |
309
+ | Third | `95ed59940` | F-77 – F-97 | 6.5 at audit, 8.8 after remediation |
310
+
311
+ The second round scored *lower* than the first's post-remediation figure. That was not a regression:
312
+ it reflected the first round's scope being narrower than its "all resolved" status suggested. Expect
313
+ the same of this file — a fourth round scoring below 8.8 most likely means the third round's scope
314
+ was narrower than it looked, which is the useful thing to find out.