♻️ 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:
AIOSAI
2026-03-06 02:45:54 -08:00
parent c9fa6696ba
commit 3cb1d98ed8
13 changed files with 76 additions and 57 deletions
+3
View File
@@ -46,3 +46,6 @@ aipass_json/
setup-workspace.sh
# Local cheat sheets (not source code)
# Docker.md
+1 -1
View File
@@ -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()