auto-coder-web 0.1.91__py3-none-any.whl → 0.1.93__py3-none-any.whl
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/common_router/chat_list_manager.py +194 -0
- auto_coder_web/common_router/chat_list_router.py +55 -115
- auto_coder_web/common_router/chat_session_manager.py +111 -0
- auto_coder_web/common_router/file_group_router.py +55 -2
- auto_coder_web/proxy.py +3 -2
- auto_coder_web/routers/auto_router.py +33 -29
- auto_coder_web/routers/chat_panels_router.py +159 -0
- auto_coder_web/routers/chat_router.py +120 -1
- auto_coder_web/routers/code_editor_tabs_router.py +191 -0
- auto_coder_web/routers/coding_router.py +28 -26
- auto_coder_web/version.py +1 -1
- auto_coder_web/web/assets/{main-edBorJ-r.css → main-D8cC7hK1.css} +1 -1
- auto_coder_web/web/assets/main.js +382 -382
- auto_coder_web/web/index.html +1 -1
- {auto_coder_web-0.1.91.dist-info → auto_coder_web-0.1.93.dist-info}/METADATA +2 -2
- {auto_coder_web-0.1.91.dist-info → auto_coder_web-0.1.93.dist-info}/RECORD +19 -18
- auto_coder_web/file_cacher/__init__.py +0 -0
- auto_coder_web/file_cacher/filecacher.py +0 -195
- auto_coder_web/file_group.py +0 -69
- {auto_coder_web-0.1.91.dist-info → auto_coder_web-0.1.93.dist-info}/WHEEL +0 -0
- {auto_coder_web-0.1.91.dist-info → auto_coder_web-0.1.93.dist-info}/entry_points.txt +0 -0
- {auto_coder_web-0.1.91.dist-info → auto_coder_web-0.1.93.dist-info}/top_level.txt +0 -0
    
        auto_coder_web/web/index.html
    CHANGED
    
    | @@ -6,7 +6,7 @@ | |
| 6 6 | 
             
              <meta name="viewport" content="width=device-width, initial-scale=1.0" />
         | 
| 7 7 | 
             
              <title>Vite React App</title>
         | 
| 8 8 | 
             
              <script type="module" crossorigin src="/assets/main.js"></script>
         | 
| 9 | 
            -
              <link rel="stylesheet" crossorigin href="/assets/main- | 
| 9 | 
            +
              <link rel="stylesheet" crossorigin href="/assets/main-D8cC7hK1.css">
         | 
| 10 10 | 
             
            </head>
         | 
| 11 11 | 
             
            <body>
         | 
| 12 12 | 
             
              <div id="root"></div>
         | 
| @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            Metadata-Version: 2.1
         | 
| 2 2 | 
             
            Name: auto_coder_web
         | 
| 3 | 
            -
            Version: 0.1. | 
| 3 | 
            +
            Version: 0.1.93
         | 
| 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.362
         | 
| 11 11 | 
             
            Requires-Dist: aiofiles
         | 
| 12 12 | 
             
            Requires-Dist: psutil
         | 
| 13 13 | 
             
            Requires-Dist: watchdog
         | 
| @@ -1,32 +1,33 @@ | |
| 1 1 | 
             
            auto_coder_web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 2 2 | 
             
            auto_coder_web/auto_coder_runner_wrapper.py,sha256=CFhhgAkiMQBp56pR8Pz2FiWTv7otO295pAwxIM81VrY,1627
         | 
| 3 | 
            -
            auto_coder_web/file_group.py,sha256=wS52bHDT_gATIrHgVq62Mv1JMLGzdY_AU08iPzw4eLU,2540
         | 
| 4 3 | 
             
            auto_coder_web/file_manager.py,sha256=eFjmhBtw5PwnGAIQQjusNdo9TU3So-YyRYJXFHK4BjQ,12008
         | 
| 5 4 | 
             
            auto_coder_web/init_project.py,sha256=udDVjNpIuyJGnEbFfHtbrpLs37QjqE1zOj3VHC6Glf8,1141
         | 
| 6 5 | 
             
            auto_coder_web/json_file_storage.py,sha256=elthpcdclXITX3jew2EtT-ypyxZzDAzG1U7_k3looHI,1757
         | 
