patch-chat 0.1.0__tar.gz → 0.3.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 (329) hide show
  1. {patch_chat-0.1.0 → patch_chat-0.3.0}/.agents/setup +4 -1
  2. patch_chat-0.3.0/.claude/commands/upstream-issue.md +122 -0
  3. patch_chat-0.3.0/.github/workflows/packaging.yml +103 -0
  4. {patch_chat-0.1.0 → patch_chat-0.3.0}/.github/workflows/pre-commit.yml +10 -0
  5. {patch_chat-0.1.0 → patch_chat-0.3.0}/.github/workflows/ubuntu-tests.yml +9 -4
  6. {patch_chat-0.1.0 → patch_chat-0.3.0}/.github/workflows/windows-tests.yml +5 -3
  7. {patch_chat-0.1.0 → patch_chat-0.3.0}/.gitignore +5 -0
  8. patch_chat-0.3.0/AGENTS.md +200 -0
  9. patch_chat-0.3.0/AUDIT_PROMPT.md +314 -0
  10. patch_chat-0.3.0/AUDIT_REPORT.md +3620 -0
  11. patch_chat-0.3.0/CHANGELOG.md +916 -0
  12. {patch_chat-0.1.0 → patch_chat-0.3.0}/CONTRIBUTING.md +289 -226
  13. {patch_chat-0.1.0/patch_chat.egg-info → patch_chat-0.3.0}/PKG-INFO +54 -22
  14. {patch_chat-0.1.0 → patch_chat-0.3.0}/README.md +50 -8
  15. {patch_chat-0.1.0 → patch_chat-0.3.0}/docker/Dockerfile +10 -7
  16. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/__init__.py +20 -20
  17. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/_version.py +3 -3
  18. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/analytics.py +66 -27
  19. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/args.py +15 -5
  20. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/args_formatter.py +226 -228
  21. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/__init__.py +53 -32
  22. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/base_coder.py +348 -223
  23. patch_chat-0.3.0/patch/coders/chat_state.py +92 -0
  24. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/editblock_coder.py +25 -11
  25. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/editblock_fenced_coder.py +9 -10
  26. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/editblock_func_coder.py +1 -2
  27. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/patch_coder.py +10 -3
  28. patch_chat-0.3.0/patch/coders/search_replace.py +309 -0
  29. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/single_wholefile_func_coder.py +1 -1
  30. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/udiff_coder.py +31 -8
  31. patch_chat-0.3.0/patch/coders/usage.py +186 -0
  32. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/wholefile_coder.py +1 -2
  33. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/wholefile_func_coder.py +133 -134
  34. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/commands.py +118 -48
  35. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/copypaste.py +71 -70
  36. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/diffs.py +4 -4
  37. patch_chat-0.3.0/patch/dump.py +33 -0
  38. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/editor.py +16 -5
  39. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/exceptions.py +43 -12
  40. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/history.py +3 -24
  41. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/io.py +199 -41
  42. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/linter.py +25 -8
  43. patch_chat-0.3.0/patch/llm.py +184 -0
  44. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/main.py +460 -545
  45. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/mdstream.py +244 -243
  46. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/models.py +44 -10
  47. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/onboarding.py +84 -25
  48. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/reasoning_tags.py +80 -82
  49. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/repo.py +44 -44
  50. patch_chat-0.3.0/patch/repo_trust.py +607 -0
  51. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/repomap.py +38 -14
  52. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/report.py +65 -4
  53. patch_chat-0.3.0/patch/run_cmd.py +338 -0
  54. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/scrape.py +332 -316
  55. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/sendchat.py +60 -61
  56. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/utils.py +33 -11
  57. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/versioncheck.py +112 -113
  58. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/voice.py +198 -200
  59. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/waiting.py +2 -1
  60. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/watch.py +6 -41
  61. {patch_chat-0.1.0 → patch_chat-0.3.0/patch_chat.egg-info}/PKG-INFO +54 -22
  62. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch_chat.egg-info/SOURCES.txt +8 -1
  63. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch_chat.egg-info/requires.txt +4 -16
  64. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch_chat.egg-info/scm_file_list.json +8 -1
  65. patch_chat-0.3.0/patch_chat.egg-info/scm_version.json +8 -0
  66. patch_chat-0.3.0/pyproject.toml +133 -0
  67. {patch_chat-0.1.0 → patch_chat-0.3.0}/requirements/common-constraints.txt +504 -535
  68. {patch_chat-0.1.0 → patch_chat-0.3.0}/requirements/requirements-browser.txt +169 -169
  69. {patch_chat-0.1.0 → patch_chat-0.3.0}/requirements/requirements-dev.in +20 -21
  70. {patch_chat-0.1.0 → patch_chat-0.3.0}/requirements/requirements-dev.txt +359 -398
  71. {patch_chat-0.1.0 → patch_chat-0.3.0}/requirements/requirements-playwright.txt +18 -18
  72. {patch_chat-0.1.0 → patch_chat-0.3.0}/requirements/requirements.in +47 -53
  73. {patch_chat-0.1.0 → patch_chat-0.3.0}/requirements/tree-sitter.in +2 -3
  74. {patch_chat-0.1.0 → patch_chat-0.3.0}/requirements.txt +464 -477
  75. {patch_chat-0.1.0 → patch_chat-0.3.0}/scripts/pip-compile.sh +46 -46
  76. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_analytics.py +73 -5
  77. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_aws_credentials.py +120 -169
  78. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_coder.py +1725 -1573
  79. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_commands.py +2447 -2226
  80. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_editblock.py +50 -0
  81. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_editor.py +23 -1
  82. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_history.py +81 -0
  83. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_io.py +277 -0
  84. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_linter.py +47 -3
  85. patch_chat-0.3.0/tests/basic/test_llm.py +107 -0
  86. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_main.py +75 -2
  87. patch_chat-0.3.0/tests/basic/test_mdstream.py +65 -0
  88. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_models.py +733 -668
  89. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_onboarding.py +77 -1
  90. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_path_containment.py +450 -286
  91. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_repo.py +737 -716
  92. patch_chat-0.3.0/tests/basic/test_repo_config_trust.py +730 -0
  93. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_repomap.py +71 -1
  94. patch_chat-0.3.0/tests/basic/test_run_cmd.py +207 -0
  95. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_udiff.py +241 -167
  96. patch_chat-0.3.0/tests/basic/test_utils.py +43 -0
  97. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/browser/test_browser.py +36 -36
  98. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/conftest.py +94 -59
  99. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/scrape/test_scrape.py +56 -0
  100. patch_chat-0.1.0/AGENTS.md +0 -92
  101. patch_chat-0.1.0/AUDIT_REPORT.md +0 -1133
  102. patch_chat-0.1.0/CHANGELOG.md +0 -178
  103. patch_chat-0.1.0/patch/coders/search_replace.py +0 -757
  104. patch_chat-0.1.0/patch/dump.py +0 -29
  105. patch_chat-0.1.0/patch/llm.py +0 -47
  106. patch_chat-0.1.0/patch/run_cmd.py +0 -146
  107. patch_chat-0.1.0/patch_chat.egg-info/scm_version.json +0 -8
  108. patch_chat-0.1.0/pyproject.toml +0 -74
  109. patch_chat-0.1.0/scripts/versionbump.py +0 -175
  110. patch_chat-0.1.0/tests/basic/test_repo_config_trust.py +0 -216
  111. patch_chat-0.1.0/tests/basic/test_run_cmd.py +0 -45
  112. patch_chat-0.1.0/tests/basic/test_utils.py +0 -22
  113. {patch_chat-0.1.0 → patch_chat-0.3.0}/.agents/resume +0 -0
  114. {patch_chat-0.1.0 → patch_chat-0.3.0}/.dockerignore +0 -0
  115. {patch_chat-0.1.0 → patch_chat-0.3.0}/.flake8 +0 -0
  116. {patch_chat-0.1.0 → patch_chat-0.3.0}/.github/ISSUE_TEMPLATE/issue.yml +0 -0
  117. {patch_chat-0.1.0 → patch_chat-0.3.0}/.pre-commit-config.yaml +0 -0
  118. {patch_chat-0.1.0 → patch_chat-0.3.0}/LICENSE.txt +0 -0
  119. {patch_chat-0.1.0 → patch_chat-0.3.0}/MANIFEST.in +0 -0
  120. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/Dockerfile +0 -0
  121. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/README.md +0 -0
  122. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/__init__.py +0 -0
  123. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/benchmark.py +0 -0
  124. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/clone-exercism.sh +0 -0
  125. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/cpp-test.sh +0 -0
  126. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/docker.sh +0 -0
  127. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/docker_build.sh +0 -0
  128. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/install-docker-ubuntu.sh +0 -0
  129. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/npm-test.sh +0 -0
  130. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/plot.sh +0 -0
  131. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/plots.py +0 -0
  132. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/prompts.py +0 -0
  133. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/refactor_tools.py +0 -0
  134. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/rsync.sh +0 -0
  135. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/rungrid.py +0 -0
  136. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/swe-bench-lite.txt +0 -0
  137. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/swe-bench.txt +0 -0
  138. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/swe_bench.py +0 -0
  139. {patch_chat-0.1.0 → patch_chat-0.3.0}/benchmark/test_benchmark.py +0 -0
  140. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/__main__.py +0 -0
  141. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/architect_coder.py +0 -0
  142. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/architect_prompts.py +0 -0
  143. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/ask_coder.py +0 -0
  144. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/ask_prompts.py +0 -0
  145. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/base_prompts.py +0 -0
  146. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/chat_chunks.py +0 -0
  147. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/context_coder.py +0 -0
  148. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/context_prompts.py +0 -0
  149. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/edit_apply.py +0 -0
  150. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/editblock_fenced_prompts.py +0 -0
  151. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/editblock_func_prompts.py +0 -0
  152. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/editblock_prompts.py +0 -0
  153. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/editor_diff_fenced_coder.py +0 -0
  154. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/editor_diff_fenced_prompts.py +0 -0
  155. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/editor_editblock_coder.py +0 -0
  156. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/editor_editblock_prompts.py +0 -0
  157. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/editor_whole_coder.py +0 -0
  158. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/editor_whole_prompts.py +0 -0
  159. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/patch_prompts.py +0 -0
  160. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/shell.py +0 -0
  161. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/single_wholefile_func_prompts.py +0 -0
  162. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/udiff_prompts.py +0 -0
  163. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/udiff_simple.py +0 -0
  164. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/udiff_simple_prompts.py +0 -0
  165. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/wholefile_func_prompts.py +0 -0
  166. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/coders/wholefile_prompts.py +0 -0
  167. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/deprecated.py +0 -0
  168. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/format_settings.py +0 -0
  169. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/gui.py +0 -0
  170. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/openrouter.py +0 -0
  171. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/prompts.py +0 -0
  172. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/README.md +0 -0
  173. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/arduino-tags.scm +0 -0
  174. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/bash-tags.scm +0 -0
  175. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/c-tags.scm +0 -0
  176. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/chatito-tags.scm +0 -0
  177. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/clojure-tags.scm +0 -0
  178. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/commonlisp-tags.scm +0 -0
  179. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/cpp-tags.scm +0 -0
  180. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/csharp-tags.scm +0 -0
  181. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/d-tags.scm +0 -0
  182. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/dart-tags.scm +0 -0
  183. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/elisp-tags.scm +0 -0
  184. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/elixir-tags.scm +0 -0
  185. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/elm-tags.scm +0 -0
  186. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/gleam-tags.scm +0 -0
  187. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/go-tags.scm +0 -0
  188. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/java-tags.scm +0 -0
  189. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/javascript-tags.scm +0 -0
  190. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/lua-tags.scm +0 -0
  191. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/matlab-tags.scm +0 -0
  192. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/ocaml-tags.scm +0 -0
  193. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +0 -0
  194. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/pony-tags.scm +0 -0
  195. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/properties-tags.scm +0 -0
  196. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/python-tags.scm +0 -0
  197. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/r-tags.scm +0 -0
  198. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/racket-tags.scm +0 -0
  199. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/ruby-tags.scm +0 -0
  200. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/rust-tags.scm +0 -0
  201. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/solidity-tags.scm +0 -0
  202. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/swift-tags.scm +0 -0
  203. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/udev-tags.scm +0 -0
  204. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/README.md +0 -0
  205. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/bash-tags.scm +0 -0
  206. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/c-tags.scm +0 -0
  207. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/c_sharp-tags.scm +0 -0
  208. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/cpp-tags.scm +0 -0
  209. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/dart-tags.scm +0 -0
  210. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/elisp-tags.scm +0 -0
  211. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/elixir-tags.scm +0 -0
  212. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/elm-tags.scm +0 -0
  213. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/fortran-tags.scm +0 -0
  214. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/go-tags.scm +0 -0
  215. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/haskell-tags.scm +0 -0
  216. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/hcl-tags.scm +0 -0
  217. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/java-tags.scm +0 -0
  218. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/javascript-tags.scm +0 -0
  219. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/julia-tags.scm +0 -0
  220. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/kotlin-tags.scm +0 -0
  221. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/matlab-tags.scm +0 -0
  222. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/ocaml-tags.scm +0 -0
  223. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/ocaml_interface-tags.scm +0 -0
  224. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/php-tags.scm +0 -0
  225. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/python-tags.scm +0 -0
  226. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/ql-tags.scm +0 -0
  227. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/ruby-tags.scm +0 -0
  228. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/rust-tags.scm +0 -0
  229. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/scala-tags.scm +0 -0
  230. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/typescript-tags.scm +0 -0
  231. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/zig-tags.scm +0 -0
  232. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/resources/__init__.py +0 -0
  233. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/resources/model-metadata.json +0 -0
  234. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/resources/model-settings.yml +0 -0
  235. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/special.py +0 -0
  236. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/urls.py +0 -0
  237. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch/watch_prompts.py +0 -0
  238. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch_chat.egg-info/dependency_links.txt +0 -0
  239. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch_chat.egg-info/entry_points.txt +0 -0
  240. {patch_chat-0.1.0 → patch_chat-0.3.0}/patch_chat.egg-info/top_level.txt +0 -0
  241. {patch_chat-0.1.0 → patch_chat-0.3.0}/pytest.ini +0 -0
  242. {patch_chat-0.1.0 → patch_chat-0.3.0}/requirements/pydub.in +0 -0
  243. {patch_chat-0.1.0 → patch_chat-0.3.0}/requirements/python-compat.in +0 -0
  244. {patch_chat-0.1.0 → patch_chat-0.3.0}/requirements/requirements-browser.in +0 -0
  245. {patch_chat-0.1.0 → patch_chat-0.3.0}/requirements/requirements-playwright.in +0 -0
  246. {patch_chat-0.1.0 → patch_chat-0.3.0}/scripts/__init__.py +0 -0
  247. {patch_chat-0.1.0 → patch_chat-0.3.0}/scripts/blame.py +0 -0
  248. {patch_chat-0.1.0 → patch_chat-0.3.0}/scripts/clean_metadata.py +0 -0
  249. {patch_chat-0.1.0 → patch_chat-0.3.0}/scripts/issues.py +0 -0
  250. {patch_chat-0.1.0 → patch_chat-0.3.0}/scripts/my_models.py +0 -0
  251. {patch_chat-0.1.0 → patch_chat-0.3.0}/scripts/redact-cast.py +0 -0
  252. {patch_chat-0.1.0 → patch_chat-0.3.0}/scripts/tmux_record.sh +0 -0
  253. {patch_chat-0.1.0 → patch_chat-0.3.0}/scripts/tsl_pack_langs.py +0 -0
  254. {patch_chat-0.1.0 → patch_chat-0.3.0}/scripts/yank-old-versions.py +0 -0
  255. {patch_chat-0.1.0 → patch_chat-0.3.0}/setup.cfg +0 -0
  256. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/__init__.py +0 -0
  257. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/__init__.py +0 -0
  258. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_copypaste.py +0 -0
  259. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_deprecated.py +0 -0
  260. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_edit_apply.py +0 -0
  261. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_exceptions.py +0 -0
  262. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_find_or_blocks.py +0 -0
  263. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_format_settings.py +0 -0
  264. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_model_info_manager.py +0 -0
  265. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_openrouter.py +0 -0
  266. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_patch_coder.py +0 -0
  267. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_reasoning.py +0 -0
  268. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_report.py +0 -0
  269. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_sanity_check_repo.py +0 -0
  270. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_scripting.py +0 -0
  271. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_sendchat.py +0 -0
  272. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_special.py +0 -0
  273. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_ssl_verification.py +0 -0
  274. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_urls.py +0 -0
  275. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_versioncheck.py +0 -0
  276. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_voice.py +0 -0
  277. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_waiting.py +0 -0
  278. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_watch.py +0 -0
  279. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/basic/test_wholefile.py +0 -0
  280. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/chat-history-search-replace-gold.txt +0 -0
  281. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/chat-history.md +0 -0
  282. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/arduino/test.ino +0 -0
  283. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/bash/test.sh +0 -0
  284. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/c/test.c +0 -0
  285. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/chatito/test.chatito +0 -0
  286. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/clojure/test.clj +0 -0
  287. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/commonlisp/test.lisp +0 -0
  288. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/cpp/test.cpp +0 -0
  289. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/csharp/test.cs +0 -0
  290. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/d/test.d +0 -0
  291. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/dart/test.dart +0 -0
  292. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/elisp/test.el +0 -0
  293. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/elixir/test.ex +0 -0
  294. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/elm/test.elm +0 -0
  295. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/gleam/test.gleam +0 -0
  296. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/go/test.go +0 -0
  297. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/haskell/test.hs +0 -0
  298. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/hcl/test.tf +0 -0
  299. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/java/test.java +0 -0
  300. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/javascript/test.js +0 -0
  301. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/kotlin/test.kt +0 -0
  302. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/lua/test.lua +0 -0
  303. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/matlab/test.m +0 -0
  304. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/ocaml/test.ml +0 -0
  305. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/ocaml_interface/test.mli +0 -0
  306. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/php/test.php +0 -0
  307. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/pony/test.pony +0 -0
  308. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/properties/test.properties +0 -0
  309. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/python/test.py +0 -0
  310. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/ql/test.ql +0 -0
  311. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/r/test.r +0 -0
  312. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/racket/test.rkt +0 -0
  313. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/ruby/test.rb +0 -0
  314. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/rust/test.rs +0 -0
  315. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/scala/test.scala +0 -0
  316. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/solidity/test.sol +0 -0
  317. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/swift/test.swift +0 -0
  318. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/tsx/test.tsx +0 -0
  319. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/typescript/test.ts +0 -0
  320. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/udev/test.rules +0 -0
  321. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/languages/zig/test.zig +0 -0
  322. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/sample-code-base/sample.js +0 -0
  323. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/sample-code-base/sample.py +0 -0
  324. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/sample-code-base-repo-map.txt +0 -0
  325. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/watch.js +0 -0
  326. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/watch.lisp +0 -0
  327. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/watch.py +0 -0
  328. {patch_chat-0.1.0 → patch_chat-0.3.0}/tests/fixtures/watch_question.js +0 -0
  329. {patch_chat-0.1.0 → patch_chat-0.3.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,122 @@
1
+ ---
2
+ description: Copy an upstream aider issue into this fork, fix it, ship it, and comment upstream
3
+ argument-hint: <upstream issue URL or number>
4
+ allowed-tools: Bash(gh:*), Bash(git:*), Bash(python:*), Bash(pytest:*), Bash(pre-commit:*), Read, Edit, Write, Grep, Glob
5
+ ---
6
+
7
+ Take the upstream issue at **$ARGUMENTS** (a `Aider-AI/aider` issue URL, or a bare number meaning
8
+ that repo) through the full pipeline below. Work top to bottom, one step at a time, and keep a
9
+ todo list.
10
+
11
+ Use the Read, Edit and Write tools for anything that reads or changes a file. Bash is for `gh`,
12
+ `git`, `pytest` and `pre-commit` — not for `cat`, `sed` or heredocs that rewrite source.
13
+
14
+ ## 1. Read the upstream issue
15
+
16
+ ```
17
+ gh issue view <N> --repo Aider-AI/aider --json number,title,body,author,createdAt,state,labels
18
+ ```
19
+
20
+ ## 2. Decide what the defect actually is
21
+
22
+ This fork renames the module: upstream `aider/foo.py` is `patch/foo.py` here, the distribution is
23
+ `patch-chat`, the CLI is `patch`. Locate the code the issue describes and confirm the behaviour
24
+ still reproduces here — upstream and fork have diverged, and some issues are already fixed.
25
+
26
+ Not every report is a code bug. A broken user environment, a provider outage or a support
27
+ question has no fix in this repo. When that is the case, say so plainly, and look for the defect
28
+ that *is* ours — usually how the tool presents the failure. Fix that instead, and explain the
29
+ split in the issue body you write in step 3. Do not invent a fix for something that is not broken.
30
+
31
+ If nothing here is worth changing, stop after step 3 and say why rather than closing the issue.
32
+
33
+ ## 3. Copy it into the fork
34
+
35
+ Create the issue in `PierrunoYT/patch`, preserving the upstream title unless it names something
36
+ this fork calls differently, and the body verbatim. Append an attribution footer:
37
+
38
+ ```
39
+ ---
40
+
41
+ _Copied from [Aider-AI/aider#<N>](<url>) (opened by @<author> on <YYYY-MM-DD>)._
42
+ ```
43
+
44
+ When your reading in step 2 differs from the reporter's — a different root cause, or the
45
+ conclusion that the real defect is elsewhere — add a short paragraph after the footer saying so.
46
+ That paragraph is your analysis, kept separate from their words.
47
+
48
+ Label it from the repo's existing labels (`gh label list --repo PierrunoYT/patch`): always the
49
+ kind (`bug`, `documentation`, `enhancement`, `security`), always a severity (`critical`, `high`,
50
+ `medium`, `low`), and `good first issue` when the fix is genuinely small and self-contained.
51
+
52
+ ## 4. Fix it
53
+
54
+ Follow the repository's own conventions in `AGENTS.md`. In short:
55
+
56
+ - Make the change, and add a regression test that fails without it. Tests live in
57
+ `tests/basic/`, mirroring the module layout.
58
+ - `pytest` — the whole suite, not just the new file.
59
+ - `pre-commit run --all-files` — all five hooks. Black may reformat; re-run until clean.
60
+
61
+ ## 5. Update every doc the change touches — in the same pass, not as a follow-up
62
+
63
+ The task is not done when the tests pass. It is done when the docs match. Go through this list
64
+ each time and decide about each entry; the answer is often "nothing to change", but it has to be
65
+ a decision rather than an oversight.
66
+
67
+ - **`CHANGELOG.md`** — always, no exceptions. Under `## [Unreleased]`, in the right subsection
68
+ (`Added`, `Changed`, `Fixed`, `Removed`, `Security`). A docs-only change still gets an entry.
69
+ Blank line between top-level bullets; nested sub-lists stay tight. Describe what changed for
70
+ the reader, not which files you edited. A released `## [X.Y.Z]` section is mirrored in the git
71
+ tag and the GitHub release — never reword or restructure one.
72
+ - **`README.md`** — installation, usage, supported Python or model versions, security boundaries,
73
+ or anything a user reads before running the tool.
74
+ - **`CONTRIBUTING.md`** — setup, testing, dependencies, or the release process.
75
+ - **`AGENTS.md`** — repository layout, tooling, conventions, or a trap worth recording so the
76
+ next agent does not rediscover it. A new module, a renamed one, or a new rule about how the
77
+ code is organised belongs here.
78
+ - **Docstrings and comments next to the code you changed** — if the fix invalidates what a
79
+ nearby comment claims, fix the comment too.
80
+ - **User-facing strings in the code** — `patch/args.py` help text and the messages in
81
+ `patch/main.py`, `patch/commands.py` and `patch/io.py` are documentation the user actually
82
+ reads. A changed flag or behaviour usually means one of them is now wrong.
83
+ - **`AUDIT_REPORT.md` / `AUDIT_PROMPT.md`** — only when the fix lands on a finding those files
84
+ track, or rules out a candidate the prompt lists.
85
+
86
+ Then grep for whatever else still describes the old behaviour
87
+ (`grep -rn "<flag or phrase>" README.md CONTRIBUTING.md AGENTS.md patch/`). A stale doc is the
88
+ same defect as stale code.
89
+
90
+ Doc updates ship in the task's own commit (step 6), never in a later one.
91
+
92
+ ## 6. Commit and push
93
+
94
+ One commit for the whole task — code, test and docs together. Conventional Commit subject, a body
95
+ explaining the defect and the fix, and a trailer line:
96
+
97
+ ```
98
+ Closes #<fork issue>. Reported upstream in Aider-AI/aider#<N>.
99
+ ```
100
+
101
+ Push to `main`. That closes the fork issue. Confirm it did:
102
+
103
+ ```
104
+ gh issue list --repo PierrunoYT/patch --state closed --limit 3
105
+ ```
106
+
107
+ ## 7. Comment upstream
108
+
109
+ Post it without asking — invoking this command is the authorisation. Write the comment to a file
110
+ and post it with `gh issue comment <N> --repo Aider-AI/aider --body-file <file>`. It is a public
111
+ comment on someone else's repository under the user's account, so write it as carefully as if you
112
+ were going to be asked to defend it: say only what step 2 actually established, and nothing the
113
+ tests do not cover.
114
+
115
+ A good comment is short and factual: confirm or correct the diagnosis, show the actual fix, say
116
+ what the tests cover, and disclose that Patch is a fork of aider. Offer a PR when the fix would
117
+ apply upstream unchanged. No promotion.
118
+
119
+ ## Report back
120
+
121
+ Finish with the fork issue number, the commit SHA, the test and hook results, and the upstream
122
+ comment link.
@@ -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,8 @@ patch/_version.py
20
20
  tmp.benchmarks/
21
21
  .docker_bash_history
22
22
  .amp/portals/*
23
+ .coverage
24
+ htmlcov/
25
+ .coverage.*
26
+ .claude/settings.json
27
+ .claude/settings.local.json
@@ -0,0 +1,200 @@
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
+ ### Upstream issues
131
+
132
+ Patch is a fork of [aider](https://github.com/Aider-AI/aider), and reports filed there often
133
+ apply here. `.claude/commands/upstream-issue.md` is a Claude Code slash command
134
+ (`/upstream-issue <url>`) that carries one from upstream to shipped: copy it into this repo's
135
+ tracker with attribution, judge whether the defect is really ours — upstream `aider/foo.py` is
136
+ `patch/foo.py` here, and a broken user environment has no fix in this code — write the fix and a
137
+ regression test, update the docs above, commit with `Closes #N`, and only then comment upstream.
138
+ Editing that file is how the procedure changes; do not keep a second copy of it here.
139
+
140
+ ## Releases
141
+
142
+ The full steps are in `CONTRIBUTING.md` under "Making a Release". Read them before cutting one;
143
+ the traps below have each cost a rebuild.
144
+
145
+ - **The version comes from the git tag, nothing else.** `patch/__init__.py`'s `safe_version` and
146
+ `pyproject.toml`'s `fallback_version` are floors, not the version. Bumping them without tagging
147
+ makes every run report `X.Y.Z.dev+less`, because the generated `patch/_version.py` left over
148
+ from the previous build is now below the new floor. Tagging and rebuilding clears it.
149
+ - **Tag with `--cleanup=verbatim`.** `git tag -F` otherwise defaults to `--cleanup=strip` and
150
+ deletes every line beginning with `#`, silently removing the `##` title and all the `###`
151
+ headings from a changelog section used as the tag message. Both `v0.1.0` and `v0.2.0` were
152
+ tagged without it, so their tag messages are flattened; the release bodies are fine, because
153
+ both were published with `--notes-file` from the changelog rather than from the tag.
154
+ - **Reuse the notes file for `gh release create --notes-file`.** Write the changelog section to a
155
+ file in step 2 and pass that same path in step 4. Never spell it as a `<placeholder>`: in
156
+ PowerShell, the default shell here, `<` is a reserved operator and the command fails to parse
157
+ before `gh` runs.
158
+ - **Re-tag only while the tag is local.** If a later commit changes the changelog section, delete
159
+ the tag, re-tag on the new HEAD, and rebuild — the artifacts must come from the tagged commit.
160
+ Once the tag is pushed this is closed off; see the rule in Workflow step 3.
161
+ - **Verify the artifact, not the checkout.** Install the built wheel into a venv outside the
162
+ repository and check `patch --version` plus the bundled data files
163
+ (`resources/model-settings.yml`, `queries/**/*.scm`). From the repository root `tests/__init__.py`
164
+ puts the working tree on `sys.path`, so an in-tree import proves nothing about the wheel.
165
+
166
+ ## Conventions
167
+
168
+ - Match the surrounding style rather than importing a new one. The codebase is
169
+ plain Python with light comments and no type annotations in most modules.
170
+ - Tests are a mix of `unittest.TestCase` classes (about half the files in
171
+ `tests/basic/`) and plain pytest functions. Follow whichever style the file
172
+ you are editing already uses.
173
+ - Commits follow Conventional Commits (`feat:`, `fix:`, `docs:`, `chore:`), as
174
+ seen in recent history.
175
+ - Separate every top-level `CHANGELOG.md` bullet with a blank line. CommonMark makes a list
176
+ *loose* -- each item wrapped in `<p>`, with paragraph margins -- as soon as any two of its items
177
+ are separated by a blank line, and *tight* otherwise. One stray blank line therefore respaces a
178
+ whole section, so a file mixing the two renders on GitHub with some sections airy and others
179
+ dense. Entries here are multi-sentence, so loose is the target. Nested sub-lists stay tight.
180
+ - Anything passed to `analytics.event(...)` leaves the machine. `Analytics.event` scrubs every
181
+ property -- URL query strings, absolute paths, length -- so a call site cannot leak by
182
+ forgetting, but the scrubber only removes shapes it knows. Send a class name, a fixed reason or
183
+ a count; never `str(err)`, never free text from a remote server, and route a model name through
184
+ `redact_model_name`. The opt-in prompt in `patch/main.py` is a promise about this.
185
+ - A new `raise SwitchCoder(...)` has to say whether the user's message was already carried out
186
+ before the switch. `/ask PROMPT` answers on a temporary coder and then switches back, so it
187
+ passes `message_handled=True`; `/model` switches instead of doing anything, and leaves the
188
+ default. `run_one_message` in `patch/main.py` uses that to decide whether a one-shot
189
+ `--message` run lost the user's request or completed it.
190
+ - A chat message's `content` is not always a string. An assistant reply that is only a function
191
+ call carries `content=None`, and a message carrying an image carries a list of parts. Read the
192
+ words with `patch.utils.message_content_text(msg)`; concatenating `msg["content"]` raises
193
+ `TypeError` on an ordinary conversation.
194
+ - Write to the terminal through `InputOutput._console_print`, never `self.console.print`
195
+ directly. A terminal write can fail on its own — a legacy Windows console rejects some writes
196
+ with `OSError: [Errno 22]`, and a closed or redirected handle raises too — and most callers are
197
+ reporting an error already, so an escaping `OSError` replaces the message with a traceback and
198
+ ends the session. `_console_print` degrades to ASCII, then to a plain `print`, then to silence.
199
+ The exception is a `Console(file=StringIO())` used to format a string, which never touches a
200
+ terminal.