patch-chat 0.2.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 (318) hide show
  1. patch_chat-0.3.0/.claude/commands/upstream-issue.md +122 -0
  2. {patch_chat-0.2.0 → patch_chat-0.3.0}/.gitignore +5 -3
  3. {patch_chat-0.2.0 → patch_chat-0.3.0}/AGENTS.md +200 -138
  4. {patch_chat-0.2.0 → patch_chat-0.3.0}/AUDIT_REPORT.md +10 -0
  5. {patch_chat-0.2.0 → patch_chat-0.3.0}/CHANGELOG.md +916 -624
  6. {patch_chat-0.2.0/patch_chat.egg-info → patch_chat-0.3.0}/PKG-INFO +8 -5
  7. {patch_chat-0.2.0 → patch_chat-0.3.0}/README.md +7 -4
  8. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/_version.py +3 -3
  9. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/analytics.py +65 -14
  10. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/args.py +3 -2
  11. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/base_coder.py +17 -8
  12. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/commands.py +60 -26
  13. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/history.py +2 -1
  14. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/io.py +1367 -1318
  15. patch_chat-0.3.0/patch/llm.py +184 -0
  16. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/main.py +28 -9
  17. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/mdstream.py +4 -1
  18. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/onboarding.py +12 -3
  19. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/repo.py +16 -1
  20. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/repo_trust.py +30 -3
  21. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/report.py +8 -0
  22. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/utils.py +21 -0
  23. {patch_chat-0.2.0 → patch_chat-0.3.0/patch_chat.egg-info}/PKG-INFO +8 -5
  24. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch_chat.egg-info/SOURCES.txt +3 -0
  25. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch_chat.egg-info/scm_file_list.json +3 -0
  26. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch_chat.egg-info/scm_version.json +2 -2
  27. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_analytics.py +73 -0
  28. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_coder.py +54 -0
  29. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_commands.py +151 -1
  30. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_history.py +81 -68
  31. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_io.py +41 -0
  32. patch_chat-0.3.0/tests/basic/test_llm.py +107 -0
  33. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_main.py +49 -0
  34. patch_chat-0.3.0/tests/basic/test_mdstream.py +65 -0
  35. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_onboarding.py +21 -1
  36. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_repo.py +11 -0
  37. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_repo_config_trust.py +50 -0
  38. patch_chat-0.3.0/tests/basic/test_utils.py +43 -0
  39. patch_chat-0.2.0/patch/llm.py +0 -48
  40. patch_chat-0.2.0/tests/basic/test_utils.py +0 -22
  41. {patch_chat-0.2.0 → patch_chat-0.3.0}/.agents/resume +0 -0
  42. {patch_chat-0.2.0 → patch_chat-0.3.0}/.agents/setup +0 -0
  43. {patch_chat-0.2.0 → patch_chat-0.3.0}/.dockerignore +0 -0
  44. {patch_chat-0.2.0 → patch_chat-0.3.0}/.flake8 +0 -0
  45. {patch_chat-0.2.0 → patch_chat-0.3.0}/.github/ISSUE_TEMPLATE/issue.yml +0 -0
  46. {patch_chat-0.2.0 → patch_chat-0.3.0}/.github/workflows/packaging.yml +0 -0
  47. {patch_chat-0.2.0 → patch_chat-0.3.0}/.github/workflows/pre-commit.yml +0 -0
  48. {patch_chat-0.2.0 → patch_chat-0.3.0}/.github/workflows/ubuntu-tests.yml +0 -0
  49. {patch_chat-0.2.0 → patch_chat-0.3.0}/.github/workflows/windows-tests.yml +0 -0
  50. {patch_chat-0.2.0 → patch_chat-0.3.0}/.pre-commit-config.yaml +0 -0
  51. {patch_chat-0.2.0 → patch_chat-0.3.0}/AUDIT_PROMPT.md +0 -0
  52. {patch_chat-0.2.0 → patch_chat-0.3.0}/CONTRIBUTING.md +0 -0
  53. {patch_chat-0.2.0 → patch_chat-0.3.0}/LICENSE.txt +0 -0
  54. {patch_chat-0.2.0 → patch_chat-0.3.0}/MANIFEST.in +0 -0
  55. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/Dockerfile +0 -0
  56. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/README.md +0 -0
  57. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/__init__.py +0 -0
  58. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/benchmark.py +0 -0
  59. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/clone-exercism.sh +0 -0
  60. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/cpp-test.sh +0 -0
  61. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/docker.sh +0 -0
  62. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/docker_build.sh +0 -0
  63. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/install-docker-ubuntu.sh +0 -0
  64. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/npm-test.sh +0 -0
  65. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/plot.sh +0 -0
  66. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/plots.py +0 -0
  67. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/prompts.py +0 -0
  68. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/refactor_tools.py +0 -0
  69. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/rsync.sh +0 -0
  70. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/rungrid.py +0 -0
  71. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/swe-bench-lite.txt +0 -0
  72. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/swe-bench.txt +0 -0
  73. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/swe_bench.py +0 -0
  74. {patch_chat-0.2.0 → patch_chat-0.3.0}/benchmark/test_benchmark.py +0 -0
  75. {patch_chat-0.2.0 → patch_chat-0.3.0}/docker/Dockerfile +0 -0
  76. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/__init__.py +0 -0
  77. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/__main__.py +0 -0
  78. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/args_formatter.py +0 -0
  79. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/__init__.py +0 -0
  80. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/architect_coder.py +0 -0
  81. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/architect_prompts.py +0 -0
  82. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/ask_coder.py +0 -0
  83. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/ask_prompts.py +0 -0
  84. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/base_prompts.py +0 -0
  85. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/chat_chunks.py +0 -0
  86. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/chat_state.py +0 -0
  87. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/context_coder.py +0 -0
  88. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/context_prompts.py +0 -0
  89. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/edit_apply.py +0 -0
  90. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/editblock_coder.py +0 -0
  91. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/editblock_fenced_coder.py +0 -0
  92. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/editblock_fenced_prompts.py +0 -0
  93. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/editblock_func_coder.py +0 -0
  94. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/editblock_func_prompts.py +0 -0
  95. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/editblock_prompts.py +0 -0
  96. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/editor_diff_fenced_coder.py +0 -0
  97. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/editor_diff_fenced_prompts.py +0 -0
  98. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/editor_editblock_coder.py +0 -0
  99. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/editor_editblock_prompts.py +0 -0
  100. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/editor_whole_coder.py +0 -0
  101. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/editor_whole_prompts.py +0 -0
  102. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/patch_coder.py +0 -0
  103. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/patch_prompts.py +0 -0
  104. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/search_replace.py +0 -0
  105. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/shell.py +0 -0
  106. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/single_wholefile_func_coder.py +0 -0
  107. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/single_wholefile_func_prompts.py +0 -0
  108. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/udiff_coder.py +0 -0
  109. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/udiff_prompts.py +0 -0
  110. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/udiff_simple.py +0 -0
  111. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/udiff_simple_prompts.py +0 -0
  112. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/usage.py +0 -0
  113. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/wholefile_coder.py +0 -0
  114. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/wholefile_func_coder.py +0 -0
  115. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/wholefile_func_prompts.py +0 -0
  116. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/coders/wholefile_prompts.py +0 -0
  117. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/copypaste.py +0 -0
  118. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/deprecated.py +0 -0
  119. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/diffs.py +0 -0
  120. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/dump.py +0 -0
  121. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/editor.py +0 -0
  122. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/exceptions.py +0 -0
  123. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/format_settings.py +0 -0
  124. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/gui.py +0 -0
  125. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/linter.py +0 -0
  126. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/models.py +0 -0
  127. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/openrouter.py +0 -0
  128. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/prompts.py +0 -0
  129. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/README.md +0 -0
  130. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/arduino-tags.scm +0 -0
  131. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/bash-tags.scm +0 -0
  132. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/c-tags.scm +0 -0
  133. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/chatito-tags.scm +0 -0
  134. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/clojure-tags.scm +0 -0
  135. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/commonlisp-tags.scm +0 -0
  136. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/cpp-tags.scm +0 -0
  137. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/csharp-tags.scm +0 -0
  138. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/d-tags.scm +0 -0
  139. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/dart-tags.scm +0 -0
  140. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/elisp-tags.scm +0 -0
  141. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/elixir-tags.scm +0 -0
  142. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/elm-tags.scm +0 -0
  143. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/gleam-tags.scm +0 -0
  144. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/go-tags.scm +0 -0
  145. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/java-tags.scm +0 -0
  146. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/javascript-tags.scm +0 -0
  147. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/lua-tags.scm +0 -0
  148. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/matlab-tags.scm +0 -0
  149. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/ocaml-tags.scm +0 -0
  150. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +0 -0
  151. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/pony-tags.scm +0 -0
  152. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/properties-tags.scm +0 -0
  153. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/python-tags.scm +0 -0
  154. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/r-tags.scm +0 -0
  155. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/racket-tags.scm +0 -0
  156. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/ruby-tags.scm +0 -0
  157. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/rust-tags.scm +0 -0
  158. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/solidity-tags.scm +0 -0
  159. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/swift-tags.scm +0 -0
  160. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-language-pack/udev-tags.scm +0 -0
  161. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/README.md +0 -0
  162. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/bash-tags.scm +0 -0
  163. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/c-tags.scm +0 -0
  164. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/c_sharp-tags.scm +0 -0
  165. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/cpp-tags.scm +0 -0
  166. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/dart-tags.scm +0 -0
  167. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/elisp-tags.scm +0 -0
  168. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/elixir-tags.scm +0 -0
  169. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/elm-tags.scm +0 -0
  170. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/fortran-tags.scm +0 -0
  171. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/go-tags.scm +0 -0
  172. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/haskell-tags.scm +0 -0
  173. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/hcl-tags.scm +0 -0
  174. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/java-tags.scm +0 -0
  175. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/javascript-tags.scm +0 -0
  176. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/julia-tags.scm +0 -0
  177. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/kotlin-tags.scm +0 -0
  178. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/matlab-tags.scm +0 -0
  179. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/ocaml-tags.scm +0 -0
  180. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/ocaml_interface-tags.scm +0 -0
  181. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/php-tags.scm +0 -0
  182. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/python-tags.scm +0 -0
  183. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/ql-tags.scm +0 -0
  184. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/ruby-tags.scm +0 -0
  185. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/rust-tags.scm +0 -0
  186. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/scala-tags.scm +0 -0
  187. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/typescript-tags.scm +0 -0
  188. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/queries/tree-sitter-languages/zig-tags.scm +0 -0
  189. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/reasoning_tags.py +0 -0
  190. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/repomap.py +0 -0
  191. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/resources/__init__.py +0 -0
  192. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/resources/model-metadata.json +0 -0
  193. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/resources/model-settings.yml +0 -0
  194. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/run_cmd.py +0 -0
  195. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/scrape.py +0 -0
  196. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/sendchat.py +0 -0
  197. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/special.py +0 -0
  198. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/urls.py +0 -0
  199. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/versioncheck.py +0 -0
  200. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/voice.py +0 -0
  201. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/waiting.py +0 -0
  202. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/watch.py +0 -0
  203. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch/watch_prompts.py +0 -0
  204. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch_chat.egg-info/dependency_links.txt +0 -0
  205. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch_chat.egg-info/entry_points.txt +0 -0
  206. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch_chat.egg-info/requires.txt +0 -0
  207. {patch_chat-0.2.0 → patch_chat-0.3.0}/patch_chat.egg-info/top_level.txt +0 -0
  208. {patch_chat-0.2.0 → patch_chat-0.3.0}/pyproject.toml +0 -0
  209. {patch_chat-0.2.0 → patch_chat-0.3.0}/pytest.ini +0 -0
  210. {patch_chat-0.2.0 → patch_chat-0.3.0}/requirements/common-constraints.txt +0 -0
  211. {patch_chat-0.2.0 → patch_chat-0.3.0}/requirements/pydub.in +0 -0
  212. {patch_chat-0.2.0 → patch_chat-0.3.0}/requirements/python-compat.in +0 -0
  213. {patch_chat-0.2.0 → patch_chat-0.3.0}/requirements/requirements-browser.in +0 -0
  214. {patch_chat-0.2.0 → patch_chat-0.3.0}/requirements/requirements-browser.txt +0 -0
  215. {patch_chat-0.2.0 → patch_chat-0.3.0}/requirements/requirements-dev.in +0 -0
  216. {patch_chat-0.2.0 → patch_chat-0.3.0}/requirements/requirements-dev.txt +0 -0
  217. {patch_chat-0.2.0 → patch_chat-0.3.0}/requirements/requirements-playwright.in +0 -0
  218. {patch_chat-0.2.0 → patch_chat-0.3.0}/requirements/requirements-playwright.txt +0 -0
  219. {patch_chat-0.2.0 → patch_chat-0.3.0}/requirements/requirements.in +0 -0
  220. {patch_chat-0.2.0 → patch_chat-0.3.0}/requirements/tree-sitter.in +0 -0
  221. {patch_chat-0.2.0 → patch_chat-0.3.0}/requirements.txt +0 -0
  222. {patch_chat-0.2.0 → patch_chat-0.3.0}/scripts/__init__.py +0 -0
  223. {patch_chat-0.2.0 → patch_chat-0.3.0}/scripts/blame.py +0 -0
  224. {patch_chat-0.2.0 → patch_chat-0.3.0}/scripts/clean_metadata.py +0 -0
  225. {patch_chat-0.2.0 → patch_chat-0.3.0}/scripts/issues.py +0 -0
  226. {patch_chat-0.2.0 → patch_chat-0.3.0}/scripts/my_models.py +0 -0
  227. {patch_chat-0.2.0 → patch_chat-0.3.0}/scripts/pip-compile.sh +0 -0
  228. {patch_chat-0.2.0 → patch_chat-0.3.0}/scripts/redact-cast.py +0 -0
  229. {patch_chat-0.2.0 → patch_chat-0.3.0}/scripts/tmux_record.sh +0 -0
  230. {patch_chat-0.2.0 → patch_chat-0.3.0}/scripts/tsl_pack_langs.py +0 -0
  231. {patch_chat-0.2.0 → patch_chat-0.3.0}/scripts/yank-old-versions.py +0 -0
  232. {patch_chat-0.2.0 → patch_chat-0.3.0}/setup.cfg +0 -0
  233. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/__init__.py +0 -0
  234. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/__init__.py +0 -0
  235. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_aws_credentials.py +0 -0
  236. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_copypaste.py +0 -0
  237. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_deprecated.py +0 -0
  238. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_edit_apply.py +0 -0
  239. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_editblock.py +0 -0
  240. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_editor.py +0 -0
  241. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_exceptions.py +0 -0
  242. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_find_or_blocks.py +0 -0
  243. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_format_settings.py +0 -0
  244. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_linter.py +0 -0
  245. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_model_info_manager.py +0 -0
  246. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_models.py +0 -0
  247. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_openrouter.py +0 -0
  248. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_patch_coder.py +0 -0
  249. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_path_containment.py +0 -0
  250. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_reasoning.py +0 -0
  251. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_repomap.py +0 -0
  252. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_report.py +0 -0
  253. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_run_cmd.py +0 -0
  254. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_sanity_check_repo.py +0 -0
  255. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_scripting.py +0 -0
  256. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_sendchat.py +0 -0
  257. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_special.py +0 -0
  258. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_ssl_verification.py +0 -0
  259. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_udiff.py +0 -0
  260. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_urls.py +0 -0
  261. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_versioncheck.py +0 -0
  262. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_voice.py +0 -0
  263. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_waiting.py +0 -0
  264. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_watch.py +0 -0
  265. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/basic/test_wholefile.py +0 -0
  266. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/browser/test_browser.py +0 -0
  267. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/conftest.py +0 -0
  268. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/chat-history-search-replace-gold.txt +0 -0
  269. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/chat-history.md +0 -0
  270. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/arduino/test.ino +0 -0
  271. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/bash/test.sh +0 -0
  272. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/c/test.c +0 -0
  273. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/chatito/test.chatito +0 -0
  274. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/clojure/test.clj +0 -0
  275. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/commonlisp/test.lisp +0 -0
  276. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/cpp/test.cpp +0 -0
  277. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/csharp/test.cs +0 -0
  278. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/d/test.d +0 -0
  279. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/dart/test.dart +0 -0
  280. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/elisp/test.el +0 -0
  281. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/elixir/test.ex +0 -0
  282. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/elm/test.elm +0 -0
  283. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/gleam/test.gleam +0 -0
  284. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/go/test.go +0 -0
  285. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/haskell/test.hs +0 -0
  286. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/hcl/test.tf +0 -0
  287. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/java/test.java +0 -0
  288. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/javascript/test.js +0 -0
  289. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/kotlin/test.kt +0 -0
  290. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/lua/test.lua +0 -0
  291. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/matlab/test.m +0 -0
  292. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/ocaml/test.ml +0 -0
  293. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/ocaml_interface/test.mli +0 -0
  294. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/php/test.php +0 -0
  295. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/pony/test.pony +0 -0
  296. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/properties/test.properties +0 -0
  297. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/python/test.py +0 -0
  298. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/ql/test.ql +0 -0
  299. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/r/test.r +0 -0
  300. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/racket/test.rkt +0 -0
  301. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/ruby/test.rb +0 -0
  302. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/rust/test.rs +0 -0
  303. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/scala/test.scala +0 -0
  304. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/solidity/test.sol +0 -0
  305. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/swift/test.swift +0 -0
  306. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/tsx/test.tsx +0 -0
  307. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/typescript/test.ts +0 -0
  308. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/udev/test.rules +0 -0
  309. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/languages/zig/test.zig +0 -0
  310. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/sample-code-base/sample.js +0 -0
  311. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/sample-code-base/sample.py +0 -0
  312. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/sample-code-base-repo-map.txt +0 -0
  313. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/watch.js +0 -0
  314. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/watch.lisp +0 -0
  315. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/watch.py +0 -0
  316. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/fixtures/watch_question.js +0 -0
  317. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/scrape/test_playwright_disable.py +0 -0
  318. {patch_chat-0.2.0 → patch_chat-0.3.0}/tests/scrape/test_scrape.py +0 -0
