Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -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`.

Expand Down Expand Up @@ -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)

<!-- stale-ignore -->
> **v3.2.0 Data Flow:** PropertyGraph содержит `ASSIGNED_FROM`-рёбра, отслеживающие
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 │
│ └───────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
```
Expand Down Expand Up @@ -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) |
Expand Down
2 changes: 1 addition & 1 deletion docs/ru/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ multilingual-e5-small ONNX (CPU, in-process) → llama-server reranker

---

## MCP Инструменты (61 всего)
## MCP Инструменты (64 всего)

### Основной поиск

Expand Down
8 changes: 5 additions & 3 deletions scripts/verify_diary.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}"

Expand Down
35 changes: 25 additions & 10 deletions src/core/change_preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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'}")
Expand Down
6 changes: 4 additions & 2 deletions src/core/git_hooks_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions src/mcp/server_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
"""

Expand Down
2 changes: 1 addition & 1 deletion tests/test_auto_doc_updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
2 changes: 1 addition & 1 deletion tests/test_lock_guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
assert (lock_dir / "src_x_py.lock").exists()
Loading