feat(system): S84: drone BUG fixes (version, dead imports, interactive constants) + spawn BUG fixes (passport path, hash length)

Co-Authored-By: @devpulse <devpulse@aipass>
This commit is contained in:
AIOSAI
2026-04-10 02:15:38 -07:00
co-authored by @devpulse
parent 576304dea3
commit 5700c21797
8 changed files with 54 additions and 20 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ from aipass.drone.apps.modules import (
from aipass.drone.apps.modules.resolver import branch_exists, get_branch_info, list_branches, resolve_branch
from aipass.drone.apps.modules.router import route_all, route_command
__version__ = "1.0.0"
__version__ = "1.1.0"
__all__ = [
# Core API
+6 -10
View File
@@ -38,6 +38,10 @@ from aipass.drone.apps.modules.module_registry import (
VERSION = "1.1.0"
MODULES_DIR = Path(__file__).parent / "modules"
# Interactive mode — commands/branches that bypass capture + timeout for live terminal output.
INTERACTIVE_COMMANDS = ("monitor", "audit")
INTERACTIVE_BRANCHES = ("cli",)
# =============================================================================
# AUTO-DISCOVERY
@@ -287,10 +291,7 @@ def _handle_custom_command(args: list[str]) -> int:
cmd_args = list(cmd_data.get("args", [])) + remaining_args
module_name = target.lstrip("@").lower()
# Interactive detection -- same logic as _handle_target
interactive_commands = ("monitor", "audit")
interactive_branches = ("cli",)
interactive = command in interactive_commands or module_name in interactive_branches
interactive = command in INTERACTIVE_COMMANDS or module_name in INTERACTIVE_BRANCHES
try:
result = route_command(
@@ -319,14 +320,9 @@ def _handle_target(args: List[str]) -> int:
rest = args[1:]
module_name = target.lstrip("@").lower()
# Interactive mode bypasses capture + timeout for human-facing output.
# Per-command: specific commands that need live terminal (progress bars, TUI).
# Per-branch: all commands from that branch get interactive mode (Rich CLI).
interactive_commands = ("monitor", "audit")
interactive_branches = ("cli",)
first_cmd = rest[0] if rest and rest[0] != "--help" else None
needs_interactive = (
first_cmd in interactive_commands or module_name in interactive_branches
first_cmd in INTERACTIVE_COMMANDS or module_name in INTERACTIVE_BRANCHES
)
# Route to internal module — unless command needs interactive terminal,
@@ -19,7 +19,6 @@ from dataclasses import dataclass, field
from pathlib import Path
from typing import Dict, List, Optional
from aipass.prax import logger
from aipass.prax.apps.modules.logger import system_logger
from .exceptions import CommandExecutionError
from aipass.drone.apps.handlers.json import json_handler
@@ -19,7 +19,6 @@ import sys
from pathlib import Path
from typing import Dict, List, Optional
from aipass.prax import logger
from aipass.prax.apps.modules.logger import system_logger
from .exceptions import CommandExecutionError
from .executor import CommandResult, execute_command
-1
View File
@@ -17,7 +17,6 @@ import os
from pathlib import Path
from typing import Dict, List, Optional
from aipass.prax import logger
from aipass.prax.apps.modules.logger import system_logger
from aipass.cli.apps.modules import console
from aipass.drone.apps.handlers.executor import CommandResult
+1 -1
View File
@@ -186,7 +186,7 @@ def regenerate_template_registry(target_dir):
file_id = f"f{file_idx:03d}"
try:
content = item.read_bytes()
content_hash = hashlib.sha256(content).hexdigest()[:16]
content_hash = hashlib.sha256(content).hexdigest()[:12]
except (IOError, PermissionError) as e:
logger.error(f"[spawn] Failed to read file for hashing {item}: {e}")
content_hash = "unreadable"
+45 -4
View File
@@ -14,10 +14,13 @@ All implementation logic lives in apps/handlers/passport_ops.py.
import argparse
from pathlib import Path
from aipass.cli.apps.modules import console, error, warning
from aipass.prax import logger
from aipass.spawn.apps.handlers.passport_ops import grant_passport
from aipass.spawn.apps.handlers.registry import find_registry
from aipass.spawn.apps.handlers.json import json_handler
@@ -58,6 +61,46 @@ def handle_command(command: str, args: list) -> bool:
return handle_passport(args) == 0
def _resolve_target(dirname: str) -> Path:
"""Resolve a @dirname to a filesystem path.
Searches CWD, project root (via registry), and src/ subdirectories.
For new directories, defaults to CWD-relative.
"""
# Absolute or home-relative path — use directly
if dirname.startswith("/") or dirname.startswith("~"):
return Path(dirname).expanduser()
# 1. CWD-relative
cwd_path = Path.cwd() / dirname
if cwd_path.exists():
return cwd_path
# 2. Project-relative via registry
try:
reg_path = find_registry()
project_root = reg_path.parent
for candidate in [
project_root / dirname,
project_root / "src" / dirname,
]:
if candidate.exists():
return candidate
# Search src/*/dirname (e.g., src/aipass/target)
src_dir = project_root / "src"
if src_dir.is_dir():
for sub in src_dir.iterdir():
if sub.is_dir():
candidate = sub / dirname
if candidate.exists():
return candidate
except Exception as exc:
logger.warning("[passport] Registry lookup failed during target resolution: %s", exc)
# 3. Default: CWD-relative (passport will create it if needed)
return cwd_path
def handle_passport(args: list[str]) -> int:
"""Parse args and execute passport grant.
@@ -93,10 +136,8 @@ def handle_passport(args: list[str]) -> int:
# Strip @ prefix if present
target = parsed.target.lstrip("@")
# Resolve relative to src/aipass/ (standard branch location)
from pathlib import Path
aipass_root = Path(__file__).parents[3] # modules -> apps -> spawn -> aipass
target_path = aipass_root / target
# Resolve target path — CWD-aware for external project support
target_path = _resolve_target(target)
result = grant_passport(
target_path=str(target_path),
+1 -1
View File
@@ -381,7 +381,7 @@ class TestRegenerateTemplateRegistry:
expected_hash = hashlib.sha256(
content.encode("utf-8")
).hexdigest()[:16]
).hexdigest()[:12]
# Find the file entry
files = data["files"]