auto-coder-web 0.1.82__tar.gz → 0.1.83__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.
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/PKG-INFO +3 -2
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/file_manager.py +9 -7
- auto_coder_web-0.1.83/src/auto_coder_web/routers/rules_router.py +601 -0
- auto_coder_web-0.1.83/src/auto_coder_web/version.py +1 -0
- auto_coder_web-0.1.83/src/auto_coder_web/web/assets/HistoryPanel-B59ay4X7.js +1 -0
- auto_coder_web-0.1.82/src/auto_coder_web/web/assets/cssMode-CQYz0o1d.js → auto_coder_web-0.1.83/src/auto_coder_web/web/assets/cssMode-dfzmIRw_.js +1 -1
- auto_coder_web-0.1.82/src/auto_coder_web/web/assets/freemarker2-BJU3cSen.js → auto_coder_web-0.1.83/src/auto_coder_web/web/assets/freemarker2-CD79_SV-.js +1 -1
- auto_coder_web-0.1.82/src/auto_coder_web/web/assets/handlebars-VxUdciXQ.js → auto_coder_web-0.1.83/src/auto_coder_web/web/assets/handlebars-B_inQ7Ga.js +2 -2
- auto_coder_web-0.1.82/src/auto_coder_web/web/assets/html-DEgskwXL.js → auto_coder_web-0.1.83/src/auto_coder_web/web/assets/html-s8IXsV2v.js +1 -1
- auto_coder_web-0.1.82/src/auto_coder_web/web/assets/htmlMode-58cXxJlI.js → auto_coder_web-0.1.83/src/auto_coder_web/web/assets/htmlMode-BNdCO4Um.js +1 -1
- auto_coder_web-0.1.82/src/auto_coder_web/web/assets/javascript-DbZlm-ig.js → auto_coder_web-0.1.83/src/auto_coder_web/web/assets/javascript-D_ZBRKl9.js +1 -1
- auto_coder_web-0.1.82/src/auto_coder_web/web/assets/jsonMode-C2HKgmE0.js → auto_coder_web-0.1.83/src/auto_coder_web/web/assets/jsonMode-lWocgRYn.js +1 -1
- auto_coder_web-0.1.82/src/auto_coder_web/web/assets/liquid-BFft-XkQ.js → auto_coder_web-0.1.83/src/auto_coder_web/web/assets/liquid-CPaH0eVF.js +1 -1
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/main.js +235 -235
- auto_coder_web-0.1.82/src/auto_coder_web/web/assets/mdx-DZdDhrJW.js → auto_coder_web-0.1.83/src/auto_coder_web/web/assets/mdx-DRx1b0qs.js +1 -1
- auto_coder_web-0.1.82/src/auto_coder_web/web/assets/python-DOHUGzLU.js → auto_coder_web-0.1.83/src/auto_coder_web/web/assets/python-5rTPwuda.js +2 -2
- auto_coder_web-0.1.82/src/auto_coder_web/web/assets/razor-Dh5mSHi2.js → auto_coder_web-0.1.83/src/auto_coder_web/web/assets/razor-zn6WfQ9V.js +1 -1
- auto_coder_web-0.1.82/src/auto_coder_web/web/assets/tsMode-tyI6CeIR.js → auto_coder_web-0.1.83/src/auto_coder_web/web/assets/tsMode-CkhihvQ0.js +1 -1
- auto_coder_web-0.1.82/src/auto_coder_web/web/assets/typescript-DZzM_VgT.js → auto_coder_web-0.1.83/src/auto_coder_web/web/assets/typescript-DH2E4fY1.js +2 -2
- auto_coder_web-0.1.82/src/auto_coder_web/web/assets/xml-Dl6413Na.js → auto_coder_web-0.1.83/src/auto_coder_web/web/assets/xml-kipCCfsB.js +2 -2
- auto_coder_web-0.1.82/src/auto_coder_web/web/assets/yaml-DML583wh.js → auto_coder_web-0.1.83/src/auto_coder_web/web/assets/yaml-BI9EB_1X.js +1 -1
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web.egg-info/PKG-INFO +3 -2
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web.egg-info/SOURCES.txt +17 -16
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web.egg-info/requires.txt +2 -1
- auto_coder_web-0.1.82/src/auto_coder_web/version.py +0 -1
- auto_coder_web-0.1.82/src/auto_coder_web/web/assets/HistoryPanel-gl864o6H.js +0 -1
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/README.md +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/setup.cfg +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/setup.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/__init__.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/auto_coder_runner_wrapper.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/common_router/__init__.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/common_router/active_context_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/common_router/auto_coder_conf_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/common_router/chat_list_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/common_router/compiler_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/common_router/completions_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/common_router/file_group_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/common_router/file_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/common_router/filecacher.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/common_router/model_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/expert_routers/__init__.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/expert_routers/history_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/file_cacher/__init__.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/file_cacher/filecacher.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/file_group.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/init_project.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/json_file_storage.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/lang.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/proxy.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/routers/__init__.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/routers/auto_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/routers/chat_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/routers/coding_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/routers/commit_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/routers/config_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/routers/direct_chat_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/routers/editable_preview_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/routers/index_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/routers/mcp_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/routers/rag_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/routers/settings_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/routers/todo_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/routers/upload_router.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/terminal.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/types.py +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/abap-BrgZPUOV.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/apex-DyP6w7ZV.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/azcli-BaLxmfj-.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/bat-CFOPXBzS.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/bicep-BfEKNvv3.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/cameligo-BFG1Mk7z.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/clojure-DTECt2xU.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/codicon-DCmgc-ay.ttf +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/coffee-CDGzqUPQ.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/cpp-CLLBncYj.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/csharp-dUCx_-0o.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/csp-5Rap-vPy.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/css-D3h14YRZ.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/cypher-DrQuvNYM.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/dart-CFKIUWau.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/dockerfile-Zznr-cwX.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/ecl-Ce3n6wWz.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/elixir-deUWdS0T.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/flow9-i9-g7ZhI.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/fsharp-CzKuDChf.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/go-Cphgjts3.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/graphql-Cg7bfA9N.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/hcl-0cvrggvQ.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/ini-Drc7WvVn.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/java-B_fMsGYe.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/julia-Bqgm2twL.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/kotlin-BSkB5QuD.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/less-BsTHnhdd.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/lexon-YWi4-JPR.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/lua-nf6ki56Z.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/m3-Cpb6xl2v.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/main-B3_hzhoO.css +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/markdown-DSZPf7rp.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/mips-B_c3zf-v.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/msdax-rUNN04Wq.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/mysql-DDwshQtU.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/objective-c-B5zXfXm9.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/pascal-CXOwvkN_.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/pascaligo-Bc-ZgV77.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/perl-CwNk8-XU.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/pgsql-tGk8EFnU.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/php-CpIb_Oan.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/pla-B03wrqEc.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/postiats-BKlk5iyT.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/powerquery-Bhzvs7bI.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/powershell-Dd3NCNK9.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/protobuf-COyEY5Pt.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/pug-BaJupSGV.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/qsharp-DXyYeYxl.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/r-CdQndTaG.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/redis-CVwtpugi.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/redshift-25W9uPmb.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/restructuredtext-DfzH4Xui.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/ruby-Cp1zYvxS.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/rust-D5C2fndG.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/sb-CDntyWJ8.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/scala-BoFRg7Ot.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/scheme-Bio4gycK.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/scss-4Ik7cdeQ.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/shell-CX-rkNHf.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/solidity-Tw7wswEv.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/sophia-C5WLch3f.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/sparql-DHaeiCBh.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/sql-CCSDG5nI.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/st-pnP8ivHi.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/swift-DwJ7jVG9.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/systemverilog-B9Xyijhd.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/tcl-DnHyzjbg.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/twig-CPajHgWi.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/typespec-D-MeaMDU.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/vb-DgyLZaXg.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/assets/wgsl-BIv9DU6q.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/bridge.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/favicon.ico +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/index.html +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/logo192.png +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/logo512.png +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/manifest.json +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/base/browser/ui/codicons/codicon/codicon.ttf +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/base/worker/workerMain.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/abap/abap.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/apex/apex.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/azcli/azcli.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/bat/bat.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/bicep/bicep.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/cameligo/cameligo.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/clojure/clojure.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/coffee/coffee.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/cpp/cpp.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/csharp/csharp.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/csp/csp.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/css/css.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/cypher/cypher.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/dart/dart.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/dockerfile/dockerfile.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/ecl/ecl.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/elixir/elixir.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/flow9/flow9.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/freemarker2/freemarker2.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/fsharp/fsharp.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/go/go.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/graphql/graphql.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/handlebars/handlebars.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/hcl/hcl.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/html/html.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/ini/ini.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/java/java.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/javascript/javascript.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/julia/julia.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/kotlin/kotlin.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/less/less.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/lexon/lexon.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/liquid/liquid.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/lua/lua.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/m3/m3.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/markdown/markdown.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/mdx/mdx.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/mips/mips.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/msdax/msdax.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/mysql/mysql.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/objective-c/objective-c.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/pascal/pascal.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/pascaligo/pascaligo.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/perl/perl.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/pgsql/pgsql.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/php/php.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/pla/pla.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/postiats/postiats.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/powerquery/powerquery.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/powershell/powershell.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/protobuf/protobuf.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/pug/pug.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/python/python.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/qsharp/qsharp.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/r/r.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/razor/razor.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/redis/redis.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/redshift/redshift.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/restructuredtext/restructuredtext.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/ruby/ruby.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/rust/rust.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/sb/sb.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/scala/scala.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/scheme/scheme.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/scss/scss.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/shell/shell.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/solidity/solidity.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/sophia/sophia.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/sparql/sparql.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/sql/sql.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/st/st.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/swift/swift.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/systemverilog/systemverilog.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/tcl/tcl.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/twig/twig.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/typescript/typescript.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/typespec/typespec.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/vb/vb.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/wgsl/wgsl.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/xml/xml.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/basic-languages/yaml/yaml.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/editor/editor.main.css +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/editor/editor.main.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/language/css/cssMode.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/language/css/cssWorker.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/language/html/htmlMode.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/language/html/htmlWorker.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/language/json/jsonMode.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/language/json/jsonWorker.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/language/typescript/tsMode.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/language/typescript/tsWorker.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/loader.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/nls.messages.de.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/nls.messages.es.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/nls.messages.fr.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/nls.messages.it.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/nls.messages.ja.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/nls.messages.ko.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/nls.messages.ru.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/nls.messages.zh-cn.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/monaco-editor/min/vs/nls.messages.zh-tw.js +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web/web/robots.txt +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web.egg-info/dependency_links.txt +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web.egg-info/entry_points.txt +0 -0
- {auto_coder_web-0.1.82 → auto_coder_web-0.1.83}/src/auto_coder_web.egg-info/top_level.txt +0 -0
@@ -1,13 +1,13 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: auto_coder_web
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.83
|
4
4
|
Summary: auto-coder.web: A Python Project
|
5
5
|
Author: allwefantasy
|
6
6
|
Classifier: Programming Language :: Python :: 3.10
|
7
7
|
Classifier: Programming Language :: Python :: 3.11
|
8
8
|
Classifier: Programming Language :: Python :: 3.12
|
9
9
|
Description-Content-Type: text/markdown
|
10
|
-
Requires-Dist: auto-coder>=0.1.
|
10
|
+
Requires-Dist: auto-coder>=0.1.356
|
11
11
|
Requires-Dist: aiofiles
|
12
12
|
Requires-Dist: psutil
|
13
13
|
Requires-Dist: watchdog
|
@@ -17,6 +17,7 @@ Requires-Dist: pywinpty; sys_platform == "win32"
|
|
17
17
|
Requires-Dist: pyyaml
|
18
18
|
Requires-Dist: gitpython
|
19
19
|
Requires-Dist: filelock>=3.13.1
|
20
|
+
Requires-Dist: python-multipart
|
20
21
|
|
21
22
|
# auto-coder.web
|
22
23
|
|
@@ -40,10 +40,11 @@ def get_directory_tree(root_path: str, path: str = None, lazy: bool = False) ->
|
|
40
40
|
|
41
41
|
def should_ignore(name: str) -> bool:
|
42
42
|
"""Check if a file or directory should be ignored"""
|
43
|
-
|
44
|
-
|
43
|
+
allowed_hidden_files = {'.autocoderrules', '.gitignore', '.autocoderignore'}
|
44
|
+
# Ignore hidden files/directories, unless they are explicitly allowed
|
45
|
+
if name.startswith('.') and name not in allowed_hidden_files:
|
45
46
|
return True
|
46
|
-
# Ignore exact matches and pattern matches
|
47
|
+
# Ignore exact matches and pattern matches from IGNORE_PATTERNS
|
47
48
|
return name in IGNORE_PATTERNS
|
48
49
|
|
49
50
|
def build_tree(current_path: str) -> List[Dict[str, Any]]:
|
@@ -146,11 +147,12 @@ async def get_directory_tree_async(root_path: str, path: str = None, lazy: bool
|
|
146
147
|
|
147
148
|
def should_ignore(name: str) -> bool:
|
148
149
|
"""Check if a file or directory should be ignored"""
|
149
|
-
|
150
|
-
|
151
|
-
|
150
|
+
allowed_hidden_files = {'.autocoderrules', '.gitignore', '.autocoderignore'}
|
151
|
+
# Ignore hidden files/directories (starting with '.'), unless explicitly allowed
|
152
|
+
## and name != ".auto-coder": # Original comment kept for context if needed
|
153
|
+
if name.startswith('.') and name not in allowed_hidden_files:
|
152
154
|
return True
|
153
|
-
# Ignore exact matches
|
155
|
+
# Ignore exact matches from IGNORE_PATTERNS
|
154
156
|
return name in IGNORE_PATTERNS
|
155
157
|
|
156
158
|
async def build_tree(current_path: str) -> List[Dict[str, Any]]:
|
@@ -0,0 +1,601 @@
|
|
1
|
+
import asyncio
|
2
|
+
import json
|
3
|
+
import os
|
4
|
+
import fnmatch
|
5
|
+
import pathspec
|
6
|
+
from threading import Thread
|
7
|
+
from concurrent.futures import ThreadPoolExecutor
|
8
|
+
from fastapi import APIRouter, HTTPException, Request, Depends, Query
|
9
|
+
from fastapi.responses import StreamingResponse
|
10
|
+
from pydantic import BaseModel, Field
|
11
|
+
from typing import Dict, Any, Optional, List
|
12
|
+
|
13
|
+
from autocoder.common.rulefiles.autocoderrules_utils import get_rules, AutocoderRulesManager, RuleFile, parse_rule_file
|
14
|
+
from autocoder.agent.auto_learn import AutoLearn
|
15
|
+
from autocoder.common import SourceCode, SourceCodeList
|
16
|
+
from autocoder.auto_coder_runner import get_final_config, get_single_llm, get_memory
|
17
|
+
from autocoder.chat_auto_coder_lang import get_message, get_message_with_format
|
18
|
+
from autocoder.rag.token_counter import count_tokens
|
19
|
+
from autocoder.events.event_manager_singleton import get_event_manager, gengerate_event_file_path, get_event_file_path
|
20
|
+
from autocoder.events import event_content as EventContentCreator
|
21
|
+
from autocoder.events.event_types import EventType
|
22
|
+
from autocoder.common.global_cancel import global_cancel, CancelRequestedException
|
23
|
+
from autocoder.command_parser import CommandParser
|
24
|
+
# Add import for AutoCoderRunnerWrapper
|
25
|
+
from auto_coder_web.auto_coder_runner_wrapper import AutoCoderRunnerWrapper
|
26
|
+
from loguru import logger
|
27
|
+
|
28
|
+
router = APIRouter()
|
29
|
+
|
30
|
+
# Thread pool for cancellation, similar to coding_router
|
31
|
+
cancel_thread_pool = ThreadPoolExecutor(max_workers=5)
|
32
|
+
|
33
|
+
# --- Pydantic Models ---
|
34
|
+
|
35
|
+
class RuleInfo(BaseModel):
|
36
|
+
file_path: str
|
37
|
+
token_count: int
|
38
|
+
description: Optional[str] = None
|
39
|
+
globs: Optional[List[str]] = None
|
40
|
+
always_apply: Optional[bool] = None
|
41
|
+
content: Optional[str] = None # Optionally include content for 'get'
|
42
|
+
|
43
|
+
class RuleListResponse(BaseModel):
|
44
|
+
rules: List[RuleInfo]
|
45
|
+
|
46
|
+
class RulePatternRequest(BaseModel):
|
47
|
+
pattern: str
|
48
|
+
|
49
|
+
class RuleAnalyzeRequest(BaseModel):
|
50
|
+
query: Optional[str] = ""
|
51
|
+
# Add other relevant parameters if needed, e.g., specific files to analyze
|
52
|
+
# files: Optional[List[str]] = None
|
53
|
+
|
54
|
+
class RuleCommitRequest(BaseModel):
|
55
|
+
commit_id: str
|
56
|
+
query: str
|
57
|
+
|
58
|
+
class RuleGeneralResponse(BaseModel):
|
59
|
+
status: str
|
60
|
+
message: str
|
61
|
+
|
62
|
+
class RuleHelpResponse(BaseModel):
|
63
|
+
help_text: str
|
64
|
+
|
65
|
+
class AsyncTaskResponse(BaseModel):
|
66
|
+
event_file_id: str
|
67
|
+
|
68
|
+
class UserResponseRequest(BaseModel):
|
69
|
+
event_id: str
|
70
|
+
event_file_id: str
|
71
|
+
response: str # For potential future use if analyze/commit become interactive
|
72
|
+
|
73
|
+
class CancelTaskRequest(BaseModel):
|
74
|
+
event_file_id: str
|
75
|
+
|
76
|
+
# --- Dependencies ---
|
77
|
+
|
78
|
+
async def get_project_path(request: Request) -> str:
|
79
|
+
"""
|
80
|
+
Gets the project path from the FastAPI request state.
|
81
|
+
"""
|
82
|
+
path = request.app.state.project_path
|
83
|
+
logger.debug(f"Retrieved project path: {path}")
|
84
|
+
if not path or not os.path.isdir(path):
|
85
|
+
logger.error(f"Invalid project path configured: {path}")
|
86
|
+
raise HTTPException(status_code=500, detail="Server configuration error: Project path is invalid or not set.")
|
87
|
+
# Ensure rules manager uses the correct project root for this request context
|
88
|
+
# This might require adjusting AutocoderRulesManager if it's a strict singleton
|
89
|
+
# For now, we rely on get_rules taking project_root
|
90
|
+
return path
|
91
|
+
|
92
|
+
# --- Helper Functions ---
|
93
|
+
|
94
|
+
def _get_rules_logic(project_root: str, pattern: str = "*") -> List[RuleInfo]:
|
95
|
+
"""Shared logic for listing/getting rules."""
|
96
|
+
logger.info(f"Fetching rules for project: {project_root} with pattern: {pattern}")
|
97
|
+
# Use the project_root specific function
|
98
|
+
rules_content = get_rules(project_root=project_root)
|
99
|
+
if not rules_content:
|
100
|
+
logger.warning(f"No rules found in project: {project_root}")
|
101
|
+
return []
|
102
|
+
|
103
|
+
matched_rules = []
|
104
|
+
rule_files_info = []
|
105
|
+
|
106
|
+
# Normalize pattern for pathspec
|
107
|
+
if pattern == "*":
|
108
|
+
# Match all .md files within the rules directories
|
109
|
+
spec = pathspec.PathSpec.from_lines(pathspec.patterns.GitWildMatchPattern, ["*.md"])
|
110
|
+
else:
|
111
|
+
# Use the provided pattern
|
112
|
+
spec = pathspec.PathSpec.from_lines(pathspec.patterns.GitWildMatchPattern, [pattern])
|
113
|
+
|
114
|
+
for file_path, content in rules_content.items():
|
115
|
+
try:
|
116
|
+
# Use relative path for matching if possible
|
117
|
+
if os.path.isabs(file_path):
|
118
|
+
try:
|
119
|
+
rel_path = os.path.relpath(file_path, project_root)
|
120
|
+
except ValueError:
|
121
|
+
# Handle cases where file_path is not under project_root (e.g., different drive on Windows)
|
122
|
+
# In such cases, maybe match against the full path or just the filename?
|
123
|
+
# Matching against filename seems safer for wildcard patterns.
|
124
|
+
rel_path = os.path.basename(file_path)
|
125
|
+
else:
|
126
|
+
rel_path = file_path
|
127
|
+
|
128
|
+
# Perform matching
|
129
|
+
if spec.match_file(rel_path):
|
130
|
+
matched_rules.append((file_path, content))
|
131
|
+
except Exception as e:
|
132
|
+
logger.error(f"Error matching pattern '{pattern}' against file '{file_path}': {str(e)}")
|
133
|
+
# Continue to next file
|
134
|
+
|
135
|
+
if not matched_rules:
|
136
|
+
logger.info(f"No rules matched pattern '{pattern}' in project: {project_root}")
|
137
|
+
return []
|
138
|
+
|
139
|
+
# Parse matched files and gather info
|
140
|
+
for file_path, content in sorted(matched_rules):
|
141
|
+
try:
|
142
|
+
# Use the project_root specific function
|
143
|
+
parsed_rule = parse_rule_file(file_path, project_root=project_root)
|
144
|
+
token_count = count_tokens(content) # Count tokens from raw content
|
145
|
+
rule_info = RuleInfo(
|
146
|
+
file_path=file_path,
|
147
|
+
token_count=token_count,
|
148
|
+
description=parsed_rule.description,
|
149
|
+
globs=parsed_rule.globs,
|
150
|
+
always_apply=parsed_rule.always_apply,
|
151
|
+
content=content # Include content for 'get' scenarios
|
152
|
+
)
|
153
|
+
rule_files_info.append(rule_info)
|
154
|
+
except Exception as e:
|
155
|
+
logger.error(f"Error processing rule file {file_path}: {e}")
|
156
|
+
# Optionally append a rule with an error state
|
157
|
+
|
158
|
+
logger.info(f"Found {len(rule_files_info)} rules matching pattern '{pattern}'")
|
159
|
+
return rule_files_info
|
160
|
+
|
161
|
+
|
162
|
+
# --- API Endpoints ---
|
163
|
+
|
164
|
+
@router.get("/api/rules/list", response_model=RuleListResponse)
|
165
|
+
async def list_rules(
|
166
|
+
pattern: Optional[str] = Query("*", description="Wildcard pattern to filter rule files (e.g., '*.md', 'common*')"),
|
167
|
+
project_path: str = Depends(get_project_path)
|
168
|
+
):
|
169
|
+
"""
|
170
|
+
Lists rule files, optionally filtered by a wildcard pattern.
|
171
|
+
Returns basic info (path, token count, metadata).
|
172
|
+
"""
|
173
|
+
try:
|
174
|
+
rules_info = _get_rules_logic(project_path, pattern)
|
175
|
+
# For list, we don't need the full content
|
176
|
+
for rule in rules_info:
|
177
|
+
rule.content = None
|
178
|
+
return RuleListResponse(rules=rules_info)
|
179
|
+
except Exception as e:
|
180
|
+
logger.exception(f"Error listing rules with pattern '{pattern}': {e}")
|
181
|
+
raise HTTPException(status_code=500, detail=f"Failed to list rules: {str(e)}")
|
182
|
+
|
183
|
+
@router.get("/api/rules/get", response_model=RuleListResponse)
|
184
|
+
async def get_rule_content(
|
185
|
+
pattern: str = Query(..., description="Wildcard pattern to match rule files for content retrieval."),
|
186
|
+
project_path: str = Depends(get_project_path)
|
187
|
+
):
|
188
|
+
"""
|
189
|
+
Gets the content of rule files matching the specified pattern.
|
190
|
+
"""
|
191
|
+
if not pattern:
|
192
|
+
raise HTTPException(status_code=400, detail="Pattern parameter is required.")
|
193
|
+
try:
|
194
|
+
# _get_rules_logic includes content by default
|
195
|
+
rules_info = _get_rules_logic(project_path, pattern)
|
196
|
+
if not rules_info:
|
197
|
+
raise HTTPException(status_code=404, detail=f"No rule files found matching pattern: {pattern}")
|
198
|
+
return RuleListResponse(rules=rules_info)
|
199
|
+
except HTTPException as e:
|
200
|
+
raise e # Re-raise HTTP exceptions
|
201
|
+
except Exception as e:
|
202
|
+
logger.exception(f"Error getting rule content with pattern '{pattern}': {e}")
|
203
|
+
raise HTTPException(status_code=500, detail=f"Failed to get rule content: {str(e)}")
|
204
|
+
|
205
|
+
|
206
|
+
@router.delete("/api/rules/remove", response_model=RuleGeneralResponse)
|
207
|
+
async def remove_rules(
|
208
|
+
pattern: str = Query(..., description="Wildcard pattern identifying rules to remove."),
|
209
|
+
project_path: str = Depends(get_project_path)
|
210
|
+
):
|
211
|
+
"""
|
212
|
+
Removes rule files matching the specified pattern.
|
213
|
+
"""
|
214
|
+
if not pattern:
|
215
|
+
raise HTTPException(status_code=400, detail="Pattern parameter is required.")
|
216
|
+
|
217
|
+
logger.info(f"Attempting to remove rules matching pattern '{pattern}' in project: {project_path}")
|
218
|
+
|
219
|
+
# Get rules manager instance specific to the project path if possible, or re-init logic
|
220
|
+
# For simplicity, we'll re-fetch rules based on project_path
|
221
|
+
rules_content = get_rules(project_root=project_path)
|
222
|
+
if not rules_content:
|
223
|
+
raise HTTPException(status_code=404, detail="No rule files found to remove.")
|
224
|
+
|
225
|
+
files_to_remove = []
|
226
|
+
try:
|
227
|
+
spec = pathspec.PathSpec.from_lines(pathspec.patterns.GitWildMatchPattern, [pattern])
|
228
|
+
for file_path in rules_content.keys():
|
229
|
+
if os.path.isabs(file_path):
|
230
|
+
try:
|
231
|
+
rel_path = os.path.relpath(file_path, project_path)
|
232
|
+
except ValueError:
|
233
|
+
rel_path = os.path.basename(file_path) # Fallback for cross-drive paths etc.
|
234
|
+
else:
|
235
|
+
rel_path = file_path
|
236
|
+
|
237
|
+
if spec.match_file(rel_path):
|
238
|
+
files_to_remove.append(file_path)
|
239
|
+
|
240
|
+
except Exception as e:
|
241
|
+
logger.error(f"Error matching pattern '{pattern}' for removal: {str(e)}")
|
242
|
+
raise HTTPException(status_code=400, detail=f"Invalid pattern '{pattern}': {str(e)}")
|
243
|
+
|
244
|
+
if not files_to_remove:
|
245
|
+
raise HTTPException(status_code=404, detail=f"No rule files found matching pattern '{pattern}' to remove.")
|
246
|
+
|
247
|
+
removed_count = 0
|
248
|
+
errors = []
|
249
|
+
for file_path in files_to_remove:
|
250
|
+
try:
|
251
|
+
os.remove(file_path)
|
252
|
+
removed_count += 1
|
253
|
+
logger.info(f"Removed rule file: {file_path}")
|
254
|
+
except Exception as e:
|
255
|
+
error_msg = f"Failed to remove file {file_path}: {str(e)}"
|
256
|
+
logger.error(error_msg)
|
257
|
+
errors.append(error_msg)
|
258
|
+
|
259
|
+
# Force reload rules in the manager if it's a shared instance (tricky)
|
260
|
+
# Or simply rely on next get_rules call to reflect the change
|
261
|
+
# AutocoderRulesManager()._load_rules() # This might affect other requests if singleton
|
262
|
+
|
263
|
+
if errors:
|
264
|
+
raise HTTPException(status_code=500, detail=f"Removed {removed_count} file(s) but encountered errors: {'; '.join(errors)}")
|
265
|
+
|
266
|
+
return RuleGeneralResponse(status="success", message=f"Successfully removed {removed_count} rule file(s) matching pattern '{pattern}'.")
|
267
|
+
|
268
|
+
@router.post("/api/rules/analyze", response_model=AsyncTaskResponse)
|
269
|
+
async def analyze_rules(
|
270
|
+
request_data: RuleAnalyzeRequest,
|
271
|
+
project_path: str = Depends(get_project_path)
|
272
|
+
):
|
273
|
+
"""
|
274
|
+
Analyzes current files (from memory/context) based on rules and an optional query.
|
275
|
+
Runs as a background task.
|
276
|
+
"""
|
277
|
+
event_file, file_id = gengerate_event_file_path(base_dir=project_path)
|
278
|
+
logger.info(f"Starting rule analysis task {file_id} for project: {project_path}")
|
279
|
+
|
280
|
+
def run_analysis_in_thread():
|
281
|
+
try:
|
282
|
+
global_cancel.register_token(event_file)
|
283
|
+
event_manager = get_event_manager(event_file)
|
284
|
+
event_manager.write_event(EventContentCreator.create_task_start(
|
285
|
+
"Rule Analysis Started", {"query": request_data.query}
|
286
|
+
).to_dict())
|
287
|
+
|
288
|
+
# --- Analysis Logic ---
|
289
|
+
args = get_final_config() # Gets config potentially influenced by project settings
|
290
|
+
llm = get_single_llm(args.model, product_mode=args.product_mode)
|
291
|
+
auto_learn = AutoLearn(llm=llm, args=args, project_root=project_path) # Pass project_path
|
292
|
+
|
293
|
+
# TODO: Determine how to get 'current_files' in the web context.
|
294
|
+
# This might need state management or explicit file list in request.
|
295
|
+
# Using a placeholder or assuming indexer provides files for now.
|
296
|
+
# Let's try fetching from memory first, might be empty in web context.
|
297
|
+
memory = get_memory(project_path) # Get memory specific to project
|
298
|
+
files = memory.get("current_files", {}).get("files", [])
|
299
|
+
|
300
|
+
if not files:
|
301
|
+
# If no files in memory, maybe analyze all project files? Or require explicit list?
|
302
|
+
# For now, report error if no files are targeted.
|
303
|
+
raise ValueError("No active files found in memory for analysis. Specify files or use a different mechanism.")
|
304
|
+
|
305
|
+
|
306
|
+
sources = SourceCodeList([])
|
307
|
+
event_manager.write_event(EventContentCreator.create_message(f"Reading {len(files)} files for analysis...").to_dict())
|
308
|
+
for file in files:
|
309
|
+
file_abs_path = os.path.join(project_path, file) if not os.path.isabs(file) else file
|
310
|
+
if not os.path.exists(file_abs_path):
|
311
|
+
logger.warning(f"File not found: {file_abs_path}, skipping.")
|
312
|
+
event_manager.write_event(EventContentCreator.create_warning(f"File not found: {file}").to_dict())
|
313
|
+
continue
|
314
|
+
try:
|
315
|
+
with open(file_abs_path, "r", encoding="utf-8") as f:
|
316
|
+
source_code = f.read()
|
317
|
+
sources.sources.append(SourceCode(module_name=file, source_code=source_code)) # Use relative path as module name
|
318
|
+
except Exception as e:
|
319
|
+
logger.error(f"Error reading file {file_abs_path}: {e}")
|
320
|
+
event_manager.write_event(EventContentCreator.create_error(
|
321
|
+
error_code="FILE_READ_ERROR",
|
322
|
+
error_message=f"Error reading file {file}: {e}"
|
323
|
+
).to_dict())
|
324
|
+
# Decide whether to continue or fail task
|
325
|
+
|
326
|
+
if not sources.sources:
|
327
|
+
raise ValueError("No valid source files could be read for analysis.")
|
328
|
+
|
329
|
+
event_manager.write_event(EventContentCreator.create_message(f"Analyzing {len(sources.sources)} files with query: '{request_data.query or 'Default analysis'}'").to_dict())
|
330
|
+
|
331
|
+
# Generate the analysis prompt text
|
332
|
+
prompt_text = auto_learn.analyze_modules.prompt(sources=sources, query=request_data.query)
|
333
|
+
|
334
|
+
# --- Use AutoCoderRunnerWrapper to execute the generated prompt ---
|
335
|
+
wrapper = AutoCoderRunnerWrapper(project_path)
|
336
|
+
wrapper.configure_wrapper(f"event_file:{event_file}")
|
337
|
+
# The coding_wapper will handle writing events, including completion/error
|
338
|
+
result = wrapper.coding_wapper(prompt_text)
|
339
|
+
# The wrapper logs completion internally, no need for manual completion event here.
|
340
|
+
# logger.info(f"Rule analysis task {file_id} completed successfully.") # Logged by wrapper
|
341
|
+
|
342
|
+
except CancelRequestedException:
|
343
|
+
logger.info(f"Rule analysis task {file_id} cancelled.")
|
344
|
+
get_event_manager(event_file).write_error(
|
345
|
+
EventContentCreator.create_error(error_code="499", error_message="Task cancelled by user.").to_dict()
|
346
|
+
)
|
347
|
+
except Exception as e:
|
348
|
+
logger.exception(f"Error during rule analysis task {file_id}: {e}")
|
349
|
+
get_event_manager(event_file).write_error(
|
350
|
+
EventContentCreator.create_error(error_code="500", error_message=str(e), details={}).to_dict()
|
351
|
+
)
|
352
|
+
finally:
|
353
|
+
global_cancel.unregister_token(event_file) # Clean up token
|
354
|
+
|
355
|
+
# Start the background thread
|
356
|
+
thread = Thread(target=run_analysis_in_thread, daemon=True)
|
357
|
+
thread.start()
|
358
|
+
|
359
|
+
return AsyncTaskResponse(event_file_id=file_id)
|
360
|
+
|
361
|
+
|
362
|
+
@router.post("/api/rules/commit", response_model=AsyncTaskResponse)
|
363
|
+
async def analyze_commit_rules(
|
364
|
+
request_data: RuleCommitRequest,
|
365
|
+
project_path: str = Depends(get_project_path)
|
366
|
+
):
|
367
|
+
"""
|
368
|
+
Analyzes a specific git commit based on rules and a query.
|
369
|
+
Runs as a background task.
|
370
|
+
"""
|
371
|
+
event_file, file_id = gengerate_event_file_path(base_dir=project_path)
|
372
|
+
logger.info(f"Starting commit analysis task {file_id} for commit {request_data.commit_id} in project: {project_path}")
|
373
|
+
|
374
|
+
def run_commit_analysis_in_thread():
|
375
|
+
try:
|
376
|
+
global_cancel.register_token(event_file)
|
377
|
+
event_manager = get_event_manager(event_file)
|
378
|
+
event_manager.write_event(EventContentCreator.create_task_start(
|
379
|
+
"Commit Analysis Started", {"commit_id": request_data.commit_id, "query": request_data.query}
|
380
|
+
).to_dict())
|
381
|
+
|
382
|
+
# --- Commit Analysis Logic ---
|
383
|
+
args = get_final_config()
|
384
|
+
llm = get_single_llm(args.model, product_mode=args.product_mode)
|
385
|
+
# Ensure AutoLearn uses the correct project path context
|
386
|
+
auto_learn = AutoLearn(llm=llm, args=args, project_root=project_path)
|
387
|
+
|
388
|
+
event_manager.write_event(EventContentCreator.create_message(f"Fetching changes for commit: {request_data.commit_id}").to_dict())
|
389
|
+
changes, _ = auto_learn.get_commit_changes(request_data.commit_id)
|
390
|
+
|
391
|
+
if not changes:
|
392
|
+
raise ValueError(f"Could not retrieve changes for commit ID: {request_data.commit_id}. Ensure it's a valid commit.")
|
393
|
+
|
394
|
+
event_manager.write_event(EventContentCreator.create_message(f"Analyzing commit {request_data.commit_id} with query: '{request_data.query}'").to_dict())
|
395
|
+
|
396
|
+
# Generate the commit analysis prompt text
|
397
|
+
prompt_text = auto_learn.analyze_commit.prompt(
|
398
|
+
querie_with_urls_and_changes=changes,
|
399
|
+
new_query=request_data.query
|
400
|
+
)
|
401
|
+
|
402
|
+
# --- Use AutoCoderRunnerWrapper to execute the generated prompt ---
|
403
|
+
wrapper = AutoCoderRunnerWrapper(project_path)
|
404
|
+
wrapper.configure_wrapper(f"event_file:{event_file}")
|
405
|
+
# The coding_wapper will handle writing events, including completion/error
|
406
|
+
result = wrapper.coding_wapper(prompt_text)
|
407
|
+
# The wrapper logs completion internally, no need for manual completion event here.
|
408
|
+
# logger.info(f"Commit analysis task {file_id} completed successfully.") # Logged by wrapper
|
409
|
+
|
410
|
+
except CancelRequestedException:
|
411
|
+
logger.info(f"Commit analysis task {file_id} cancelled.")
|
412
|
+
get_event_manager(event_file).write_error(
|
413
|
+
EventContentCreator.create_error(error_code="499", error_message="Task cancelled by user.").to_dict()
|
414
|
+
)
|
415
|
+
except Exception as e:
|
416
|
+
logger.exception(f"Error during commit analysis task {file_id}: {e}")
|
417
|
+
get_event_manager(event_file).write_error(
|
418
|
+
EventContentCreator.create_error(error_code="500", error_message=str(e), details={}).to_dict()
|
419
|
+
)
|
420
|
+
finally:
|
421
|
+
global_cancel.unregister_token(event_file) # Clean up token
|
422
|
+
|
423
|
+
# Start the background thread
|
424
|
+
thread = Thread(target=run_commit_analysis_in_thread, daemon=True)
|
425
|
+
thread.start()
|
426
|
+
|
427
|
+
return AsyncTaskResponse(event_file_id=file_id)
|
428
|
+
|
429
|
+
|
430
|
+
@router.get("/api/rules/help", response_model=RuleHelpResponse)
|
431
|
+
async def get_help():
|
432
|
+
"""
|
433
|
+
Returns the help text for the /rules command.
|
434
|
+
"""
|
435
|
+
# Attempt to get localized help text
|
436
|
+
help_text = get_message("rules_help_text")
|
437
|
+
if not help_text or help_text == "rules_help_text": # Check if translation failed
|
438
|
+
# Provide a default English help text if localization fails
|
439
|
+
help_text = """
|
440
|
+
Available /rules API Endpoints:
|
441
|
+
GET /api/rules/list?pattern=<wildcard> - List rule files (basic info), optionally filter by pattern.
|
442
|
+
GET /api/rules/get?pattern=<wildcard> - Get content of rule files matching the pattern.
|
443
|
+
DELETE /api/rules/remove?pattern=<wildcard> - Remove rule files matching the pattern.
|
444
|
+
POST /api/rules/analyze - Analyze current files (requires files in context/memory) with optional query in body. Runs async.
|
445
|
+
Body: { "query": "Optional analysis query" }
|
446
|
+
POST /api/rules/commit - Analyze a specific git commit with a query. Runs async.
|
447
|
+
Body: { "commit_id": "your_commit_hash", "query": "Your analysis query" }
|
448
|
+
GET /api/rules/help - Show this help message.
|
449
|
+
GET /api/rules/events?event_file_id=<id> - Stream events for async tasks (analyze, commit).
|
450
|
+
POST /api/rules/cancel - Cancel an ongoing async task.
|
451
|
+
Body: { "event_file_id": "task_event_id" }
|
452
|
+
"""
|
453
|
+
return RuleHelpResponse(help_text=help_text.strip())
|
454
|
+
|
455
|
+
|
456
|
+
@router.get("/api/rules/events")
|
457
|
+
async def poll_rule_events(event_file_id: str, project_path: str = Depends(get_project_path)):
|
458
|
+
"""
|
459
|
+
SSE endpoint to stream events for background rule tasks (analyze, commit).
|
460
|
+
"""
|
461
|
+
async def event_stream():
|
462
|
+
event_file = get_event_file_path(event_file_id, project_path)
|
463
|
+
if not event_file or not os.path.exists(os.path.dirname(event_file)):
|
464
|
+
logger.error(f"Event file path directory does not exist for ID {event_file_id} in project {project_path}")
|
465
|
+
# Send an error event and close
|
466
|
+
error_event = EventContentCreator.create_error("404", "Event stream not found or invalid ID.").to_dict()
|
467
|
+
yield f"data: {json.dumps(error_event)}\n\n"
|
468
|
+
return
|
469
|
+
|
470
|
+
logger.info(f"Starting SSE stream for event file: {event_file}")
|
471
|
+
event_manager = get_event_manager(event_file)
|
472
|
+
while True:
|
473
|
+
try:
|
474
|
+
# Use asyncio.to_thread for blocking read_events
|
475
|
+
events = await asyncio.to_thread(event_manager.read_events, block=False)
|
476
|
+
|
477
|
+
if not events:
|
478
|
+
# Check if the task is globally cancelled
|
479
|
+
if global_cancel.is_set(token=event_file):
|
480
|
+
logger.info(f"SSE stream {event_file_id}: Task cancellation detected, closing stream.")
|
481
|
+
# Send a final cancellation event if not already sent by the task thread
|
482
|
+
cancel_event = EventContentCreator.create_error("499", "Task cancelled.").to_dict()
|
483
|
+
yield f"data: {json.dumps(cancel_event)}\n\n"
|
484
|
+
break
|
485
|
+
await asyncio.sleep(0.2) # Slightly longer sleep if no events
|
486
|
+
continue
|
487
|
+
|
488
|
+
current_event = None
|
489
|
+
for event in events:
|
490
|
+
current_event = event
|
491
|
+
event_json = event.to_json()
|
492
|
+
yield f"data: {event_json}\n\n"
|
493
|
+
await asyncio.sleep(0.01) # Small delay to allow client processing
|
494
|
+
|
495
|
+
if current_event is not None:
|
496
|
+
if current_event.event_type in [EventType.ERROR, EventType.COMPLETION]:
|
497
|
+
logger.info(f"SSE stream {event_file_id}: Terminal event received ({current_event.event_type.name}), closing stream.")
|
498
|
+
break
|
499
|
+
# Add check for explicit CANCELLED event type if implemented
|
500
|
+
# elif current_event.event_type == EventType.CANCELLED:
|
501
|
+
# logger.info(f"SSE stream {event_file_id}: Cancelled event received, closing stream.")
|
502
|
+
# break
|
503
|
+
|
504
|
+
except CancelRequestedException:
|
505
|
+
logger.info(f"SSE stream {event_file_id}: Cancellation detected during event read, closing stream.")
|
506
|
+
yield f"data: {EventContentCreator.create_error('499', 'Task cancelled.').to_json()}\n\n"
|
507
|
+
break
|
508
|
+
except Exception as e:
|
509
|
+
logger.error(f"Error in SSE stream {event_file_id}: {str(e)}")
|
510
|
+
# Check if it's a file not found error after task completion/cleanup
|
511
|
+
if isinstance(e, FileNotFoundError) or "No such file or directory" in str(e):
|
512
|
+
logger.warning(f"SSE stream {event_file_id}: Event file likely removed after task completion. Closing stream.")
|
513
|
+
yield f"data: {EventContentCreator.create_error('410', 'Task finished and event log expired.').to_json()}\n\n"
|
514
|
+
else:
|
515
|
+
logger.exception(e) # Log full traceback for unexpected errors
|
516
|
+
yield f"data: {EventContentCreator.create_error('500', f'SSE stream error: {str(e)}').to_json()}\n\n"
|
517
|
+
break
|
518
|
+
|
519
|
+
return StreamingResponse(
|
520
|
+
event_stream(),
|
521
|
+
media_type="text/event-stream",
|
522
|
+
headers={
|
523
|
+
"Cache-Control": "no-cache, no-transform",
|
524
|
+
"Connection": "keep-alive",
|
525
|
+
"Content-Type": "text/event-stream",
|
526
|
+
"X-Accel-Buffering": "no",
|
527
|
+
"Transfer-Encoding": "chunked",
|
528
|
+
},
|
529
|
+
)
|
530
|
+
|
531
|
+
# Note: User response endpoint might not be directly applicable to analyze/commit unless they become interactive.
|
532
|
+
# Including it for consistency with coding_router pattern.
|
533
|
+
@router.post("/api/rules/response")
|
534
|
+
async def response_user_rules(request: UserResponseRequest, project_path: str = Depends(get_project_path)):
|
535
|
+
"""
|
536
|
+
Handles user responses if rule tasks become interactive (currently unlikely).
|
537
|
+
"""
|
538
|
+
logger.warning(f"Received user response for rule task {request.event_file_id}, but rule tasks are not currently interactive.")
|
539
|
+
# Implement similar logic to coding_router if interaction is needed in the future.
|
540
|
+
# For now, just acknowledge or return an informative message.
|
541
|
+
return {"status": "received", "message": "Rule tasks are not currently interactive."}
|
542
|
+
# Example future implementation:
|
543
|
+
# try:
|
544
|
+
# event_file = get_event_file_path(file_id=request.event_file_id, project_path=project_path)
|
545
|
+
# event_manager = get_event_manager(event_file)
|
546
|
+
# response_event = event_manager.respond_to_user(request.event_id, request.response)
|
547
|
+
# return {"status": "success", "message": "Response sent", "event_id": response_event.event_id}
|
548
|
+
# except Exception as e:
|
549
|
+
# logger.error(f"Error sending user response for rule task {request.event_file_id}: {str(e)}")
|
550
|
+
# raise HTTPException(status_code=500, detail=f"Failed to send response: {str(e)}")
|
551
|
+
|
552
|
+
@router.post("/api/rules/cancel")
|
553
|
+
async def cancel_rule_task(request: CancelTaskRequest, project_path: str = Depends(get_project_path)):
|
554
|
+
"""
|
555
|
+
Cancels a running background rule task (analyze, commit).
|
556
|
+
"""
|
557
|
+
try:
|
558
|
+
event_file = get_event_file_path(file_id=request.event_file_id, project_path=project_path)
|
559
|
+
logger.info(f"Received cancel request for task {request.event_file_id} associated with file: {event_file}")
|
560
|
+
|
561
|
+
if not event_file:
|
562
|
+
raise HTTPException(status_code=404, detail=f"Event file ID {request.event_file_id} not found or invalid.")
|
563
|
+
|
564
|
+
# Check if the event file exists - indicates if the task might still be running or recently finished
|
565
|
+
event_manager = get_event_manager(event_file) # This implicitly checks existence somewhat
|
566
|
+
|
567
|
+
def cancel_in_thread():
|
568
|
+
try:
|
569
|
+
logger.info(f"Setting cancellation flag for token: {event_file}")
|
570
|
+
global_cancel.set(token=event_file)
|
571
|
+
|
572
|
+
# Attempt to write a cancel event immediately for faster feedback via SSE
|
573
|
+
# This might fail if the task already cleaned up the file, which is acceptable.
|
574
|
+
try:
|
575
|
+
event_manager.write_error(
|
576
|
+
EventContentCreator.create_error(
|
577
|
+
error_code="499", error_message="Cancel request received", details={}
|
578
|
+
).to_dict()
|
579
|
+
)
|
580
|
+
logger.info(f"Cancellation event written for task {request.event_file_id}")
|
581
|
+
except Exception as write_err:
|
582
|
+
logger.warning(f"Could not write immediate cancel event for task {request.event_file_id} (might be already finished): {write_err}")
|
583
|
+
|
584
|
+
except Exception as e:
|
585
|
+
# Log errors during the cancellation signaling process itself
|
586
|
+
logger.error(f"Error during cancellation signaling for task {request.event_file_id}: {str(e)}")
|
587
|
+
# Don't raise HTTPException here, as the request to cancel was received.
|
588
|
+
# The client will see the task end via SSE or timeout.
|
589
|
+
|
590
|
+
# Use the shared cancel thread pool
|
591
|
+
cancel_thread_pool.submit(cancel_in_thread)
|
592
|
+
|
593
|
+
return {"status": "success", "message": "Cancel request sent. Task termination depends on the task's current state."}
|
594
|
+
except Exception as e:
|
595
|
+
logger.error(f"Error processing cancel request for {request.event_file_id}: {str(e)}")
|
596
|
+
raise HTTPException(status_code=500, detail=f"Failed to process cancel request: {str(e)}")
|
597
|
+
|
598
|
+
# TODO: Add endpoints for saving/loading rule task history if needed, similar to coding_router
|
599
|
+
# @router.post("/api/rules/save-history")
|
600
|
+
# @router.get("/api/rules/history")
|
601
|
+
# @router.get("/api/rules/task/{task_id}")
|
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "0.1.83"
|