Enable cli options for plugin (#22)
* added the entry point for plugin with cli group option
This commit is contained in:
+4
-2
@@ -1,7 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "goose-ai"
|
name = "goose-ai"
|
||||||
description = "a programming agent that runs on your machine"
|
description = "a programming agent that runs on your machine"
|
||||||
version = "0.8.0"
|
version = "0.8.1"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
@@ -30,9 +30,11 @@ default = "goose.profile:default_profile"
|
|||||||
[project.entry-points."goose.command"]
|
[project.entry-points."goose.command"]
|
||||||
file = "goose.command.file:FileCommand"
|
file = "goose.command.file:FileCommand"
|
||||||
|
|
||||||
[project.entry-points."goose.cli"]
|
[project.entry-points."goose.cli.group"]
|
||||||
goose = "goose.cli.main:goose_cli"
|
goose = "goose.cli.main:goose_cli"
|
||||||
|
|
||||||
|
[project.entry-points."goose.cli.group_option"]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
goose = "goose.cli.main:cli"
|
goose = "goose.cli.main:cli"
|
||||||
|
|
||||||
|
|||||||
+17
-8
@@ -12,12 +12,10 @@ from goose.cli.session import Session
|
|||||||
from goose.utils import load_plugins
|
from goose.utils import load_plugins
|
||||||
from goose.utils.session_file import list_sorted_session_files
|
from goose.utils.session_file import list_sorted_session_files
|
||||||
|
|
||||||
|
|
||||||
@click.group()
|
@click.group()
|
||||||
def goose_cli() -> None:
|
def goose_cli() -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@goose_cli.command()
|
@goose_cli.command()
|
||||||
def version() -> None:
|
def version() -> None:
|
||||||
"""Lists the version of goose and any plugins"""
|
"""Lists the version of goose and any plugins"""
|
||||||
@@ -81,7 +79,7 @@ def session_start(profile: str, plan: Optional[str] = None) -> None:
|
|||||||
@session.command(name="resume")
|
@session.command(name="resume")
|
||||||
@click.argument("name", required=False)
|
@click.argument("name", required=False)
|
||||||
@click.option("--profile")
|
@click.option("--profile")
|
||||||
def session_resume(name: str, profile: str) -> None:
|
def session_resume(name: Optional[str], profile: str) -> None:
|
||||||
"""Resume an existing goose session"""
|
"""Resume an existing goose session"""
|
||||||
if name is None:
|
if name is None:
|
||||||
session_files = get_session_files()
|
session_files = get_session_files()
|
||||||
@@ -97,6 +95,7 @@ def session_resume(name: str, profile: str) -> None:
|
|||||||
|
|
||||||
@session.command(name="list")
|
@session.command(name="list")
|
||||||
def session_list() -> None:
|
def session_list() -> None:
|
||||||
|
"""List goose sessions"""
|
||||||
session_files = get_session_files().items()
|
session_files = get_session_files().items()
|
||||||
for session_name, session_file in session_files:
|
for session_name, session_file in session_files:
|
||||||
print(f"{datetime.fromtimestamp(session_file.stat().st_mtime).strftime('%Y-%m-%d %H:%M:%S')} {session_name}")
|
print(f"{datetime.fromtimestamp(session_file.stat().st_mtime).strftime('%Y-%m-%d %H:%M:%S')} {session_name}")
|
||||||
@@ -105,6 +104,7 @@ def session_list() -> None:
|
|||||||
@session.command(name="clear")
|
@session.command(name="clear")
|
||||||
@click.option("--keep", default=3, help="Keep this many entries, default 3")
|
@click.option("--keep", default=3, help="Keep this many entries, default 3")
|
||||||
def session_clear(keep: int) -> None:
|
def session_clear(keep: int) -> None:
|
||||||
|
"""Delete old goose sessions, keeping the most recent sessions up to the specified number"""
|
||||||
for i, (_, session_file) in enumerate(get_session_files().items()):
|
for i, (_, session_file) in enumerate(get_session_files().items()):
|
||||||
if i >= keep:
|
if i >= keep:
|
||||||
session_file.unlink()
|
session_file.unlink()
|
||||||
@@ -113,13 +113,22 @@ def session_clear(keep: int) -> None:
|
|||||||
def get_session_files() -> Dict[str, Path]:
|
def get_session_files() -> Dict[str, Path]:
|
||||||
return list_sorted_session_files(SESSIONS_PATH)
|
return list_sorted_session_files(SESSIONS_PATH)
|
||||||
|
|
||||||
|
@click.group(
|
||||||
|
invoke_without_command=True,
|
||||||
|
name="goose",
|
||||||
|
help="AI-powered tool to assist in solving programming and operational tasks",)
|
||||||
|
@click.pass_context
|
||||||
|
def cli(_: click.Context, **kwargs: Dict) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
# merging goose cli with additional cli plugins.
|
all_cli_group_options = load_plugins("goose.cli.group_option")
|
||||||
def cli() -> None:
|
for option in all_cli_group_options.values():
|
||||||
clis = load_plugins("goose.cli")
|
cli = option()(cli)
|
||||||
cli_list = list(clis.values()) or []
|
|
||||||
click.CommandCollection(sources=cli_list)()
|
|
||||||
|
|
||||||
|
all_cli_groups = load_plugins("goose.cli.group")
|
||||||
|
for group in all_cli_groups.values():
|
||||||
|
for command in group.commands.values():
|
||||||
|
cli.add_command(command)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
cli()
|
cli()
|
||||||
|
|||||||
+41
-1
@@ -1,11 +1,13 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import importlib
|
||||||
from time import time
|
from time import time
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
|
import click
|
||||||
import pytest
|
import pytest
|
||||||
from click.testing import CliRunner
|
from click.testing import CliRunner
|
||||||
from exchange import Message
|
from exchange import Message
|
||||||
from goose.cli.main import goose_cli
|
from goose.cli.main import cli, goose_cli
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@@ -78,3 +80,41 @@ def test_session_clear_command(mock_session_files_path, create_session_file):
|
|||||||
session_files = list(mock_session_files_path.glob("*.jsonl"))
|
session_files = list(mock_session_files_path.glob("*.jsonl"))
|
||||||
assert len(session_files) == 1
|
assert len(session_files) == 1
|
||||||
assert session_files[0].stem == "second"
|
assert session_files[0].stem == "second"
|
||||||
|
|
||||||
|
|
||||||
|
def test_combined_group_option():
|
||||||
|
with patch("goose.utils.load_plugins") as mock_load_plugin:
|
||||||
|
group_option_name = "--describe-commands"
|
||||||
|
def option_callback(ctx, *_):
|
||||||
|
click.echo("Option callback")
|
||||||
|
ctx.exit()
|
||||||
|
mock_group_options = {
|
||||||
|
'option1': lambda: click.option(
|
||||||
|
group_option_name,
|
||||||
|
is_flag=True,
|
||||||
|
callback=option_callback,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
def side_effect_func(param):
|
||||||
|
if param == "goose.cli.group_option":
|
||||||
|
return mock_group_options
|
||||||
|
elif param == "goose.cli.group":
|
||||||
|
return { }
|
||||||
|
mock_load_plugin.side_effect = side_effect_func
|
||||||
|
|
||||||
|
# reload cli after mocking
|
||||||
|
importlib.reload(importlib.import_module('goose.cli.main'))
|
||||||
|
import goose.cli.main
|
||||||
|
cli = goose.cli.main.cli
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
result = runner.invoke(cli, [group_option_name])
|
||||||
|
assert result.exit_code == 0
|
||||||
|
|
||||||
|
def test_combined_group_commands(mock_session):
|
||||||
|
mock_session_class, mock_session_instance = mock_session
|
||||||
|
runner = CliRunner()
|
||||||
|
runner.invoke(cli, ["session", "resume", "session1", "--profile", "default"])
|
||||||
|
mock_session_class.assert_called_once_with(name="session1", profile="default")
|
||||||
|
mock_session_instance.run.assert_called_once()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user