Skip to content

Commit 5355a91

Browse files
committed
fix the reintroduced dead code
1 parent af7a25b commit 5355a91

6 files changed

Lines changed: 8 additions & 224 deletions

File tree

src/autoskillit/server/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
#!/usr/bin/env python3
22
"""MCP server for orchestrating automated skill-driven workflows.
33
4-
Kitchen tools (19 gated) are hidden at startup via FastMCP v3
4+
Kitchen tools (24 gated) are hidden at startup via FastMCP v3
55
mcp.disable(tags={'kitchen'}) applied once after all tool modules are
66
imported. Each new session sees only the 12 ungated tools (including
77
open_kitchen and close_kitchen). Calling the open_kitchen tool reveals
88
all 36 tools for that session via ctx.enable_components(tags={'kitchen'}).
9-
The GateState + .kitchen_gate file mechanism is retained as defense-in-depth.
109
1110
Transport: stdio (default for FastMCP).
1211
"""

src/autoskillit/server/_state.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
from __future__ import annotations
1717

1818
from datetime import UTC
19-
from pathlib import Path
2019

2120
from autoskillit.config import AutomationConfig
2221
from autoskillit.core import get_logger
@@ -32,14 +31,6 @@ def _initialize(ctx: ToolContext) -> None:
3231
global _ctx
3332
_ctx = ctx
3433

35-
# Gate file cleanup: remove stale gate files left by crashed sessions.
36-
try:
37-
from autoskillit.server.helpers import cleanup_stale_gate_file
38-
39-
cleanup_stale_gate_file(Path.cwd())
40-
except Exception:
41-
logger.debug("stale_gate_cleanup_at_startup_failed", exc_info=True)
42-
4334
# Recovery sweep: finalize any orphaned tmpfs trace files from crashed sessions.
4435
try:
4536
from autoskillit.execution import recover_crashed_sessions

src/autoskillit/server/helpers.py

Lines changed: 1 addition & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
"""Gate helpers, dry-walkthrough check, and subprocess wrapper for MCP tools."""
1+
"""Subprocess wrapper, dry-walkthrough check, and shared helpers for MCP tools."""
22

33
from __future__ import annotations
44

5-
import json
6-
import os
75
import time
86
from pathlib import Path
97
from typing import TYPE_CHECKING, Any
108