| 7 6 | 
             
            auto_coder_web/lang.py,sha256=cXypkDesnMwZ0U6D_CZtxhDTAOp__hoJzYTulQ_8xPc,1108
         | 
| 8 | 
            -
            auto_coder_web/proxy.py,sha256= | 
| 7 | 
            +
            auto_coder_web/proxy.py,sha256=if9-XT7bxD8dP_ddqQFuxTECr2XZmcmL94m1VrMlpTg,11878
         | 
| 9 8 | 
             
            auto_coder_web/terminal.py,sha256=jtAH7FaC573cgxc7FnI_mOZ3D2dSCO3PrZN0OehtbNQ,9521
         | 
| 10 9 | 
             
            auto_coder_web/types.py,sha256=TT-0UruUi67wz7w1DpjFyYeaCnkdKYviJvlpSnrdtD4,1435
         | 
| 11 | 
            -
            auto_coder_web/version.py,sha256= | 
| 10 | 
            +
            auto_coder_web/version.py,sha256=9ZJPYemtF-vnUzZtNNDjmi0UnkkMXYvPkfRASPJ5iWc,23
         | 
| 12 11 | 
             
            auto_coder_web/common_router/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 13 12 | 
             
            auto_coder_web/common_router/active_context_router.py,sha256=wbwG-J2iS5uBorN20q2PVoyJCVueECBR66xYjtIEWhM,6228
         | 
| 14 13 | 
             
            auto_coder_web/common_router/auto_coder_conf_router.py,sha256=oIRZE5OqeSfp-TYkGtX1M1Qd54iBYxftQtDbivdRj1o,1059
         | 
| 15 | 
            -
            auto_coder_web/common_router/ | 
| 14 | 
            +
            auto_coder_web/common_router/chat_list_manager.py,sha256=_0ZO3md0SaW51OnpNzirys9XhbRe_PbLuK7XOhSPPb4,6378
         | 
| 15 | 
            +
            auto_coder_web/common_router/chat_list_router.py,sha256=p4C6_trEKqvLEP01EEk4GXdQkU22_gHAKfBeaZMqbk8,5717
         | 
| 16 | 
            +
            auto_coder_web/common_router/chat_session_manager.py,sha256=oMwMaaYWToqn_QJIdFS8QcSaWDdqHhxPMbyQ6tuJUg0,3590
         | 
| 16 17 | 
             
            auto_coder_web/common_router/compiler_router.py,sha256=nHlD6VdxV9-CLhYZnykmaI8AP1zq2isA-3eD8ckxFHw,3840
         | 
| 17 18 | 
             
            auto_coder_web/common_router/completions_router.py,sha256=3pHDp2FRlSwasjn1jwrWXhQ6YN_zvRnri2aZpEooCzg,6590
         | 
| 18 | 
            -
            auto_coder_web/common_router/file_group_router.py,sha256= | 
| 19 | 
            +
            auto_coder_web/common_router/file_group_router.py,sha256=jZ0Qc5pWeFsNa5DZQnGr_IKAEWewqDWlEXiLpZOnZII,8747
         | 
| 19 20 | 
             
            auto_coder_web/common_router/file_router.py,sha256=orTiG9hn-eEd8i4HhMhbob4SsRbbEsJvOxk7CCbhoQY,10759
         | 
| 20 21 | 
             
            auto_coder_web/common_router/filecacher.py,sha256=3LgmGUqfjUyfRz2rxWvXsP-ovyjGW-t0Cl49Tibhd0Y,4666
         | 
| 21 22 | 
             
            auto_coder_web/common_router/model_router.py,sha256=w-t6d6FkfF8sDo_8ZHfclHb50y7pJ9uBWPfCLcxd7Lo,13449
         | 
| 22 23 | 
             
            auto_coder_web/expert_routers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 23 24 | 
             
            auto_coder_web/expert_routers/history_router.py,sha256=9NUPlDQJJY5xhGepj38ej3qXAlbaquJDVaSniNhFpqw,12471
         | 
| 24 | 
            -
            auto_coder_web/file_cacher/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 25 | 
            -
            auto_coder_web/file_cacher/filecacher.py,sha256=1VugN4kvANc2CKLqDfRgOmjQ9WGKmG8O95Bx2-n7td4,7255
         | 
