patch-chat 0.4.0__tar.gz → 0.5.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.
- patch_chat-0.5.0/.github/dependabot.yml +30 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/AGENTS.md +7 -1
- {patch_chat-0.4.0 → patch_chat-0.5.0}/CHANGELOG.md +72 -1
- {patch_chat-0.4.0 → patch_chat-0.5.0}/CONTRIBUTING.md +10 -0
- {patch_chat-0.4.0/patch_chat.egg-info → patch_chat-0.5.0}/PKG-INFO +20 -6
- {patch_chat-0.4.0 → patch_chat-0.5.0}/README.md +15 -1
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/_version.py +3 -3
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/args.py +27 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/base_coder.py +21 -6
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/wholefile_coder.py +57 -3
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/commands.py +1 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/main.py +12 -2
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/repo.py +33 -13
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/repo_trust.py +8 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/scrape.py +466 -332
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/utils.py +23 -1
- {patch_chat-0.4.0 → patch_chat-0.5.0/patch_chat.egg-info}/PKG-INFO +20 -6
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch_chat.egg-info/SOURCES.txt +1 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch_chat.egg-info/requires.txt +4 -4
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch_chat.egg-info/scm_file_list.json +1 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch_chat.egg-info/scm_version.json +2 -2
- {patch_chat-0.4.0 → patch_chat-0.5.0}/requirements/common-constraints.txt +509 -506
- {patch_chat-0.4.0 → patch_chat-0.5.0}/requirements/requirements-browser.txt +169 -169
- {patch_chat-0.4.0 → patch_chat-0.5.0}/requirements/requirements-dev.txt +359 -359
- patch_chat-0.5.0/requirements/requirements.in +63 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/requirements.txt +467 -465
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_coder.py +79 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_repo.py +51 -0
- patch_chat-0.5.0/tests/basic/test_utils.py +88 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_wholefile.py +79 -0
- patch_chat-0.5.0/tests/browser/test_browser.py +69 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/scrape/test_scrape.py +163 -54
- patch_chat-0.4.0/requirements/requirements.in +0 -48
- patch_chat-0.4.0/tests/basic/test_utils.py +0 -43
- patch_chat-0.4.0/tests/browser/test_browser.py +0 -36
- {patch_chat-0.4.0 → patch_chat-0.5.0}/.agents/resume +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/.agents/setup +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/.claude/commands/upstream-issue.md +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/.dockerignore +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/.flake8 +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/.github/ISSUE_TEMPLATE/issue.yml +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/.github/workflows/packaging.yml +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/.github/workflows/pre-commit.yml +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/.github/workflows/ubuntu-tests.yml +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/.github/workflows/windows-tests.yml +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/.gitignore +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/.pre-commit-config.yaml +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/AUDIT_PROMPT.md +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/AUDIT_REPORT.md +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/LICENSE.txt +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/MANIFEST.in +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/Dockerfile +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/README.md +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/__init__.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/benchmark.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/clone-exercism.sh +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/cpp-test.sh +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/docker.sh +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/docker_build.sh +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/install-docker-ubuntu.sh +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/npm-test.sh +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/plot.sh +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/plots.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/refactor_tools.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/rsync.sh +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/rungrid.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/swe-bench-lite.txt +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/swe-bench.txt +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/swe_bench.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/benchmark/test_benchmark.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/docker/Dockerfile +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/__init__.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/__main__.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/analytics.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/args_formatter.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/__init__.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/architect_coder.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/architect_prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/ask_coder.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/ask_prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/base_prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/chat_chunks.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/chat_state.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/context_coder.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/context_prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/edit_apply.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/editblock_coder.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/editblock_fenced_coder.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/editblock_fenced_prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/editblock_func_coder.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/editblock_func_prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/editblock_prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/editor_diff_fenced_coder.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/editor_diff_fenced_prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/editor_editblock_coder.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/editor_editblock_prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/editor_whole_coder.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/editor_whole_prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/patch_coder.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/patch_prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/search_replace.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/shell.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/single_wholefile_func_coder.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/single_wholefile_func_prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/udiff_coder.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/udiff_prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/udiff_simple.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/udiff_simple_prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/usage.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/wholefile_func_coder.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/wholefile_func_prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/coders/wholefile_prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/copypaste.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/deprecated.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/diffs.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/dump.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/editor.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/exceptions.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/format_settings.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/gui.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/history.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/io.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/linter.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/llm.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/mdstream.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/models.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/onboarding.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/openrouter.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/README.md +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/arduino-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/bash-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/c-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/chatito-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/clojure-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/commonlisp-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/cpp-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/csharp-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/d-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/dart-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/elisp-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/elixir-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/elm-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/gleam-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/go-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/java-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/javascript-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/lua-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/matlab-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/ocaml-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/pony-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/properties-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/python-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/r-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/racket-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/ruby-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/rust-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/solidity-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/swift-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-language-pack/udev-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/README.md +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/bash-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/c-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/c_sharp-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/cpp-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/dart-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/elisp-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/elixir-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/elm-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/fortran-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/go-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/haskell-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/hcl-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/java-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/javascript-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/julia-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/kotlin-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/matlab-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/ocaml-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/ocaml_interface-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/php-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/python-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/ql-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/ruby-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/rust-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/scala-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/typescript-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/queries/tree-sitter-languages/zig-tags.scm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/reasoning_tags.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/repomap.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/report.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/resources/__init__.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/resources/model-metadata.json +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/resources/model-settings.yml +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/run_cmd.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/sendchat.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/special.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/urls.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/versioncheck.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/voice.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/waiting.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/watch.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch/watch_prompts.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch_chat.egg-info/dependency_links.txt +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch_chat.egg-info/entry_points.txt +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/patch_chat.egg-info/top_level.txt +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/pyproject.toml +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/pytest.ini +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/requirements/pydub.in +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/requirements/python-compat.in +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/requirements/requirements-browser.in +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/requirements/requirements-dev.in +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/requirements/requirements-playwright.in +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/requirements/requirements-playwright.txt +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/requirements/tree-sitter.in +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/scripts/__init__.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/scripts/blame.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/scripts/clean_metadata.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/scripts/issues.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/scripts/my_models.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/scripts/pip-compile.sh +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/scripts/redact-cast.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/scripts/tmux_record.sh +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/scripts/tsl_pack_langs.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/scripts/yank-old-versions.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/setup.cfg +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/__init__.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/__init__.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_analytics.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_aws_credentials.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_commands.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_copypaste.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_dependency_security.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_deprecated.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_edit_apply.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_editblock.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_editor.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_exceptions.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_find_or_blocks.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_format_settings.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_history.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_io.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_linter.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_llm.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_main.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_mdstream.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_model_info_manager.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_models.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_onboarding.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_openrouter.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_patch_coder.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_path_containment.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_reasoning.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_repo_config_trust.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_repomap.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_report.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_run_cmd.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_sanity_check_repo.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_scripting.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_sendchat.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_special.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_ssl_verification.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_udiff.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_urls.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_versioncheck.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_voice.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_waiting.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/basic/test_watch.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/conftest.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/chat-history-search-replace-gold.txt +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/chat-history.md +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/arduino/test.ino +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/bash/test.sh +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/c/test.c +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/chatito/test.chatito +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/clojure/test.clj +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/commonlisp/test.lisp +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/cpp/test.cpp +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/csharp/test.cs +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/d/test.d +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/dart/test.dart +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/elisp/test.el +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/elixir/test.ex +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/elm/test.elm +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/gleam/test.gleam +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/go/test.go +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/haskell/test.hs +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/hcl/test.tf +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/java/test.java +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/javascript/test.js +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/kotlin/test.kt +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/lua/test.lua +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/matlab/test.m +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/ocaml/test.ml +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/ocaml_interface/test.mli +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/php/test.php +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/pony/test.pony +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/properties/test.properties +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/python/test.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/ql/test.ql +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/r/test.r +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/racket/test.rkt +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/ruby/test.rb +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/rust/test.rs +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/scala/test.scala +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/solidity/test.sol +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/swift/test.swift +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/tsx/test.tsx +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/typescript/test.ts +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/udev/test.rules +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/languages/zig/test.zig +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/sample-code-base/sample.js +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/sample-code-base/sample.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/sample-code-base-repo-map.txt +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/watch.js +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/watch.lisp +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/watch.py +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/fixtures/watch_question.js +0 -0
- {patch_chat-0.4.0 → patch_chat-0.5.0}/tests/scrape/test_playwright_disable.py +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
|
|
3
|
+
# Nothing was watching the pins, which is how five months of advisories
|
|
4
|
+
# accumulated in requirements.txt unnoticed. See issue #1472.
|
|
5
|
+
#
|
|
6
|
+
# requirements.txt and requirements/*.txt are generated by
|
|
7
|
+
# ./scripts/pip-compile.sh from the matching .in files, so a Dependabot PR that
|
|
8
|
+
# edits a .txt is a signal, not a patch to merge: raise the floor in the .in
|
|
9
|
+
# file, re-run the script, and close the PR. AGENTS.md records the same rule.
|
|
10
|
+
updates:
|
|
11
|
+
- package-ecosystem: pip
|
|
12
|
+
directory: /
|
|
13
|
+
schedule:
|
|
14
|
+
interval: weekly
|
|
15
|
+
open-pull-requests-limit: 10
|
|
16
|
+
labels:
|
|
17
|
+
- security
|
|
18
|
+
groups:
|
|
19
|
+
# One PR per batch rather than ten: these are lockfiles, and they are
|
|
20
|
+
# regenerated as a set anyway.
|
|
21
|
+
python-dependencies:
|
|
22
|
+
patterns:
|
|
23
|
+
- "*"
|
|
24
|
+
|
|
25
|
+
- package-ecosystem: github-actions
|
|
26
|
+
directory: /
|
|
27
|
+
schedule:
|
|
28
|
+
interval: weekly
|
|
29
|
+
labels:
|
|
30
|
+
- security
|
|
@@ -85,7 +85,13 @@ Two root-level documents cover the audit history:
|
|
|
85
85
|
- `patch/_version.py` — generated by setuptools_scm, gitignored.
|
|
86
86
|
- `requirements/*.txt` — compiled from the matching `.in` files by
|
|
87
87
|
`./scripts/pip-compile.sh`. Edit the `.in` file and re-run the script; never
|
|
88
|
-
hand-edit the `.txt`.
|
|
88
|
+
hand-edit the `.txt`. `requirements.txt` is also the distribution's install set
|
|
89
|
+
(`pyproject.toml` reads `dependencies` from it), so a pin here is what every
|
|
90
|
+
`pip install patch-chat` resolves to — a stale one ships to users, not just to
|
|
91
|
+
contributors. Security floors go in the `.in` file as `package>=fixed.version`,
|
|
92
|
+
next to a comment saying which advisory forced it. `.github/dependabot.yml`
|
|
93
|
+
watches these weekly; its PRs edit the generated `.txt` and are a signal to act
|
|
94
|
+
on, never a patch to merge.
|
|
89
95
|
|
|
90
96
|
## CI
|
|
91
97
|
|
|
@@ -7,6 +7,76 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.5.0] - 2026-09-01
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `--no-detect-file-mentions` stops Patch offering to add files the model names in its reply, for
|
|
15
|
+
sessions where the context should stay exactly what you added yourself. The prompt is otherwise
|
|
16
|
+
unchanged, and `--detect-file-mentions` is still the default.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- A reply that both edits files and asks for more files no longer loses the edits. Adding the
|
|
21
|
+
mentioned files returned before the edits were applied, so the edits in that reply were dropped
|
|
22
|
+
while the model was told its files had arrived -- it then carried on believing the edit had
|
|
23
|
+
landed, and its next edit failed to match a file that had never changed. The edits are applied
|
|
24
|
+
and committed first, and the request for more files is reflected back afterwards. An edit error
|
|
25
|
+
and a file request arriving together are now both reported, rather than only the file request.
|
|
26
|
+
|
|
27
|
+
- A whole-file listing of a markdown file no longer stops at the first fenced block inside it.
|
|
28
|
+
Any ```` ``` ```` line ended the listing, so a file containing a code block was truncated there
|
|
29
|
+
and everything after it was written to a second file named after whichever line preceded the
|
|
30
|
+
next fence. A fence carrying a language ("```json") is now read as opening a block within the
|
|
31
|
+
listing, and the listing ends at the fence that closes it. A ```` ```diff ```` block inside a
|
|
32
|
+
listing is likewise content, not a mis-selected edit format. An inner block opened with a bare
|
|
33
|
+
```` ``` ```` and no language remains ambiguous and still ends the listing.
|
|
34
|
+
|
|
35
|
+
- A debug dump of the chat transcript no longer ends the session when the transcript holds text
|
|
36
|
+
the console cannot encode. Content reaches the transcript from files read with
|
|
37
|
+
`surrogateescape` and from model replies, so a lone surrogate can appear in it; printing one
|
|
38
|
+
raised an uncaught `UnicodeEncodeError` from inside `--verbose` output. Unprintable characters
|
|
39
|
+
are now replaced, and the dump is shown.
|
|
40
|
+
|
|
41
|
+
- `/commit` now respects `--subtree-only`. It committed through `git commit -a`, which stages
|
|
42
|
+
every dirty file in the repository regardless of the subtree the session was scoped to, so
|
|
43
|
+
unrelated work elsewhere in the tree was swept into the commit without appearing anywhere the
|
|
44
|
+
user could see it. The commit is now restricted to dirty files inside the subtree, and does
|
|
45
|
+
nothing at all when the only changes are outside it.
|
|
46
|
+
|
|
47
|
+
### Security
|
|
48
|
+
|
|
49
|
+
- Web scraping no longer fetches private, loopback or link-local addresses. A URL that resolves
|
|
50
|
+
into one of those ranges is refused before the request is made, which closes the path from a
|
|
51
|
+
repository README naming `http://169.254.169.254/latest/meta-data/iam/security-credentials/` to
|
|
52
|
+
Patch fetching the cloud metadata service it happens to be running next to and putting IAM
|
|
53
|
+
credentials in the chat. The check runs after DNS resolution, so a hostname pointing at a private
|
|
54
|
+
address is refused too, and it runs again on every redirect hop, so a public URL cannot bounce
|
|
55
|
+
the scraper somewhere private. Under Playwright the same rule applies to what the page itself
|
|
56
|
+
loads, not only to the address in the URL bar. `--allow-private-urls` scrapes a local dev server
|
|
57
|
+
deliberately; a repository config cannot set it, since the repository is also what supplies the
|
|
58
|
+
URLs.
|
|
59
|
+
|
|
60
|
+
- The browser UI now listens on `127.0.0.1` instead of every interface. `--browser` handed
|
|
61
|
+
Streamlit no address, and its default is to accept connections from anywhere, so running the UI
|
|
62
|
+
on a shared network put an unauthenticated page that can edit the repository and spend the user's
|
|
63
|
+
API credits in reach of everyone on it. `--gui-address ADDR` binds somewhere else on purpose and
|
|
64
|
+
warns when that address is not loopback; a repository config cannot set it.
|
|
65
|
+
|
|
66
|
+
- litellm is now constrained to 1.84.0 or later, carrying the fixes for an authentication bypass
|
|
67
|
+
via Host header injection (CVE-2026-49468) along with CVE-2026-42208 and CVE-2026-35030. This is
|
|
68
|
+
the library every provider request passes through, so it is the code holding the user's API keys.
|
|
69
|
+
The pin is held below 1.85 deliberately: resolving the floor open-ended lands on 1.99, which adds
|
|
70
|
+
the AWS SDK to every install and downgrades `importlib-metadata`, and that is a change to make
|
|
71
|
+
and validate on its own terms rather than inside a security patch.
|
|
72
|
+
|
|
73
|
+
- soupsieve is now constrained to 2.8.4 or later.
|
|
74
|
+
|
|
75
|
+
- Dependency pins are now watched weekly by Dependabot, for both Python packages and GitHub
|
|
76
|
+
Actions. Nothing had been watching them, which is how a lockfile that is also the published
|
|
77
|
+
install set accumulated advisories unnoticed. `CONTRIBUTING.md` and `AGENTS.md` describe how to
|
|
78
|
+
act on what it reports, since the files it edits are generated.
|
|
79
|
+
|
|
10
80
|
## [0.4.0] - 2026-09-01
|
|
11
81
|
|
|
12
82
|
### Changed
|
|
@@ -1004,7 +1074,8 @@ than continuing the upstream `0.86.x` numbering.
|
|
|
1004
1074
|
`.env`, including `OPENAI_API_KEY` and `PATCH_MODEL`, still load normally; and anything passed on
|
|
1005
1075
|
the command line always wins.
|
|
1006
1076
|
|
|
1007
|
-
[Unreleased]: https://github.com/PierrunoYT/patch/compare/v0.
|
|
1077
|
+
[Unreleased]: https://github.com/PierrunoYT/patch/compare/v0.5.0...main
|
|
1078
|
+
[0.5.0]: https://github.com/PierrunoYT/patch/compare/v0.4.0...v0.5.0
|
|
1008
1079
|
[0.4.0]: https://github.com/PierrunoYT/patch/compare/v0.3.0...v0.4.0
|
|
1009
1080
|
[0.3.0]: https://github.com/PierrunoYT/patch/compare/v0.2.0...v0.3.0
|
|
1010
1081
|
[0.2.0]: https://github.com/PierrunoYT/patch/compare/v0.1.0...v0.2.0
|
|
@@ -280,6 +280,16 @@ Any arguments you pass to `pip-compile.sh` flow through to `uv pip compile`. For
|
|
|
280
280
|
Note that a plain re-run keeps the existing pins: `uv` treats the current lock as a preference, so
|
|
281
281
|
moving a dependency needs one of the `--upgrade` flags above.
|
|
282
282
|
|
|
283
|
+
**Security updates.** `requirements.txt` is the distribution's install set — `pyproject.toml` reads
|
|
284
|
+
`dependencies` from it — so a vulnerable pin is what everyone who runs `pip install patch-chat`
|
|
285
|
+
receives. Raise the floor in the `.in` file (`package>=fixed.version`) with a comment naming the
|
|
286
|
+
advisory, then re-run the script. Prefer the narrowest range that carries the fix: resolving an
|
|
287
|
+
open-ended floor can jump many minor versions at once and bring new transitive dependencies with
|
|
288
|
+
it, which is a change to review on its own terms rather than inside a security patch.
|
|
289
|
+
`.github/dependabot.yml` watches the pins weekly, and its pull requests edit the generated `.txt`
|
|
290
|
+
files — treat them as notification that a floor needs raising, and close them in favour of a
|
|
291
|
+
regenerated lock.
|
|
292
|
+
|
|
283
293
|
### Pre-commit Hooks
|
|
284
294
|
|
|
285
295
|
The project uses [pre-commit](https://pre-commit.com/) hooks to automatically format code, lint, and run other checks before committing changes. After cloning the repository, run the following command to set up the pre-commit hooks:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: patch-chat
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Patch is AI pair programming in your terminal
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Project-URL: Homepage, https://github.com/PierrunoYT/patch
|
|
@@ -19,7 +19,7 @@ Requires-Python: <3.15,>=3.10
|
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
20
|
License-File: LICENSE.txt
|
|
21
21
|
Requires-Dist: aiohappyeyeballs==2.6.1
|
|
22
|
-
Requires-Dist: aiohttp==3.
|
|
22
|
+
Requires-Dist: aiohttp==3.14.3
|
|
23
23
|
Requires-Dist: aiosignal==1.4.0
|
|
24
24
|
Requires-Dist: annotated-doc==0.0.4
|
|
25
25
|
Requires-Dist: annotated-types==0.7.0
|
|
@@ -53,14 +53,14 @@ Requires-Dist: httpcore==1.0.9
|
|
|
53
53
|
Requires-Dist: httpx==0.28.1
|
|
54
54
|
Requires-Dist: huggingface-hub==1.7.1
|
|
55
55
|
Requires-Dist: idna==3.11
|
|
56
|
-
Requires-Dist: importlib-metadata==9.0
|
|
56
|
+
Requires-Dist: importlib-metadata==8.9.0
|
|
57
57
|
Requires-Dist: importlib-resources==6.5.2
|
|
58
58
|
Requires-Dist: jinja2==3.1.6
|
|
59
59
|
Requires-Dist: jiter==0.13.0
|
|
60
60
|
Requires-Dist: json5==0.13.0
|
|
61
61
|
Requires-Dist: jsonschema==4.26.0
|
|
62
62
|
Requires-Dist: jsonschema-specifications==2025.9.1
|
|
63
|
-
Requires-Dist: litellm==1.
|
|
63
|
+
Requires-Dist: litellm==1.84.10
|
|
64
64
|
Requires-Dist: markdown-it-py==4.0.0
|
|
65
65
|
Requires-Dist: markupsafe==3.0.3
|
|
66
66
|
Requires-Dist: mdurl==0.1.2
|
|
@@ -104,7 +104,7 @@ Requires-Dist: smmap==5.0.3
|
|
|
104
104
|
Requires-Dist: sniffio==1.3.1
|
|
105
105
|
Requires-Dist: sounddevice==0.5.5
|
|
106
106
|
Requires-Dist: soundfile==0.13.1
|
|
107
|
-
Requires-Dist: soupsieve==2.
|
|
107
|
+
Requires-Dist: soupsieve==2.9.2
|
|
108
108
|
Requires-Dist: tiktoken==0.12.0
|
|
109
109
|
Requires-Dist: tokenizers==0.22.2
|
|
110
110
|
Requires-Dist: tqdm==4.67.3
|
|
@@ -346,7 +346,8 @@ refused whether it sits inside the repository or outside it.
|
|
|
346
346
|
|
|
347
347
|
**The repository's own config is not trusted.** A `.patch.conf.yml` or `.env` discovered inside
|
|
348
348
|
the repository cannot set execution-capable options (`test`, `test-cmd`, `lint-cmd`, `load`,
|
|
349
|
-
`notifications-command`, `editor`, `verify-ssl`, `git-commit-verify`
|
|
349
|
+
`notifications-command`, `editor`, `verify-ssl`, `git-commit-verify`, `allow-private-urls`,
|
|
350
|
+
`gui-address`) or environment variables
|
|
350
351
|
that redirect API endpoints or proxies (`*_API_BASE`, `*_BASE_URL`, `HTTP(S)_PROXY`,
|
|
351
352
|
`REQUESTS_CA_BUNDLE`, ...). Nor can it name another file for Patch to trust — `env-file`,
|
|
352
353
|
`model-settings-file` and `model-metadata-file` are refused from repository config for that reason.
|
|
@@ -364,6 +365,19 @@ Pass `--trust-repo-config` to opt back in for a repository you trust. You can al
|
|
|
364
365
|
`PATCH_TRUST_REPO_CONFIG` in your shell. The setting is ignored when it comes from the repository's
|
|
365
366
|
own config or `.env`, so a repository cannot grant itself trust.
|
|
366
367
|
|
|
368
|
+
**Scraping stays on public addresses.** `/web`, and any URL Patch fetches on your behalf, is
|
|
369
|
+
refused when it resolves to a private, loopback or link-local address. Cloud metadata services
|
|
370
|
+
answer on `169.254.169.254` and hand out IAM credentials to whatever asks, and the URL usually
|
|
371
|
+
comes from the repository — a README is enough to aim it. Names are checked after resolution, so a
|
|
372
|
+
hostname with an A record pointing at a private address is refused too, as is a redirect that
|
|
373
|
+
arrives at one. Pass `--allow-private-urls` to scrape a local dev server deliberately; a repository
|
|
374
|
+
config cannot set it.
|
|
375
|
+
|
|
376
|
+
**The browser UI listens on this machine only.** `--browser` / `--gui` binds `127.0.0.1`. The UI
|
|
377
|
+
has no authentication and can edit your repository and spend your API credits, so it is not
|
|
378
|
+
something to put on a shared network by accident. `--gui-address ADDR` moves it deliberately —
|
|
379
|
+
`--gui-address 0.0.0.0` accepts connections from anywhere and says so at startup.
|
|
380
|
+
|
|
367
381
|
**Running in a container.** The boundary above distinguishes your files from the repository's by
|
|
368
382
|
comparing against your home directory, so do not set `HOME` to the directory you mount the project
|
|
369
383
|
into — the two become indistinguishable and every filter above stops applying. The bundled
|
|
@@ -94,7 +94,8 @@ refused whether it sits inside the repository or outside it.
|
|
|
94
94
|
|
|
95
95
|
**The repository's own config is not trusted.** A `.patch.conf.yml` or `.env` discovered inside
|
|
96
96
|
the repository cannot set execution-capable options (`test`, `test-cmd`, `lint-cmd`, `load`,
|
|
97
|
-
`notifications-command`, `editor`, `verify-ssl`, `git-commit-verify`
|
|
97
|
+
`notifications-command`, `editor`, `verify-ssl`, `git-commit-verify`, `allow-private-urls`,
|
|
98
|
+
`gui-address`) or environment variables
|
|
98
99
|
that redirect API endpoints or proxies (`*_API_BASE`, `*_BASE_URL`, `HTTP(S)_PROXY`,
|
|
99
100
|
`REQUESTS_CA_BUNDLE`, ...). Nor can it name another file for Patch to trust — `env-file`,
|
|
100
101
|
`model-settings-file` and `model-metadata-file` are refused from repository config for that reason.
|
|
@@ -112,6 +113,19 @@ Pass `--trust-repo-config` to opt back in for a repository you trust. You can al
|
|
|
112
113
|
`PATCH_TRUST_REPO_CONFIG` in your shell. The setting is ignored when it comes from the repository's
|
|
113
114
|
own config or `.env`, so a repository cannot grant itself trust.
|
|
114
115
|
|
|
116
|
+
**Scraping stays on public addresses.** `/web`, and any URL Patch fetches on your behalf, is
|
|
117
|
+
refused when it resolves to a private, loopback or link-local address. Cloud metadata services
|
|
118
|
+
answer on `169.254.169.254` and hand out IAM credentials to whatever asks, and the URL usually
|
|
119
|
+
comes from the repository — a README is enough to aim it. Names are checked after resolution, so a
|
|
120
|
+
hostname with an A record pointing at a private address is refused too, as is a redirect that
|
|
121
|
+
arrives at one. Pass `--allow-private-urls` to scrape a local dev server deliberately; a repository
|
|
122
|
+
config cannot set it.
|
|
123
|
+
|
|
124
|
+
**The browser UI listens on this machine only.** `--browser` / `--gui` binds `127.0.0.1`. The UI
|
|
125
|
+
has no authentication and can edit your repository and spend your API credits, so it is not
|
|
126
|
+
something to put on a shared network by accident. `--gui-address ADDR` moves it deliberately —
|
|
127
|
+
`--gui-address 0.0.0.0` accepts connections from anywhere and says so at startup.
|
|
128
|
+
|
|
115
129
|
**Running in a container.** The boundary above distinguishes your files from the repository's by
|
|
116
130
|
comparing against your home directory, so do not set `HOME` to the directory you mount the project
|
|
117
131
|
into — the two become indistinguishable and every filter above stops applying. The bundled
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.
|
|
22
|
-
__version_tuple__ = version_tuple = (0,
|
|
21
|
+
__version__ = version = '0.5.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 5, 0)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g5ca14cb5c'
|
|
@@ -669,6 +669,15 @@ def get_parser(default_config_files, git_root):
|
|
|
669
669
|
help="Run Patch in your browser (default: False)",
|
|
670
670
|
default=False,
|
|
671
671
|
)
|
|
672
|
+
group.add_argument(
|
|
673
|
+
"--gui-address",
|
|
674
|
+
metavar="ADDR",
|
|
675
|
+
default="127.0.0.1",
|
|
676
|
+
help=(
|
|
677
|
+
"Address the browser UI listens on (default: 127.0.0.1, this machine only)."
|
|
678
|
+
" Use 0.0.0.0 to expose it to your network -- it has no authentication."
|
|
679
|
+
),
|
|
680
|
+
)
|
|
672
681
|
group.add_argument(
|
|
673
682
|
"--copy-paste",
|
|
674
683
|
action=argparse.BooleanOptionalAction,
|
|
@@ -735,6 +744,15 @@ def get_parser(default_config_files, git_root):
|
|
|
735
744
|
help="Never prompt for or attempt to install Playwright for web scraping (default: False).",
|
|
736
745
|
default=False,
|
|
737
746
|
)
|
|
747
|
+
group.add_argument(
|
|
748
|
+
"--allow-private-urls",
|
|
749
|
+
action="store_true",
|
|
750
|
+
help=(
|
|
751
|
+
"Scrape private, loopback and link-local addresses, such as a local dev server."
|
|
752
|
+
" Refused by default because cloud metadata services answer there (default: False)."
|
|
753
|
+
),
|
|
754
|
+
default=False,
|
|
755
|
+
)
|
|
738
756
|
group.add_argument(
|
|
739
757
|
"--file",
|
|
740
758
|
action="append",
|
|
@@ -865,6 +883,15 @@ def get_parser(default_config_files, git_root):
|
|
|
865
883
|
default=True,
|
|
866
884
|
help="Enable/disable detection and offering to add URLs to chat (default: True)",
|
|
867
885
|
)
|
|
886
|
+
group.add_argument(
|
|
887
|
+
"--detect-file-mentions",
|
|
888
|
+
action=argparse.BooleanOptionalAction,
|
|
889
|
+
default=True,
|
|
890
|
+
help=(
|
|
891
|
+
"Enable/disable offering to add files the model mentions to the chat"
|
|
892
|
+
" (default: True). Turn it off to keep the context to what you add yourself."
|
|
893
|
+
),
|
|
894
|
+
)
|
|
868
895
|
group.add_argument(
|
|
869
896
|
"--editor",
|
|
870
897
|
help="Specify which editor to use for the /editor command",
|
|
@@ -137,6 +137,7 @@ class Coder:
|
|
|
137
137
|
num_cache_warming_pings = 0
|
|
138
138
|
suggest_shell_commands = True
|
|
139
139
|
detect_urls = True
|
|
140
|
+
detect_file_mentions = True
|
|
140
141
|
ignore_mentions = None
|
|
141
142
|
chat_language = None
|
|
142
143
|
commit_language = None
|
|
@@ -368,6 +369,7 @@ class Coder:
|
|
|
368
369
|
chat_language=None,
|
|
369
370
|
commit_language=None,
|
|
370
371
|
detect_urls=True,
|
|
372
|
+
detect_file_mentions=True,
|
|
371
373
|
ignore_mentions=None,
|
|
372
374
|
total_tokens_sent=0,
|
|
373
375
|
total_tokens_received=0,
|
|
@@ -400,6 +402,7 @@ class Coder:
|
|
|
400
402
|
|
|
401
403
|
self.suggest_shell_commands = suggest_shell_commands
|
|
402
404
|
self.detect_urls = detect_urls
|
|
405
|
+
self.detect_file_mentions = detect_file_mentions
|
|
403
406
|
|
|
404
407
|
self.num_cache_warming_pings = num_cache_warming_pings
|
|
405
408
|
|
|
@@ -1794,15 +1797,17 @@ class Coder:
|
|
|
1794
1797
|
else:
|
|
1795
1798
|
content = ""
|
|
1796
1799
|
|
|
1800
|
+
add_rel_files_message = None
|
|
1801
|
+
|
|
1797
1802
|
if not interrupted:
|
|
1798
1803
|
add_rel_files_message = self.check_for_file_mentions(content)
|
|
1799
|
-
if add_rel_files_message:
|
|
1800
|
-
if self.reflected_message:
|
|
1801
|
-
self.reflected_message += "\n\n" + add_rel_files_message
|
|
1802
|
-
else:
|
|
1803
|
-
self.reflected_message = add_rel_files_message
|
|
1804
|
-
return
|
|
1805
1804
|
|
|
1805
|
+
# A reply that both edits files and asks for more used to return here,
|
|
1806
|
+
# above apply_updates, so its edits were dropped on the floor. The model
|
|
1807
|
+
# was then told the files were added and carried on believing its edit
|
|
1808
|
+
# had landed -- and the next one failed to match, because it never had.
|
|
1809
|
+
# The edits are applied below first; the reflection happens after.
|
|
1810
|
+
if not interrupted and not add_rel_files_message:
|
|
1806
1811
|
try:
|
|
1807
1812
|
if self.reply_completed():
|
|
1808
1813
|
return
|
|
@@ -1830,6 +1835,13 @@ class Coder:
|
|
|
1830
1835
|
|
|
1831
1836
|
self.move_back_cur_messages(saved_message)
|
|
1832
1837
|
|
|
1838
|
+
if add_rel_files_message:
|
|
1839
|
+
if self.reflected_message:
|
|
1840
|
+
self.reflected_message += "\n\n" + add_rel_files_message
|
|
1841
|
+
else:
|
|
1842
|
+
self.reflected_message = add_rel_files_message
|
|
1843
|
+
return
|
|
1844
|
+
|
|
1833
1845
|
if self.reflected_message:
|
|
1834
1846
|
return
|
|
1835
1847
|
|
|
@@ -1999,6 +2011,9 @@ class Coder:
|
|
|
1999
2011
|
return mentioned_rel_fnames
|
|
2000
2012
|
|
|
2001
2013
|
def check_for_file_mentions(self, content):
|
|
2014
|
+
if not self.detect_file_mentions:
|
|
2015
|
+
return
|
|
2016
|
+
|
|
2002
2017
|
mentioned_rel_fnames = self.get_file_mentions(content)
|
|
2003
2018
|
|
|
2004
2019
|
new_mentions = mentioned_rel_fnames - self.ignore_mentions
|
|
@@ -28,6 +28,33 @@ class WholeFileCoder(Coder):
|
|
|
28
28
|
fname = fname.lstrip("#")
|
|
29
29
|
return fname.strip()
|
|
30
30
|
|
|
31
|
+
def nested_fence_delta(self, line):
|
|
32
|
+
"""+1 if `line` opens a block nested inside a listing, -1 if it closes one.
|
|
33
|
+
|
|
34
|
+
A markdown file legitimately contains fenced code blocks, and a model
|
|
35
|
+
writes the same three backticks for the inner block as for the listing
|
|
36
|
+
wrapped around it. When the opening and closing markers are identical,
|
|
37
|
+
an info string ("```json") is the only thing distinguishing one from the
|
|
38
|
+
other, so that is what this reads.
|
|
39
|
+
|
|
40
|
+
A language-less inner block ("```" alone opening a code sample) stays
|
|
41
|
+
ambiguous -- nothing in the text separates it from the fence that ends
|
|
42
|
+
the listing -- and is still read as the end of the listing.
|
|
43
|
+
"""
|
|
44
|
+
open_fence, close_fence = self.fence
|
|
45
|
+
|
|
46
|
+
if open_fence != close_fence:
|
|
47
|
+
if line.startswith(open_fence):
|
|
48
|
+
return 1
|
|
49
|
+
if line.startswith(close_fence):
|
|
50
|
+
return -1
|
|
51
|
+
return 0
|
|
52
|
+
|
|
53
|
+
if not line.startswith(open_fence):
|
|
54
|
+
return 0
|
|
55
|
+
|
|
56
|
+
return 1 if line[len(open_fence) :].strip() else -1
|
|
57
|
+
|
|
31
58
|
def fence_fname(self, lines, i, chat_files):
|
|
32
59
|
"""The file the fence at `lines[i]` is listing, or None if that line names none.
|
|
33
60
|
|
|
@@ -60,12 +87,21 @@ class WholeFileCoder(Coder):
|
|
|
60
87
|
|
|
61
88
|
diff_fences = ("```diff", "```patch", f"{self.fence[0]}diff", f"{self.fence[0]}patch")
|
|
62
89
|
in_listing = False
|
|
90
|
+
listing_depth = 0
|
|
63
91
|
diff_fence = None
|
|
64
92
|
diff_header = None
|
|
65
93
|
for i, line in enumerate(lines[:-1]):
|
|
66
94
|
if in_listing:
|
|
67
|
-
|
|
68
|
-
|
|
95
|
+
# Fenced blocks inside the listing are content, not the end of
|
|
96
|
+
# it -- including a ```diff block in a file that documents one.
|
|
97
|
+
delta = self.nested_fence_delta(line)
|
|
98
|
+
if delta > 0:
|
|
99
|
+
listing_depth += 1
|
|
100
|
+
elif delta < 0:
|
|
101
|
+
if listing_depth:
|
|
102
|
+
listing_depth -= 1
|
|
103
|
+
else:
|
|
104
|
+
in_listing = False
|
|
69
105
|
continue
|
|
70
106
|
|
|
71
107
|
if line.startswith(diff_fences):
|
|
@@ -100,11 +136,29 @@ class WholeFileCoder(Coder):
|
|
|
100
136
|
fname = None
|
|
101
137
|
fname_source = None
|
|
102
138
|
new_lines = []
|
|
139
|
+
depth = 0
|
|
103
140
|
for i, line in enumerate(lines):
|
|
104
|
-
|
|
141
|
+
is_fence = line.startswith(self.fence[0]) or line.startswith(self.fence[1])
|
|
142
|
+
|
|
143
|
+
if is_fence and fname is not None:
|
|
144
|
+
# The listing ends at its own closing fence, not at the first
|
|
145
|
+
# fence inside it. Reading an inner block as the end truncated
|
|
146
|
+
# the file there and wrote everything after it to a file named
|
|
147
|
+
# after whatever line happened to precede the next fence.
|
|
148
|
+
if self.nested_fence_delta(line) > 0:
|
|
149
|
+
depth += 1
|
|
150
|
+
new_lines.append(line)
|
|
151
|
+
continue
|
|
152
|
+
if depth:
|
|
153
|
+
depth -= 1
|
|
154
|
+
new_lines.append(line)
|
|
155
|
+
continue
|
|
156
|
+
|
|
157
|
+
if is_fence:
|
|
105
158
|
if fname is not None:
|
|
106
159
|
# ending an existing block
|
|
107
160
|
saw_fname = None
|
|
161
|
+
depth = 0
|
|
108
162
|
|
|
109
163
|
full_path = self.abs_root_path(fname)
|
|
110
164
|
|
|
@@ -228,7 +228,7 @@ def write_streamlit_credentials():
|
|
|
228
228
|
print("Streamlit credentials already exist.")
|
|
229
229
|
|
|
230
230
|
|
|
231
|
-
def launch_gui(args):
|
|
231
|
+
def launch_gui(args, address="127.0.0.1"):
|
|
232
232
|
from streamlit.web import cli
|
|
233
233
|
|
|
234
234
|
from patch import gui
|
|
@@ -243,7 +243,16 @@ def launch_gui(args):
|
|
|
243
243
|
|
|
244
244
|
st_args = ["run", target]
|
|
245
245
|
|
|
246
|
+
# Streamlit binds every interface when it is not told otherwise, which put
|
|
247
|
+
# an unauthenticated UI holding the user's repository and API keys on the
|
|
248
|
+
# local network for anyone who ran --browser on a shared wifi. Loopback is
|
|
249
|
+
# the default; --gui-address is how you opt out of it.
|
|
250
|
+
if address not in ("127.0.0.1", "localhost", "::1"):
|
|
251
|
+
print(f"Warning: the browser UI will accept connections on {address}.")
|
|
252
|
+
print("It has no authentication: anyone who can reach it can edit your repository.")
|
|
253
|
+
|
|
246
254
|
st_args += [
|
|
255
|
+
f"--server.address={address}",
|
|
247
256
|
"--browser.gatherUsageStats=false",
|
|
248
257
|
"--runner.magicEnabled=false",
|
|
249
258
|
"--server.runOnSave=false",
|
|
@@ -980,7 +989,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
|
|
980
989
|
analytics.event("exit", reason="Streamlit not installed")
|
|
981
990
|
return
|
|
982
991
|
analytics.event("gui session")
|
|
983
|
-
launch_gui(argv)
|
|
992
|
+
launch_gui(argv, args.gui_address)
|
|
984
993
|
analytics.event("exit", reason="GUI session ended")
|
|
985
994
|
return
|
|
986
995
|
|
|
@@ -1187,6 +1196,7 @@ def main(argv=None, input=None, output=None, force_git_root=None, return_coder=F
|
|
|
1187
1196
|
chat_language=args.chat_language,
|
|
1188
1197
|
commit_language=args.commit_language,
|
|
1189
1198
|
detect_urls=args.detect_urls,
|
|
1199
|
+
detect_file_mentions=args.detect_file_mentions,
|
|
1190
1200
|
auto_copy_context=args.copy_paste,
|
|
1191
1201
|
auto_accept_architect=args.auto_accept_architect,
|
|
1192
1202
|
add_gitignore_files=args.add_gitignore_files,
|
|
@@ -171,6 +171,15 @@ class GitRepo:
|
|
|
171
171
|
- User commit with explicit no-committer: patch_edits=False,
|
|
172
172
|
--no-attribute-committer -> Author=You, Committer=You
|
|
173
173
|
"""
|
|
174
|
+
if not fnames and self.subtree_only:
|
|
175
|
+
# `git commit -a` commits every dirty file in the repository, which
|
|
176
|
+
# is not what --subtree-only asked for: the session is scoped to one
|
|
177
|
+
# directory, and sweeping in unrelated work elsewhere in the tree is
|
|
178
|
+
# a commit the user cannot see coming. Name the files instead.
|
|
179
|
+
fnames = [f for f in self.get_dirty_files() if self.path_in_subtree(f)]
|
|
180
|
+
if not fnames:
|
|
181
|
+
return
|
|
182
|
+
|
|
174
183
|
if not fnames and not self.repo.is_dirty():
|
|
175
184
|
return
|
|
176
185
|
|
|
@@ -527,20 +536,31 @@ class GitRepo:
|
|
|
527
536
|
self.ignore_file_cache[fname] = result
|
|
528
537
|
return result
|
|
529
538
|
|
|
530
|
-
def
|
|
531
|
-
|
|
532
|
-
try:
|
|
533
|
-
fname_path = Path(self.normalize_path(fname))
|
|
534
|
-
cwd_path = Path.cwd().resolve().relative_to(Path(self.root).resolve())
|
|
535
|
-
except ValueError:
|
|
536
|
-
# Issue #1524
|
|
537
|
-
# ValueError: 'C:\\dev\\squid-certbot' is not in the subpath of
|
|
538
|
-
# 'C:\\dev\\squid-certbot'
|
|
539
|
-
# Clearly, fname is not under cwd... so ignore it
|
|
540
|
-
return True
|
|
539
|
+
def path_in_subtree(self, fname):
|
|
540
|
+
"""Is `fname` inside the subtree this session is scoped to?
|
|
541
541
|
|
|
542
|
-
|
|
543
|
-
|
|
542
|
+
Always True without `--subtree-only`, which is what scopes it. Every
|
|
543
|
+
question about that scope goes through here, so committing and ignoring
|
|
544
|
+
cannot drift apart on what "in the subtree" means.
|
|
545
|
+
"""
|
|
546
|
+
if not self.subtree_only:
|
|
547
|
+
return True
|
|
548
|
+
|
|
549
|
+
try:
|
|
550
|
+
fname_path = Path(self.normalize_path(fname))
|
|
551
|
+
cwd_path = Path.cwd().resolve().relative_to(Path(self.root).resolve())
|
|
552
|
+
except ValueError:
|
|
553
|
+
# Issue #1524
|
|
554
|
+
# ValueError: 'C:\\dev\\squid-certbot' is not in the subpath of
|
|
555
|
+
# 'C:\\dev\\squid-certbot'
|
|
556
|
+
# Clearly, fname is not under cwd... so it is not in the subtree
|
|
557
|
+
return False
|
|
558
|
+
|
|
559
|
+
return cwd_path in fname_path.parents or fname_path == cwd_path
|
|
560
|
+
|
|
561
|
+
def ignored_file_raw(self, fname):
|
|
562
|
+
if not self.path_in_subtree(fname):
|
|
563
|
+
return True
|
|
544
564
|
|
|
545
565
|
if not self.patch_ignore_file or not self.patch_ignore_file.is_file():
|
|
546
566
|
return False
|
|
@@ -55,6 +55,13 @@ EXECUTION_KEYS = {
|
|
|
55
55
|
"editor",
|
|
56
56
|
"verify-ssl",
|
|
57
57
|
"git-commit-verify",
|
|
58
|
+
# The repository is the one supplying the URLs -- a README pointing at
|
|
59
|
+
# 169.254.169.254 plus `allow-private-urls: true` in its own config is the
|
|
60
|
+
# whole attack, assembled from two files it controls.
|
|
61
|
+
"allow-private-urls",
|
|
62
|
+
# Moves an unauthenticated UI holding this repository and the user's keys
|
|
63
|
+
# off loopback and onto the network.
|
|
64
|
+
"gui-address",
|
|
58
65
|
}
|
|
59
66
|
|
|
60
67
|
# Substitute credentials or redirect where prompts and code are sent. The .env
|
|
@@ -151,6 +158,7 @@ REVIEWED_SAFE_KEYS = {
|
|
|
151
158
|
"editor-edit-format": "an edit-format name",
|
|
152
159
|
"encoding": "a codec name",
|
|
153
160
|
"line-endings": "an enum",
|
|
161
|
+
"detect-file-mentions": "a boolean; whether to offer to add mentioned files, still confirmed",
|
|
154
162
|
}
|
|
155
163
|
|
|
156
164
|
|