diff --git a/AGENTS.md b/AGENTS.md index 2c752b0..bd1ce48 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,7 +1,7 @@ -# Project Agent Rules — MSCodeBase Hybrid Architecture (61 Registered Tools) +# Project Agent Rules — MSCodeBase Hybrid Architecture (64 Registered Tools) > Global system prompt / context injection for the AI Agent in Zed IDE. Applied across all projects. -> Optimized for the hybrid model: 16 Intel Layer + 28 Core MCP (включая `codebase` hub + 6 LSP) + 13 Inline/Diagnostic + 4 Dev Tools = 61 registered (+1 `execute_script` при `MSCODEBASE_EXECUTE_SCRIPT_ENABLED=true` → 62) +> Optimized for the hybrid model: 16 Intel Layer + 31 Core MCP (включая `codebase` hub + 6 LSP + `predict_change`) + 13 Inline/Diagnostic + 4 Dev Tools = 64 registered (+1 `execute_script` при `MSCODEBASE_EXECUTE_SCRIPT_ENABLED=true` → 65) > \* `execute_script` отключён по умолчанию. Включить: `MSCODEBASE_EXECUTE_SCRIPT_ENABLED=true` в `.env`. @@ -319,7 +319,7 @@ intel_get_project_context ──> (aggregates 5+ calls) Inline/Diagnostic (12): `debug_runtime_passport`, `intel_get_project_context`, `intel_explain_project_state`, `get_runtime_counters`, `intel_tool_health`, `intel_execution_timeline`, `refresh_db_connection`, `notify_change`, `read_live_file`, `get_logs`, `get_health_report`, `ack_impact`. -### B. Core MCP & Search (28 tools) +### B. Core MCP & Search (31 tools) > **v3.2.0 Data Flow:** PropertyGraph содержит `ASSIGNED_FROM`-рёбра, отслеживающие diff --git a/README.md b/README.md index 421db17..f2d3e6b 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ This is **not** an LSP server or a replacement for the editor's built-in autocom │ │ · Call graph & impact analysis │ │ │ │ · Project memory (ADR, tech debt) │ │ │ │ · Self-diagnostics and self-healing │ │ -│ │ · 63 tools for AI assistant │ +│ │ · 64 tools for AI assistant │ │ └───────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────┘ ``` @@ -118,7 +118,7 @@ Designed and tested on **Windows**. macOS and Linux should work but have not bee | 💾 **LanceDB v2** | Vector DB with per-project isolation (incremental BM25 reindex) | | 🛡 **Rate Limiting** | DebounceBatch + CircuitBreaker — protection against VFS loops | | 🏥 **Self-Diagnosis** | `get_health_report` + `index_health` — full check and recovery | -| 🧪 **Clean Architecture** | DI Container (18 services), 63 tools (30 core + 16 intel + 13 inline + 4 dev), 1371 tests | +| 🧪 **Clean Architecture** | DI Container (18 services), 64 tools (31 core + 16 intel + 13 inline + 4 dev), 1371 tests | | 🪟 **Multi-Window** | `ProjectIndexerRegistry` — isolated Indexer per project, LRU 5, ResourceMonitor throttle | | ✏️ **Write Tools** | `codebase(action=...)` — unified hub: rename, move, delete, replace, insert, ack | | ⚡ **Meta-Patching** | LanceDB `move_chunks_metadata` — file_path rename without re-embedding (50ms vs 5s) | diff --git a/docs/ru/README.md b/docs/ru/README.md index 4ccf3a5..093b765 100644 --- a/docs/ru/README.md +++ b/docs/ru/README.md @@ -183,7 +183,7 @@ multilingual-e5-small ONNX (CPU, in-process) → llama-server reranker --- -## MCP Инструменты (61 всего) +## MCP Инструменты (64 всего) ### Основной поиск diff --git a/scripts/verify_diary.py b/scripts/verify_diary.py index 5fe65e5..2052e49 100644 --- a/scripts/verify_diary.py +++ b/scripts/verify_diary.py @@ -403,15 +403,17 @@ def gate_zero_full_suite() -> Tuple[bool, str]: env=env, creationflags=getattr(subprocess, 'CREATE_NO_WINDOW', 0), ) - # 120s кап флаки при нагрузке (pytest ~108-130s) — 300s запас (2026-08-08). - stdout, _ = proc.communicate(timeout=300) + # 120s кап флаки при нагрузке (pytest ~108-130s) — 300s запас (2026-08-08); + # 300→900 (2026-08-24): сюита выросла (1499+ live-sync/predict-наборы), + # даже в CI clean-state pytest идёт ~171s — 300s флакал при параллельной нагрузке. + stdout, _ = proc.communicate(timeout=900) output = stdout.decode("utf-8", errors="replace").strip() # Извлекаем итоговую строку lines = [l for l in output.split("\n") if "passed" in l or "failed" in l] summary = lines[-1] if lines else output[-200:] return proc.returncode == 0, summary except subprocess.TimeoutExpired: - return False, "TIMEOUT: pytest tests/ > 120s" + return False, "TIMEOUT: pytest tests/ > 900s" except Exception as e: return False, f"ERROR: {e}" diff --git a/src/core/change_preview.py b/src/core/change_preview.py index d063be2..3e4a388 100644 --- a/src/core/change_preview.py +++ b/src/core/change_preview.py @@ -30,16 +30,23 @@ def _run(cmd: List[str], cwd: Path, timeout: int = DEFAULT_TIMEOUT) -> subprocess.CompletedProcess: - """Popen + communicate (§5.16: не capture_output — pipe-deadlock на Windows).""" - proc = subprocess.Popen( - cmd, - cwd=str(cwd), - stdout=subprocess.PIPE, - stderr=subprocess.DEVNULL, - encoding="utf-8", - errors="replace", - creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0), - ) + """Popen + communicate (§5.16: не capture_output — pipe-deadlock на Windows). + + FileNotFoundError (бинарник не установлен, напр. ruff в clean-state без + dev-экстр) → CompletedProcess(returncode=127) — вызывающий решает: skip. + """ + try: + proc = subprocess.Popen( + cmd, + cwd=str(cwd), + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + encoding="utf-8", + errors="replace", + creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0), + ) + except FileNotFoundError: + return subprocess.CompletedProcess(cmd, 127, f"command not found: {cmd[0]}") try: stdout, _ = proc.communicate(timeout=timeout) except subprocess.TimeoutExpired: @@ -176,11 +183,19 @@ def _apply_and_verify(self, changed: List[str]) -> List[str]: }.get(gate) if script and (wt / script).exists(): res = _run([sys.executable, script], wt, timeout=120) + if res.returncode == 127: + print(f" ⏭️ {gate}: интерпретатор недоступен (skip)") + continue if res.returncode != 0: failures.append(f"[{gate}] Failed (exit {res.returncode})") print(f" 🔒 {gate}: {'PASSED' if res.returncode == 0 else 'FAILED'}") elif gate == "ruff": res = _run(["ruff", "check", "src/", "tests/"], wt, timeout=120) + if res.returncode == 127: + # clean-state ставит только .[base] без dev-экстр — ruff может + # отсутствовать; это окружение, а не провал изменения + print(" ⏭️ ruff: не установлен (skip — окружение без dev-экстр)") + continue if res.returncode != 0: failures.append("[ruff] Failed") print(f" 🔒 ruff: {'PASSED' if res.returncode == 0 else 'FAILED'}") diff --git a/src/core/git_hooks_installer.py b/src/core/git_hooks_installer.py index bd40a98..7e20665 100644 --- a/src/core/git_hooks_installer.py +++ b/src/core/git_hooks_installer.py @@ -84,8 +84,10 @@ def run_script(script_path: str, label: str) -> bool: creationflags=getattr(subprocess, 'CREATE_NO_WINDOW', 0), ) # Таймаут-запас: verify_diary гоняет gate-zero (полный pytest ~108-130s под - # нагрузкой) — кап 120s давал флаки TimeoutExpired на коммитах (2026-08-08). - stdout, _ = proc.communicate(timeout=300) + # нагрузкой) — кап 120s давал флаки TimeoutExpired на коммитах (2026-08-08); + # 300→900 (2026-08-24): сюита выросла (live-sync + predict-наборы), 300s + # начал флакать при параллельной нагрузке. + stdout, _ = proc.communicate(timeout=900) if proc.returncode != 0: print(f" ❌ {{label}}: exit {{proc.returncode}}") if stdout: diff --git a/src/mcp/server_tools.py b/src/mcp/server_tools.py index 818f7c3..16425dc 100644 --- a/src/mcp/server_tools.py +++ b/src/mcp/server_tools.py @@ -3,11 +3,11 @@ Выделено из server.py (Фаза 2, Шаг 1). Содержит: -- register_all_tools() — регистрация 30 core-инструментов (20 + 6 LSP + find_duplicates + get_context + get_action_receipt + predict_change) + execute_script +- register_all_tools() — регистрация 31 core-инструмента (30 существующих + predict_change, 2026-08-24) + execute_script - _register_intelligence_tools() — 16 intel_* инструментов (intelligence/tools_reg.py) - _register_inline_tools() — 13 inline @mcp.tool (debug_runtime_passport, intel_get_project_context, intel_explain_project_state, get_runtime_counters, intel_tool_health, intel_execution_timeline, refresh_db_connection, notify_change, read_live_file, get_logs, get_health_report, ack_impact) - dev_tools: generate_docs, bump_version, auto_update_docs, install_git_hooks (4) -- Всего: 30 + 16 + 13 + 4 = 63 инструментов (+ 1 optional execute_script = 64 при env-on) +- Всего: 31 + 16 + 13 + 4 = 64 инструмента (+ 1 optional execute_script = 65 при env-on) - DI Container: 18 unique services (19 add_singleton calls, 1 duplicate key) """ diff --git a/tests/test_auto_doc_updater.py b/tests/test_auto_doc_updater.py index 9b69d1c..c2579c2 100644 --- a/tests/test_auto_doc_updater.py +++ b/tests/test_auto_doc_updater.py @@ -141,4 +141,4 @@ def test_count_tools_real_project_guard(): tools = AutoDocUpdater()._count_tools(root) assert tools >= 44, f"_count_tools вернул {tools} — снова баг подсчёта?" if os.environ.get("MSCODEBASE_EXECUTE_SCRIPT_ENABLED", "false").lower() != "true": - assert tools == 63, f"ожидалось 63 (README-контракт), получено {tools}" + assert tools == 64, f"ожидалось 64 (README-контракт), получено {tools}" diff --git a/tests/test_lock_guard.py b/tests/test_lock_guard.py index bb90021..f572781 100644 --- a/tests/test_lock_guard.py +++ b/tests/test_lock_guard.py @@ -72,4 +72,4 @@ def test_foreign_lock_not_released(patched, monkeypatch, capsys): ) assert lg.cmd_release(repo, "src/x.py") != 0 assert "чужой" in capsys.readouterr().out - assert (lock_dir / "src_x_py.lock").exists() \ No newline at end of file + assert (lock_dir / "src_x_py.lock").exists()