| 26 25 | 
             
            auto_coder_web/routers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 27 | 
            -
            auto_coder_web/routers/auto_router.py,sha256= | 
| 28 | 
            -
            auto_coder_web/routers/ | 
| 29 | 
            -
            auto_coder_web/routers/ | 
| 26 | 
            +
            auto_coder_web/routers/auto_router.py,sha256=IzBR_IbslmVUj83eyhVAWUTwd-Rh3QAMo6DethvT3yc,16552
         | 
| 27 | 
            +
            auto_coder_web/routers/chat_panels_router.py,sha256=3I4M746NCORdpcyk-SuAmBJAKuQeG4FtX7m3FEXrnWM,5417
         | 
| 28 | 
            +
            auto_coder_web/routers/chat_router.py,sha256=Zxt8lUdLF1EJY1IMHdcS9tvw9ayec8jA-EKloYV3Bqk,16980
         | 
| 29 | 
            +
            auto_coder_web/routers/code_editor_tabs_router.py,sha256=ogCQUp7YoIYIkphDqCLKdfBGq-HdrfKQvZA8UkArrrc,6168
         | 
| 30 | 
            +
            auto_coder_web/routers/coding_router.py,sha256=vQX2YQ7VjddUG-OkKPKH-u2ip4ltULE93ldw27HrNsM,14866
         | 
| 30 31 | 
             
            auto_coder_web/routers/commit_router.py,sha256=MRxL_aJ3YazP6vC5C-bv0x9u3tvecRdGT6I7gHFXl18,26781
         | 
| 31 32 | 
             
            auto_coder_web/routers/config_router.py,sha256=E3twdQ_b0udO4NqyYL06feuM1KfKcgR7I4te86VstbA,3156
         | 
| 32 33 | 
             
            auto_coder_web/routers/direct_chat_router.py,sha256=tS8g4yZjmC2LjdLMQkq8KaCDJmyEuWidGRqIii-Hq1o,1265
         | 
| @@ -40,7 +41,7 @@ auto_coder_web/routers/todo_router.py,sha256=IkQurQTw0Xk9P8yEtY_iie1z5ZK3CzDQE_N | |
| 40 41 | 
             
            auto_coder_web/routers/upload_router.py,sha256=HdQIl3ICcT3EB2kwryTbF-PItWV-Gugses7Y0Eaw2WQ,1798
         | 
| 41 42 | 
             
            auto_coder_web/web/bridge.js,sha256=us40dbuGHa2_zBBVBCa_GznOvpuZNDObViksMeoQch0,7364
         | 
| 42 43 | 
             
            auto_coder_web/web/favicon.ico,sha256=PRD32mxgMXg0AIFmjErFs66XQ8qaJiqw_NMS-7n0i90,3870
         | 
| 43 | 
            -
            auto_coder_web/web/index.html,sha256= | 
| 44 | 
            +
            auto_coder_web/web/index.html,sha256=WScQCWe648qOft38Bcydg94SPqSdX4HL2eUWyz-Bs8Y,410
         | 
| 44 45 | 
             
            auto_coder_web/web/logo192.png,sha256=w4Y5bscNs2CAdbX7-qxKscyqhroFpoqzk-xVHrZsPgA,5347
         | 
| 45 46 | 
             
            auto_coder_web/web/logo512.png,sha256=nqT02nBQwMxAiSb2o5wlNiTpursdQ8eXfNghRFpgtGE,9664
         | 
| 46 47 | 
             
            auto_coder_web/web/manifest.json,sha256=ULPYw5A68_eNhxuUVXqxT045yhkurKPSz6hjyGcnmhQ,492
         | 
| @@ -85,8 +86,8 @@ auto_coder_web/web/assets/lexon-YWi4-JPR.js,sha256=l9pURhF6kU3UKzKOIIQprnjMAXzdI | |
| 85 86 | 
             
            auto_coder_web/web/assets/liquid-CPaH0eVF.js,sha256=uXE_OsLEw3W8B-ReZOUwybkJu3J6se8VlGWx0MFpx7g,4208
         | 
| 86 87 | 
             
            auto_coder_web/web/assets/lua-nf6ki56Z.js,sha256=O3vMsGoiFHDMGSxTP1bHnDnRPebfmFnC7kf8-ovGkO8,2369
         | 
