shellmcp: tool description lists installed modern tools
This commit is contained in:
+25
@@ -56,3 +56,28 @@ def sandbox(cwd, hide=()):
|
||||
elif os.path.exists(path):
|
||||
argv += ["--ro-bind", "/dev/null", path]
|
||||
return argv + ["--chdir", cwd]
|
||||
|
||||
PREFERRED = { # named in the tool description when installed, in this order
|
||||
"rg": "search file contents (instead of grep)", "fd": "find files (instead of find)",
|
||||
"eza": "list files (instead of ls)", "sd": "find and replace (instead of sed)",
|
||||
"dust": "disk usage (instead of du)", "procs": "processes (instead of ps)",
|
||||
"jq": "query JSON", "ast-grep": "search code by syntax", "tokei": "count lines of code"}
|
||||
|
||||
|
||||
def describe(mode, cwd, timeout, limit):
|
||||
"""The tool description: where commands run, the limits, and the modern tools installed."""
|
||||
text = (f"Run a bash command on {socket.gethostname()} as {getpass.getuser()} in {cwd}. "
|
||||
f"Returns its exit code and combined stdout and stderr (at most {limit} characters; "
|
||||
f"the middle of longer output is cut). Commands are killed after {timeout} s. "
|
||||
"There is no terminal: interactive programs, pagers and prompts fail.")
|
||||
if mode == "readonly":
|
||||
text += (" Read-only sandbox: nothing can be written except /tmp, which is emptied "
|
||||
"after every command; no network; other processes are not visible. To change "
|
||||
"something, give the user the command to run instead.")
|
||||
else:
|
||||
text += (" Commands run with the user's full permissions: they can change files, "
|
||||
"processes and the network.")
|
||||
tools = [f"{name}: {what}" for name, what in PREFERRED.items() if shutil.which(name)]
|
||||
if tools:
|
||||
text += " Installed, prefer these: " + "; ".join(tools) + "."
|
||||
return text
|
||||
|
||||
@@ -44,3 +44,14 @@ class Sandbox(unittest.TestCase):
|
||||
self.assertNotIn("key", out)
|
||||
self.assertIn("tmp-ok", out)
|
||||
self.assertFalse(os.path.exists(os.path.join(d, "new")))
|
||||
|
||||
class Describe(unittest.TestCase):
|
||||
def test_names_only_installed_tools_and_the_mode(self):
|
||||
with mock.patch("shutil.which", lambda name: name in ("fd", "rg")):
|
||||
text = shellmcp.describe("readonly", "/srv", 60, 8000)
|
||||
self.assertIn("in /srv.", text)
|
||||
self.assertIn("Read-only sandbox", text)
|
||||
self.assertIn("prefer these: rg: search file contents (instead of grep); "
|
||||
"fd: find files (instead of find).", text)
|
||||
self.assertNotIn("jq", text)
|
||||
self.assertIn("full permissions", shellmcp.describe("all", "/srv", 60, 8000))
|
||||
|
||||
Reference in New Issue
Block a user