@@ -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.
@@ -20,6 +20,8 @@ patch/_version.py
20
20
  tmp.benchmarks/
21
21
  .docker_bash_history
22
22
  .amp/portals/*
23
- .coverage
24
- htmlcov/
25
- .coverage.*
23
+ .coverage
24
+ htmlcov/
25
+ .coverage.*
26
+ .claude/settings.json
27
+ .claude/settings.local.json
@@ -1,138 +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
- ## 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.
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.
@@ -274,6 +274,16 @@ Reject in `allowed_to_edit` and in `patch_coder`'s `move_path` (see F-8).
274
274
  `.env` supplying a key is a common legitimate workflow and is not the exfiltration primitive; the
275
275
  endpoint redirect is, and that is blocked.
276
276
 
277
+ **Revised** while porting `Aider-AI/aider#5622`. The narrowing above was half right: supplying a
278
+ key is a legitimate workflow, but *replacing* the user's own key is a second exfiltration
279
+ primitive, not a lesser version of the first. A repository shipping `OPENAI_API_KEY=sk-attacker`
280
+ sends the victim's prompts to the real provider on the attacker's account, where the attacker can
281
+ read them — no fake endpoint required, and nothing on the denylist touches it. An untrusted
282
+ repository `.env` now applies only to variables the inherited environment does not already define,
283
+ and reports the ones it left alone. The legitimate workflow is unaffected, because a project key
284
+ still applies when the user has not set one; `override=False` for the user's own files was *not*
285
+ adopted, since naming `--env-file` on the command line is an instruction rather than a surprise.
286
+
277
287
  Opt back in with `--trust-repo-config` / `PATCH_TRUST_REPO_CONFIG`, accepted only from the command
278
288
  line or the ambient shell environment — both read before the repository `.env` is loaded — and
279
289
  `trust-repo-config` is itself on the blocked list, so a repository cannot self-grant from either