| 87 88 | 
             
            auto_coder_web/web/assets/m3-Cpb6xl2v.js,sha256=PmotBCyVZvUGHh9t9juODmjXptTEP5K6bnPj2WgYO6c,3063
         | 
| 88 | 
            -
            auto_coder_web/web/assets/main- | 
| 89 | 
            -
            auto_coder_web/web/assets/main.js,sha256= | 
| 89 | 
            +
            auto_coder_web/web/assets/main-D8cC7hK1.css,sha256=WawWwZrOFXdkI61Qln2UMzryDj2lQGXjHqvz7t3rHeU,242684
         | 
| 90 | 
            +
            auto_coder_web/web/assets/main.js,sha256=D6nSIwZ3pwKgrSE12s0bQkuU3oXdpO76jW3wvEETUSg,6673763
         | 
| 90 91 | 
             
            auto_coder_web/web/assets/markdown-DSZPf7rp.js,sha256=3ZMgfYxjKX9U8l6GFCNrO28Hj7JU-4rKrEqXIezyqT4,4034
         | 
| 91 92 | 
             
            auto_coder_web/web/assets/mdx-DRx1b0qs.js,sha256=awzor_jnBNHRhTxk3_jcpGXsNUFbi9Ow0OIqWYq4CQA,5113
         | 
| 92 93 | 
             
            auto_coder_web/web/assets/mips-B_c3zf-v.js,sha256=L4uNgcwtDWPbyL0qnO-2w9x2PdI02UJcc8yQrYnHahA,2825
         | 
| @@ -240,8 +241,8 @@ auto_coder_web/web/monaco-editor/min/vs/language/typescript/tsWorker.js,sha256=_ | |
| 240 241 | 
             
            auto_coder_web/web/sounds/ding-dong.wav,sha256=BveDrGCyt_YMHaJwFJ80L5NfbUF5cl5QjzR-SRehxTk,35324
         | 
| 241 242 | 
             
            auto_coder_web/web/sounds/gentle-notification.wav,sha256=bzd0MwECdrjmNz7mbqv_y03S7WwD3G6agbIh1rWJ9cQ,72124
         | 
| 242 243 | 
             
            auto_coder_web/web/sounds/soft-chime.wav,sha256=Akpw7_rHLnX3rE13dRYpyZbmQFLGtp8P53LCdAkT9sA,40364
         | 
| 243 | 
            -
            auto_coder_web-0.1. | 
| 244 | 
            -
            auto_coder_web-0.1. | 
| 245 | 
            -
            auto_coder_web-0.1. | 
| 246 | 
            -
            auto_coder_web-0.1. | 
| 247 | 
            -
            auto_coder_web-0.1. | 
| 244 | 
            +
            auto_coder_web-0.1.93.dist-info/METADATA,sha256=OFvZ7kkbyQglKhbE1zhh82Cza_KsJn4X438ZWh5l4W8,1435
         | 
| 245 | 
            +
            auto_coder_web-0.1.93.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
         | 
| 246 | 
            +
            auto_coder_web-0.1.93.dist-info/entry_points.txt,sha256=oh8kd1ZecWDgdv-bIj_ru3phvl4scuxwXl9DK0Khltg,61
         | 
| 247 | 
            +
            auto_coder_web-0.1.93.dist-info/top_level.txt,sha256=UCzEw494Im0KvR-FTYf2jh-okqHvLsC_0JLOrQZoSpg,15
         | 
| 248 | 
            +
            auto_coder_web-0.1.93.dist-info/RECORD,,
         | 
| 
            File without changes
         | 
| @@ -1,195 +0,0 @@ | |
| 1 | 
            -
            import os
         | 
| 2 | 
            -
            import json
         | 
| 3 | 
            -
            import threading
         | 
| 4 | 
            -
            import time
         | 
| 5 | 
            -
            from watchdog.observers import Observer
         | 
| 6 | 
            -
            from watchdog.events import FileSystemEventHandler
         | 
| 7 | 
            -
            from pydantic import BaseModel
         | 
| 8 | 
            -
             | 
| 9 | 
            -
            class FileCacheResult(BaseModel):
         | 
| 10 | 
            -
                miss: bool
         | 
| 11 | 
            -
                files: list[str]
         | 
| 12 | 
            -
             | 
| 13 | 
            -
            class FileCacheHandler(FileSystemEventHandler):
         | 
