makefile-agent 0.4.2__tar.gz → 0.4.3__tar.gz
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.
- {makefile_agent-0.4.2/makefile_agent.egg-info → makefile_agent-0.4.3}/PKG-INFO +1 -1
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/builtin_tools/skill_tools.py +19 -3
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/main.py +43 -3
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/skill_backend.py +5 -1
- {makefile_agent-0.4.2 → makefile_agent-0.4.3/makefile_agent.egg-info}/PKG-INFO +1 -1
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/makefile_agent.egg-info/SOURCES.txt +1 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/pyproject.toml +1 -1
- makefile_agent-0.4.3/tests/test_enabled_skills.py +210 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/tests/test_main.py +1 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/LICENSE +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/README.md +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/__init__.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/agent_core/__init__.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/agent_core/agent.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/agent_core/bridge.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/agent_core/constants.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/agent_core/events.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/agent_core/export.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/agent_core/loop.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/agent_core/middleware.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/agent_core/provider.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/agent_shell/__init__.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/agent_shell/run.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/agent_shell/shell.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/agent_shell/user_messages.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/app_dirs.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/builtin_tools/__init__.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/builtin_tools/file_tools.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/memory/__init__.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/memory/memory.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/memory/tools.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/parser.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/protocols.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/provider/__init__.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/provider/anthropic.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/provider/base.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/provider/openai.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/templates/makefile/SYSTEM.md +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/tool_display.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/tool_handler/__init__.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/tool_handler/handler.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/make_agent/tool_handler/runner.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/makefile_agent.egg-info/dependency_links.txt +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/makefile_agent.egg-info/entry_points.txt +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/makefile_agent.egg-info/requires.txt +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/makefile_agent.egg-info/top_level.txt +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/setup.cfg +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/tests/test_agent.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/tests/test_agent_shell.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/tests/test_app_dirs.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/tests/test_bridge.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/tests/test_builtin_tools.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/tests/test_commands.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/tests/test_compact.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/tests/test_memory.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/tests/test_middleware.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/tests/test_parser.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/tests/test_tools.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/tests/test_trusted_skill.py +0 -0
- {makefile_agent-0.4.2 → makefile_agent-0.4.3}/tests/test_user_messages.py +0 -0
|
@@ -120,16 +120,31 @@ def _skill_description(mk_path: Path) -> str:
|
|
|
120
120
|
return " (no description)"
|
|
121
121
|
|
|
122
122
|
|
|
123
|
-
def list_skills(skills_dir: str) -> str:
|
|
124
|
-
"""List all available skills with their names and descriptions.
|
|
123
|
+
def list_skills(skills_dir: str, enabled_skills: frozenset[str] | None = None) -> str:
|
|
124
|
+
"""List all available skills with their names and descriptions.
|
|
125
|
+
|
|
126
|
+
If *enabled_skills* is provided and is not ``{"*"}`` or empty, only those
|
|
127
|
+
skill names are shown. When the set contains ``"*"`` or is None, all
|
|
128
|
+
discovered skills are listed (default: show everything).
|
|
129
|
+
"""
|
|
125
130
|
path = Path(skills_dir)
|
|
126
131
|
if not path.exists():
|
|
127
132
|
return "No skills found (directory does not exist)"
|
|
128
|
-
|
|
133
|
+
|
|
134
|
+
all_skill_dirs = sorted(
|
|
129
135
|
p for p in path.iterdir() if p.is_dir() and (p / "skill.mk").exists()
|
|
130
136
|
)
|
|
137
|
+
if not all_skill_dirs:
|
|
138
|
+
return "No skills found"
|
|
139
|
+
|
|
140
|
+
if enabled_skills is not None:
|
|
141
|
+
skill_dirs = [sd for sd in all_skill_dirs if sd.name in enabled_skills]
|
|
142
|
+
else:
|
|
143
|
+
skill_dirs = all_skill_dirs
|
|
144
|
+
|
|
131
145
|
if not skill_dirs:
|
|
132
146
|
return "No skills found"
|
|
147
|
+
|
|
133
148
|
entries = []
|
|
134
149
|
for sd in skill_dirs:
|
|
135
150
|
desc = _skill_description(sd / "skill.mk")
|
|
@@ -168,6 +183,7 @@ def execute_skill(
|
|
|
168
183
|
injected as environment variables; tokens after ``make`` are passed as make
|
|
169
184
|
arguments (targets and/or make-style variable assignments).
|
|
170
185
|
"""
|
|
186
|
+
|
|
171
187
|
if not _valid_skill_name(name):
|
|
172
188
|
return f"Error: invalid skill name {name!r}. Use letters, numbers, hyphens, underscores, and dots only."
|
|
173
189
|
safe_paths = _resolve_safe_skill_path(skills_dir, name, "skill.mk")
|
|
@@ -10,6 +10,7 @@ from make_agent.agent_core import (
|
|
|
10
10
|
DEFAULT_COMPACT_MODE,
|
|
11
11
|
DEFAULT_MAX_TOKENS,
|
|
12
12
|
DEFAULT_MAX_TOOL_OUTPUT,
|
|
13
|
+
DEFAULT_TOOL_TIMEOUT,
|
|
13
14
|
DEFAULT_USE_PROMPT_CACHE,
|
|
14
15
|
)
|
|
15
16
|
from make_agent.agent_shell import run
|
|
@@ -94,8 +95,36 @@ def _parse_trusted_skills(value: str | None) -> frozenset[str]:
|
|
|
94
95
|
return frozenset(name.strip() for name in value.split(",") if name.strip())
|
|
95
96
|
|
|
96
97
|
|
|
97
|
-
def
|
|
98
|
-
|
|
98
|
+
def _parse_enabled_skills(
|
|
99
|
+
value: str | None, all_names: frozenset[str]
|
|
100
|
+
) -> frozenset[str] | None:
|
|
101
|
+
"""Parse --enabled-skills into a frozenset.
|
|
102
|
+
|
|
103
|
+
Returns None when the user didn't pass the flag (meaning: use all discovered skills).
|
|
104
|
+
When the flag is passed, returns the parsed set. 'all' maps to * (keep all).
|
|
105
|
+
Raises sys.exit on unknown skill names.
|
|
106
|
+
"""
|
|
107
|
+
if not value:
|
|
108
|
+
return None
|
|
109
|
+
|
|
110
|
+
names = frozenset(name.strip() for name in value.split(",") if name.strip())
|
|
111
|
+
unknown = names - all_names
|
|
112
|
+
if unknown:
|
|
113
|
+
sys.exit(
|
|
114
|
+
"make-agent: unknown skill(s): "
|
|
115
|
+
f"{', '.join(sorted(unknown))}. Valid names: {', '.join(sorted(all_names))}"
|
|
116
|
+
)
|
|
117
|
+
return names
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _discover_skill_names(skills_dir: str) -> list[str]:
|
|
121
|
+
"""Return a sorted list of all discoverable skill names from *skills_dir*."""
|
|
122
|
+
path = Path(skills_dir)
|
|
123
|
+
if not path.exists():
|
|
124
|
+
return []
|
|
125
|
+
return sorted(
|
|
126
|
+
p.name for p in path.iterdir() if p.is_dir() and (p / "skill.mk").exists()
|
|
127
|
+
)
|
|
99
128
|
|
|
100
129
|
|
|
101
130
|
def _cmd_run(args: argparse.Namespace) -> None:
|
|
@@ -117,8 +146,13 @@ def _cmd_run(args: argparse.Namespace) -> None:
|
|
|
117
146
|
else:
|
|
118
147
|
skills_dir = str(default_skills_dir(_SKILL_MODE))
|
|
119
148
|
|
|
149
|
+
all_names = _discover_skill_names(skills_dir)
|
|
150
|
+
enabled_skills = _parse_enabled_skills(args.enabled_skills, frozenset(all_names))
|
|
151
|
+
|
|
120
152
|
memory = Memory(mode_memory_path(_SKILL_MODE))
|
|
121
|
-
backend =
|
|
153
|
+
backend = MakefileSkillBackend(
|
|
154
|
+
skills_dir, DEFAULT_TOOL_TIMEOUT, Path.cwd(), enabled_skills
|
|
155
|
+
)
|
|
122
156
|
trusted_skills = _parse_trusted_skills(getattr(args, "trusted_skills", None))
|
|
123
157
|
tool_handler = ToolHandler(backend, memory, disabled, trusted_skills)
|
|
124
158
|
|
|
@@ -231,6 +265,12 @@ def main() -> None:
|
|
|
231
265
|
metavar="EFFORT",
|
|
232
266
|
help=f"Reasoning effort level ({'/'.join(_REASONING_EFFORT_VALUES)}, default: auto)",
|
|
233
267
|
)
|
|
268
|
+
run_p.add_argument(
|
|
269
|
+
"--enabled-skills",
|
|
270
|
+
default=None,
|
|
271
|
+
metavar="SKILLS",
|
|
272
|
+
help="Comma-separated skill names to enable. By default all discovered skills are enabled.",
|
|
273
|
+
)
|
|
234
274
|
run_p.add_argument(
|
|
235
275
|
"--trusted-skills",
|
|
236
276
|
default=None,
|
|
@@ -32,13 +32,17 @@ class MakefileSkillBackend:
|
|
|
32
32
|
skills_dir: str,
|
|
33
33
|
tool_timeout: int = 600,
|
|
34
34
|
base_dir: Path | None = None,
|
|
35
|
+
enabled_skills: frozenset[str] | None = None,
|
|
35
36
|
) -> None:
|
|
36
37
|
self._skills_dir = skills_dir
|
|
37
38
|
self._tool_timeout = tool_timeout
|
|
38
39
|
self._base_dir = base_dir if base_dir is not None else Path.cwd()
|
|
40
|
+
self._enabled_skills = enabled_skills
|
|
39
41
|
self._schemas = MAKEFILE_SKILL_SCHEMAS + FILE_SCHEMAS
|
|
40
42
|
self._executors: dict[str, Any] = {
|
|
41
|
-
"list_skills": lambda **_kw: list_makefile_skills(
|
|
43
|
+
"list_skills": lambda **_kw: list_makefile_skills(
|
|
44
|
+
self._skills_dir, self._enabled_skills
|
|
45
|
+
),
|
|
42
46
|
"read_skill": lambda name, **_kw: read_makefile_skill(
|
|
43
47
|
name, self._skills_dir
|
|
44
48
|
),
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"""Tests for the --enabled-skills CLI feature."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import sys
|
|
7
|
+
from unittest.mock import patch
|
|
8
|
+
|
|
9
|
+
import make_agent.main as main_module
|
|
10
|
+
from make_agent.builtin_tools.skill_tools import list_skills
|
|
11
|
+
from make_agent.main import _discover_skill_names
|
|
12
|
+
from make_agent.skill_backend import MakefileSkillBackend
|
|
13
|
+
|
|
14
|
+
_SKILL_MK = """\
|
|
15
|
+
define DESCRIPTION
|
|
16
|
+
A test skill
|
|
17
|
+
endef
|
|
18
|
+
|
|
19
|
+
.PHONY: greet
|
|
20
|
+
greet:
|
|
21
|
+
@echo hello
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TestParseEnabledSkills:
|
|
26
|
+
def test_none_returns_none(self):
|
|
27
|
+
assert main_module._parse_enabled_skills(None, frozenset()) is None
|
|
28
|
+
|
|
29
|
+
def test_comma_separated_list(self):
|
|
30
|
+
all_names = frozenset({"git", "run", "file-list"})
|
|
31
|
+
result = main_module._parse_enabled_skills("git,run", all_names)
|
|
32
|
+
assert result == frozenset({"git", "run"})
|
|
33
|
+
|
|
34
|
+
def test_single_name(self):
|
|
35
|
+
result = main_module._parse_enabled_skills("git", frozenset({"git"}))
|
|
36
|
+
assert result == frozenset({"git"})
|
|
37
|
+
|
|
38
|
+
def test_unknown_name_exits(self):
|
|
39
|
+
all_names = frozenset({"git", "run"})
|
|
40
|
+
with patch.object(sys, "exit", side_effect=SystemExit) as mock_exit:
|
|
41
|
+
try:
|
|
42
|
+
main_module._parse_enabled_skills("ghost", all_names)
|
|
43
|
+
except SystemExit:
|
|
44
|
+
pass
|
|
45
|
+
mock_exit.assert_called_once()
|
|
46
|
+
|
|
47
|
+
def test_whitespace_stripped(self):
|
|
48
|
+
result = main_module._parse_enabled_skills(
|
|
49
|
+
" git , run ", frozenset({"git", "run"})
|
|
50
|
+
)
|
|
51
|
+
assert result == frozenset({"git", "run"})
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class TestDiscoverSkillNames:
|
|
55
|
+
def test_missing_dir(self, tmp_path):
|
|
56
|
+
assert _discover_skill_names(str(tmp_path / "nonexistent")) == []
|
|
57
|
+
|
|
58
|
+
def test_empty_dir(self, tmp_path):
|
|
59
|
+
assert _discover_skill_names(str(tmp_path)) == []
|
|
60
|
+
|
|
61
|
+
def test_returns_sorted_names(self, tmp_path):
|
|
62
|
+
(tmp_path / "zzz").mkdir()
|
|
63
|
+
(tmp_path / "zzz" / "skill.mk").write_text(_SKILL_MK)
|
|
64
|
+
(tmp_path / "aaa").mkdir()
|
|
65
|
+
(tmp_path / "aaa" / "skill.mk").write_text(_SKILL_MK)
|
|
66
|
+
assert _discover_skill_names(str(tmp_path)) == ["aaa", "zzz"]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class TestListSkillsFiltering:
|
|
70
|
+
def test_no_filter_shows_all(self, tmp_path):
|
|
71
|
+
for name in ("git", "run", "file-list"):
|
|
72
|
+
(tmp_path / name).mkdir()
|
|
73
|
+
(tmp_path / name / "skill.mk").write_text(_SKILL_MK)
|
|
74
|
+
result = list_skills(str(tmp_path))
|
|
75
|
+
assert "git:" in result
|
|
76
|
+
assert "run:" in result
|
|
77
|
+
assert "file-list:" in result
|
|
78
|
+
|
|
79
|
+
def test_subset_filters_correctly(self, tmp_path):
|
|
80
|
+
for name in ("git", "run", "file-list"):
|
|
81
|
+
(tmp_path / name).mkdir()
|
|
82
|
+
(tmp_path / name / "skill.mk").write_text(_SKILL_MK)
|
|
83
|
+
result = list_skills(
|
|
84
|
+
str(tmp_path), enabled_skills=frozenset({"git", "file-list"})
|
|
85
|
+
)
|
|
86
|
+
assert "git:" in result
|
|
87
|
+
assert "file-list:" in result
|
|
88
|
+
assert "run:" not in result
|
|
89
|
+
|
|
90
|
+
def test_empty_result_when_none_match(self, tmp_path):
|
|
91
|
+
(tmp_path / "git").mkdir()
|
|
92
|
+
(tmp_path / "git" / "skill.mk").write_text(_SKILL_MK)
|
|
93
|
+
result = list_skills(str(tmp_path), enabled_skills=frozenset({"ghost"}))
|
|
94
|
+
assert "No skills found" in result
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class TestBackendIntegration:
|
|
98
|
+
def test_list_skills_filtered(self, tmp_path):
|
|
99
|
+
for name in ("git", "run"):
|
|
100
|
+
(tmp_path / name).mkdir()
|
|
101
|
+
(tmp_path / name / "skill.mk").write_text(_SKILL_MK)
|
|
102
|
+
backend = MakefileSkillBackend(str(tmp_path), enabled_skills=frozenset({"git"}))
|
|
103
|
+
result = backend.executors["list_skills"]()
|
|
104
|
+
assert "git:" in result
|
|
105
|
+
assert "run:" not in result
|
|
106
|
+
|
|
107
|
+
def test_default_no_filter(self, tmp_path):
|
|
108
|
+
"""When enabled_skills is None (default), all skills work."""
|
|
109
|
+
(tmp_path / "git").mkdir()
|
|
110
|
+
(tmp_path / "git" / "skill.mk").write_text(_SKILL_MK)
|
|
111
|
+
backend = MakefileSkillBackend(str(tmp_path)) # no enabled_skills
|
|
112
|
+
result = backend.executors["list_skills"]()
|
|
113
|
+
assert "git:" in result
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class TestCmdRunWithEnabledSkills:
|
|
117
|
+
def test_enabled_skills_passed_to_backend(self, tmp_path):
|
|
118
|
+
# _cmd_run appends /makefile to the skills_dir, so create there.
|
|
119
|
+
skills_dir = tmp_path / "skills" / "makefile"
|
|
120
|
+
skills_dir.mkdir(parents=True)
|
|
121
|
+
(skills_dir / "git").mkdir()
|
|
122
|
+
(skills_dir / "git" / "skill.mk").write_text(_SKILL_MK)
|
|
123
|
+
(skills_dir / "run").mkdir()
|
|
124
|
+
(skills_dir / "run" / "skill.mk").write_text(_SKILL_MK)
|
|
125
|
+
|
|
126
|
+
args = _run_args(
|
|
127
|
+
prompt="do it",
|
|
128
|
+
skills_dir=str(tmp_path / "skills"),
|
|
129
|
+
enabled_skills="git",
|
|
130
|
+
)
|
|
131
|
+
captured: dict = {}
|
|
132
|
+
|
|
133
|
+
async def _fake_run(**kwargs):
|
|
134
|
+
captured.update(kwargs)
|
|
135
|
+
|
|
136
|
+
with (
|
|
137
|
+
patch.object(main_module, "run", _fake_run),
|
|
138
|
+
patch.object(main_module, "ensure_mode_system_prompt"),
|
|
139
|
+
patch.object(
|
|
140
|
+
main_module, "mode_dir", return_value=tmp_path / "makefile-mode"
|
|
141
|
+
),
|
|
142
|
+
patch.object(
|
|
143
|
+
main_module,
|
|
144
|
+
"mode_memory_path",
|
|
145
|
+
return_value=tmp_path / "makefile-memory.db",
|
|
146
|
+
),
|
|
147
|
+
):
|
|
148
|
+
main_module._cmd_run(args)
|
|
149
|
+
|
|
150
|
+
backend = captured["tool_handler"]._backend
|
|
151
|
+
assert isinstance(backend, MakefileSkillBackend)
|
|
152
|
+
result = backend.executors["list_skills"]()
|
|
153
|
+
assert "git:" in result
|
|
154
|
+
assert "run:" not in result
|
|
155
|
+
|
|
156
|
+
def test_no_enabled_skills_flag_passes_none(self, tmp_path):
|
|
157
|
+
# _cmd_run appends /makefile to the skills_dir, so create there.
|
|
158
|
+
skills_dir = tmp_path / "skills" / "makefile"
|
|
159
|
+
skills_dir.mkdir(parents=True)
|
|
160
|
+
(skills_dir / "git").mkdir()
|
|
161
|
+
(skills_dir / "git" / "skill.mk").write_text(_SKILL_MK)
|
|
162
|
+
|
|
163
|
+
args = _run_args(prompt="do it", skills_dir=str(tmp_path / "skills"))
|
|
164
|
+
captured: dict = {}
|
|
165
|
+
|
|
166
|
+
async def _fake_run(**kwargs):
|
|
167
|
+
captured.update(kwargs)
|
|
168
|
+
|
|
169
|
+
with (
|
|
170
|
+
patch.object(main_module, "run", _fake_run),
|
|
171
|
+
patch.object(main_module, "ensure_mode_system_prompt"),
|
|
172
|
+
patch.object(
|
|
173
|
+
main_module, "mode_dir", return_value=tmp_path / "makefile-mode"
|
|
174
|
+
),
|
|
175
|
+
patch.object(
|
|
176
|
+
main_module,
|
|
177
|
+
"mode_memory_path",
|
|
178
|
+
return_value=tmp_path / "makefile-memory.db",
|
|
179
|
+
),
|
|
180
|
+
):
|
|
181
|
+
main_module._cmd_run(args)
|
|
182
|
+
|
|
183
|
+
backend = captured["tool_handler"]._backend
|
|
184
|
+
assert isinstance(backend, MakefileSkillBackend)
|
|
185
|
+
# None means all skills enabled
|
|
186
|
+
result = backend.executors["list_skills"]()
|
|
187
|
+
assert "git:" in result
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _run_args(**kwargs) -> argparse.Namespace:
|
|
191
|
+
defaults = dict(
|
|
192
|
+
model="model-x",
|
|
193
|
+
prompt=None,
|
|
194
|
+
prompt_file=None,
|
|
195
|
+
system=None,
|
|
196
|
+
system_file=None,
|
|
197
|
+
max_retries=5,
|
|
198
|
+
tool_timeout=600,
|
|
199
|
+
max_tool_output=20000,
|
|
200
|
+
max_tokens=4096,
|
|
201
|
+
skills_dir=None,
|
|
202
|
+
disable_builtin_tools=None,
|
|
203
|
+
reasoning_effort="auto",
|
|
204
|
+
skill_mode="makefile",
|
|
205
|
+
prompt_cache=False,
|
|
206
|
+
compact_mode="drop",
|
|
207
|
+
enabled_skills=None,
|
|
208
|
+
)
|
|
209
|
+
defaults.update(kwargs)
|
|
210
|
+
return argparse.Namespace(**defaults)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|