refactor: Update component structure to use behavior and stack attributes, enhancing clarity and functionality across services, tools, and frontends

This commit is contained in:
2026-02-23 16:32:55 -08:00
parent 3343e955fd
commit 56b9c8ddf1
45 changed files with 698 additions and 667 deletions

View File

@@ -25,7 +25,7 @@ class TestCreateCommand:
args = Namespace(
name="my-api",
type="service",
stack="python-fastapi",
description="My API service",
port=9050,
)
@@ -60,7 +60,7 @@ class TestCreateCommand:
from castle_cli.commands.create import run_create
args = Namespace(name="my-tool2", type="tool", description="My tool", port=None)
args = Namespace(name="my-tool2", stack="python-cli", description="My tool", port=None)
result = run_create(args)
assert result == 0
@@ -73,27 +73,6 @@ class TestCreateCommand:
assert comp.tool is not None
assert comp.install is not None
def test_create_library(self, castle_root: Path) -> None:
"""Create a new library project."""
with (
patch("castle_cli.commands.create.load_config") as mock_load,
patch("castle_cli.commands.create.save_config"),
):
config = load_config(castle_root)
mock_load.return_value = config
from castle_cli.commands.create import run_create
args = Namespace(name="my-lib", type="library", description="My library", port=None)
result = run_create(args)
assert result == 0
project_dir = castle_root / "components" / "my-lib"
assert project_dir.exists()
assert (project_dir / "src" / "my_lib" / "__init__.py").exists()
assert (project_dir / "CLAUDE.md").exists()
assert "my-lib" in config.components
def test_create_duplicate_fails(self, castle_root: Path, capsys: object) -> None:
"""Creating a project with existing name fails."""
with patch("castle_cli.commands.create.load_config") as mock_load:
@@ -105,7 +84,7 @@ class TestCreateCommand:
# test-svc exists in the services section
args = Namespace(
name="test-svc",
type="service",
stack="python-fastapi",
description="Duplicate",
port=None,
)
@@ -126,7 +105,7 @@ class TestCreateCommand:
args = Namespace(
name="auto-port-svc",
type="service",
stack="python-fastapi",
description="Auto port",
port=None,
)

View File

@@ -25,7 +25,7 @@ class TestInfoCommand:
assert result == 0
output = capsys.readouterr().out
assert "test-svc" in output
assert "service" in output
assert "daemon" in output
assert "19000" in output
def test_info_tool(self, castle_root: Path, capsys) -> None:
@@ -73,7 +73,7 @@ class TestInfoCommand:
assert result == 0
output = capsys.readouterr().out
data = json.loads(output)
assert data["category"] == "service"
assert data["behavior"] == "daemon"
assert data["service"]["expose"]["http"]["internal"]["port"] == 19000
def test_info_shows_env(self, castle_root: Path, capsys) -> None:
@@ -91,8 +91,8 @@ class TestInfoCommand:
output = capsys.readouterr().out
assert "TEST_SVC_DATA_DIR" in output
def test_info_shows_category(self, castle_root: Path, capsys) -> None:
"""Info displays category instead of roles."""
def test_info_shows_behavior(self, castle_root: Path, capsys) -> None:
"""Info displays behavior."""
from castle_cli.config import load_config
with patch("castle_cli.commands.info.load_config") as mock_load:
@@ -104,5 +104,5 @@ class TestInfoCommand:
assert result == 0
output = capsys.readouterr().out
assert "category" in output
assert "service" in output
assert "behavior" in output
assert "daemon" in output

View File

@@ -19,7 +19,7 @@ class TestListCommand:
from castle_cli.config import load_config
mock_load.return_value = load_config(castle_root)
args = Namespace(type=None, json=False)
args = Namespace(behavior=None, stack=None, json=False)
result = run_list(args)
assert result == 0
@@ -27,13 +27,13 @@ class TestListCommand:
assert "test-svc" in captured.out
assert "test-tool" in captured.out
def test_list_filter_service(self, castle_root: Path, capsys: object) -> None:
"""List filtered to services."""
def test_list_filter_daemon(self, castle_root: Path, capsys: object) -> None:
"""List filtered to daemons."""
with patch("castle_cli.commands.list_cmd.load_config") as mock_load:
from castle_cli.config import load_config
mock_load.return_value = load_config(castle_root)
args = Namespace(type="service", json=False)
args = Namespace(behavior="daemon", stack=None, json=False)
result = run_list(args)
assert result == 0
@@ -47,7 +47,7 @@ class TestListCommand:
from castle_cli.config import load_config
mock_load.return_value = load_config(castle_root)
args = Namespace(type="tool", json=False)
args = Namespace(behavior="tool", stack=None, json=False)
result = run_list(args)
assert result == 0
@@ -56,12 +56,12 @@ class TestListCommand:
assert "test-svc" not in captured.out
def test_list_filter_job(self, castle_root: Path, capsys: object) -> None:
"""List filtered to jobs."""
"""List filtered to jobs (shown under tool behavior)."""
with patch("castle_cli.commands.list_cmd.load_config") as mock_load:
from castle_cli.config import load_config
mock_load.return_value = load_config(castle_root)
args = Namespace(type="job", json=False)
args = Namespace(behavior="tool", stack=None, json=False)
result = run_list(args)
assert result == 0
@@ -75,7 +75,7 @@ class TestListCommand:
from castle_cli.config import load_config
mock_load.return_value = load_config(castle_root)
args = Namespace(type=None, json=True)
args = Namespace(behavior=None, stack=None, json=True)
result = run_list(args)
assert result == 0
@@ -85,4 +85,4 @@ class TestListCommand:
assert "test-svc" in names
assert "test-tool" in names
svc = next(p for p in data if p["name"] == "test-svc")
assert svc["category"] == "service"
assert svc["behavior"] == "daemon"