| 14 | 
            -
                def __init__(self, cacher):
         | 
| 15 | 
            -
                    super().__init__()
         | 
| 16 | 
            -
                    self.cacher = cacher
         | 
| 17 | 
            -
             | 
| 18 | 
            -
                def on_created(self, event):
         | 
| 19 | 
            -
                    if not event.is_directory:
         | 
| 20 | 
            -
                        self.cacher._update_file(event.src_path)
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                def on_modified(self, event):
         | 
| 23 | 
            -
                    if not event.is_directory:
         | 
| 24 | 
            -
                        self.cacher._update_file(event.src_path)
         | 
| 25 | 
            -
             | 
| 26 | 
            -
                def on_deleted(self, event):
         | 
| 27 | 
            -
                    if not event.is_directory:
         | 
| 28 | 
            -
                        self.cacher._remove_file(event.src_path)
         | 
| 29 | 
            -
             | 
| 30 | 
            -
                def on_moved(self, event):
         | 
| 31 | 
            -
                    if not event.is_directory:
         | 
| 32 | 
            -
                        self.cacher._remove_file(event.src_path)
         | 
| 33 | 
            -
                        self.cacher._update_file(event.dest_path)
         | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
            class FileCacher:
         | 
| 37 | 
            -
                def __init__(self, project_path):
         | 
| 38 | 
            -
                    self.project_path = project_path
         | 
| 39 | 
            -
                    self.index_file = os.path.join(
         | 
| 40 | 
            -
                        project_path, ".auto-coder", "cache", "file_cache.json")
         | 
| 41 | 
            -
                    self.file_info = {}  # key: absolute path, value: metadata dict
         | 
| 42 | 
            -
                    self.ready = False
         | 
| 43 | 
            -
                    self.lock = threading.RLock()
         | 
| 44 | 
            -
                    self.observer = None
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                def start(self):
         | 
| 47 | 
            -
                    """启动缓存构建和监控"""
         | 
| 48 | 
            -
                    # 启动索引构建线程
         | 
| 49 | 
            -
                    t = threading.Thread(target=self._build_cache_thread, daemon=True)
         | 
| 50 | 
            -
                    t.start()
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                def _build_cache_thread(self):
         | 
| 53 | 
            -
                    """后台构建索引并启动watchdog监控"""
         | 
| 54 | 
            -
                    try:
         | 
| 55 | 
            -
                        self._build_cache()
         | 
| 56 | 
            -
                    finally:
         | 
| 57 | 
            -
                        self.ready = True
         | 
| 58 | 
            -
                        self._save_cache()
         | 
| 59 | 
            -
                        self._start_watchdog()
         | 
| 60 | 
            -
             | 
| 61 | 
            -
                def _build_cache(self):
         | 
| 62 | 
            -
                    """遍历项目目录,构建初始缓存"""
         | 
| 63 | 
            -
                    exclude_dirs = {".git", "node_modules", "dist",
         | 
| 64 | 
            -
                                    "build", "__pycache__", ".venv", ".auto-coder"}
         | 
| 65 | 
            -
                    for root, dirs, files in os.walk(self.project_path, followlinks=True):
         | 
| 66 | 
            -
                        # 过滤目录
         | 
| 67 | 
            -
                        dirs[:] = [
         | 
| 68 | 
            -
                            d for d in dirs if d not in exclude_dirs and not d.startswith('.')]
         | 
| 69 | 
            -
                        for f in files:
         | 
| 70 | 
            -
                            abs_path = os.path.join(root, f)
         | 
| 71 | 
            -
                            self._update_file(abs_path)
         | 
| 72 | 
            -
             | 
| 73 | 
            -
                def _update_file(self, abs_path):
         | 
| 74 | 
            -
                    """添加或更新单个文件的缓存信息"""
         | 
| 75 | 
            -
                    try:
         | 
| 76 | 
            -
                        if not os.path.isfile(abs_path):
         | 
| 77 | 
            -
                            return
         | 
| 78 | 
            -
                        stat = os.stat(abs_path)
         | 
| 79 | 
            -
                        rel_path = os.path.relpath(abs_path, self.project_path)
         | 
| 80 | 
            -
                        with self.lock:
         | 
