✨ feat(drone): add internal module routing system for drone commands
- introduce drone module registry with metadata and command routing - add seedgo as a registered internal drone module with adapter - update drone CLI to route commands to modules or branches by @target - enhance `drone systems` to list registered modules with descriptions - provide module help integration alongside branch help ✨ feat(seedgo): create drone adapter for seedgo module commands - implement handle_command forwarding to seedgo CLI subprocess - provide get_help function with command-specific help text - support commands: check, audit, list, init with options and examples ✨ feat(seedgo): add __main__.py to support `python -m seedgo` execution ✨ feat(seedgo plugin): add drone-compliance plugin to verify drone adapter compliance - checks existence of drone_adapter.py and required interface elements - validates presence of DRONE_MODULE dict, handle_command(), and get_help() - reports compliance results with pass/fail and score with detailed checks - skips non-target packages and handles syntax errors gracefully ✅ test(drone modules): add comprehensive tests for drone module registry and routing - test listing, info retrieval, command routing, and help retrieval - test CLI integration for `drone systems` and `drone @seedgo` commands - verify module priority over branch routing and error handling ✅ test(seedgo drone compliance): add tests for drone-compliance plugin - test passing cases with proper adapter and interface - test failures for missing adapter, metadata, or functions - test warnings for missing get_help function - test skipping non-target packages and file-not-found cases - test handling of syntax errors in adapter files
This commit is contained in:
+76
-14
@@ -7,9 +7,10 @@ Usage:
|
||||
drone Show available commands
|
||||
drone --help Show help
|
||||
drone --version Show version
|
||||
drone systems List registered branches
|
||||
drone systems List registered branches and modules
|
||||
drone @branch command [args] Route command to branch
|
||||
drone @branch --help Show help for branch
|
||||
drone @module command [args] Route command to internal module
|
||||
drone @branch --help Show help for branch or module
|
||||
|
||||
Zero external dependencies — stdlib only (sys).
|
||||
"""
|
||||
@@ -26,22 +27,30 @@ from aipass.drone import (
|
||||
list_branches,
|
||||
route_command,
|
||||
)
|
||||
from aipass.drone.modules import (
|
||||
is_module,
|
||||
list_modules,
|
||||
get_module_info,
|
||||
route_module_command,
|
||||
get_module_help,
|
||||
)
|
||||
|
||||
_HELP_TEXT = """\
|
||||
drone — AIPass branch command router
|
||||
drone — AIPass command router
|
||||
|
||||
Usage:
|
||||
drone Show this help
|
||||
drone --help Show this help
|
||||
drone --version Show version
|
||||
drone systems List registered branches
|
||||
drone @branch command [args] Route command to branch
|
||||
drone @branch --help Show help for branch
|
||||
drone systems List registered branches and modules
|
||||
drone @target command [args] Route command to branch or module
|
||||
drone @target --help Show help for branch or module
|
||||
|
||||
Examples:
|
||||
drone systems
|
||||
drone @seedgo audit src/
|
||||
drone @seedgo check src/myfile.py
|
||||
drone @flow status
|
||||
drone @flow run --verbose
|
||||
drone @flow --help
|
||||
"""
|
||||
|
||||
@@ -82,23 +91,49 @@ def main() -> None:
|
||||
|
||||
|
||||
def _cmd_systems() -> None:
|
||||
"""Handle `drone systems` — list registered branches."""
|
||||
"""Handle `drone systems` — list registered branches and modules."""
|
||||
branches = list_branches()
|
||||
if not branches:
|
||||
print("No branches registered.")
|
||||
modules = list_modules()
|
||||
|
||||
if not branches and not modules:
|
||||
print("No branches or modules registered.")
|
||||
sys.exit(0)
|
||||
|
||||
print(f"Registered branches ({len(branches)}):")
|
||||
for name in sorted(branches):
|
||||
print(f" {name}")
|
||||
if modules:
|
||||
print(f"Modules ({len(modules)}):")
|
||||
for name in modules:
|
||||
info = get_module_info(name)
|
||||
if info:
|
||||
print(f" @{name} {info.description}")
|
||||
else:
|
||||
print(f" @{name} (not available)")
|
||||
if branches:
|
||||
print()
|
||||
|
||||
if branches:
|
||||
print(f"Branches ({len(branches)}):")
|
||||
for name in sorted(branches):
|
||||
print(f" {name}")
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def _cmd_branch(args: list[str]) -> None:
|
||||
"""Handle `drone @branch command [args]` or `drone @branch --help`."""
|
||||
"""Handle `drone @target command [args]` or `drone @target --help`.
|
||||
|
||||
Checks internal modules first (e.g. @seedgo), then falls back
|
||||
to branch registry for external branches.
|
||||
"""
|
||||
target = args[0]
|
||||
rest = args[1:]
|
||||
module_name = target.lstrip("@")
|
||||
|
||||
# Check if this is a registered internal module
|
||||
if is_module(module_name):
|
||||
_cmd_module(module_name, rest)
|
||||
return
|
||||
|
||||
# Fall through to branch routing
|
||||
# drone @branch --help
|
||||
if not rest or rest == ["--help"]:
|
||||
try:
|
||||
@@ -133,3 +168,30 @@ def _cmd_branch(args: list[str]) -> None:
|
||||
if result.stderr:
|
||||
print(result.stderr, end="", file=sys.stderr)
|
||||
sys.exit(result.exit_code)
|
||||
|
||||
|
||||
def _cmd_module(name: str, args: list[str]) -> None:
|
||||
"""Handle routing to an internal module (e.g. @seedgo)."""
|
||||
# drone @module --help (or no args)
|
||||
if not args or args == ["--help"]:
|
||||
help_text = get_module_help(name)
|
||||
if help_text:
|
||||
print(help_text, end="")
|
||||
else:
|
||||
print(f"No help available for @{name}.")
|
||||
sys.exit(0)
|
||||
|
||||
command = args[0]
|
||||
cmd_args = args[1:] if len(args) > 1 else None
|
||||
|
||||
try:
|
||||
result = route_module_command(name, command, cmd_args)
|
||||
except (ImportError, AttributeError) as exc:
|
||||
print(f"drone: module @{name} is registered but not available: {exc}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if result.get("stdout"):
|
||||
print(result["stdout"], end="")
|
||||
if result.get("stderr"):
|
||||
print(result["stderr"], end="", file=sys.stderr)
|
||||
sys.exit(result.get("exit_code", 0))
|
||||
|
||||
Reference in New Issue
Block a user