File size: 3,061 Bytes
53b2ac9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# SPDX-License-Identifier: MIT
"""Tests that command-line flags survive the config reload done by --cwd.

Uses only pytest + stdlib. No LLM server is contacted: agent_turn is stubbed
and only records the global state main() ended up with.
"""

import os
import sys

import pytest

sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))

import trashclaw


@pytest.fixture
def run_main(tmp_path, monkeypatch):
    """Run main() with the given argv and report the resulting settings."""
    # Isolate from the developer's own config/env so defaults are the real ones.
    monkeypatch.setattr(trashclaw, "CONFIG_FILE", str(tmp_path / "no-such-config.json"))
    for var in ("TRASHCLAW_READONLY", "TRASHCLAW_AUTO_SHELL", "TRASHCLAW_URL"):
        monkeypatch.delenv(var, raising=False)
    monkeypatch.setattr(trashclaw, "READ_ONLY_MODE", False)
    monkeypatch.setattr(trashclaw, "APPROVE_SHELL", True)
    monkeypatch.setattr(trashclaw, "LLAMA_URL", "http://localhost:8080")

    project = tmp_path / "project"
    project.mkdir()

    def _run(*flags):
        seen = {}
        monkeypatch.setattr(
            trashclaw,
            "agent_turn",
            lambda msg: seen.update(
                read_only=trashclaw.READ_ONLY_MODE,
                approve_shell=trashclaw.APPROVE_SHELL,
                url=trashclaw.LLAMA_URL,
                blocks_write=trashclaw._read_only_blocked("write_file", {}),
                tool_names={
                    t["function"]["name"] for t in trashclaw._available_tools()
                },
            ),
        )
        argv = ["trashclaw.py"]
        for flag in flags:
            argv.extend(flag.replace("{cwd}", str(project)).split(" "))
        argv.extend(["-e", "audit this repo"])
        monkeypatch.setattr(sys, "argv", argv)
        trashclaw.main()
        return seen

    _run.project = project
    return _run


def test_read_only_survives_later_cwd(run_main):
    """--read-only before --cwd must still block writes (order must not matter)."""
    for flags in (
        ("--read-only",),
        ("--read-only", "--cwd {cwd}"),
        ("--cwd {cwd}", "--read-only"),
        ("--read-only", "--cwd={cwd}"),
    ):
        seen = run_main(*flags)
        assert seen["read_only"] is True, flags
        assert seen["blocks_write"] is True, flags
        for blocked in trashclaw.READ_ONLY_BLOCKED_TOOLS:
            assert blocked not in seen["tool_names"], (flags, blocked)


def test_url_and_auto_shell_survive_later_cwd(run_main):
    seen = run_main("--url http://box:9999", "--cwd {cwd}")
    assert seen["url"] == "http://box:9999"

    seen = run_main("--auto-shell", "--cwd {cwd}")
    assert seen["approve_shell"] is False


def test_project_config_still_applies_when_no_flag_overrides_it(run_main):
    """--cwd must keep loading the project config for settings not set on the CLI."""
    (run_main.project / ".trashclaw.json").write_text('{"read_only": true}')
    seen = run_main("--cwd {cwd}")
    assert seen["read_only"] is True
    assert seen["blocks_write"] is True