| 81 | 
            -
                            self.file_info[rel_path] = {
         | 
| 82 | 
            -
                                "mtime": stat.st_mtime,
         | 
| 83 | 
            -
                                "size": stat.st_size,
         | 
| 84 | 
            -
                                "abs_path": abs_path,
         | 
| 85 | 
            -
                                "name": os.path.basename(abs_path),
         | 
| 86 | 
            -
                            }
         | 
| 87 | 
            -
                    except Exception:
         | 
| 88 | 
            -
                        pass  # ignore errors
         | 
| 89 | 
            -
             | 
| 90 | 
            -
                def _remove_file(self, abs_path):
         | 
| 91 | 
            -
                    try:
         | 
| 92 | 
            -
                        rel_path = os.path.relpath(abs_path, self.project_path)
         | 
| 93 | 
            -
                        with self.lock:
         | 
| 94 | 
            -
                            if rel_path in self.file_info:
         | 
| 95 | 
            -
                                del self.file_info[rel_path]
         | 
| 96 | 
            -
                    except Exception:
         | 
| 97 | 
            -
                        pass
         | 
| 98 | 
            -
             | 
| 99 | 
            -
                def _start_watchdog(self):
         | 
| 100 | 
            -
                    """启动watchdog监控项目目录变更"""
         | 
| 101 | 
            -
                    event_handler = FileCacheHandler(self)
         | 
| 102 | 
            -
                    self.observer = Observer()
         | 
| 103 | 
            -
                    self.observer.schedule(
         | 
| 104 | 
            -
                        event_handler, self.project_path, recursive=True)
         | 
| 105 | 
            -
                    self.observer.daemon = True
         | 
| 106 | 
            -
                    self.observer.start()
         | 
| 107 | 
            -
             | 
| 108 | 
            -
                def stop(self):
         | 
| 109 | 
            -
                    """停止监控"""
         | 
| 110 | 
            -
                    if self.observer:
         | 
| 111 | 
            -
                        self.observer.stop()
         | 
| 112 | 
            -
                        self.observer.join()
         | 
| 113 | 
            -
             | 
| 114 | 
            -
                def _save_cache(self):
         | 
| 115 | 
            -
                    """将缓存写入磁盘"""
         | 
| 116 | 
            -
                    try:
         | 
| 117 | 
            -
                        cache_dir = os.path.dirname(self.index_file)
         | 
| 118 | 
            -
                        os.makedirs(cache_dir, exist_ok=True)
         | 
| 119 | 
            -
                        with open(self.index_file, 'w', encoding='utf-8') as f:
         | 
| 120 | 
            -
                            json.dump(self.file_info, f)
         | 
| 121 | 
            -
                    except Exception:
         | 
| 122 | 
            -
                        pass
         | 
| 123 | 
            -
             | 
| 124 | 
            -
                def load_cache(self):
         | 
| 125 | 
            -
                    """尝试加载磁盘缓存"""
         | 
| 126 | 
            -
                    try:
         | 
| 127 | 
            -
                        if os.path.exists(self.index_file):
         | 
| 128 | 
            -
                            with open(self.index_file, 'r', encoding='utf-8') as f:
         | 
| 129 | 
            -
                                self.file_info = json.load(f)
         | 
| 130 | 
            -
                            self.ready = True
         | 
| 131 | 
            -
                    except Exception:
         | 
| 132 | 
            -
                        pass
         | 
| 133 | 
            -
             | 
| 134 | 
            -
                def search_files(self, patterns):
         | 
| 135 | 
            -
                    """
         | 
| 136 | 
            -
                    根据模式列表查找匹配文件
         | 
| 137 | 
            -
                    :param patterns: list[str]
         | 
| 138 | 
            -
                    :return: FileCacheResult(miss=True/False, files=List[str])
         | 
| 139 | 
            -
                    """
         | 
| 140 | 
            -
                    if not self.ready:
         | 
| 141 | 
            -
                        # 索引未准备好,返回 miss = True,空文件列表
         | 
| 142 | 
            -
                        return self.FileCacheResult(miss=True, files=[])
         | 
| 143 | 
            -
             | 
| 144 | 
            -
                    matched = set()
         | 
| 145 | 
            -
                    default_exclude_dirs = [".git", "node_modules", "dist", "build", "__pycache__", ".venv", ".auto-coder"]
         | 