119
from autoskillit.core import RESERVED_LOG_RECORD_KEYS, TerminationReason, get_logger
12-
from autoskillit.execution import read_boot_id, read_starttime_ticks
1310
from autoskillit.pipeline import gate_error_result
1411
from autoskillit.recipe import (
1512
StaleItem,
@@ -29,7 +26,6 @@
2926
logger = get_logger(__name__)
3027

3128
_HOOK_CONFIG_FILENAME: str = ".autoskillit_hook_config.json"
32-
_GATE_FILENAME: str = ".kitchen_gate"
3329
_HOOK_DIR_COMPONENTS: tuple[str, ...] = (".autoskillit", "temp")
3430

3531

@@ -38,67 +34,6 @@ def _hook_config_path(project_root: Path) -> Path:
3834
return project_root.joinpath(*_HOOK_DIR_COMPONENTS, _HOOK_CONFIG_FILENAME)
3935

4036

41-
def _gate_file_path(project_root: Path) -> Path:
42-
"""Return the canonical path to the kitchen gate file."""
43-
return project_root.joinpath(*_HOOK_DIR_COMPONENTS, _GATE_FILENAME)
44-
45-
46-
def _is_pid_alive(
47-
pid: int,
48-
starttime_ticks: int | None = None,
49-
boot_id: str | None = None,
50-
) -> bool:
51-
"""Return True if the process with pid is the same process that wrote the gate file."""
52-
try:
53-
os.kill(pid, 0)
54-
except ProcessLookupError:
55-
return False
56-
except PermissionError:
57-
pass # process exists but we cannot signal it
58-
59-
if starttime_ticks is not None:
60-
current_ticks = read_starttime_ticks(pid)
61-
if current_ticks is not None and current_ticks != starttime_ticks:
62-
return False # PID reused
63-
64-
if boot_id is not None:
65-
current_boot = read_boot_id()
66-
if current_boot is not None and current_boot != boot_id:
67-
return False # different boot session
68-
69-
return True
70-
71-
72-
def cleanup_stale_gate_file(project_root: Path) -> None:
73-
"""Remove the gate file and companion hook config if the owning process is gone."""
74-
gate_file = _gate_file_path(project_root)
75-
hook_config = _hook_config_path(project_root)
76-
77-
if not gate_file.exists():
78-
return
79-
80-
try:
81-
data = json.loads(gate_file.read_text())
82-
pid = data.get("pid")
83-
starttime_ticks = data.get("starttime_ticks")
84-
boot_id = data.get("boot_id")
85-
except (json.JSONDecodeError, OSError):
86-
# Malformed gate file — remove it and companion
87-
try:
88-
gate_file.unlink(missing_ok=True)
89-
hook_config.unlink(missing_ok=True)
90-
except OSError:
91-
pass
92-
return
93-
94-
if pid is None or not _is_pid_alive(pid, starttime_ticks, boot_id):
95-
try:
96-
gate_file.unlink(missing_ok=True)
97-
hook_config.unlink(missing_ok=True)
98-
except OSError:
99-
pass
100-
101-
10237
async def _notify(
10338
ctx: Context,
10439
level: str,

src/autoskillit/server/tools_kitchen.py

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,15 @@
22

33
from __future__ import annotations
44

5-
import atexit
65
import json
7-
import os
8-
from datetime import UTC, datetime
96
from pathlib import Path
107

118
from fastmcp import Context
129
from fastmcp.dependencies import CurrentContext
1310

1411
from autoskillit.core import PIPELINE_FORBIDDEN_TOOLS, atomic_write, pkg_root
1512
from autoskillit.server import mcp
16-
from autoskillit.server.helpers import (
17-
_find_recipe,
18-
_gate_file_path,
19-
_hook_config_path,
20-
_prime_quota_cache,
21-
read_boot_id,
22-
read_starttime_ticks,
23-
)
24-
25-
26-
def _register_gate_cleanup() -> None:
27-
"""Write the gate file and register an atexit handler to remove it on exit."""
28-
gate_file = _gate_file_path(pkg_root())
29-
try:
30-
gate_file.parent.mkdir(parents=True, exist_ok=True)
31-
payload = {
32-
"pid": os.getpid(),
33-
"starttime_ticks": read_starttime_ticks(os.getpid()),
34-
"boot_id": read_boot_id(),
35-
"opened_at": datetime.now(UTC).isoformat(),
36-
}
37-
atomic_write(gate_file, json.dumps(payload))
38-
except OSError:
39-
return
40-
41-
def _cleanup() -> None:
42-
try:
43-
gate_file.unlink(missing_ok=True)
44-
except OSError:
45-
pass
46-
47-
atexit.register(_cleanup)
13+
from autoskillit.server.helpers import _find_recipe, _hook_config_path, _prime_quota_cache
4814

4915

5016
def _write_hook_config() -> None:
@@ -80,7 +46,6 @@ async def _open_kitchen_handler() -> None:
8046
_get_ctx().gate.enable()
8147
logger.info("open_kitchen", gate_state="open")
8248
_write_hook_config()
83-
_register_gate_cleanup()
8449
await _prime_quota_cache()
8550

8651

tests/server/test_server_init.py

Lines changed: 1 addition & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,7 @@ async def test_disable_reverses_enable(self, tool_ctx):
301301

302302
with patch.object(tools_kitchen_mod, "_prime_quota_cache", new=AsyncMock()):
303303
with patch.object(tools_kitchen_mod, "_write_hook_config"):
304-
with patch.object(tools_kitchen_mod, "_register_gate_cleanup"):
305-
await _open_kitchen_handler()
304+
await _open_kitchen_handler()
306305
_close_kitchen_handler()
307306
result = json.loads(await run_cmd(cmd="echo hi", cwd="/tmp"))
308307
assert result["success"] is False
@@ -612,110 +611,6 @@ def test_get_config_raises_before_initialize(self, monkeypatch):
612611
_state._get_config()
613612

614613

615-
class TestGateFileRecovery:
616-
"""T-RECOVER: _initialize removes stale/malformed gate files at startup."""
617-
618-
@pytest.mark.anyio
619-
async def test_initialize_removes_stale_gate_file(self, monkeypatch, tmp_path):
620-
"""_initialize must remove gate files whose owning PID is dead."""
621-
monkeypatch.chdir(tmp_path)
622-
gate_dir = tmp_path / ".autoskillit" / "temp"
623-
gate_dir.mkdir(parents=True)
624-
gate_file = gate_dir / ".kitchen_gate"
625-
gate_file.write_text(json.dumps({"pid": 999999999, "opened_at": "2026-01-01T00:00:00Z"}))
626-
627-
from autoskillit.server._factory import make_context
628-
from tests.conftest import MockSubprocessRunner
629-
630-
ctx = make_context(
631-
AutomationConfig(), runner=MockSubprocessRunner(), plugin_dir=str(tmp_path)
632-
)
633-
from autoskillit.server._state import _initialize
634-
635-
_initialize(ctx)
636-
assert not gate_file.exists()
637-
638-
@pytest.mark.anyio
639-
async def test_initialize_preserves_live_gate_file(self, monkeypatch, tmp_path):
640-
"""_initialize must NOT remove gate files whose owning PID is alive."""
641-
import os
642-
643-
monkeypatch.chdir(tmp_path)
644-
gate_dir = tmp_path / ".autoskillit" / "temp"
645-
gate_dir.mkdir(parents=True)
646-
gate_file = gate_dir / ".kitchen_gate"
647-
from datetime import UTC, datetime
648-
649-
from autoskillit.execution import read_boot_id, read_starttime_ticks
650-
651-
gate_file.write_text(
652-
json.dumps(
653-
{
654-
"pid": os.getpid(),
655-
"starttime_ticks": read_starttime_ticks(os.getpid()),
656-
"boot_id": read_boot_id(),
657-
"opened_at": datetime.now(UTC).isoformat(),
658-
}
659-
)
660-
)
661-
662-
from autoskillit.server._factory import make_context
663-
from tests.conftest import MockSubprocessRunner
664-
665-
ctx = make_context(
666-
AutomationConfig(), runner=MockSubprocessRunner(), plugin_dir=str(tmp_path)
667-
)
668-
from autoskillit.server._state import _initialize
669-
670-
_initialize(ctx)
671-
assert gate_file.exists() # still there — owning process is alive
672-
673-
@pytest.mark.anyio
674-
async def test_initialize_removes_malformed_gate_file(self, monkeypatch, tmp_path):
675-
"""Malformed gate files must be removed at startup."""
676-
monkeypatch.chdir(tmp_path)
677-
gate_dir = tmp_path / ".autoskillit" / "temp"
678-
gate_dir.mkdir(parents=True)
679-
gate_file = gate_dir / ".kitchen_gate"
680-
gate_file.write_text("not valid json")
681-
682-
from autoskillit.server._factory import make_context
683-
from tests.conftest import MockSubprocessRunner
684-
685-
ctx = make_context(
686-
AutomationConfig(), runner=MockSubprocessRunner(), plugin_dir=str(tmp_path)
687-
)
688-
from autoskillit.server._state import _initialize
689-
690-
_initialize(ctx)
691-
assert not gate_file.exists()
692-
693-
@pytest.mark.anyio
694-
async def test_initialize_removes_companion_hook_config_with_stale_gate(
695-
self, monkeypatch, tmp_path
696-
):
697-
"""_initialize must remove both gate file and companion hook config when stale."""
698-
monkeypatch.chdir(tmp_path)
699-
gate_dir = tmp_path / ".autoskillit" / "temp"
700-
gate_dir.mkdir(parents=True)
701-
gate_file = gate_dir / ".kitchen_gate"
702-
gate_file.write_text(json.dumps({"pid": 999999999, "opened_at": "2026-01-01T00:00:00Z"}))
703-
companion = gate_dir / ".autoskillit_hook_config.json"
704-
companion.write_text("{}")
705-
706-
from autoskillit.server._factory import make_context
707-
from tests.conftest import MockSubprocessRunner
708-
709-
ctx = make_context(
710-
AutomationConfig(), runner=MockSubprocessRunner(), plugin_dir=str(tmp_path)
711-
)
712-
from autoskillit.server._state import _initialize
713-
714-
_initialize(ctx)
715-
assert not gate_file.exists()
716-
assert not companion.exists()
717-
718-
719614
class TestConfigDrivenBehavior:
720615
"""S1-S10: Verify tools use config instead of hardcoded values."""
721616

tests/server/test_tools_kitchen.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,8 @@ async def test_close_kitchen_tool_calls_reset_visibility(tmp_path, monkeypatch):
189189

190190

191191
@pytest.mark.anyio
192-
async def test_open_kitchen_does_not_write_gate_file_directly(tmp_path, monkeypatch):
193-
"""_open_kitchen_handler must not directly write to the gate path (delegates to _register_gate_cleanup)."""
192+
async def test_open_kitchen_does_not_write_gate_file(tmp_path, monkeypatch):
193+
"""_open_kitchen_handler must never write a gate file."""
194194
monkeypatch.chdir(tmp_path)
195195
mock_ctx = _make_mock_ctx()
196196
mock_ctx.config.quota_guard.threshold = None
@@ -199,10 +199,9 @@ async def test_open_kitchen_does_not_write_gate_file_directly(tmp_path, monkeypa
199199
with patch("autoskillit.server._get_ctx", return_value=mock_ctx):
200200
with patch("autoskillit.server.logger"):
201201
with patch("autoskillit.server.tools_kitchen._prime_quota_cache", new=AsyncMock()):
202-
with patch("autoskillit.server.tools_kitchen._register_gate_cleanup"):
203-
from autoskillit.server.tools_kitchen import _open_kitchen_handler
202+
from autoskillit.server.tools_kitchen import _open_kitchen_handler
204203

205-
await _open_kitchen_handler()
204+
await _open_kitchen_handler()
206205
gate_file = tmp_path / ".autoskillit" / "temp" / ".kitchen_gate"
207206
assert not gate_file.exists()
208207

0 commit comments

Comments
 (0)