♻️ refactor(aipass): unify branch registry discovery and path resolution
- implement _find_registry() to locate AIPASS_REGISTRY.json dynamically - update discover_branches() to resolve absolute branch paths consistently - fix _is_branch_private() to use _find_registry() and private registry path correctly - update readme_ops, verify checks, and cli_standard to resolve paths relative to current file - adjust standards_audit to use discover_branches() for private branch path lookup - improve robustness and flexibility by removing hardcoded home directory paths 📝 docs(gitignore): add local cheat sheets and Docker.md to gitignore - ignore local cheat sheets and Docker.md files as they are not source code ♻️ refactor(architecture_check): fix branch root detection loop condition - change loop condition to stop at filesystem root instead of home directory - prevent infinite loop by checking if current directory equals its parent ♻️ refactor(readme_generator): default target to current working directory - change default path from fixed user home subdirectory to current working dir - improves usability and flexibility when running script without arguments
This commit is contained in:
@@ -46,3 +46,6 @@ aipass_json/
|
||||
|
||||
|
||||
setup-workspace.sh
|
||||
|
||||
# Local cheat sheets (not source code)
|
||||
# Docker.md
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
},
|
||||
{
|
||||
"name": "DEVPULSE",
|
||||
"path": "/home/aipass/aipass_business/AIPass/src/aipass/devpulse",
|
||||
"path": "src/aipass/devpulse",
|
||||
"profile": "library",
|
||||
"description": "Orchestration hub for AIPass public repo. Manages dev notes, DPLANs, system status dashboards. The DEV_CENTRAL of AIPass.",
|
||||
"email": "@devpulse",
|
||||
|
||||
@@ -31,11 +31,12 @@ import json
|
||||
|
||||
def _is_branch_private(branch_name: str) -> bool:
|
||||
"""Check if branch is in the private registry."""
|
||||
registry_path = Path.home() / "PRIVATE_BRANCH_REGISTRY.json"
|
||||
if not registry_path.exists():
|
||||
registry_path = _find_registry()
|
||||
priv_path = registry_path.parent / "PRIVATE_BRANCH_REGISTRY.json" if registry_path.exists() else None
|
||||
if not priv_path or not priv_path.exists():
|
||||
return False
|
||||
try:
|
||||
with open(registry_path, 'r', encoding='utf-8') as f:
|
||||
with open(priv_path, 'r', encoding='utf-8') as f:
|
||||
registry = json.load(f)
|
||||
for branch in registry.get("branches", []):
|
||||
if branch.get("name", "").upper() == branch_name.upper():
|
||||
|
||||
@@ -1,42 +1,68 @@
|
||||
"""
|
||||
Branch Discovery Handler
|
||||
|
||||
Discovers all branches from the registry for diagnostics scanning.
|
||||
Discovers all branches from AIPASS_REGISTRY.json for diagnostics scanning.
|
||||
"""
|
||||
|
||||
# =================== META ====================
|
||||
# Name: discovery.py
|
||||
# Description: Branch Discovery Handler
|
||||
# Version: 1.0.0
|
||||
# Version: 2.0.0
|
||||
# Created: 2026-03-05
|
||||
# Modified: 2026-03-05
|
||||
# Modified: 2026-03-06
|
||||
# =============================================
|
||||
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Dict, List
|
||||
|
||||
|
||||
def _find_registry() -> Path:
|
||||
"""Find AIPASS_REGISTRY.json by walking up from this file's location."""
|
||||
current = Path(__file__).resolve().parent
|
||||
for parent in [current] + list(current.parents):
|
||||
candidate = parent / "AIPASS_REGISTRY.json"
|
||||
if candidate.exists():
|
||||
return candidate
|
||||
return Path.cwd() / "AIPASS_REGISTRY.json"
|
||||
|
||||
|
||||
def discover_branches() -> List[Dict]:
|
||||
"""
|
||||
Discover all branches from registry
|
||||
Discover all branches from AIPASS_REGISTRY.json for diagnostics.
|
||||
|
||||
Returns:
|
||||
List of dicts with 'name' and 'path' keys
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
branches = []
|
||||
registry_path = _find_registry()
|
||||
|
||||
# Infrastructure
|
||||
AIPASS_ROOT = Path.home() / "aipass_core"
|
||||
sys.path.insert(0, str(AIPASS_ROOT))
|
||||
sys.path.insert(0, str(Path.home()))
|
||||
|
||||
# Import at function level to avoid orchestration at module level
|
||||
from drone.apps.modules import get_all_branches
|
||||
if not registry_path.exists():
|
||||
return branches
|
||||
|
||||
try:
|
||||
branches = get_all_branches()
|
||||
return branches
|
||||
except Exception as e:
|
||||
with open(registry_path, 'r', encoding='utf-8') as f:
|
||||
registry_data = json.load(f)
|
||||
|
||||
registry_dir = registry_path.parent
|
||||
|
||||
for branch in registry_data.get('branches', []):
|
||||
branch_name = branch.get('name', '')
|
||||
raw_path = branch.get('path', '')
|
||||
branch_path = Path(raw_path)
|
||||
|
||||
if not branch_path.is_absolute():
|
||||
branch_path = (registry_dir / branch_path).resolve()
|
||||
|
||||
if branch_path.exists():
|
||||
branches.append({
|
||||
'name': branch_name,
|
||||
'path': str(branch_path)
|
||||
})
|
||||
|
||||
return sorted(branches, key=lambda x: x['name'])
|
||||
|
||||
except (json.JSONDecodeError, IOError) as e:
|
||||
print(f"Error discovering branches: {e}")
|
||||
return []
|
||||
return branches
|
||||
|
||||
@@ -411,7 +411,7 @@ def check_template_baseline(module_path: str, bypass_rules: list | None = None)
|
||||
|
||||
# Find the branch root (parent of apps/ directory)
|
||||
current = path.parent
|
||||
while current != Path.home() and current.name != '/':
|
||||
while current != current.parent:
|
||||
if current.name == 'apps' and current.parent:
|
||||
branch_path = current.parent
|
||||
break
|
||||
|
||||
@@ -661,7 +661,7 @@ def update_readme_auto_sections(branch_path: str, dry_run: bool = False) -> dict
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
target = sys.argv[1] if len(sys.argv) > 1 else str(Path.home() / "aipass_core" / "cortex")
|
||||
target = sys.argv[1] if len(sys.argv) > 1 else str(Path.cwd())
|
||||
print(f"Generating README sections for: {target}\n{'='*70}")
|
||||
sections = generate_all_sections(target)
|
||||
for name, content in sections.items():
|
||||
|
||||
@@ -28,8 +28,18 @@ from typing import Dict, List, Optional
|
||||
# CONSTANTS
|
||||
# =============================================================================
|
||||
|
||||
REGISTRY_PATH = Path.home() / "BRANCH_REGISTRY.json"
|
||||
GENERATOR_PATH = Path.home() / "seed" / "apps" / "handlers" / "standards" / "readme_generator.py"
|
||||
def _find_registry() -> Path:
|
||||
"""Find AIPASS_REGISTRY.json by walking up from this file's location."""
|
||||
current = Path(__file__).resolve().parent
|
||||
for parent in [current] + list(current.parents):
|
||||
candidate = parent / "AIPASS_REGISTRY.json"
|
||||
if candidate.exists():
|
||||
return candidate
|
||||
return Path.cwd() / "AIPASS_REGISTRY.json"
|
||||
|
||||
REGISTRY_PATH = _find_registry()
|
||||
# Generator lives in same handlers/standards/ directory as this file
|
||||
GENERATOR_PATH = Path(__file__).resolve().parent / "readme_generator.py"
|
||||
|
||||
# Section display names for output
|
||||
SECTION_NAMES = {
|
||||
|
||||
@@ -33,7 +33,7 @@ def check_command_consistency() -> Dict:
|
||||
Returns:
|
||||
Dict with check results
|
||||
"""
|
||||
seed_path = Path.home() / "seed"
|
||||
seed_path = Path(__file__).resolve().parents[5] # -> seedgo root
|
||||
missing_docs = []
|
||||
|
||||
# Define command flags to check (source of truth: where they're implemented)
|
||||
|
||||
@@ -26,7 +26,7 @@ def check_file_freshness() -> Dict:
|
||||
Returns:
|
||||
Dict with check results
|
||||
"""
|
||||
seed_path = Path.home() / "seed"
|
||||
seed_path = Path(__file__).resolve().parents[5] # -> seedgo root
|
||||
issues = []
|
||||
|
||||
# Check if standards_audit.py exists
|
||||
|
||||
@@ -29,7 +29,7 @@ def check_help_consistency() -> Dict:
|
||||
Returns:
|
||||
Dict with check results
|
||||
"""
|
||||
seed_file = Path.home() / "seed" / "apps" / "seed.py"
|
||||
seed_file = Path(__file__).resolve().parents[5] / "apps" / "seedgo.py" # seedgo root / apps / seedgo.py
|
||||
issues = []
|
||||
|
||||
if not seed_file.exists():
|
||||
|
||||
@@ -29,7 +29,7 @@ def check_stale_patterns() -> Dict:
|
||||
Returns:
|
||||
Dict with check results
|
||||
"""
|
||||
seed_path = Path.home() / "seed"
|
||||
seed_path = Path(__file__).resolve().parents[5] # -> seedgo root
|
||||
deprecated_patterns = ignore_handler.get_deprecated_patterns()
|
||||
|
||||
violations = []
|
||||
|
||||
@@ -121,7 +121,7 @@ def print_standard():
|
||||
def run_demo():
|
||||
"""Run the CLI layout demo"""
|
||||
import subprocess
|
||||
demo_path = "/home/aipass/aipass_core/cli/tools/cli_layout_demo.py"
|
||||
demo_path = str(Path(__file__).resolve().parents[3] / "cli" / "tools" / "cli_layout_demo.py")
|
||||
|
||||
console.print()
|
||||
console.print("[bold cyan]Running CLI Demo...[/bold cyan]")
|
||||
|
||||
@@ -100,34 +100,13 @@ def handle_command(command: str, args: List[str]) -> bool:
|
||||
# If targeting a private branch directly, only allow audit from inside
|
||||
# that branch's directory. This enforces isolation per DPLAN-035.
|
||||
if specific_branch and _is_branch_private(specific_branch):
|
||||
# Resolve branch path from registry to check CWD
|
||||
import json as _json
|
||||
_registry_path = Path.home() / "BRANCH_REGISTRY.json"
|
||||
# Look up branch path from discovered branches (uses registry internally)
|
||||
_branch_path = None
|
||||
if _registry_path.exists():
|
||||
try:
|
||||
with open(_registry_path, 'r', encoding='utf-8') as _f:
|
||||
_reg = _json.load(_f)
|
||||
for _b in _reg.get('branches', []):
|
||||
if _b.get('name', '').upper() == specific_branch.upper():
|
||||
_branch_path = Path(_b['path'])
|
||||
break
|
||||
except (ValueError, IOError):
|
||||
pass
|
||||
|
||||
# Also check PRIVATE_BRANCH_REGISTRY for path
|
||||
if _branch_path is None:
|
||||
_priv_path = Path.home() / "PRIVATE_BRANCH_REGISTRY.json"
|
||||
if _priv_path.exists():
|
||||
try:
|
||||
with open(_priv_path, 'r', encoding='utf-8') as _f:
|
||||
_priv = _json.load(_f)
|
||||
for _b in _priv.get('branches', []):
|
||||
if _b.get('name', '').upper() == specific_branch.upper():
|
||||
_branch_path = Path(_b['path'])
|
||||
break
|
||||
except (ValueError, IOError):
|
||||
pass
|
||||
_priv_branches = discover_branches(include_private=True)
|
||||
for _b in _priv_branches:
|
||||
if _b['name'].upper() == specific_branch.upper():
|
||||
_branch_path = Path(_b['path'])
|
||||
break
|
||||
|
||||
if _branch_path is not None:
|
||||
cwd = Path.cwd()
|
||||
|
||||
Reference in New Issue
Block a user