| 146 | 
            -
                    project_root = self.project_path
         | 
| 147 | 
            -
             | 
| 148 | 
            -
                    def should_exclude_path(path: str) -> bool:
         | 
| 149 | 
            -
                        """检查路径是否应该被排除(路径中包含排除目录或以.开头的目录/文件)"""
         | 
| 150 | 
            -
                        # 处理相对/绝对路径
         | 
| 151 | 
            -
                        rel_path = path
         | 
| 152 | 
            -
                        if os.path.isabs(path):
         | 
| 153 | 
            -
                            try:
         | 
| 154 | 
            -
                                rel_path = os.path.relpath(path, project_root)
         | 
| 155 | 
            -
                            except ValueError:
         | 
| 156 | 
            -
                                rel_path = path
         | 
| 157 | 
            -
             | 
| 158 | 
            -
                        # 检查文件或目录本身是否以.开头
         | 
| 159 | 
            -
                        if os.path.basename(rel_path).startswith('.'):
         | 
| 160 | 
            -
                            return True
         | 
| 161 | 
            -
             | 
| 162 | 
            -
                        # 检查路径中是否包含排除目录
         | 
| 163 | 
            -
                        path_parts = rel_path.split(os.sep)
         | 
| 164 | 
            -
                        return any(part in default_exclude_dirs or part.startswith('.') for part in path_parts)
         | 
| 165 | 
            -
             | 
| 166 | 
            -
                    with self.lock:
         | 
| 167 | 
            -
                        # 如果没有提供有效模式,返回过滤后的缓存列表
         | 
| 168 | 
            -
                        if not patterns or (len(patterns) == 1 and patterns[0] == ""):
         | 
| 169 | 
            -
                            for rel_path, info in self.file_info.items():
         | 
| 170 | 
            -
                                abs_path = info.get("abs_path", "")
         | 
| 171 | 
            -
                                if not should_exclude_path(rel_path):
         | 
| 172 | 
            -
                                    matched.add(rel_path)
         | 
| 173 | 
            -
                            return self.FileCacheResult(miss=False, files=list(matched))
         | 
| 174 | 
            -
             | 
| 175 | 
            -
                        for pattern in patterns:
         | 
| 176 | 
            -
                            # 1. 在缓存中匹配文件名
         | 
| 177 | 
            -
                            for rel_path, info in self.file_info.items():
         | 
| 178 | 
            -
                                filename = info.get("name", "")
         | 
| 179 | 
            -
                                abs_path = info.get("abs_path", "")
         | 
| 180 | 
            -
                                if should_exclude_path(rel_path):
         | 
| 181 | 
            -
                                    continue
         | 
| 182 | 
            -
                                if pattern in filename:
         | 
| 183 | 
            -
                                    matched.add(rel_path)
         | 
| 184 | 
            -
             | 
| 185 | 
            -
                            # 2. 如果pattern本身是存在的文件路径(绝对或相对)
         | 
| 186 | 
            -
                            abs_pattern_path = pattern
         | 
| 187 | 
            -
                            if not os.path.isabs(abs_pattern_path):
         | 
| 188 | 
            -
                                abs_pattern_path = os.path.join(project_root, pattern)
         | 
| 189 | 
            -
                            if os.path.exists(abs_pattern_path) and os.path.isfile(abs_pattern_path) and not should_exclude_path(abs_pattern_path):
         | 
| 190 | 
            -
                                try:
         | 
| 191 | 
            -
                                    rel_p = os.path.relpath(abs_pattern_path, project_root)
         | 
| 192 | 
            -
                                    matched.add(rel_p)
         | 
| 193 | 
            -
                                except:
         | 
| 194 | 
            -
                                    matched.add(abs_pattern_path)
         | 
| 195 | 
            -
                    return self.FileCacheResult(miss=False, files=list(matched))
         | 
    
        auto_coder_web/file_group.py
    DELETED
    
    | @@ -1,69 +0,0 @@ | |
| 1 | 
            -
            from fastapi import HTTPException
         | 
| 2 | 
            -
            from typing import List, Dict, Optional
         | 
| 3 | 
            -
            import os
         | 
| 4 | 
            -
            from .auto_coder_runner import AutoCoderRunner
         | 
| 5 | 
            -
             | 
| 6 | 
            -
            class FileGroupManager:
         | 
