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:
AIPass
2026-03-17 16:44:50 -07:00
committed by GitHub
co-authored by @spawn Claude Opus 4.6 @ai_mail
parent 8a4f8b0c61
commit 8c3ad2657c
25 changed files with 206 additions and 102 deletions
+9 -2
View File
@@ -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.
+4 -1
View File
@@ -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,
+4 -1
View File
@@ -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
+7 -5
View File
@@ -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:
+4 -5
View File
@@ -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
+1 -1
View File
@@ -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."""
+1 -1
View File
@@ -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.
+5 -1
View File
@@ -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,
+5 -3
View File
@@ -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."""
+12 -4
View File
@@ -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,
+14 -4
View File
@@ -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
+12 -5
View File
@@ -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")
+13 -4
View File
@@ -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
+14 -4
View File
@@ -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
+1 -1
View File
@@ -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
# =============================================
"""
-15
View File
@@ -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
-