refactor: Update component structure to use behavior and stack attributes, enhancing clarity and functionality across services, tools, and frontends
This commit is contained in:
@@ -22,6 +22,13 @@ from castle_cli.manifest import (
|
||||
)
|
||||
from castle_cli.templates.scaffold import scaffold_project
|
||||
|
||||
# Stack determines default behavior and scaffold template
|
||||
STACK_DEFAULTS: dict[str, str] = {
|
||||
"python-fastapi": "daemon",
|
||||
"python-cli": "tool",
|
||||
"react-vite": "frontend",
|
||||
}
|
||||
|
||||
|
||||
def next_available_port(config: object) -> int:
|
||||
"""Find the next available port starting from 9001 (9000 is reserved for gateway)."""
|
||||
@@ -42,7 +49,8 @@ def run_create(args: argparse.Namespace) -> int:
|
||||
"""Create a new project."""
|
||||
config = load_config()
|
||||
name = args.name
|
||||
proj_type = args.type
|
||||
stack = args.stack
|
||||
behavior = STACK_DEFAULTS.get(stack)
|
||||
|
||||
if name in config.components or name in config.services or name in config.jobs:
|
||||
print(f"Error: '{name}' already exists in castle.yaml")
|
||||
@@ -55,9 +63,9 @@ def run_create(args: argparse.Namespace) -> int:
|
||||
print(f"Error: directory 'components/{name}' already exists")
|
||||
return 1
|
||||
|
||||
# Determine port for services
|
||||
# Determine port for daemons
|
||||
port = args.port
|
||||
if proj_type == "service" and port is None:
|
||||
if behavior == "daemon" and port is None:
|
||||
port = next_available_port(config)
|
||||
|
||||
# Package name: convert kebab-case to snake_case
|
||||
@@ -68,18 +76,19 @@ def run_create(args: argparse.Namespace) -> int:
|
||||
project_dir=project_dir,
|
||||
name=name,
|
||||
package_name=package_name,
|
||||
proj_type=proj_type,
|
||||
description=args.description or f"A castle {proj_type}",
|
||||
stack=stack,
|
||||
description=args.description or f"A castle {stack} component",
|
||||
port=port,
|
||||
)
|
||||
|
||||
# Build entries
|
||||
if proj_type == "service":
|
||||
if behavior == "daemon":
|
||||
# Component for software identity
|
||||
config.components[name] = ComponentSpec(
|
||||
id=name,
|
||||
description=args.description or f"A castle {proj_type}",
|
||||
description=args.description or f"A castle {stack} component",
|
||||
source=f"components/{name}",
|
||||
stack=stack,
|
||||
)
|
||||
# Service for deployment
|
||||
config.services[name] = ServiceSpec(
|
||||
@@ -95,32 +104,34 @@ def run_create(args: argparse.Namespace) -> int:
|
||||
proxy=ProxySpec(caddy=CaddySpec(path_prefix=f"/{name}")),
|
||||
manage=ManageSpec(systemd=SystemdSpec()),
|
||||
)
|
||||
elif proj_type == "tool":
|
||||
elif behavior == "tool":
|
||||
config.components[name] = ComponentSpec(
|
||||
id=name,
|
||||
description=args.description or f"A castle {proj_type}",
|
||||
description=args.description or f"A castle {stack} component",
|
||||
source=f"components/{name}",
|
||||
stack=stack,
|
||||
tool=ToolSpec(),
|
||||
install=InstallSpec(path=PathInstallSpec(alias=name)),
|
||||
)
|
||||
else:
|
||||
# library or other
|
||||
# frontend or other
|
||||
config.components[name] = ComponentSpec(
|
||||
id=name,
|
||||
description=args.description or f"A castle {proj_type}",
|
||||
description=args.description or f"A castle {stack} component",
|
||||
source=f"components/{name}",
|
||||
stack=stack,
|
||||
)
|
||||
|
||||
save_config(config)
|
||||
|
||||
print(f"Created {proj_type} '{name}' at {project_dir}")
|
||||
print(f"Created {stack} component '{name}' at {project_dir}")
|
||||
if port:
|
||||
print(f" Port: {port}")
|
||||
print(" Registered in castle.yaml")
|
||||
print("\nNext steps:")
|
||||
print(f" cd components/{name}")
|
||||
print(" uv sync")
|
||||
if proj_type == "service":
|
||||
if behavior == "daemon":
|
||||
print(f" uv run {name} # starts on port {port}")
|
||||
print(f" castle deploy {name} # deploy to ~/.castle/")
|
||||
print(f" castle test {name}")
|
||||
|
||||
Reference in New Issue
Block a user