| 7 | 
            -
                def __init__(self,auto_coder_runner: AutoCoderRunner):
         | 
| 8 | 
            -
                    self.runner = auto_coder_runner        
         | 
| 9 | 
            -
                    
         | 
| 10 | 
            -
                async def create_group(self, name: str, description: str) -> Dict:
         | 
| 11 | 
            -
                    group = self.runner.add_group(name,description=description)
         | 
| 12 | 
            -
                    if group is None:
         | 
| 13 | 
            -
                        raise HTTPException(status_code=400, detail="Group already exists")
         | 
| 14 | 
            -
                    return {
         | 
| 15 | 
            -
                        "name": name,
         | 
| 16 | 
            -
                        "description": description,
         | 
| 17 | 
            -
                        "files": []  
         | 
| 18 | 
            -
                    }
         | 
| 19 | 
            -
                
         | 
| 20 | 
            -
                async def switch_groups(self, group_names: List[str]) -> Dict:
         | 
| 21 | 
            -
                    result = self.runner.switch_groups(group_names)
         | 
| 22 | 
            -
                    if result is None:
         | 
| 23 | 
            -
                        raise HTTPException(status_code=404, detail="Group not found")
         | 
| 24 | 
            -
                    return result
         | 
| 25 | 
            -
                
         | 
| 26 | 
            -
                async def delete_group(self, name: str) -> None:
         | 
| 27 | 
            -
                    result = self.runner.remove_group(name)
         | 
| 28 | 
            -
                    if result is None:
         | 
| 29 | 
            -
                        raise HTTPException(status_code=404, detail="Group not found")
         | 
| 30 | 
            -
                
         | 
| 31 | 
            -
                async def add_files_to_group(self, group_name: str, files: List[str]) -> Dict:
         | 
| 32 | 
            -
                    result = self.runner.add_files_to_group(group_name, files)
         | 
| 33 | 
            -
                    if result is None:
         | 
| 34 | 
            -
                        raise HTTPException(status_code=404, detail="Group not found")
         | 
| 35 | 
            -
                    return {
         | 
| 36 | 
            -
                        "name": group_name,
         | 
| 37 | 
            -
                        "files": result.get("files", [])
         | 
| 38 | 
            -
                    }
         | 
| 39 | 
            -
                
         | 
| 40 | 
            -
                async def remove_files_from_group(self, group_name: str, files: List[str]) -> Dict:
         | 
| 41 | 
            -
                    result = self.runner.remove_files_from_group(group_name, files)
         | 
| 42 | 
            -
                    if result is None:
         | 
| 43 | 
            -
                        raise HTTPException(status_code=404, detail="Group not found")
         | 
| 44 | 
            -
                    return {
         | 
| 45 | 
            -
                        "name": group_name, 
         | 
| 46 | 
            -
                        "files": result.get("files", [])
         | 
| 47 | 
            -
                    }
         | 
| 48 | 
            -
                
         | 
| 49 | 
            -
                async def get_groups(self) -> List[Dict]:
         | 
| 50 | 
            -
                    groups = self.runner.get_groups()
         | 
| 51 | 
            -
                    if not groups:
         | 
| 52 | 
            -
                        return []
         | 
| 53 | 
            -
                    return [
         | 
| 54 | 
            -
                        {
         | 
| 55 | 
            -
                            "name": group_name,
         | 
| 56 | 
            -
                            "files": self.runner.get_files_in_group(group_name).get("files", []),
         | 
| 57 | 
            -
                            "description": self.runner.get_group_description(group_name)
         | 
| 58 | 
            -
                        }
         | 
| 59 | 
            -
                        for group_name in groups.get("groups", [])
         | 
| 60 | 
            -
                    ]
         | 
| 61 | 
            -
                
         | 
| 62 | 
            -
                async def get_group(self, name: str) -> Optional[Dict]:
         | 
| 63 | 
            -
                    files = self.runner.get_files_in_group(name)
         | 
| 64 | 
            -
                    if files is None:
         | 
| 65 | 
            -
                        return None
         | 
| 66 | 
            -
                    return {
         | 
| 67 | 
            -
                        "name": name,
         | 
| 68 | 
            -
                        "files": files.get("files", [])
         | 
| 69 | 
            -
                    }
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
| 
            File without changes
         |