feat(spawn): seedgo compliance cleanup — 93% to 98% (#68)
* fix(ai_mail): resolve relative mailbox_path bug + archive dead handlers Fix get_user_by_email() and get_all_users() returning relative mailbox_path values from registry instead of absolute paths (causing doubled paths in reply). Added path resolution matching get_current_user() pattern. Archive 7 unused handler files to apps/.archive/ (gitignored): - pending_work.py — planned feature, never wired - lock_utils.py — superseded by inbox_lock.py - data_ops.py — consumer (error_monitor) was archived - config_generator.py, users/load.py, registry/validate.py — scaffolded, never used - trigger/error_handler.py — superseded by trigger branch's event system Added test_user_paths.py (13 tests) covering absolute path resolution. Co-Authored-By: @ai_mail <ai_mail@aipass> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(spawn): seedgo compliance cleanup — 93% to 98% Archive legacy files (dev.local.md, ai_mail.local/, .seed/). Update META Modified dates on 22 files. Update README architecture tree and freshness. Fix 15 Pyright unused warnings. Add introspection no-args gates to 6 modules. Wire json_handler + log_operation to 15 operational files. Add seedgo bypass for 5 pure data files and log_structure. Remove deprecated dev.local.md from builder template. Co-Authored-By: @spawn <spawn@aipass> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: @ai_mail <ai_mail@aipass> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: @spawn <spawn@aipass>
This commit is contained in:
co-authored by
@spawn
Claude Opus 4.6
@ai_mail
parent
8a4f8b0c61
commit
8c3ad2657c
@@ -91,6 +91,12 @@ spawn/
|
||||
│ ├── metadata.py # Branch name extraction, profile detection
|
||||
│ ├── placeholders.py # {{PLACEHOLDER}} replacement engine
|
||||
│ ├── registry.py # AIPASS_REGISTRY.json CRUD
|
||||
│ ├── json_ops.py # JSON read/write operations
|
||||
│ ├── json/
|
||||
│ │ └── json_handler.py # JSON I/O abstraction
|
||||
│ ├── meta_ops.py # Branch metadata generation
|
||||
│ ├── change_detection.py # File diff detection
|
||||
│ ├── reconcile.py # Registry/filesystem reconciliation
|
||||
│ ├── update_ops.py # Update implementation (class-aware)
|
||||
│ ├── delete_ops.py # Delete implementation logic
|
||||
│ ├── sync_registry_ops.py # Registry sync implementation
|
||||
@@ -98,7 +104,8 @@ spawn/
|
||||
├── templates/
|
||||
│ ├── builder/ # Full scaffold template (apps/, modules/, handlers/)
|
||||
│ ├── birthright/ # Minimal template (.trinity/, .aipass/, README.md)
|
||||
│ └── agent_mock_branch/ # Reference implementation
|
||||
│ └── .archive/
|
||||
│ └── agent_mock_branch/ # Reference implementation
|
||||
├── tools/ # Branch verification utilities
|
||||
├── docs/ # Documentation
|
||||
├── spawn_json/ # JSON tracking directory
|
||||
@@ -144,4 +151,4 @@ spawn/
|
||||
|
||||
---
|
||||
|
||||
*Last Updated: 2026-03-07*
|
||||
*Last Updated: 2026-03-17*
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Template change detection — template vs branch metadata
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-03-07
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-10
|
||||
# =============================================
|
||||
|
||||
"""Template change detection handler.
|
||||
@@ -16,8 +16,6 @@ identify additions, updates, renames, and pruned files.
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from aipass.prax.apps.modules.logger import system_logger as logger
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# CHANGE DETECTION
|
||||
@@ -125,8 +123,6 @@ def detect_changes(
|
||||
|
||||
template_path = t_info.get("path", t_info.get("current_name", ""))
|
||||
branch_path = b_info.get("current_path", "")
|
||||
template_name = t_info.get("current_name", Path(template_path).name)
|
||||
branch_name = b_info.get("current_name", "")
|
||||
|
||||
# Check for RENAME: same ID but path changed in template
|
||||
# Compare the template-side path against the template_name stored in branch meta
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Citizen class registry — maps class names to template directories
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-03-07
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-10
|
||||
# =============================================
|
||||
|
||||
"""Citizen class registry for spawn template system.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Delete handler — implementation logic for branch deletion
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-03-07
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-10
|
||||
# =============================================
|
||||
|
||||
"""Delete handler implementation for branch lifecycle management.
|
||||
@@ -24,6 +24,7 @@ from aipass.spawn.apps.handlers.registry import (
|
||||
save_registry,
|
||||
_branches_as_list,
|
||||
)
|
||||
from aipass.spawn.apps.handlers.json import json_handler
|
||||
|
||||
# Repo root — resolved from spawn package location
|
||||
_REPO_ROOT = Path(__file__).parents[5] # handlers/apps/spawn/aipass/src/AIPass
|
||||
@@ -193,6 +194,8 @@ def delete_branch(
|
||||
"error": msg,
|
||||
}
|
||||
|
||||
json_handler.log_operation("delete_executed", data={"branch": branch_name})
|
||||
|
||||
return {
|
||||
"branch": branch_name,
|
||||
"success": True,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Template copy and file operations
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-03-05
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-10
|
||||
# =============================================
|
||||
|
||||
"""Template copy and file rename operations."""
|
||||
@@ -15,6 +15,7 @@ from pathlib import Path
|
||||
|
||||
from aipass.prax.apps.modules.logger import system_logger as logger
|
||||
from aipass.spawn.apps.handlers.placeholders import replace_placeholders
|
||||
from aipass.spawn.apps.handlers.json import json_handler
|
||||
|
||||
# Patterns to skip during template copy
|
||||
SKIP_NAMES = {"__pycache__", ".git", ".template_registry.json"}
|
||||
@@ -72,6 +73,8 @@ def copy_template(template_dir, target_dir, replacements):
|
||||
shutil.copy2(item, dest)
|
||||
copied.append(f"{dest_rel} (binary)")
|
||||
|
||||
json_handler.log_operation("template_copied", data={"target": str(target_dir)})
|
||||
|
||||
return copied, skipped
|
||||
|
||||
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
# =================== AIPass ====================
|
||||
# Name: json_handler.py
|
||||
# Description: JSON file read/write operations for spawn
|
||||
# Version: 1.0.0
|
||||
# Description: JSON file read/write and operation logging for spawn
|
||||
# Version: 1.1.0
|
||||
# Created: 2026-03-07
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-17
|
||||
# =============================================
|
||||
|
||||
"""JSON handler for spawn module."""
|
||||
"""JSON handler for spawn module.
|
||||
|
||||
Provides JSON I/O utilities and operation logging for the three-JSON system.
|
||||
"""
|
||||
|
||||
import inspect
|
||||
import json
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
_SPAWN_ROOT = Path(__file__).resolve().parents[3]
|
||||
_JSON_DIR = _SPAWN_ROOT / "spawn_json"
|
||||
|
||||
|
||||
def read_json(file_path: Path) -> Optional[dict]:
|
||||
@@ -29,3 +37,60 @@ def write_json(file_path: Path, data: Any, indent: int = 2) -> bool:
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
|
||||
def _get_caller_module_name() -> str:
|
||||
"""Auto-detect calling module name from call stack."""
|
||||
stack = inspect.stack()
|
||||
if len(stack) > 2:
|
||||
caller_path = Path(stack[2].filename)
|
||||
module_name = caller_path.stem
|
||||
if module_name and not module_name.startswith('_'):
|
||||
return module_name
|
||||
return "unknown"
|
||||
|
||||
|
||||
def log_operation(operation: str, data: Dict[str, Any] | None = None, module_name: str | None = None) -> bool:
|
||||
"""Add entry to module operation log with automatic rotation.
|
||||
|
||||
Auto-detects calling module if module_name not provided.
|
||||
|
||||
Args:
|
||||
operation: Operation name to log
|
||||
data: Optional data dict
|
||||
module_name: Optional module name (auto-detected if not provided)
|
||||
|
||||
Returns:
|
||||
True if successful, False otherwise
|
||||
"""
|
||||
if module_name is None:
|
||||
module_name = _get_caller_module_name()
|
||||
|
||||
_JSON_DIR.mkdir(parents=True, exist_ok=True)
|
||||
log_path = _JSON_DIR / f"{module_name}_log.json"
|
||||
|
||||
log: list = []
|
||||
if log_path.exists():
|
||||
try:
|
||||
log = json.loads(log_path.read_text())
|
||||
except (json.JSONDecodeError, OSError):
|
||||
log = []
|
||||
|
||||
entry: Dict[str, Any] = {
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"operation": operation,
|
||||
}
|
||||
if data:
|
||||
entry["data"] = data
|
||||
|
||||
log.append(entry)
|
||||
|
||||
# Rotate at 100 entries
|
||||
if len(log) > 100:
|
||||
log = log[-100:]
|
||||
|
||||
try:
|
||||
log_path.write_text(json.dumps(log, indent=2) + "\n")
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: JSON operations — deep merge, migrations, backups
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-03-07
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-10
|
||||
# =============================================
|
||||
|
||||
"""JSON operations handler for branch updates.
|
||||
@@ -16,11 +16,11 @@ transformations, and backup utilities.
|
||||
import json
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
from fnmatch import fnmatch
|
||||
from pathlib import Path
|
||||
from typing import Any, Optional
|
||||
|
||||
from aipass.prax.apps.modules.logger import system_logger as logger
|
||||
from aipass.spawn.apps.handlers.json import json_handler
|
||||
|
||||
# Branch metadata location
|
||||
_BRANCH_META_DIR = ".spawn"
|
||||
@@ -171,10 +171,12 @@ def apply_migrations(data: dict, migrations: list) -> dict:
|
||||
f"'{op_type}' failed: {exc}"
|
||||
)
|
||||
|
||||
json_handler.log_operation("migration_applied", data={"migration": migration_id})
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def _apply_key_rename(data: dict, op: dict, migration_id: str) -> None:
|
||||
def _apply_key_rename(data: dict, op: dict, _migration_id: str) -> None:
|
||||
"""Rename a key, preserving its value.
|
||||
|
||||
Args:
|
||||
@@ -202,7 +204,7 @@ def _apply_key_rename(data: dict, op: dict, migration_id: str) -> None:
|
||||
_delete_nested_key(data, from_key)
|
||||
|
||||
|
||||
def _apply_move_to_nested(data: dict, op: dict, migration_id: str) -> None:
|
||||
def _apply_move_to_nested(data: dict, op: dict, _migration_id: str) -> None:
|
||||
"""Move multiple keys under a new parent key.
|
||||
|
||||
Args:
|
||||
@@ -242,7 +244,7 @@ def _apply_move_to_nested(data: dict, op: dict, migration_id: str) -> None:
|
||||
del data[key]
|
||||
|
||||
|
||||
def _apply_add_missing_keys(data: dict, op: dict, migration_id: str) -> None:
|
||||
def _apply_add_missing_keys(data: dict, op: dict, _migration_id: str) -> None:
|
||||
"""Add keys with default values if they don't exist.
|
||||
|
||||
Args:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Branch metadata operations for update tracking
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-03-07
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-10
|
||||
# =============================================
|
||||
|
||||
"""Branch metadata operations — manages .spawn/.branch_meta.json for per-branch tracking.
|
||||
@@ -20,15 +20,12 @@ from pathlib import Path
|
||||
from typing import Any, Optional
|
||||
|
||||
from aipass.prax.apps.modules.logger import system_logger as logger
|
||||
from aipass.spawn.apps.handlers.json import json_handler
|
||||
|
||||
# =============================================================================
|
||||
# CONSTANTS
|
||||
# =============================================================================
|
||||
|
||||
# Path to the agent template directory (relative to this file)
|
||||
_SPAWN_ROOT = Path(__file__).parents[2] # spawn/
|
||||
_TEMPLATE_DIR = _SPAWN_ROOT / "templates" / "builder"
|
||||
|
||||
_BRANCH_META_DIR = ".spawn"
|
||||
_BRANCH_META_FILE = ".branch_meta.json"
|
||||
_TEMPLATE_REGISTRY_FILE = ".template_registry.json"
|
||||
@@ -282,4 +279,6 @@ def generate_branch_meta(branch_dir: Path, template_registry: dict) -> dict:
|
||||
"directory_tracking": directory_tracking,
|
||||
}
|
||||
|
||||
json_handler.log_operation("meta_generated", data={"branch": branch_name})
|
||||
|
||||
return meta
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Branch name extraction and profile detection
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-03-05
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-10
|
||||
# =============================================
|
||||
|
||||
"""Branch name extraction and profile detection."""
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Passport command — grants birthright citizenship to a directory
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-03-07
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-10
|
||||
# =============================================
|
||||
|
||||
"""Passport command implementation for granting birthright citizenship.
|
||||
@@ -36,6 +36,7 @@ from aipass.spawn.apps.handlers.registry import (
|
||||
get_next_citizen_number,
|
||||
)
|
||||
from aipass.spawn.apps.handlers.class_registry import get_template_dir
|
||||
from aipass.spawn.apps.handlers.json import json_handler
|
||||
|
||||
|
||||
def grant_passport(
|
||||
@@ -89,10 +90,10 @@ def grant_passport(
|
||||
ensure_directory(target)
|
||||
|
||||
# Copy birthright template with placeholder replacement
|
||||
copied, skipped = copy_template(template, target, replacements)
|
||||
copied, _ = copy_template(template, target, replacements)
|
||||
|
||||
# Rename any placeholder paths
|
||||
renamed = rename_placeholder_paths(target, folder_name)
|
||||
_ = rename_placeholder_paths(target, folder_name)
|
||||
|
||||
# Regenerate template registry
|
||||
regenerate_template_registry(target)
|
||||
@@ -107,6 +108,7 @@ def grant_passport(
|
||||
issues = validate_no_placeholders(target)
|
||||
|
||||
logger.info(f"[passport] Granted birthright to {branch_upper} at {target}")
|
||||
json_handler.log_operation("passport_created", data={"target": str(target)})
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Placeholder replacement engine
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-03-05
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-13
|
||||
# =============================================
|
||||
|
||||
"""Placeholder replacement engine for agent templates."""
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Branch state reconciliation — filesystem vs metadata
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-03-07
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-10
|
||||
# =============================================
|
||||
|
||||
"""Branch state reconciliation handler.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: *_REGISTRY.json discovery and CRUD operations
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-03-05
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-13
|
||||
# =============================================
|
||||
|
||||
"""*_REGISTRY.json discovery and CRUD operations."""
|
||||
@@ -13,6 +13,8 @@ import os
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
from aipass.spawn.apps.handlers.json import json_handler
|
||||
|
||||
|
||||
def _branches_as_list(branches):
|
||||
"""Normalize branches to a list regardless of storage format.
|
||||
@@ -217,4 +219,6 @@ def add_to_registry(registry_path, branch_name, branch_path, profile, email, pur
|
||||
registry["branches"] = branches
|
||||
registry["metadata"]["total_branches"] = len(_branches_as_list(branches))
|
||||
|
||||
json_handler.log_operation("registry_updated", data={"branch": branch_name})
|
||||
|
||||
return save_registry(registry_path, registry)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Registry sync handler — implementation logic for registry repair
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-03-07
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-10
|
||||
# =============================================
|
||||
|
||||
"""Registry synchronization handler for branch lifecycle management.
|
||||
@@ -32,6 +32,7 @@ from aipass.spawn.apps.handlers.meta_ops import (
|
||||
)
|
||||
from aipass.spawn.apps.handlers.file_ops import regenerate_template_registry
|
||||
from aipass.spawn.apps.handlers.class_registry import get_template_dir
|
||||
from aipass.spawn.apps.handlers.json import json_handler
|
||||
|
||||
# Repo root — resolved from spawn package location
|
||||
_REPO_ROOT = Path(__file__).parents[5] # handlers/apps/spawn/aipass/src/AIPass
|
||||
@@ -103,7 +104,7 @@ def sync_registry(fix: bool = False) -> dict:
|
||||
stale.append(name)
|
||||
|
||||
# Check filesystem branches against registry
|
||||
for name, path in filesystem_branches.items():
|
||||
for name, _path in filesystem_branches.items():
|
||||
if name not in registered:
|
||||
unregistered_list.append(name)
|
||||
|
||||
@@ -206,6 +207,8 @@ def sync_registry(fix: bool = False) -> dict:
|
||||
spawn_rebuilt.append(name)
|
||||
logger.info(f"[sync-registry] Rebuilt .spawn/ for: {name}")
|
||||
|
||||
json_handler.log_operation("registry_scanned")
|
||||
|
||||
return {
|
||||
"stale": stale,
|
||||
"unregistered": unregistered_list,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Template sync handler — implementation logic for template sync
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-03-07
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-10
|
||||
# =============================================
|
||||
|
||||
"""Template synchronization handler for branch lifecycle management.
|
||||
@@ -18,6 +18,7 @@ import shutil
|
||||
from pathlib import Path
|
||||
|
||||
from aipass.prax.apps.modules.logger import system_logger as logger
|
||||
from aipass.spawn.apps.handlers.json import json_handler
|
||||
|
||||
# Repo root — resolved from spawn package location
|
||||
_REPO_ROOT = Path(__file__).parents[5] # handlers/apps/spawn/aipass/src/AIPass
|
||||
@@ -113,6 +114,8 @@ def sync_templates(sync: bool = False, dry_run: bool = False) -> dict:
|
||||
errors.append(f"Failed to sync {file_key}: {exc}")
|
||||
logger.error(f"[sync-templates] Failed to sync {file_key}: {exc}")
|
||||
|
||||
json_handler.log_operation("templates_pulled")
|
||||
|
||||
return {
|
||||
"managed_files": len(managed_files),
|
||||
"current": current,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Update handler — implementation logic for branch updates
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-03-07
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-10
|
||||
# =============================================
|
||||
|
||||
"""Update handler implementation for branch lifecycle management.
|
||||
@@ -22,7 +22,6 @@ from typing import Any
|
||||
from aipass.prax.apps.modules.logger import system_logger as logger
|
||||
|
||||
from aipass.spawn.apps.handlers.meta_ops import (
|
||||
compute_file_hash,
|
||||
generate_branch_meta,
|
||||
get_template_dir,
|
||||
load_branch_meta,
|
||||
@@ -34,6 +33,7 @@ from aipass.spawn.apps.handlers.change_detection import detect_changes
|
||||
from aipass.spawn.apps.handlers.json_ops import backup_json, deep_merge
|
||||
from aipass.spawn.apps.handlers.placeholders import build_replacements_dict, replace_placeholders
|
||||
from aipass.spawn.apps.handlers.registry import find_registry, load_registry, _branches_as_list
|
||||
from aipass.spawn.apps.handlers.json import json_handler
|
||||
|
||||
# Repo root — resolved from spawn package location
|
||||
_REPO_ROOT = Path(__file__).parents[5] # handlers/apps/spawn/aipass/src/AIPass
|
||||
@@ -241,6 +241,8 @@ def update_branch(branch_name: str, dry_run: bool = False, trace: bool = False)
|
||||
# 10. Return summary
|
||||
# ------------------------------------------------------------------
|
||||
success = len(errors) == 0
|
||||
if success:
|
||||
json_handler.log_operation("update_executed", data={"branch": branch_name})
|
||||
return _result(branch_name, success, counts, errors, dry_run)
|
||||
|
||||
|
||||
@@ -367,7 +369,7 @@ def _execute_addition(
|
||||
template_dir: Path,
|
||||
add_info: dict,
|
||||
replacements: dict,
|
||||
template_registry: dict,
|
||||
_template_registry: dict,
|
||||
trace: bool,
|
||||
) -> None:
|
||||
"""Copy a new template file/directory to the branch with placeholder replacement."""
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Main orchestrator for agent spawning
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-03-05
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-10
|
||||
# =============================================
|
||||
|
||||
"""
|
||||
@@ -36,11 +36,12 @@ from aipass.spawn.apps.handlers.file_ops import copy_template, rename_placeholde
|
||||
from aipass.spawn.apps.handlers.meta_ops import load_template_registry, generate_branch_meta, save_branch_meta
|
||||
from aipass.spawn.apps.handlers.registry import find_registry, add_to_registry, get_next_citizen_number
|
||||
from aipass.spawn.apps.handlers.class_registry import (
|
||||
validate_class,
|
||||
get_default_class,
|
||||
get_available_classes,
|
||||
get_template_dir as _get_template_dir,
|
||||
validate_class as validate_class,
|
||||
get_default_class as get_default_class,
|
||||
get_available_classes as get_available_classes,
|
||||
)
|
||||
from aipass.spawn.apps.handlers.json import json_handler
|
||||
|
||||
# Default template location (relative to spawn package root)
|
||||
DEFAULT_TEMPLATE = Path(__file__).parents[2] / "templates" / "builder"
|
||||
@@ -74,6 +75,11 @@ def handle_command(command: str, args: List[str]) -> bool:
|
||||
Returns:
|
||||
True if command succeeded, False otherwise
|
||||
"""
|
||||
# No args → introspection
|
||||
if not args:
|
||||
print_introspection()
|
||||
return True
|
||||
|
||||
if command == "create":
|
||||
if not args:
|
||||
logger.error("spawn create requires a target path")
|
||||
@@ -185,6 +191,8 @@ def _spawn_agent(target_path, role="", traits="", purpose="", profile=None,
|
||||
# Step 5: Validate no unreplaced placeholders
|
||||
issues = validate_no_placeholders(target)
|
||||
|
||||
json_handler.log_operation("branch_created", data={"branch": branch_upper})
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"branch_name": branch_upper,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Branch deletion — thin CLI layer for archive and deregister
|
||||
# Version: 1.1.0
|
||||
# Created: 2026-03-07
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-14
|
||||
# =============================================
|
||||
|
||||
"""Delete orchestrator for branch lifecycle management.
|
||||
@@ -17,6 +17,7 @@ from aipass.prax import logger
|
||||
from aipass.cli.apps.modules import console, error, warning
|
||||
|
||||
from aipass.spawn.apps.handlers.delete_ops import delete_branch
|
||||
from aipass.spawn.apps.handlers.json import json_handler
|
||||
|
||||
|
||||
def print_introspection():
|
||||
@@ -45,9 +46,15 @@ def handle_command(command: str, args: list) -> bool:
|
||||
Returns:
|
||||
True if command was handled, False otherwise.
|
||||
"""
|
||||
if command == "delete":
|
||||
return handle_delete(args) == 0
|
||||
return False
|
||||
if command != "delete":
|
||||
return False
|
||||
|
||||
# No args → introspection
|
||||
if not args:
|
||||
print_introspection()
|
||||
return True
|
||||
|
||||
return handle_delete(args) == 0
|
||||
|
||||
|
||||
# =============================================================================
|
||||
@@ -95,6 +102,9 @@ def handle_delete(args: list[str]) -> int:
|
||||
error(f"Error deleting {branch_name}: {exc}")
|
||||
return 1
|
||||
|
||||
if result.get("success"):
|
||||
json_handler.log_operation("branch_deleted", data={"branch": branch_name})
|
||||
|
||||
_print_summary(result, dry_run)
|
||||
return 0 if result.get("success") else 1
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Passport command — thin CLI layer for granting birthright citizenship
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-03-07
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-14
|
||||
# =============================================
|
||||
|
||||
"""Passport command orchestrator for branch lifecycle management.
|
||||
@@ -14,10 +14,10 @@ All implementation logic lives in apps/handlers/passport_ops.py.
|
||||
|
||||
import argparse
|
||||
|
||||
from aipass.prax import logger
|
||||
from aipass.cli.apps.modules import console, error, warning
|
||||
|
||||
from aipass.spawn.apps.handlers.passport_ops import grant_passport
|
||||
from aipass.spawn.apps.handlers.json import json_handler
|
||||
|
||||
|
||||
def print_introspection():
|
||||
@@ -42,9 +42,15 @@ def handle_command(command: str, args: list) -> bool:
|
||||
Returns:
|
||||
True if command was handled, False otherwise.
|
||||
"""
|
||||
if command == "passport":
|
||||
return handle_passport(args) == 0
|
||||
return False
|
||||
if command != "passport":
|
||||
return False
|
||||
|
||||
# No args → introspection
|
||||
if not args:
|
||||
print_introspection()
|
||||
return True
|
||||
|
||||
return handle_passport(args) == 0
|
||||
|
||||
|
||||
def handle_passport(args: list[str]) -> int:
|
||||
@@ -89,6 +95,7 @@ def handle_passport(args: list[str]) -> int:
|
||||
)
|
||||
|
||||
if result["success"]:
|
||||
json_handler.log_operation("passport_granted", data={"branch": result["branch_name"]})
|
||||
console.print()
|
||||
console.print(f"[green]Passport granted: {result['branch_name']}[/green]")
|
||||
console.print(f" Class: birthright")
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Registry repair — thin CLI layer for registry synchronization
|
||||
# Version: 1.1.0
|
||||
# Created: 2026-03-07
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-14
|
||||
# =============================================
|
||||
|
||||
"""Registry synchronization for branch lifecycle management.
|
||||
@@ -17,6 +17,7 @@ from aipass.prax import logger
|
||||
from aipass.cli.apps.modules import console, error, warning
|
||||
|
||||
from aipass.spawn.apps.handlers.sync_registry_ops import sync_registry
|
||||
from aipass.spawn.apps.handlers.json import json_handler
|
||||
|
||||
|
||||
def print_introspection():
|
||||
@@ -45,9 +46,15 @@ def handle_command(command: str, args: list) -> bool:
|
||||
Returns:
|
||||
True if command was handled, False otherwise.
|
||||
"""
|
||||
if command == "sync-registry":
|
||||
return handle_sync_registry(args) == 0
|
||||
return False
|
||||
if command != "sync-registry":
|
||||
return False
|
||||
|
||||
# No args → introspection
|
||||
if not args:
|
||||
print_introspection()
|
||||
return True
|
||||
|
||||
return handle_sync_registry(args) == 0
|
||||
|
||||
|
||||
# =============================================================================
|
||||
@@ -79,6 +86,8 @@ def handle_sync_registry(args: list[str]) -> int:
|
||||
error(str(exc))
|
||||
return 1
|
||||
|
||||
json_handler.log_operation("registry_synced")
|
||||
|
||||
_print_summary(result)
|
||||
return 0
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Template sync — thin CLI layer for template synchronization
|
||||
# Version: 1.1.0
|
||||
# Created: 2026-03-07
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-14
|
||||
# =============================================
|
||||
|
||||
"""Template synchronization for branch lifecycle management.
|
||||
@@ -17,6 +17,7 @@ from aipass.prax import logger
|
||||
from aipass.cli.apps.modules import console, error, warning
|
||||
|
||||
from aipass.spawn.apps.handlers.sync_templates_ops import sync_templates
|
||||
from aipass.spawn.apps.handlers.json import json_handler
|
||||
|
||||
|
||||
def print_introspection():
|
||||
@@ -45,9 +46,15 @@ def handle_command(command: str, args: list) -> bool:
|
||||
Returns:
|
||||
True if command was handled, False otherwise.
|
||||
"""
|
||||
if command == "sync-templates":
|
||||
return handle_sync_templates(args) == 0
|
||||
return False
|
||||
if command != "sync-templates":
|
||||
return False
|
||||
|
||||
# No args → introspection
|
||||
if not args:
|
||||
print_introspection()
|
||||
return True
|
||||
|
||||
return handle_sync_templates(args) == 0
|
||||
|
||||
|
||||
# =============================================================================
|
||||
@@ -84,6 +91,8 @@ def handle_sync_templates(args: list[str]) -> int:
|
||||
error(str(exc))
|
||||
return 1
|
||||
|
||||
json_handler.log_operation("templates_synced")
|
||||
|
||||
_print_summary(result, dry_run)
|
||||
return 0
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Update orchestrator — thin CLI layer for branch updates
|
||||
# Version: 1.1.0
|
||||
# Created: 2026-03-07
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-14
|
||||
# =============================================
|
||||
|
||||
"""Update orchestrator for branch lifecycle management.
|
||||
@@ -20,6 +20,7 @@ from aipass.spawn.apps.handlers.update_ops import (
|
||||
update_branch,
|
||||
update_all,
|
||||
)
|
||||
from aipass.spawn.apps.handlers.json import json_handler
|
||||
|
||||
|
||||
def print_introspection():
|
||||
@@ -48,9 +49,15 @@ def handle_command(command: str, args: list) -> bool:
|
||||
Returns:
|
||||
True if command was handled, False otherwise.
|
||||
"""
|
||||
if command == "update":
|
||||
return handle_update(args) == 0
|
||||
return False
|
||||
if command != "update":
|
||||
return False
|
||||
|
||||
# No args → introspection
|
||||
if not args:
|
||||
print_introspection()
|
||||
return True
|
||||
|
||||
return handle_update(args) == 0
|
||||
|
||||
|
||||
# =============================================================================
|
||||
@@ -121,6 +128,9 @@ def handle_update(args: list[str]) -> int:
|
||||
error(f"Error updating {branch_name}: {exc}")
|
||||
return 1
|
||||
|
||||
if result.get("success"):
|
||||
json_handler.log_operation("branch_updated", data={"branch": branch_name})
|
||||
|
||||
_print_branch_summary(result, dry_run)
|
||||
return 0 if result.get("success") else 1
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Description: Entry point CLI for drone @spawn
|
||||
# Version: 1.0.0
|
||||
# Created: 2026-03-05
|
||||
# Modified: 2026-03-07
|
||||
# Modified: 2026-03-14
|
||||
# =============================================
|
||||
|
||||
"""
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# dev.local.md - spawn
|
||||
```
|
||||
Branch: src/aipass/spawn
|
||||
Created: 2026-03-05
|
||||
```
|
||||
|
||||
## Issues
|
||||
|
||||
- None currently
|
||||
|
||||
---
|
||||
|
||||
## Todos
|
||||
|
||||
- None currently
|
||||
@@ -1,23 +0,0 @@
|
||||
# dev.local.md - {{BRANCHNAME}}
|
||||
```
|
||||
Branch: {{CWD}}
|
||||
Created: {{DATE}}
|
||||
```
|
||||
|
||||
## Active Work
|
||||
|
||||
-
|
||||
|
||||
## Issues
|
||||
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
## Todos
|
||||
|
||||
-
|
||||
|
||||
## Notepad
|
||||
|
||||
-
|
||||
Reference in New Issue
Block a user