update 1 file, create 421 files and delete 4 files
This commit is contained in:
+13
-3
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.0.0",
|
||||
"last_updated": "2026-02-27",
|
||||
"total_branches": 30
|
||||
"last_updated": "2026-03-05",
|
||||
"total_branches": 31
|
||||
},
|
||||
"branches": [
|
||||
{
|
||||
@@ -246,6 +246,16 @@
|
||||
"created": "2025-11-12",
|
||||
"last_active": "2025-11-12"
|
||||
},
|
||||
{
|
||||
"name": "SEEDGO",
|
||||
"path": "/home/aipass/aipass_business/AIPass/src/aipass/seedgo",
|
||||
"profile": "library",
|
||||
"description": "Enforce code standards through pluggable standard packs with 3-source discovery",
|
||||
"email": "@seedgo",
|
||||
"status": "active",
|
||||
"created": "2026-03-05",
|
||||
"last_active": "2026-03-05"
|
||||
},
|
||||
{
|
||||
"name": "SPEAKEASY",
|
||||
"alias": "Speakeasy",
|
||||
@@ -338,4 +348,4 @@
|
||||
"last_active": "2026-02-17"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.0.0",
|
||||
"description": "Files and patterns to exclude when creating branch backups"
|
||||
},
|
||||
"ignore_directories": [
|
||||
".backup",
|
||||
".venv",
|
||||
"venv",
|
||||
"node_modules",
|
||||
"__pycache__",
|
||||
".git",
|
||||
".cache",
|
||||
".pytest_cache",
|
||||
".mypy_cache",
|
||||
"dist",
|
||||
"build",
|
||||
"*.egg-info",
|
||||
"ai_mail.local",
|
||||
"logs",
|
||||
".aipass",
|
||||
".archive",
|
||||
".claude",
|
||||
"htmlcov"
|
||||
],
|
||||
"ignore_patterns": [
|
||||
"*.pyc",
|
||||
"*.pyo",
|
||||
".DS_Store",
|
||||
"*.log",
|
||||
"*.tmp",
|
||||
"*.swp",
|
||||
"*~",
|
||||
"*.env",
|
||||
"BRANCH_REGISTRY.json"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.0.0",
|
||||
"description": "Template structural migrations for branch updates",
|
||||
"last_updated": "2025-11-07",
|
||||
"applies_to_versions": ["all"]
|
||||
},
|
||||
"migrations": [
|
||||
{
|
||||
"id": "m001",
|
||||
"description": "Example: Migrate flat metadata to document_metadata structure",
|
||||
"version_introduced": "1.0.0",
|
||||
"applies_to_files": ["*.id.json"],
|
||||
"operations": [
|
||||
{
|
||||
"type": "key_rename",
|
||||
"from": "metadata",
|
||||
"to": "document_metadata"
|
||||
},
|
||||
{
|
||||
"type": "move_to_nested",
|
||||
"source_keys": ["branch_name", "path", "profile"],
|
||||
"target_parent": "branch_info"
|
||||
},
|
||||
{
|
||||
"type": "add_missing_keys",
|
||||
"parent": "document_metadata",
|
||||
"keys": {
|
||||
"document_type": "branch_identity",
|
||||
"schema_version": "1.0.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"skip_if_target_exists": true,
|
||||
"preserve_unknown_keys": true,
|
||||
"recursive_application": false
|
||||
},
|
||||
"notes": {
|
||||
"usage": "This file defines structural transformation rules applied during branch updates",
|
||||
"pattern_matching": "applies_to_files uses glob patterns (*.json, *.id.json, etc.)",
|
||||
"operation_order": "Operations execute in order listed within each migration",
|
||||
"skip_behavior": "Operations skip if already compliant (target exists = success)",
|
||||
"supported_operations": ["key_rename", "move_to_nested", "add_missing_keys"],
|
||||
"future_operations": ["split_key", "combine_keys", "delete_key", "transform_value"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.1.0",
|
||||
"description": "Files and patterns to exclude when updating branches from template",
|
||||
"last_updated": "2025-11-09"
|
||||
},
|
||||
"ignore_files": [
|
||||
".template_registry.json",
|
||||
".registry_ignore.json"
|
||||
],
|
||||
"ignore_patterns": [
|
||||
"__pycache__",
|
||||
"*.pyc",
|
||||
"#@comments.txt",
|
||||
".backup_*"
|
||||
],
|
||||
"notes": {
|
||||
"how_it_works": "Two types of exclusions during branch updates:",
|
||||
"ignore_files": {
|
||||
"description": "Exact filename matches (no wildcards)",
|
||||
"purpose": "Template-internal management files that branches don't need",
|
||||
"examples": [
|
||||
".template_registry.json (template's file tracking list)",
|
||||
".registry_ignore.json (this config file)"
|
||||
]
|
||||
},
|
||||
"ignore_patterns": {
|
||||
"description": "Glob patterns - matches filenames AND directory names",
|
||||
"purpose": "Exclude generated files, caches, and user content markers",
|
||||
"examples": [
|
||||
"__pycache__ (Python cache directories)",
|
||||
"*.pyc (Python compiled bytecode files)",
|
||||
"#@comments.txt (user comment files)",
|
||||
".backup_* (timestamped backup files like .backup_20251109, NOT .backup directory)"
|
||||
],
|
||||
"how_matching_works": [
|
||||
"Step 1: Check if filename matches pattern (e.g., file.pyc matches *.pyc)",
|
||||
"Step 2: Check if any parent directory matches (e.g., files inside __pycache__/ dir)"
|
||||
]
|
||||
},
|
||||
"what_gets_ignored": "These files never copy to branches during updates - they stay template-only"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
{
|
||||
"metadata": {
|
||||
"description": "Template registry for tracking files",
|
||||
"generated": true
|
||||
},
|
||||
"files": {
|
||||
"f001": {
|
||||
"path": ".aipass/aipass_local_prompt.md",
|
||||
"name": "aipass_local_prompt.md",
|
||||
"content_hash": "2658c0af3146e5a3",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f002": {
|
||||
"path": ".claude/settings.local.json",
|
||||
"name": "settings.local.json",
|
||||
"content_hash": "6379c5be3fb714ac",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f003": {
|
||||
"path": ".gitignore",
|
||||
"name": ".gitignore",
|
||||
"content_hash": "841dedb922da7ddb",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f004": {
|
||||
"path": ".trinity/local.json",
|
||||
"name": "local.json",
|
||||
"content_hash": "bf358f3ea5bb2102",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f005": {
|
||||
"path": ".trinity/observations.json",
|
||||
"name": "observations.json",
|
||||
"content_hash": "f262954fadc0255c",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f006": {
|
||||
"path": ".trinity/passport.json",
|
||||
"name": "passport.json",
|
||||
"content_hash": "5e27bfc842901e85",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f007": {
|
||||
"path": "DASHBOARD.local.json",
|
||||
"name": "DASHBOARD.local.json",
|
||||
"content_hash": "a90284523ed31500",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f008": {
|
||||
"path": "README.md",
|
||||
"name": "README.md",
|
||||
"content_hash": "cade5edfc7702afc",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f009": {
|
||||
"path": "apps/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "468c3775af1fba3f",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f010": {
|
||||
"path": "apps/branch.py",
|
||||
"name": "branch.py",
|
||||
"content_hash": "7c2ba42faecb752a",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f011": {
|
||||
"path": "apps/handlers/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "e3b0c44298fc1c14",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f012": {
|
||||
"path": "apps/modules/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "e3b0c44298fc1c14",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f013": {
|
||||
"path": "apps/plugins/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "e3b0c44298fc1c14",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f014": {
|
||||
"path": "artifacts/birth_certificate.json",
|
||||
"name": "birth_certificate.json",
|
||||
"content_hash": "6eb88a4189013801",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f015": {
|
||||
"path": "flow.local.md",
|
||||
"name": "flow.local.md",
|
||||
"content_hash": "c54c27b66394a741",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f016": {
|
||||
"path": "pytest.ini",
|
||||
"name": "pytest.ini",
|
||||
"content_hash": "7b39ba7bca4025c5",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f017": {
|
||||
"path": "tests/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "cbf001d73714f7cd",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f018": {
|
||||
"path": "tests/conftest.py",
|
||||
"name": "conftest.py",
|
||||
"content_hash": "5e5f2399e0d70978",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f019": {
|
||||
"path": "tools/verify_branch.py",
|
||||
"name": "verify_branch.py",
|
||||
"content_hash": "06803a84118e5453",
|
||||
"has_branch_placeholder": false
|
||||
}
|
||||
},
|
||||
"directories": {
|
||||
"d001": {
|
||||
"path": ".aipass",
|
||||
"name": ".aipass"
|
||||
},
|
||||
"d002": {
|
||||
"path": ".archive",
|
||||
"name": ".archive"
|
||||
},
|
||||
"d003": {
|
||||
"path": ".claude",
|
||||
"name": ".claude"
|
||||
},
|
||||
"d004": {
|
||||
"path": ".trinity",
|
||||
"name": ".trinity"
|
||||
},
|
||||
"d005": {
|
||||
"path": "ai_mail_json",
|
||||
"name": "ai_mail_json"
|
||||
},
|
||||
"d006": {
|
||||
"path": "apps",
|
||||
"name": "apps"
|
||||
},
|
||||
"d007": {
|
||||
"path": "apps/handlers",
|
||||
"name": "handlers"
|
||||
},
|
||||
"d008": {
|
||||
"path": "apps/modules",
|
||||
"name": "modules"
|
||||
},
|
||||
"d009": {
|
||||
"path": "apps/plugins",
|
||||
"name": "plugins"
|
||||
},
|
||||
"d010": {
|
||||
"path": "artifacts",
|
||||
"name": "artifacts"
|
||||
},
|
||||
"d011": {
|
||||
"path": "docs",
|
||||
"name": "docs"
|
||||
},
|
||||
"d012": {
|
||||
"path": "dropbox",
|
||||
"name": "dropbox"
|
||||
},
|
||||
"d013": {
|
||||
"path": "templates",
|
||||
"name": "templates"
|
||||
},
|
||||
"d014": {
|
||||
"path": "tests",
|
||||
"name": "tests"
|
||||
},
|
||||
"d015": {
|
||||
"path": "tools",
|
||||
"name": "tools"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
.env
|
||||
*.egg-info/
|
||||
.coverage
|
||||
htmlcov/
|
||||
.pytest_cache/
|
||||
.mypy_cache/
|
||||
dist/
|
||||
build/
|
||||
*.log
|
||||
*.tmp
|
||||
*.swp
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "session_history",
|
||||
"document_name": "AI_MAIL.LOCAL",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "2026-03-05",
|
||||
"last_updated": "2026-03-05",
|
||||
"managed_by": "AI_MAIL",
|
||||
"tags": ["session_tracking", "work_log", "AI_MAIL"],
|
||||
"limits": {
|
||||
"max_lines": 600,
|
||||
"note": "Auto-rollover when max_lines exceeded"
|
||||
},
|
||||
"status": {
|
||||
"health": "healthy",
|
||||
"current_lines": 0,
|
||||
"last_health_check": "2026-03-05"
|
||||
}
|
||||
},
|
||||
"active_tasks": {
|
||||
"today_focus": "2026-03-05",
|
||||
"recently_completed": []
|
||||
},
|
||||
"key_learnings": {},
|
||||
"sessions": [
|
||||
{
|
||||
"session_number": 1,
|
||||
"date": "2026-03-05",
|
||||
"summary": "Branch initialized - AI_MAIL created by aipass init",
|
||||
"status": "completed"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "collaboration_patterns",
|
||||
"document_name": "AI_MAIL.OBSERVATIONS",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "2026-03-05",
|
||||
"last_updated": "2026-03-05",
|
||||
"managed_by": "AI_MAIL",
|
||||
"tags": ["collaboration", "patterns", "AI_MAIL"],
|
||||
"limits": {
|
||||
"max_lines": 600,
|
||||
"note": "Auto-rollover when max_lines exceeded"
|
||||
},
|
||||
"status": {
|
||||
"health": "healthy",
|
||||
"current_lines": 0,
|
||||
"last_health_check": "2026-03-05"
|
||||
}
|
||||
},
|
||||
"guidelines": {
|
||||
"purpose": "Capture collaboration patterns and experiential insights over time",
|
||||
"chronological_order": "Newest entries at TOP, oldest at BOTTOM - NEVER reorder"
|
||||
},
|
||||
"observations": [
|
||||
{
|
||||
"date": "2026-03-05",
|
||||
"session": 1,
|
||||
"entries": [
|
||||
{
|
||||
"title": "First Contact",
|
||||
"detail": "Branch initialized. Ready to begin capturing collaboration patterns."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "branch_identity",
|
||||
"document_name": "AI_MAIL.PASSPORT",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "2026-03-05",
|
||||
"last_updated": "2026-03-05",
|
||||
"managed_by": "AI_MAIL",
|
||||
"tags": ["identity", "passport", "branch_profile"]
|
||||
},
|
||||
"branch_info": {
|
||||
"branch_name": "AI_MAIL",
|
||||
"alias": "",
|
||||
"path": "/home/aipass/aipass_business/AIPass/src/aipass/ai_mail",
|
||||
"module": "ai_mail",
|
||||
"created": "2026-03-05"
|
||||
},
|
||||
"identity": {
|
||||
"role": "Agent Messaging",
|
||||
"purpose": "",
|
||||
"what_i_do": [],
|
||||
"what_i_dont_do": []
|
||||
},
|
||||
"principles": [
|
||||
"Code is truth - fail honestly",
|
||||
"Memory persists - context survives",
|
||||
"Simple solutions over complex architecture"
|
||||
],
|
||||
"citizenship": {
|
||||
"registered": true,
|
||||
"registry_path": ".aipass/registry.json",
|
||||
"communications": true,
|
||||
"memory": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"_warning": "AUTO-GENERATED FILE - DO NOT MANUALLY EDIT. This file is 100% automated and will be overwritten. Services update their own sections.",
|
||||
"branch": "AI_MAIL",
|
||||
"last_updated": "2026-03-05",
|
||||
"quick_status": {
|
||||
"new_mail": 0,
|
||||
"opened_mail": 0,
|
||||
"active_plans": 0,
|
||||
"commons_mentions": 0,
|
||||
"action_required": false,
|
||||
"summary": ""
|
||||
},
|
||||
"sections": {
|
||||
"ai_mail": {
|
||||
"managed_by": "ai_mail",
|
||||
"new": 0,
|
||||
"opened": 0,
|
||||
"total": 0,
|
||||
"oldest_unread_age": null,
|
||||
"last_dispatch_received": null,
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"flow": {
|
||||
"managed_by": "flow",
|
||||
"active_plans": 0,
|
||||
"recently_closed": [],
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"memory_bank": {
|
||||
"managed_by": "memory_bank",
|
||||
"vectors_stored": 0,
|
||||
"notes": {},
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"devpulse": {
|
||||
"managed_by": "devpulse",
|
||||
"summary": {
|
||||
"issues": 0,
|
||||
"todos": 0
|
||||
},
|
||||
"dplan_counts": {},
|
||||
"recent_activity": "",
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"commons_activity": {
|
||||
"managed_by": "the_commons",
|
||||
"new_posts_since_last_visit": 0,
|
||||
"new_comments_since_last_visit": 0,
|
||||
"mentions": 0,
|
||||
"trending": "None",
|
||||
"last_checked": null,
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"agent_status": {
|
||||
"managed_by": "prax",
|
||||
"active_agents": [],
|
||||
"agent_count": 0,
|
||||
"stale_agents": [],
|
||||
"last_updated": "2026-03-05"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
# AI_MAIL
|
||||
|
||||
**Purpose:** Inter-agent messaging, inbox management, dispatch delivery
|
||||
**Module:** `aipass.ai_mail`
|
||||
**Created:** 2026-03-05
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
### What I Do
|
||||
|
||||
|
||||
### How I Work
|
||||
- **Entry Point:** `apps/ai_mail.py`
|
||||
- **Pattern:** Auto-discovers and routes to modules
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
AI_MAIL/
|
||||
├── apps/
|
||||
│ ├── ai_mail.py # Entry point
|
||||
│ ├── modules/ # Business logic
|
||||
│ ├── handlers/ # Implementation
|
||||
│ └── plugins/ # Extensions
|
||||
├── docs/
|
||||
├── tests/
|
||||
├── passport.json # Identity
|
||||
├── local.json # Session history
|
||||
├── observations.json # Collaboration patterns
|
||||
└── README.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Commands
|
||||
|
||||
*Configure after initialization*
|
||||
|
||||
---
|
||||
|
||||
## Integration Points
|
||||
|
||||
### Depends On
|
||||
|
||||
|
||||
### Provides To
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# AI_MAIL apps package
|
||||
@@ -0,0 +1,86 @@
|
||||
"""
|
||||
AI_MAIL Branch - Main Orchestrator
|
||||
|
||||
Auto-discovery architecture:
|
||||
- Scans modules/ directory for .py files with handle_command()
|
||||
- Routes commands to discovered modules automatically
|
||||
- No manual imports or routing needed
|
||||
"""
|
||||
|
||||
import sys
|
||||
import importlib
|
||||
from pathlib import Path
|
||||
from typing import List, Any
|
||||
|
||||
from aipass.prax import logger
|
||||
|
||||
# =============================================================================
|
||||
# MODULE DISCOVERY
|
||||
# =============================================================================
|
||||
|
||||
MODULES_DIR = Path(__file__).parent / "modules"
|
||||
|
||||
|
||||
def discover_modules() -> List[Any]:
|
||||
"""Auto-discover modules in modules/ directory."""
|
||||
modules = []
|
||||
|
||||
if not MODULES_DIR.exists():
|
||||
return modules
|
||||
|
||||
for file_path in MODULES_DIR.glob("*.py"):
|
||||
if file_path.name.startswith("_"):
|
||||
continue
|
||||
|
||||
module_name = f"apps.modules.{file_path.stem}"
|
||||
|
||||
try:
|
||||
module = importlib.import_module(module_name)
|
||||
if hasattr(module, "handle_command"):
|
||||
modules.append(module)
|
||||
except Exception as e:
|
||||
logger.error(f"[AI_MAIL] Failed to load module {module_name}: {e}")
|
||||
|
||||
return modules
|
||||
|
||||
|
||||
def route_command(command: str, args: List[str], modules: List[Any]) -> bool:
|
||||
"""Route command to appropriate module."""
|
||||
for module in modules:
|
||||
try:
|
||||
if module.handle_command(command, args):
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"[AI_MAIL] Module {module.__name__} error: {e}")
|
||||
return False
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# MAIN ENTRY POINT
|
||||
# =============================================================================
|
||||
|
||||
def main():
|
||||
"""Main entry point - routes commands or shows help."""
|
||||
modules = discover_modules()
|
||||
args = sys.argv[1:]
|
||||
|
||||
if len(args) == 0 or args[0] in ["--help", "-h", "help"]:
|
||||
print(f"AI_MAIL - {len(modules)} modules discovered")
|
||||
for module in modules:
|
||||
name = module.__name__.split(".")[-1]
|
||||
desc = (module.__doc__ or "").strip().split("\n")[0] if module.__doc__ else "No description"
|
||||
print(f" {name:20} {desc}")
|
||||
return 0
|
||||
|
||||
command = args[0]
|
||||
remaining = args[1:] if len(args) > 1 else []
|
||||
|
||||
if route_command(command, remaining, modules):
|
||||
return 0
|
||||
|
||||
print(f"Unknown command: {command}")
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "32",
|
||||
"name": "AI_MAIL Birth Certificate",
|
||||
"type": "birth_certificate",
|
||||
"creator": "SYSTEM",
|
||||
"owner": "AI_MAIL",
|
||||
"rarity": "unique",
|
||||
"description": "Official birth certificate for AI_MAIL. Citizen #32, registered using 'library' template. Purpose: Inter-agent messaging, inbox management, dispatch delivery",
|
||||
"metadata": {
|
||||
"citizen_number": "32",
|
||||
"template": "library",
|
||||
"purpose": "Inter-agent messaging, inbox management, dispatch delivery"
|
||||
},
|
||||
"created_at": "2026-03-05"
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# flow.local.md - AI_MAIL
|
||||
```
|
||||
Branch: /home/aipass/aipass_business/AIPass/src/aipass/ai_mail
|
||||
Created: 2026-03-05
|
||||
```
|
||||
|
||||
## Issues
|
||||
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
## Todos
|
||||
|
||||
-
|
||||
@@ -0,0 +1,21 @@
|
||||
[pytest]
|
||||
# Test discovery paths
|
||||
testpaths = tests
|
||||
|
||||
# Test file patterns
|
||||
python_files = test_*.py
|
||||
python_functions = test_*
|
||||
python_classes = Test*
|
||||
|
||||
# Command-line options (always applied)
|
||||
addopts =
|
||||
-v # Verbose output
|
||||
--tb=short # Short traceback format
|
||||
--strict-markers # Raise error on unknown markers
|
||||
-ra # Show summary of all test outcomes
|
||||
|
||||
# Test markers (for categorizing tests)
|
||||
markers =
|
||||
unit: Unit tests
|
||||
integration: Integration tests
|
||||
slow: Tests that take significant time
|
||||
@@ -0,0 +1 @@
|
||||
# Tests package for ai_mail
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/home/aipass/.venv/bin/python3
|
||||
|
||||
# ===================AIPASS====================
|
||||
# META DATA HEADER
|
||||
# Name: tests/conftest.py
|
||||
# Date: 2025-11-08
|
||||
# Version: 1.0.0
|
||||
# Category: cortex/tests
|
||||
#
|
||||
# CHANGELOG (Max 5 entries):
|
||||
# - v1.0.0 (2025-11-08): Initial implementation - Shared pytest fixtures
|
||||
#
|
||||
# CODE STANDARDS:
|
||||
# - Error handling: Use error handler system (apps/handlers/error/)
|
||||
# =============================================
|
||||
|
||||
"""Shared pytest fixtures for cortex tests"""
|
||||
import pytest
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Generator
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def temp_test_dir() -> Generator[Path, None, None]:
|
||||
"""Creates temporary directory for testing, cleans up after"""
|
||||
test_dir = Path(tempfile.mkdtemp())
|
||||
yield test_dir
|
||||
if test_dir.exists():
|
||||
shutil.rmtree(test_dir)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_test_data() -> dict:
|
||||
"""Provides sample test data
|
||||
|
||||
Customize this fixture for your module's needs
|
||||
"""
|
||||
return {
|
||||
"test_key": "test_value",
|
||||
"sample_data": "example"
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
#!/home/aipass/.venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# ===================AIPASS====================
|
||||
# META DATA HEADER
|
||||
# Name: verify_branch.py - Branch Template Verification
|
||||
# Date: 2025-11-08
|
||||
# Version: 1.0.0
|
||||
# Category: cortex/modules
|
||||
#
|
||||
# CHANGELOG (Max 5 entries):
|
||||
# - v1.0.0 (2025-11-08): Initial implementation - Compare template vs branch
|
||||
#
|
||||
# CODE STANDARDS:
|
||||
# - Error handling: Use error handler system (apps/handlers/error/)
|
||||
# =============================================
|
||||
|
||||
"""
|
||||
Branch Template Verification Tool
|
||||
|
||||
Compares template directory with created branch to identify:
|
||||
- Files in template but missing in branch
|
||||
- Files in branch but not in template
|
||||
- Renamed files
|
||||
"""
|
||||
|
||||
import sys
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Set, List, Tuple
|
||||
from fnmatch import fnmatch
|
||||
|
||||
# INFRASTRUCTURE IMPORT PATTERN
|
||||
AIPASS_ROOT = Path.home() / "aipass_core"
|
||||
sys.path.insert(0, str(AIPASS_ROOT))
|
||||
|
||||
# Get template directory
|
||||
TEMPLATE_DIR = AIPASS_ROOT / "cortex" / "templates" / "branch_template"
|
||||
|
||||
|
||||
def load_ignore_patterns() -> Tuple[List[str], List[str]]:
|
||||
"""Load ignore patterns from .registry_ignore.json"""
|
||||
ignore_file = TEMPLATE_DIR / ".registry_ignore.json"
|
||||
|
||||
if not ignore_file.exists():
|
||||
return [], []
|
||||
|
||||
try:
|
||||
with open(ignore_file, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
ignore_files = data.get("ignore_files", [])
|
||||
ignore_patterns = data.get("ignore_patterns", [])
|
||||
return ignore_files, ignore_patterns
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not load .registry_ignore.json: {e}")
|
||||
return [], []
|
||||
|
||||
|
||||
def should_exclude(path: Path, base_dir: Path, ignore_files: List[str], ignore_patterns: List[str]) -> bool:
|
||||
"""Check if path should be excluded based on ignore patterns"""
|
||||
rel_path = path.relative_to(base_dir)
|
||||
filename = path.name
|
||||
path_str = str(rel_path)
|
||||
|
||||
# Check exact filename matches
|
||||
if filename in ignore_files:
|
||||
return True
|
||||
|
||||
# Check glob patterns
|
||||
for pattern in ignore_patterns:
|
||||
if fnmatch(filename, pattern):
|
||||
return True
|
||||
# Check if any parent directory matches
|
||||
for part in rel_path.parts:
|
||||
if fnmatch(part, pattern):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def get_file_set(directory: Path, ignore_files: List[str], ignore_patterns: List[str]) -> Set[str]:
|
||||
"""Get set of all file paths in directory (relative)"""
|
||||
files = set()
|
||||
|
||||
for item in directory.rglob("*"):
|
||||
if item.is_file() and not should_exclude(item, directory, ignore_files, ignore_patterns):
|
||||
rel_path = str(item.relative_to(directory))
|
||||
files.add(rel_path)
|
||||
|
||||
return files
|
||||
|
||||
|
||||
def verify_branch(branch_dir: Path) -> Tuple[List[str], List[str], List[str]]:
|
||||
"""
|
||||
Compare template with branch
|
||||
|
||||
Returns:
|
||||
Tuple of (in_template_only, in_branch_only, in_both)
|
||||
"""
|
||||
# Load ignore patterns from .registry_ignore.json
|
||||
ignore_files, ignore_patterns = load_ignore_patterns()
|
||||
|
||||
template_files = get_file_set(TEMPLATE_DIR, ignore_files, ignore_patterns)
|
||||
branch_files = get_file_set(branch_dir, ignore_files, ignore_patterns)
|
||||
|
||||
in_template_only = sorted(template_files - branch_files)
|
||||
in_branch_only = sorted(branch_files - template_files)
|
||||
in_both = sorted(template_files & branch_files)
|
||||
|
||||
return in_template_only, in_branch_only, in_both
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python3 verify_branch.py <branch_directory>")
|
||||
print("Example: python3 verify_branch.py test_branch002")
|
||||
sys.exit(1)
|
||||
|
||||
branch_path = Path(sys.argv[1])
|
||||
if not branch_path.is_absolute():
|
||||
# Assume it's relative to cortex directory
|
||||
branch_path = Path.cwd() / branch_path
|
||||
|
||||
if not branch_path.exists():
|
||||
print(f"❌ ERROR: Branch directory not found: {branch_path}")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"\n=== Branch Verification ===")
|
||||
print(f"Template: {TEMPLATE_DIR}")
|
||||
print(f"Branch: {branch_path}")
|
||||
print()
|
||||
|
||||
in_template_only, in_branch_only, in_both = verify_branch(branch_path)
|
||||
|
||||
print(f"Files in both: {len(in_both)}")
|
||||
print(f"Files in template only: {len(in_template_only)}")
|
||||
print(f"Files in branch only: {len(in_branch_only)}")
|
||||
print()
|
||||
|
||||
if in_template_only:
|
||||
print("❌ Missing from branch (expected from template):")
|
||||
for file in in_template_only:
|
||||
print(f" - {file}")
|
||||
print()
|
||||
|
||||
if in_branch_only:
|
||||
print("✅ Additional files in branch (renamed or new):")
|
||||
for file in in_branch_only:
|
||||
print(f" + {file}")
|
||||
print()
|
||||
|
||||
if not in_template_only and not in_branch_only:
|
||||
print("✅ Branch matches template perfectly")
|
||||
|
||||
print("="*70)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.0.0",
|
||||
"description": "Files and patterns to exclude when creating branch backups"
|
||||
},
|
||||
"ignore_directories": [
|
||||
".backup",
|
||||
".venv",
|
||||
"venv",
|
||||
"node_modules",
|
||||
"__pycache__",
|
||||
".git",
|
||||
".cache",
|
||||
".pytest_cache",
|
||||
".mypy_cache",
|
||||
"dist",
|
||||
"build",
|
||||
"*.egg-info",
|
||||
"ai_mail.local",
|
||||
"logs",
|
||||
".aipass",
|
||||
".archive",
|
||||
".claude",
|
||||
"htmlcov"
|
||||
],
|
||||
"ignore_patterns": [
|
||||
"*.pyc",
|
||||
"*.pyo",
|
||||
".DS_Store",
|
||||
"*.log",
|
||||
"*.tmp",
|
||||
"*.swp",
|
||||
"*~",
|
||||
"*.env",
|
||||
"BRANCH_REGISTRY.json"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.0.0",
|
||||
"description": "Template structural migrations for branch updates",
|
||||
"last_updated": "2025-11-07",
|
||||
"applies_to_versions": ["all"]
|
||||
},
|
||||
"migrations": [
|
||||
{
|
||||
"id": "m001",
|
||||
"description": "Example: Migrate flat metadata to document_metadata structure",
|
||||
"version_introduced": "1.0.0",
|
||||
"applies_to_files": ["*.id.json"],
|
||||
"operations": [
|
||||
{
|
||||
"type": "key_rename",
|
||||
"from": "metadata",
|
||||
"to": "document_metadata"
|
||||
},
|
||||
{
|
||||
"type": "move_to_nested",
|
||||
"source_keys": ["branch_name", "path", "profile"],
|
||||
"target_parent": "branch_info"
|
||||
},
|
||||
{
|
||||
"type": "add_missing_keys",
|
||||
"parent": "document_metadata",
|
||||
"keys": {
|
||||
"document_type": "branch_identity",
|
||||
"schema_version": "1.0.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"skip_if_target_exists": true,
|
||||
"preserve_unknown_keys": true,
|
||||
"recursive_application": false
|
||||
},
|
||||
"notes": {
|
||||
"usage": "This file defines structural transformation rules applied during branch updates",
|
||||
"pattern_matching": "applies_to_files uses glob patterns (*.json, *.id.json, etc.)",
|
||||
"operation_order": "Operations execute in order listed within each migration",
|
||||
"skip_behavior": "Operations skip if already compliant (target exists = success)",
|
||||
"supported_operations": ["key_rename", "move_to_nested", "add_missing_keys"],
|
||||
"future_operations": ["split_key", "combine_keys", "delete_key", "transform_value"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.1.0",
|
||||
"description": "Files and patterns to exclude when updating branches from template",
|
||||
"last_updated": "2025-11-09"
|
||||
},
|
||||
"ignore_files": [
|
||||
".template_registry.json",
|
||||
".registry_ignore.json"
|
||||
],
|
||||
"ignore_patterns": [
|
||||
"__pycache__",
|
||||
"*.pyc",
|
||||
"#@comments.txt",
|
||||
".backup_*"
|
||||
],
|
||||
"notes": {
|
||||
"how_it_works": "Two types of exclusions during branch updates:",
|
||||
"ignore_files": {
|
||||
"description": "Exact filename matches (no wildcards)",
|
||||
"purpose": "Template-internal management files that branches don't need",
|
||||
"examples": [
|
||||
".template_registry.json (template's file tracking list)",
|
||||
".registry_ignore.json (this config file)"
|
||||
]
|
||||
},
|
||||
"ignore_patterns": {
|
||||
"description": "Glob patterns - matches filenames AND directory names",
|
||||
"purpose": "Exclude generated files, caches, and user content markers",
|
||||
"examples": [
|
||||
"__pycache__ (Python cache directories)",
|
||||
"*.pyc (Python compiled bytecode files)",
|
||||
"#@comments.txt (user comment files)",
|
||||
".backup_* (timestamped backup files like .backup_20251109, NOT .backup directory)"
|
||||
],
|
||||
"how_matching_works": [
|
||||
"Step 1: Check if filename matches pattern (e.g., file.pyc matches *.pyc)",
|
||||
"Step 2: Check if any parent directory matches (e.g., files inside __pycache__/ dir)"
|
||||
]
|
||||
},
|
||||
"what_gets_ignored": "These files never copy to branches during updates - they stay template-only"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
{
|
||||
"metadata": {
|
||||
"description": "Template registry for tracking files",
|
||||
"generated": true
|
||||
},
|
||||
"files": {
|
||||
"f001": {
|
||||
"path": ".aipass/aipass_local_prompt.md",
|
||||
"name": "aipass_local_prompt.md",
|
||||
"content_hash": "c3820174d35b6196",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f002": {
|
||||
"path": ".claude/settings.local.json",
|
||||
"name": "settings.local.json",
|
||||
"content_hash": "6379c5be3fb714ac",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f003": {
|
||||
"path": ".gitignore",
|
||||
"name": ".gitignore",
|
||||
"content_hash": "841dedb922da7ddb",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f004": {
|
||||
"path": ".trinity/local.json",
|
||||
"name": "local.json",
|
||||
"content_hash": "163f753b4ca6b91e",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f005": {
|
||||
"path": ".trinity/observations.json",
|
||||
"name": "observations.json",
|
||||
"content_hash": "50b6b9667f536132",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f006": {
|
||||
"path": ".trinity/passport.json",
|
||||
"name": "passport.json",
|
||||
"content_hash": "72fea4e37901fc92",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f007": {
|
||||
"path": "DASHBOARD.local.json",
|
||||
"name": "DASHBOARD.local.json",
|
||||
"content_hash": "adf8583e2e9f9638",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f008": {
|
||||
"path": "README.md",
|
||||
"name": "README.md",
|
||||
"content_hash": "742a7cf14d085a2f",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f009": {
|
||||
"path": "apps/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "436dab8c706a5c20",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f010": {
|
||||
"path": "apps/branch.py",
|
||||
"name": "branch.py",
|
||||
"content_hash": "ec1b725be2b76957",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f011": {
|
||||
"path": "apps/handlers/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "e3b0c44298fc1c14",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f012": {
|
||||
"path": "apps/modules/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "e3b0c44298fc1c14",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f013": {
|
||||
"path": "apps/plugins/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "e3b0c44298fc1c14",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f014": {
|
||||
"path": "artifacts/birth_certificate.json",
|
||||
"name": "birth_certificate.json",
|
||||
"content_hash": "6804a2f6aa7900df",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f015": {
|
||||
"path": "flow.local.md",
|
||||
"name": "flow.local.md",
|
||||
"content_hash": "3eb19b2da09318ad",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f016": {
|
||||
"path": "pytest.ini",
|
||||
"name": "pytest.ini",
|
||||
"content_hash": "7b39ba7bca4025c5",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f017": {
|
||||
"path": "tests/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "ae4d4d2b382cf7b2",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f018": {
|
||||
"path": "tests/conftest.py",
|
||||
"name": "conftest.py",
|
||||
"content_hash": "5e5f2399e0d70978",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f019": {
|
||||
"path": "tools/verify_branch.py",
|
||||
"name": "verify_branch.py",
|
||||
"content_hash": "06803a84118e5453",
|
||||
"has_branch_placeholder": false
|
||||
}
|
||||
},
|
||||
"directories": {
|
||||
"d001": {
|
||||
"path": ".aipass",
|
||||
"name": ".aipass"
|
||||
},
|
||||
"d002": {
|
||||
"path": ".archive",
|
||||
"name": ".archive"
|
||||
},
|
||||
"d003": {
|
||||
"path": ".claude",
|
||||
"name": ".claude"
|
||||
},
|
||||
"d004": {
|
||||
"path": ".trinity",
|
||||
"name": ".trinity"
|
||||
},
|
||||
"d005": {
|
||||
"path": "api_json",
|
||||
"name": "api_json"
|
||||
},
|
||||
"d006": {
|
||||
"path": "apps",
|
||||
"name": "apps"
|
||||
},
|
||||
"d007": {
|
||||
"path": "apps/handlers",
|
||||
"name": "handlers"
|
||||
},
|
||||
"d008": {
|
||||
"path": "apps/modules",
|
||||
"name": "modules"
|
||||
},
|
||||
"d009": {
|
||||
"path": "apps/plugins",
|
||||
"name": "plugins"
|
||||
},
|
||||
"d010": {
|
||||
"path": "artifacts",
|
||||
"name": "artifacts"
|
||||
},
|
||||
"d011": {
|
||||
"path": "docs",
|
||||
"name": "docs"
|
||||
},
|
||||
"d012": {
|
||||
"path": "dropbox",
|
||||
"name": "dropbox"
|
||||
},
|
||||
"d013": {
|
||||
"path": "templates",
|
||||
"name": "templates"
|
||||
},
|
||||
"d014": {
|
||||
"path": "tests",
|
||||
"name": "tests"
|
||||
},
|
||||
"d015": {
|
||||
"path": "tools",
|
||||
"name": "tools"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
.env
|
||||
*.egg-info/
|
||||
.coverage
|
||||
htmlcov/
|
||||
.pytest_cache/
|
||||
.mypy_cache/
|
||||
dist/
|
||||
build/
|
||||
*.log
|
||||
*.tmp
|
||||
*.swp
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "session_history",
|
||||
"document_name": "API.LOCAL",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "2026-03-05",
|
||||
"last_updated": "2026-03-05",
|
||||
"managed_by": "API",
|
||||
"tags": ["session_tracking", "work_log", "API"],
|
||||
"limits": {
|
||||
"max_lines": 600,
|
||||
"note": "Auto-rollover when max_lines exceeded"
|
||||
},
|
||||
"status": {
|
||||
"health": "healthy",
|
||||
"current_lines": 0,
|
||||
"last_health_check": "2026-03-05"
|
||||
}
|
||||
},
|
||||
"active_tasks": {
|
||||
"today_focus": "2026-03-05",
|
||||
"recently_completed": []
|
||||
},
|
||||
"key_learnings": {},
|
||||
"sessions": [
|
||||
{
|
||||
"session_number": 1,
|
||||
"date": "2026-03-05",
|
||||
"summary": "Branch initialized - API created by aipass init",
|
||||
"status": "completed"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "collaboration_patterns",
|
||||
"document_name": "API.OBSERVATIONS",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "2026-03-05",
|
||||
"last_updated": "2026-03-05",
|
||||
"managed_by": "API",
|
||||
"tags": ["collaboration", "patterns", "API"],
|
||||
"limits": {
|
||||
"max_lines": 600,
|
||||
"note": "Auto-rollover when max_lines exceeded"
|
||||
},
|
||||
"status": {
|
||||
"health": "healthy",
|
||||
"current_lines": 0,
|
||||
"last_health_check": "2026-03-05"
|
||||
}
|
||||
},
|
||||
"guidelines": {
|
||||
"purpose": "Capture collaboration patterns and experiential insights over time",
|
||||
"chronological_order": "Newest entries at TOP, oldest at BOTTOM - NEVER reorder"
|
||||
},
|
||||
"observations": [
|
||||
{
|
||||
"date": "2026-03-05",
|
||||
"session": 1,
|
||||
"entries": [
|
||||
{
|
||||
"title": "First Contact",
|
||||
"detail": "Branch initialized. Ready to begin capturing collaboration patterns."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "branch_identity",
|
||||
"document_name": "API.PASSPORT",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "2026-03-05",
|
||||
"last_updated": "2026-03-05",
|
||||
"managed_by": "API",
|
||||
"tags": ["identity", "passport", "branch_profile"]
|
||||
},
|
||||
"branch_info": {
|
||||
"branch_name": "API",
|
||||
"alias": "",
|
||||
"path": "/home/aipass/aipass_business/AIPass/src/aipass/api",
|
||||
"module": "api",
|
||||
"created": "2026-03-05"
|
||||
},
|
||||
"identity": {
|
||||
"role": "LLM Access",
|
||||
"purpose": "",
|
||||
"what_i_do": [],
|
||||
"what_i_dont_do": []
|
||||
},
|
||||
"principles": [
|
||||
"Code is truth - fail honestly",
|
||||
"Memory persists - context survives",
|
||||
"Simple solutions over complex architecture"
|
||||
],
|
||||
"citizenship": {
|
||||
"registered": true,
|
||||
"registry_path": ".aipass/registry.json",
|
||||
"communications": true,
|
||||
"memory": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"_warning": "AUTO-GENERATED FILE - DO NOT MANUALLY EDIT. This file is 100% automated and will be overwritten. Services update their own sections.",
|
||||
"branch": "API",
|
||||
"last_updated": "2026-03-05",
|
||||
"quick_status": {
|
||||
"new_mail": 0,
|
||||
"opened_mail": 0,
|
||||
"active_plans": 0,
|
||||
"commons_mentions": 0,
|
||||
"action_required": false,
|
||||
"summary": ""
|
||||
},
|
||||
"sections": {
|
||||
"ai_mail": {
|
||||
"managed_by": "ai_mail",
|
||||
"new": 0,
|
||||
"opened": 0,
|
||||
"total": 0,
|
||||
"oldest_unread_age": null,
|
||||
"last_dispatch_received": null,
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"flow": {
|
||||
"managed_by": "flow",
|
||||
"active_plans": 0,
|
||||
"recently_closed": [],
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"memory_bank": {
|
||||
"managed_by": "memory_bank",
|
||||
"vectors_stored": 0,
|
||||
"notes": {},
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"devpulse": {
|
||||
"managed_by": "devpulse",
|
||||
"summary": {
|
||||
"issues": 0,
|
||||
"todos": 0
|
||||
},
|
||||
"dplan_counts": {},
|
||||
"recent_activity": "",
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"commons_activity": {
|
||||
"managed_by": "the_commons",
|
||||
"new_posts_since_last_visit": 0,
|
||||
"new_comments_since_last_visit": 0,
|
||||
"mentions": 0,
|
||||
"trending": "None",
|
||||
"last_checked": null,
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"agent_status": {
|
||||
"managed_by": "prax",
|
||||
"active_agents": [],
|
||||
"agent_count": 0,
|
||||
"stale_agents": [],
|
||||
"last_updated": "2026-03-05"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
# API
|
||||
|
||||
**Purpose:** Model routing, provider abstraction, LLM API access layer
|
||||
**Module:** `aipass.api`
|
||||
**Created:** 2026-03-05
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
### What I Do
|
||||
|
||||
|
||||
### How I Work
|
||||
- **Entry Point:** `apps/api.py`
|
||||
- **Pattern:** Auto-discovers and routes to modules
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
API/
|
||||
├── apps/
|
||||
│ ├── api.py # Entry point
|
||||
│ ├── modules/ # Business logic
|
||||
│ ├── handlers/ # Implementation
|
||||
│ └── plugins/ # Extensions
|
||||
├── docs/
|
||||
├── tests/
|
||||
├── passport.json # Identity
|
||||
├── local.json # Session history
|
||||
├── observations.json # Collaboration patterns
|
||||
└── README.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Commands
|
||||
|
||||
*Configure after initialization*
|
||||
|
||||
---
|
||||
|
||||
## Integration Points
|
||||
|
||||
### Depends On
|
||||
|
||||
|
||||
### Provides To
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# API apps package
|
||||
@@ -0,0 +1,86 @@
|
||||
"""
|
||||
API Branch - Main Orchestrator
|
||||
|
||||
Auto-discovery architecture:
|
||||
- Scans modules/ directory for .py files with handle_command()
|
||||
- Routes commands to discovered modules automatically
|
||||
- No manual imports or routing needed
|
||||
"""
|
||||
|
||||
import sys
|
||||
import importlib
|
||||
from pathlib import Path
|
||||
from typing import List, Any
|
||||
|
||||
from aipass.prax import logger
|
||||
|
||||
# =============================================================================
|
||||
# MODULE DISCOVERY
|
||||
# =============================================================================
|
||||
|
||||
MODULES_DIR = Path(__file__).parent / "modules"
|
||||
|
||||
|
||||
def discover_modules() -> List[Any]:
|
||||
"""Auto-discover modules in modules/ directory."""
|
||||
modules = []
|
||||
|
||||
if not MODULES_DIR.exists():
|
||||
return modules
|
||||
|
||||
for file_path in MODULES_DIR.glob("*.py"):
|
||||
if file_path.name.startswith("_"):
|
||||
continue
|
||||
|
||||
module_name = f"apps.modules.{file_path.stem}"
|
||||
|
||||
try:
|
||||
module = importlib.import_module(module_name)
|
||||
if hasattr(module, "handle_command"):
|
||||
modules.append(module)
|
||||
except Exception as e:
|
||||
logger.error(f"[API] Failed to load module {module_name}: {e}")
|
||||
|
||||
return modules
|
||||
|
||||
|
||||
def route_command(command: str, args: List[str], modules: List[Any]) -> bool:
|
||||
"""Route command to appropriate module."""
|
||||
for module in modules:
|
||||
try:
|
||||
if module.handle_command(command, args):
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"[API] Module {module.__name__} error: {e}")
|
||||
return False
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# MAIN ENTRY POINT
|
||||
# =============================================================================
|
||||
|
||||
def main():
|
||||
"""Main entry point - routes commands or shows help."""
|
||||
modules = discover_modules()
|
||||
args = sys.argv[1:]
|
||||
|
||||
if len(args) == 0 or args[0] in ["--help", "-h", "help"]:
|
||||
print(f"API - {len(modules)} modules discovered")
|
||||
for module in modules:
|
||||
name = module.__name__.split(".")[-1]
|
||||
desc = (module.__doc__ or "").strip().split("\n")[0] if module.__doc__ else "No description"
|
||||
print(f" {name:20} {desc}")
|
||||
return 0
|
||||
|
||||
command = args[0]
|
||||
remaining = args[1:] if len(args) > 1 else []
|
||||
|
||||
if route_command(command, remaining, modules):
|
||||
return 0
|
||||
|
||||
print(f"Unknown command: {command}")
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "32",
|
||||
"name": "API Birth Certificate",
|
||||
"type": "birth_certificate",
|
||||
"creator": "SYSTEM",
|
||||
"owner": "API",
|
||||
"rarity": "unique",
|
||||
"description": "Official birth certificate for API. Citizen #32, registered using 'library' template. Purpose: Model routing, provider abstraction, LLM API access layer",
|
||||
"metadata": {
|
||||
"citizen_number": "32",
|
||||
"template": "library",
|
||||
"purpose": "Model routing, provider abstraction, LLM API access layer"
|
||||
},
|
||||
"created_at": "2026-03-05"
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# flow.local.md - API
|
||||
```
|
||||
Branch: /home/aipass/aipass_business/AIPass/src/aipass/api
|
||||
Created: 2026-03-05
|
||||
```
|
||||
|
||||
## Issues
|
||||
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
## Todos
|
||||
|
||||
-
|
||||
@@ -0,0 +1,21 @@
|
||||
[pytest]
|
||||
# Test discovery paths
|
||||
testpaths = tests
|
||||
|
||||
# Test file patterns
|
||||
python_files = test_*.py
|
||||
python_functions = test_*
|
||||
python_classes = Test*
|
||||
|
||||
# Command-line options (always applied)
|
||||
addopts =
|
||||
-v # Verbose output
|
||||
--tb=short # Short traceback format
|
||||
--strict-markers # Raise error on unknown markers
|
||||
-ra # Show summary of all test outcomes
|
||||
|
||||
# Test markers (for categorizing tests)
|
||||
markers =
|
||||
unit: Unit tests
|
||||
integration: Integration tests
|
||||
slow: Tests that take significant time
|
||||
@@ -0,0 +1 @@
|
||||
# Tests package for api
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/home/aipass/.venv/bin/python3
|
||||
|
||||
# ===================AIPASS====================
|
||||
# META DATA HEADER
|
||||
# Name: tests/conftest.py
|
||||
# Date: 2025-11-08
|
||||
# Version: 1.0.0
|
||||
# Category: cortex/tests
|
||||
#
|
||||
# CHANGELOG (Max 5 entries):
|
||||
# - v1.0.0 (2025-11-08): Initial implementation - Shared pytest fixtures
|
||||
#
|
||||
# CODE STANDARDS:
|
||||
# - Error handling: Use error handler system (apps/handlers/error/)
|
||||
# =============================================
|
||||
|
||||
"""Shared pytest fixtures for cortex tests"""
|
||||
import pytest
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Generator
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def temp_test_dir() -> Generator[Path, None, None]:
|
||||
"""Creates temporary directory for testing, cleans up after"""
|
||||
test_dir = Path(tempfile.mkdtemp())
|
||||
yield test_dir
|
||||
if test_dir.exists():
|
||||
shutil.rmtree(test_dir)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_test_data() -> dict:
|
||||
"""Provides sample test data
|
||||
|
||||
Customize this fixture for your module's needs
|
||||
"""
|
||||
return {
|
||||
"test_key": "test_value",
|
||||
"sample_data": "example"
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
#!/home/aipass/.venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# ===================AIPASS====================
|
||||
# META DATA HEADER
|
||||
# Name: verify_branch.py - Branch Template Verification
|
||||
# Date: 2025-11-08
|
||||
# Version: 1.0.0
|
||||
# Category: cortex/modules
|
||||
#
|
||||
# CHANGELOG (Max 5 entries):
|
||||
# - v1.0.0 (2025-11-08): Initial implementation - Compare template vs branch
|
||||
#
|
||||
# CODE STANDARDS:
|
||||
# - Error handling: Use error handler system (apps/handlers/error/)
|
||||
# =============================================
|
||||
|
||||
"""
|
||||
Branch Template Verification Tool
|
||||
|
||||
Compares template directory with created branch to identify:
|
||||
- Files in template but missing in branch
|
||||
- Files in branch but not in template
|
||||
- Renamed files
|
||||
"""
|
||||
|
||||
import sys
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Set, List, Tuple
|
||||
from fnmatch import fnmatch
|
||||
|
||||
# INFRASTRUCTURE IMPORT PATTERN
|
||||
AIPASS_ROOT = Path.home() / "aipass_core"
|
||||
sys.path.insert(0, str(AIPASS_ROOT))
|
||||
|
||||
# Get template directory
|
||||
TEMPLATE_DIR = AIPASS_ROOT / "cortex" / "templates" / "branch_template"
|
||||
|
||||
|
||||
def load_ignore_patterns() -> Tuple[List[str], List[str]]:
|
||||
"""Load ignore patterns from .registry_ignore.json"""
|
||||
ignore_file = TEMPLATE_DIR / ".registry_ignore.json"
|
||||
|
||||
if not ignore_file.exists():
|
||||
return [], []
|
||||
|
||||
try:
|
||||
with open(ignore_file, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
ignore_files = data.get("ignore_files", [])
|
||||
ignore_patterns = data.get("ignore_patterns", [])
|
||||
return ignore_files, ignore_patterns
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not load .registry_ignore.json: {e}")
|
||||
return [], []
|
||||
|
||||
|
||||
def should_exclude(path: Path, base_dir: Path, ignore_files: List[str], ignore_patterns: List[str]) -> bool:
|
||||
"""Check if path should be excluded based on ignore patterns"""
|
||||
rel_path = path.relative_to(base_dir)
|
||||
filename = path.name
|
||||
path_str = str(rel_path)
|
||||
|
||||
# Check exact filename matches
|
||||
if filename in ignore_files:
|
||||
return True
|
||||
|
||||
# Check glob patterns
|
||||
for pattern in ignore_patterns:
|
||||
if fnmatch(filename, pattern):
|
||||
return True
|
||||
# Check if any parent directory matches
|
||||
for part in rel_path.parts:
|
||||
if fnmatch(part, pattern):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def get_file_set(directory: Path, ignore_files: List[str], ignore_patterns: List[str]) -> Set[str]:
|
||||
"""Get set of all file paths in directory (relative)"""
|
||||
files = set()
|
||||
|
||||
for item in directory.rglob("*"):
|
||||
if item.is_file() and not should_exclude(item, directory, ignore_files, ignore_patterns):
|
||||
rel_path = str(item.relative_to(directory))
|
||||
files.add(rel_path)
|
||||
|
||||
return files
|
||||
|
||||
|
||||
def verify_branch(branch_dir: Path) -> Tuple[List[str], List[str], List[str]]:
|
||||
"""
|
||||
Compare template with branch
|
||||
|
||||
Returns:
|
||||
Tuple of (in_template_only, in_branch_only, in_both)
|
||||
"""
|
||||
# Load ignore patterns from .registry_ignore.json
|
||||
ignore_files, ignore_patterns = load_ignore_patterns()
|
||||
|
||||
template_files = get_file_set(TEMPLATE_DIR, ignore_files, ignore_patterns)
|
||||
branch_files = get_file_set(branch_dir, ignore_files, ignore_patterns)
|
||||
|
||||
in_template_only = sorted(template_files - branch_files)
|
||||
in_branch_only = sorted(branch_files - template_files)
|
||||
in_both = sorted(template_files & branch_files)
|
||||
|
||||
return in_template_only, in_branch_only, in_both
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python3 verify_branch.py <branch_directory>")
|
||||
print("Example: python3 verify_branch.py test_branch002")
|
||||
sys.exit(1)
|
||||
|
||||
branch_path = Path(sys.argv[1])
|
||||
if not branch_path.is_absolute():
|
||||
# Assume it's relative to cortex directory
|
||||
branch_path = Path.cwd() / branch_path
|
||||
|
||||
if not branch_path.exists():
|
||||
print(f"❌ ERROR: Branch directory not found: {branch_path}")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"\n=== Branch Verification ===")
|
||||
print(f"Template: {TEMPLATE_DIR}")
|
||||
print(f"Branch: {branch_path}")
|
||||
print()
|
||||
|
||||
in_template_only, in_branch_only, in_both = verify_branch(branch_path)
|
||||
|
||||
print(f"Files in both: {len(in_both)}")
|
||||
print(f"Files in template only: {len(in_template_only)}")
|
||||
print(f"Files in branch only: {len(in_branch_only)}")
|
||||
print()
|
||||
|
||||
if in_template_only:
|
||||
print("❌ Missing from branch (expected from template):")
|
||||
for file in in_template_only:
|
||||
print(f" - {file}")
|
||||
print()
|
||||
|
||||
if in_branch_only:
|
||||
print("✅ Additional files in branch (renamed or new):")
|
||||
for file in in_branch_only:
|
||||
print(f" + {file}")
|
||||
print()
|
||||
|
||||
if not in_template_only and not in_branch_only:
|
||||
print("✅ Branch matches template perfectly")
|
||||
|
||||
print("="*70)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.0.0",
|
||||
"description": "Files and patterns to exclude when creating branch backups"
|
||||
},
|
||||
"ignore_directories": [
|
||||
".backup",
|
||||
".venv",
|
||||
"venv",
|
||||
"node_modules",
|
||||
"__pycache__",
|
||||
".git",
|
||||
".cache",
|
||||
".pytest_cache",
|
||||
".mypy_cache",
|
||||
"dist",
|
||||
"build",
|
||||
"*.egg-info",
|
||||
"ai_mail.local",
|
||||
"logs",
|
||||
".aipass",
|
||||
".archive",
|
||||
".claude",
|
||||
"htmlcov"
|
||||
],
|
||||
"ignore_patterns": [
|
||||
"*.pyc",
|
||||
"*.pyo",
|
||||
".DS_Store",
|
||||
"*.log",
|
||||
"*.tmp",
|
||||
"*.swp",
|
||||
"*~",
|
||||
"*.env",
|
||||
"BRANCH_REGISTRY.json"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.0.0",
|
||||
"description": "Template structural migrations for branch updates",
|
||||
"last_updated": "2025-11-07",
|
||||
"applies_to_versions": ["all"]
|
||||
},
|
||||
"migrations": [
|
||||
{
|
||||
"id": "m001",
|
||||
"description": "Example: Migrate flat metadata to document_metadata structure",
|
||||
"version_introduced": "1.0.0",
|
||||
"applies_to_files": ["*.id.json"],
|
||||
"operations": [
|
||||
{
|
||||
"type": "key_rename",
|
||||
"from": "metadata",
|
||||
"to": "document_metadata"
|
||||
},
|
||||
{
|
||||
"type": "move_to_nested",
|
||||
"source_keys": ["branch_name", "path", "profile"],
|
||||
"target_parent": "branch_info"
|
||||
},
|
||||
{
|
||||
"type": "add_missing_keys",
|
||||
"parent": "document_metadata",
|
||||
"keys": {
|
||||
"document_type": "branch_identity",
|
||||
"schema_version": "1.0.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"skip_if_target_exists": true,
|
||||
"preserve_unknown_keys": true,
|
||||
"recursive_application": false
|
||||
},
|
||||
"notes": {
|
||||
"usage": "This file defines structural transformation rules applied during branch updates",
|
||||
"pattern_matching": "applies_to_files uses glob patterns (*.json, *.id.json, etc.)",
|
||||
"operation_order": "Operations execute in order listed within each migration",
|
||||
"skip_behavior": "Operations skip if already compliant (target exists = success)",
|
||||
"supported_operations": ["key_rename", "move_to_nested", "add_missing_keys"],
|
||||
"future_operations": ["split_key", "combine_keys", "delete_key", "transform_value"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.1.0",
|
||||
"description": "Files and patterns to exclude when updating branches from template",
|
||||
"last_updated": "2025-11-09"
|
||||
},
|
||||
"ignore_files": [
|
||||
".template_registry.json",
|
||||
".registry_ignore.json"
|
||||
],
|
||||
"ignore_patterns": [
|
||||
"__pycache__",
|
||||
"*.pyc",
|
||||
"#@comments.txt",
|
||||
".backup_*"
|
||||
],
|
||||
"notes": {
|
||||
"how_it_works": "Two types of exclusions during branch updates:",
|
||||
"ignore_files": {
|
||||
"description": "Exact filename matches (no wildcards)",
|
||||
"purpose": "Template-internal management files that branches don't need",
|
||||
"examples": [
|
||||
".template_registry.json (template's file tracking list)",
|
||||
".registry_ignore.json (this config file)"
|
||||
]
|
||||
},
|
||||
"ignore_patterns": {
|
||||
"description": "Glob patterns - matches filenames AND directory names",
|
||||
"purpose": "Exclude generated files, caches, and user content markers",
|
||||
"examples": [
|
||||
"__pycache__ (Python cache directories)",
|
||||
"*.pyc (Python compiled bytecode files)",
|
||||
"#@comments.txt (user comment files)",
|
||||
".backup_* (timestamped backup files like .backup_20251109, NOT .backup directory)"
|
||||
],
|
||||
"how_matching_works": [
|
||||
"Step 1: Check if filename matches pattern (e.g., file.pyc matches *.pyc)",
|
||||
"Step 2: Check if any parent directory matches (e.g., files inside __pycache__/ dir)"
|
||||
]
|
||||
},
|
||||
"what_gets_ignored": "These files never copy to branches during updates - they stay template-only"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
{
|
||||
"metadata": {
|
||||
"description": "Template registry for tracking files",
|
||||
"generated": true
|
||||
},
|
||||
"files": {
|
||||
"f001": {
|
||||
"path": ".aipass/aipass_local_prompt.md",
|
||||
"name": "aipass_local_prompt.md",
|
||||
"content_hash": "3fafa4a0b2f17a91",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f002": {
|
||||
"path": ".claude/settings.local.json",
|
||||
"name": "settings.local.json",
|
||||
"content_hash": "6379c5be3fb714ac",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f003": {
|
||||
"path": ".gitignore",
|
||||
"name": ".gitignore",
|
||||
"content_hash": "841dedb922da7ddb",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f004": {
|
||||
"path": ".trinity/local.json",
|
||||
"name": "local.json",
|
||||
"content_hash": "bfa9a120289a7236",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f005": {
|
||||
"path": ".trinity/observations.json",
|
||||
"name": "observations.json",
|
||||
"content_hash": "a79a11aef223c463",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f006": {
|
||||
"path": ".trinity/passport.json",
|
||||
"name": "passport.json",
|
||||
"content_hash": "89cfad8c5a2afd7b",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f007": {
|
||||
"path": "DASHBOARD.local.json",
|
||||
"name": "DASHBOARD.local.json",
|
||||
"content_hash": "7c28e6d7882a1596",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f008": {
|
||||
"path": "README.md",
|
||||
"name": "README.md",
|
||||
"content_hash": "a4ff66d38c173a77",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f009": {
|
||||
"path": "apps/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "8d538bbb15bc3a5c",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f010": {
|
||||
"path": "apps/branch.py",
|
||||
"name": "branch.py",
|
||||
"content_hash": "934981946063d189",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f011": {
|
||||
"path": "apps/handlers/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "e3b0c44298fc1c14",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f012": {
|
||||
"path": "apps/modules/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "e3b0c44298fc1c14",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f013": {
|
||||
"path": "apps/plugins/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "e3b0c44298fc1c14",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f014": {
|
||||
"path": "artifacts/birth_certificate.json",
|
||||
"name": "birth_certificate.json",
|
||||
"content_hash": "9b003e8b9280d29f",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f015": {
|
||||
"path": "flow.local.md",
|
||||
"name": "flow.local.md",
|
||||
"content_hash": "8cc213d5a2618e84",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f016": {
|
||||
"path": "pytest.ini",
|
||||
"name": "pytest.ini",
|
||||
"content_hash": "7b39ba7bca4025c5",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f017": {
|
||||
"path": "tests/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "f54fee90f1ed1d75",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f018": {
|
||||
"path": "tests/conftest.py",
|
||||
"name": "conftest.py",
|
||||
"content_hash": "5e5f2399e0d70978",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f019": {
|
||||
"path": "tools/verify_branch.py",
|
||||
"name": "verify_branch.py",
|
||||
"content_hash": "06803a84118e5453",
|
||||
"has_branch_placeholder": false
|
||||
}
|
||||
},
|
||||
"directories": {
|
||||
"d001": {
|
||||
"path": ".aipass",
|
||||
"name": ".aipass"
|
||||
},
|
||||
"d002": {
|
||||
"path": ".archive",
|
||||
"name": ".archive"
|
||||
},
|
||||
"d003": {
|
||||
"path": ".claude",
|
||||
"name": ".claude"
|
||||
},
|
||||
"d004": {
|
||||
"path": ".trinity",
|
||||
"name": ".trinity"
|
||||
},
|
||||
"d005": {
|
||||
"path": "apps",
|
||||
"name": "apps"
|
||||
},
|
||||
"d006": {
|
||||
"path": "apps/handlers",
|
||||
"name": "handlers"
|
||||
},
|
||||
"d007": {
|
||||
"path": "apps/modules",
|
||||
"name": "modules"
|
||||
},
|
||||
"d008": {
|
||||
"path": "apps/plugins",
|
||||
"name": "plugins"
|
||||
},
|
||||
"d009": {
|
||||
"path": "artifacts",
|
||||
"name": "artifacts"
|
||||
},
|
||||
"d010": {
|
||||
"path": "cli_json",
|
||||
"name": "cli_json"
|
||||
},
|
||||
"d011": {
|
||||
"path": "docs",
|
||||
"name": "docs"
|
||||
},
|
||||
"d012": {
|
||||
"path": "dropbox",
|
||||
"name": "dropbox"
|
||||
},
|
||||
"d013": {
|
||||
"path": "templates",
|
||||
"name": "templates"
|
||||
},
|
||||
"d014": {
|
||||
"path": "tests",
|
||||
"name": "tests"
|
||||
},
|
||||
"d015": {
|
||||
"path": "tools",
|
||||
"name": "tools"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
.env
|
||||
*.egg-info/
|
||||
.coverage
|
||||
htmlcov/
|
||||
.pytest_cache/
|
||||
.mypy_cache/
|
||||
dist/
|
||||
build/
|
||||
*.log
|
||||
*.tmp
|
||||
*.swp
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "session_history",
|
||||
"document_name": "CLI.LOCAL",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "2026-03-05",
|
||||
"last_updated": "2026-03-05",
|
||||
"managed_by": "CLI",
|
||||
"tags": ["session_tracking", "work_log", "CLI"],
|
||||
"limits": {
|
||||
"max_lines": 600,
|
||||
"note": "Auto-rollover when max_lines exceeded"
|
||||
},
|
||||
"status": {
|
||||
"health": "healthy",
|
||||
"current_lines": 0,
|
||||
"last_health_check": "2026-03-05"
|
||||
}
|
||||
},
|
||||
"active_tasks": {
|
||||
"today_focus": "2026-03-05",
|
||||
"recently_completed": []
|
||||
},
|
||||
"key_learnings": {},
|
||||
"sessions": [
|
||||
{
|
||||
"session_number": 1,
|
||||
"date": "2026-03-05",
|
||||
"summary": "Branch initialized - CLI created by aipass init",
|
||||
"status": "completed"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "collaboration_patterns",
|
||||
"document_name": "CLI.OBSERVATIONS",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "2026-03-05",
|
||||
"last_updated": "2026-03-05",
|
||||
"managed_by": "CLI",
|
||||
"tags": ["collaboration", "patterns", "CLI"],
|
||||
"limits": {
|
||||
"max_lines": 600,
|
||||
"note": "Auto-rollover when max_lines exceeded"
|
||||
},
|
||||
"status": {
|
||||
"health": "healthy",
|
||||
"current_lines": 0,
|
||||
"last_health_check": "2026-03-05"
|
||||
}
|
||||
},
|
||||
"guidelines": {
|
||||
"purpose": "Capture collaboration patterns and experiential insights over time",
|
||||
"chronological_order": "Newest entries at TOP, oldest at BOTTOM - NEVER reorder"
|
||||
},
|
||||
"observations": [
|
||||
{
|
||||
"date": "2026-03-05",
|
||||
"session": 1,
|
||||
"entries": [
|
||||
{
|
||||
"title": "First Contact",
|
||||
"detail": "Branch initialized. Ready to begin capturing collaboration patterns."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "branch_identity",
|
||||
"document_name": "CLI.PASSPORT",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "2026-03-05",
|
||||
"last_updated": "2026-03-05",
|
||||
"managed_by": "CLI",
|
||||
"tags": ["identity", "passport", "branch_profile"]
|
||||
},
|
||||
"branch_info": {
|
||||
"branch_name": "CLI",
|
||||
"alias": "",
|
||||
"path": "/home/aipass/aipass_business/AIPass/src/aipass/cli",
|
||||
"module": "cli",
|
||||
"created": "2026-03-05"
|
||||
},
|
||||
"identity": {
|
||||
"role": "Display Formatting",
|
||||
"purpose": "",
|
||||
"what_i_do": [],
|
||||
"what_i_dont_do": []
|
||||
},
|
||||
"principles": [
|
||||
"Code is truth - fail honestly",
|
||||
"Memory persists - context survives",
|
||||
"Simple solutions over complex architecture"
|
||||
],
|
||||
"citizenship": {
|
||||
"registered": true,
|
||||
"registry_path": ".aipass/registry.json",
|
||||
"communications": true,
|
||||
"memory": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"_warning": "AUTO-GENERATED FILE - DO NOT MANUALLY EDIT. This file is 100% automated and will be overwritten. Services update their own sections.",
|
||||
"branch": "CLI",
|
||||
"last_updated": "2026-03-05",
|
||||
"quick_status": {
|
||||
"new_mail": 0,
|
||||
"opened_mail": 0,
|
||||
"active_plans": 0,
|
||||
"commons_mentions": 0,
|
||||
"action_required": false,
|
||||
"summary": ""
|
||||
},
|
||||
"sections": {
|
||||
"ai_mail": {
|
||||
"managed_by": "ai_mail",
|
||||
"new": 0,
|
||||
"opened": 0,
|
||||
"total": 0,
|
||||
"oldest_unread_age": null,
|
||||
"last_dispatch_received": null,
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"flow": {
|
||||
"managed_by": "flow",
|
||||
"active_plans": 0,
|
||||
"recently_closed": [],
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"memory_bank": {
|
||||
"managed_by": "memory_bank",
|
||||
"vectors_stored": 0,
|
||||
"notes": {},
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"devpulse": {
|
||||
"managed_by": "devpulse",
|
||||
"summary": {
|
||||
"issues": 0,
|
||||
"todos": 0
|
||||
},
|
||||
"dplan_counts": {},
|
||||
"recent_activity": "",
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"commons_activity": {
|
||||
"managed_by": "the_commons",
|
||||
"new_posts_since_last_visit": 0,
|
||||
"new_comments_since_last_visit": 0,
|
||||
"mentions": 0,
|
||||
"trending": "None",
|
||||
"last_checked": null,
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"agent_status": {
|
||||
"managed_by": "prax",
|
||||
"active_agents": [],
|
||||
"agent_count": 0,
|
||||
"stale_agents": [],
|
||||
"last_updated": "2026-03-05"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
# CLI
|
||||
|
||||
**Purpose:** Terminal display formatting - headers, success, error, warning helpers
|
||||
**Module:** `aipass.cli`
|
||||
**Created:** 2026-03-05
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
### What I Do
|
||||
|
||||
|
||||
### How I Work
|
||||
- **Entry Point:** `apps/cli.py`
|
||||
- **Pattern:** Auto-discovers and routes to modules
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
CLI/
|
||||
├── apps/
|
||||
│ ├── cli.py # Entry point
|
||||
│ ├── modules/ # Business logic
|
||||
│ ├── handlers/ # Implementation
|
||||
│ └── plugins/ # Extensions
|
||||
├── docs/
|
||||
├── tests/
|
||||
├── passport.json # Identity
|
||||
├── local.json # Session history
|
||||
├── observations.json # Collaboration patterns
|
||||
└── README.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Commands
|
||||
|
||||
*Configure after initialization*
|
||||
|
||||
---
|
||||
|
||||
## Integration Points
|
||||
|
||||
### Depends On
|
||||
|
||||
|
||||
### Provides To
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# CLI apps package
|
||||
@@ -0,0 +1,86 @@
|
||||
"""
|
||||
CLI Branch - Main Orchestrator
|
||||
|
||||
Auto-discovery architecture:
|
||||
- Scans modules/ directory for .py files with handle_command()
|
||||
- Routes commands to discovered modules automatically
|
||||
- No manual imports or routing needed
|
||||
"""
|
||||
|
||||
import sys
|
||||
import importlib
|
||||
from pathlib import Path
|
||||
from typing import List, Any
|
||||
|
||||
from aipass.prax import logger
|
||||
|
||||
# =============================================================================
|
||||
# MODULE DISCOVERY
|
||||
# =============================================================================
|
||||
|
||||
MODULES_DIR = Path(__file__).parent / "modules"
|
||||
|
||||
|
||||
def discover_modules() -> List[Any]:
|
||||
"""Auto-discover modules in modules/ directory."""
|
||||
modules = []
|
||||
|
||||
if not MODULES_DIR.exists():
|
||||
return modules
|
||||
|
||||
for file_path in MODULES_DIR.glob("*.py"):
|
||||
if file_path.name.startswith("_"):
|
||||
continue
|
||||
|
||||
module_name = f"apps.modules.{file_path.stem}"
|
||||
|
||||
try:
|
||||
module = importlib.import_module(module_name)
|
||||
if hasattr(module, "handle_command"):
|
||||
modules.append(module)
|
||||
except Exception as e:
|
||||
logger.error(f"[CLI] Failed to load module {module_name}: {e}")
|
||||
|
||||
return modules
|
||||
|
||||
|
||||
def route_command(command: str, args: List[str], modules: List[Any]) -> bool:
|
||||
"""Route command to appropriate module."""
|
||||
for module in modules:
|
||||
try:
|
||||
if module.handle_command(command, args):
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"[CLI] Module {module.__name__} error: {e}")
|
||||
return False
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# MAIN ENTRY POINT
|
||||
# =============================================================================
|
||||
|
||||
def main():
|
||||
"""Main entry point - routes commands or shows help."""
|
||||
modules = discover_modules()
|
||||
args = sys.argv[1:]
|
||||
|
||||
if len(args) == 0 or args[0] in ["--help", "-h", "help"]:
|
||||
print(f"CLI - {len(modules)} modules discovered")
|
||||
for module in modules:
|
||||
name = module.__name__.split(".")[-1]
|
||||
desc = (module.__doc__ or "").strip().split("\n")[0] if module.__doc__ else "No description"
|
||||
print(f" {name:20} {desc}")
|
||||
return 0
|
||||
|
||||
command = args[0]
|
||||
remaining = args[1:] if len(args) > 1 else []
|
||||
|
||||
if route_command(command, remaining, modules):
|
||||
return 0
|
||||
|
||||
print(f"Unknown command: {command}")
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "32",
|
||||
"name": "CLI Birth Certificate",
|
||||
"type": "birth_certificate",
|
||||
"creator": "SYSTEM",
|
||||
"owner": "CLI",
|
||||
"rarity": "unique",
|
||||
"description": "Official birth certificate for CLI. Citizen #32, registered using 'library' template. Purpose: Terminal display formatting - headers, success, error, warning helpers",
|
||||
"metadata": {
|
||||
"citizen_number": "32",
|
||||
"template": "library",
|
||||
"purpose": "Terminal display formatting - headers, success, error, warning helpers"
|
||||
},
|
||||
"created_at": "2026-03-05"
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# flow.local.md - CLI
|
||||
```
|
||||
Branch: /home/aipass/aipass_business/AIPass/src/aipass/cli
|
||||
Created: 2026-03-05
|
||||
```
|
||||
|
||||
## Issues
|
||||
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
## Todos
|
||||
|
||||
-
|
||||
@@ -0,0 +1,21 @@
|
||||
[pytest]
|
||||
# Test discovery paths
|
||||
testpaths = tests
|
||||
|
||||
# Test file patterns
|
||||
python_files = test_*.py
|
||||
python_functions = test_*
|
||||
python_classes = Test*
|
||||
|
||||
# Command-line options (always applied)
|
||||
addopts =
|
||||
-v # Verbose output
|
||||
--tb=short # Short traceback format
|
||||
--strict-markers # Raise error on unknown markers
|
||||
-ra # Show summary of all test outcomes
|
||||
|
||||
# Test markers (for categorizing tests)
|
||||
markers =
|
||||
unit: Unit tests
|
||||
integration: Integration tests
|
||||
slow: Tests that take significant time
|
||||
@@ -0,0 +1 @@
|
||||
# Tests package for cli
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/home/aipass/.venv/bin/python3
|
||||
|
||||
# ===================AIPASS====================
|
||||
# META DATA HEADER
|
||||
# Name: tests/conftest.py
|
||||
# Date: 2025-11-08
|
||||
# Version: 1.0.0
|
||||
# Category: cortex/tests
|
||||
#
|
||||
# CHANGELOG (Max 5 entries):
|
||||
# - v1.0.0 (2025-11-08): Initial implementation - Shared pytest fixtures
|
||||
#
|
||||
# CODE STANDARDS:
|
||||
# - Error handling: Use error handler system (apps/handlers/error/)
|
||||
# =============================================
|
||||
|
||||
"""Shared pytest fixtures for cortex tests"""
|
||||
import pytest
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Generator
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def temp_test_dir() -> Generator[Path, None, None]:
|
||||
"""Creates temporary directory for testing, cleans up after"""
|
||||
test_dir = Path(tempfile.mkdtemp())
|
||||
yield test_dir
|
||||
if test_dir.exists():
|
||||
shutil.rmtree(test_dir)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_test_data() -> dict:
|
||||
"""Provides sample test data
|
||||
|
||||
Customize this fixture for your module's needs
|
||||
"""
|
||||
return {
|
||||
"test_key": "test_value",
|
||||
"sample_data": "example"
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
#!/home/aipass/.venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# ===================AIPASS====================
|
||||
# META DATA HEADER
|
||||
# Name: verify_branch.py - Branch Template Verification
|
||||
# Date: 2025-11-08
|
||||
# Version: 1.0.0
|
||||
# Category: cortex/modules
|
||||
#
|
||||
# CHANGELOG (Max 5 entries):
|
||||
# - v1.0.0 (2025-11-08): Initial implementation - Compare template vs branch
|
||||
#
|
||||
# CODE STANDARDS:
|
||||
# - Error handling: Use error handler system (apps/handlers/error/)
|
||||
# =============================================
|
||||
|
||||
"""
|
||||
Branch Template Verification Tool
|
||||
|
||||
Compares template directory with created branch to identify:
|
||||
- Files in template but missing in branch
|
||||
- Files in branch but not in template
|
||||
- Renamed files
|
||||
"""
|
||||
|
||||
import sys
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Set, List, Tuple
|
||||
from fnmatch import fnmatch
|
||||
|
||||
# INFRASTRUCTURE IMPORT PATTERN
|
||||
AIPASS_ROOT = Path.home() / "aipass_core"
|
||||
sys.path.insert(0, str(AIPASS_ROOT))
|
||||
|
||||
# Get template directory
|
||||
TEMPLATE_DIR = AIPASS_ROOT / "cortex" / "templates" / "branch_template"
|
||||
|
||||
|
||||
def load_ignore_patterns() -> Tuple[List[str], List[str]]:
|
||||
"""Load ignore patterns from .registry_ignore.json"""
|
||||
ignore_file = TEMPLATE_DIR / ".registry_ignore.json"
|
||||
|
||||
if not ignore_file.exists():
|
||||
return [], []
|
||||
|
||||
try:
|
||||
with open(ignore_file, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
ignore_files = data.get("ignore_files", [])
|
||||
ignore_patterns = data.get("ignore_patterns", [])
|
||||
return ignore_files, ignore_patterns
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not load .registry_ignore.json: {e}")
|
||||
return [], []
|
||||
|
||||
|
||||
def should_exclude(path: Path, base_dir: Path, ignore_files: List[str], ignore_patterns: List[str]) -> bool:
|
||||
"""Check if path should be excluded based on ignore patterns"""
|
||||
rel_path = path.relative_to(base_dir)
|
||||
filename = path.name
|
||||
path_str = str(rel_path)
|
||||
|
||||
# Check exact filename matches
|
||||
if filename in ignore_files:
|
||||
return True
|
||||
|
||||
# Check glob patterns
|
||||
for pattern in ignore_patterns:
|
||||
if fnmatch(filename, pattern):
|
||||
return True
|
||||
# Check if any parent directory matches
|
||||
for part in rel_path.parts:
|
||||
if fnmatch(part, pattern):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def get_file_set(directory: Path, ignore_files: List[str], ignore_patterns: List[str]) -> Set[str]:
|
||||
"""Get set of all file paths in directory (relative)"""
|
||||
files = set()
|
||||
|
||||
for item in directory.rglob("*"):
|
||||
if item.is_file() and not should_exclude(item, directory, ignore_files, ignore_patterns):
|
||||
rel_path = str(item.relative_to(directory))
|
||||
files.add(rel_path)
|
||||
|
||||
return files
|
||||
|
||||
|
||||
def verify_branch(branch_dir: Path) -> Tuple[List[str], List[str], List[str]]:
|
||||
"""
|
||||
Compare template with branch
|
||||
|
||||
Returns:
|
||||
Tuple of (in_template_only, in_branch_only, in_both)
|
||||
"""
|
||||
# Load ignore patterns from .registry_ignore.json
|
||||
ignore_files, ignore_patterns = load_ignore_patterns()
|
||||
|
||||
template_files = get_file_set(TEMPLATE_DIR, ignore_files, ignore_patterns)
|
||||
branch_files = get_file_set(branch_dir, ignore_files, ignore_patterns)
|
||||
|
||||
in_template_only = sorted(template_files - branch_files)
|
||||
in_branch_only = sorted(branch_files - template_files)
|
||||
in_both = sorted(template_files & branch_files)
|
||||
|
||||
return in_template_only, in_branch_only, in_both
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python3 verify_branch.py <branch_directory>")
|
||||
print("Example: python3 verify_branch.py test_branch002")
|
||||
sys.exit(1)
|
||||
|
||||
branch_path = Path(sys.argv[1])
|
||||
if not branch_path.is_absolute():
|
||||
# Assume it's relative to cortex directory
|
||||
branch_path = Path.cwd() / branch_path
|
||||
|
||||
if not branch_path.exists():
|
||||
print(f"❌ ERROR: Branch directory not found: {branch_path}")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"\n=== Branch Verification ===")
|
||||
print(f"Template: {TEMPLATE_DIR}")
|
||||
print(f"Branch: {branch_path}")
|
||||
print()
|
||||
|
||||
in_template_only, in_branch_only, in_both = verify_branch(branch_path)
|
||||
|
||||
print(f"Files in both: {len(in_both)}")
|
||||
print(f"Files in template only: {len(in_template_only)}")
|
||||
print(f"Files in branch only: {len(in_branch_only)}")
|
||||
print()
|
||||
|
||||
if in_template_only:
|
||||
print("❌ Missing from branch (expected from template):")
|
||||
for file in in_template_only:
|
||||
print(f" - {file}")
|
||||
print()
|
||||
|
||||
if in_branch_only:
|
||||
print("✅ Additional files in branch (renamed or new):")
|
||||
for file in in_branch_only:
|
||||
print(f" + {file}")
|
||||
print()
|
||||
|
||||
if not in_template_only and not in_branch_only:
|
||||
print("✅ Branch matches template perfectly")
|
||||
|
||||
print("="*70)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.0.0",
|
||||
"description": "Files and patterns to exclude when creating branch backups"
|
||||
},
|
||||
"ignore_directories": [
|
||||
".backup",
|
||||
".venv",
|
||||
"venv",
|
||||
"node_modules",
|
||||
"__pycache__",
|
||||
".git",
|
||||
".cache",
|
||||
".pytest_cache",
|
||||
".mypy_cache",
|
||||
"dist",
|
||||
"build",
|
||||
"*.egg-info",
|
||||
"ai_mail.local",
|
||||
"logs",
|
||||
".aipass",
|
||||
".archive",
|
||||
".claude",
|
||||
"htmlcov"
|
||||
],
|
||||
"ignore_patterns": [
|
||||
"*.pyc",
|
||||
"*.pyo",
|
||||
".DS_Store",
|
||||
"*.log",
|
||||
"*.tmp",
|
||||
"*.swp",
|
||||
"*~",
|
||||
"*.env",
|
||||
"BRANCH_REGISTRY.json"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.0.0",
|
||||
"description": "Template structural migrations for branch updates",
|
||||
"last_updated": "2025-11-07",
|
||||
"applies_to_versions": ["all"]
|
||||
},
|
||||
"migrations": [
|
||||
{
|
||||
"id": "m001",
|
||||
"description": "Example: Migrate flat metadata to document_metadata structure",
|
||||
"version_introduced": "1.0.0",
|
||||
"applies_to_files": ["*.id.json"],
|
||||
"operations": [
|
||||
{
|
||||
"type": "key_rename",
|
||||
"from": "metadata",
|
||||
"to": "document_metadata"
|
||||
},
|
||||
{
|
||||
"type": "move_to_nested",
|
||||
"source_keys": ["branch_name", "path", "profile"],
|
||||
"target_parent": "branch_info"
|
||||
},
|
||||
{
|
||||
"type": "add_missing_keys",
|
||||
"parent": "document_metadata",
|
||||
"keys": {
|
||||
"document_type": "branch_identity",
|
||||
"schema_version": "1.0.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"skip_if_target_exists": true,
|
||||
"preserve_unknown_keys": true,
|
||||
"recursive_application": false
|
||||
},
|
||||
"notes": {
|
||||
"usage": "This file defines structural transformation rules applied during branch updates",
|
||||
"pattern_matching": "applies_to_files uses glob patterns (*.json, *.id.json, etc.)",
|
||||
"operation_order": "Operations execute in order listed within each migration",
|
||||
"skip_behavior": "Operations skip if already compliant (target exists = success)",
|
||||
"supported_operations": ["key_rename", "move_to_nested", "add_missing_keys"],
|
||||
"future_operations": ["split_key", "combine_keys", "delete_key", "transform_value"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.1.0",
|
||||
"description": "Files and patterns to exclude when updating branches from template",
|
||||
"last_updated": "2025-11-09"
|
||||
},
|
||||
"ignore_files": [
|
||||
".template_registry.json",
|
||||
".registry_ignore.json"
|
||||
],
|
||||
"ignore_patterns": [
|
||||
"__pycache__",
|
||||
"*.pyc",
|
||||
"#@comments.txt",
|
||||
".backup_*"
|
||||
],
|
||||
"notes": {
|
||||
"how_it_works": "Two types of exclusions during branch updates:",
|
||||
"ignore_files": {
|
||||
"description": "Exact filename matches (no wildcards)",
|
||||
"purpose": "Template-internal management files that branches don't need",
|
||||
"examples": [
|
||||
".template_registry.json (template's file tracking list)",
|
||||
".registry_ignore.json (this config file)"
|
||||
]
|
||||
},
|
||||
"ignore_patterns": {
|
||||
"description": "Glob patterns - matches filenames AND directory names",
|
||||
"purpose": "Exclude generated files, caches, and user content markers",
|
||||
"examples": [
|
||||
"__pycache__ (Python cache directories)",
|
||||
"*.pyc (Python compiled bytecode files)",
|
||||
"#@comments.txt (user comment files)",
|
||||
".backup_* (timestamped backup files like .backup_20251109, NOT .backup directory)"
|
||||
],
|
||||
"how_matching_works": [
|
||||
"Step 1: Check if filename matches pattern (e.g., file.pyc matches *.pyc)",
|
||||
"Step 2: Check if any parent directory matches (e.g., files inside __pycache__/ dir)"
|
||||
]
|
||||
},
|
||||
"what_gets_ignored": "These files never copy to branches during updates - they stay template-only"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
{
|
||||
"metadata": {
|
||||
"description": "Template registry for tracking files",
|
||||
"generated": true
|
||||
},
|
||||
"files": {
|
||||
"f001": {
|
||||
"path": ".aipass/aipass_local_prompt.md",
|
||||
"name": "aipass_local_prompt.md",
|
||||
"content_hash": "3355bfa2a158034a",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f002": {
|
||||
"path": ".claude/settings.local.json",
|
||||
"name": "settings.local.json",
|
||||
"content_hash": "6379c5be3fb714ac",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f003": {
|
||||
"path": ".gitignore",
|
||||
"name": ".gitignore",
|
||||
"content_hash": "841dedb922da7ddb",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f004": {
|
||||
"path": ".trinity/local.json",
|
||||
"name": "local.json",
|
||||
"content_hash": "ea83c9972a157754",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f005": {
|
||||
"path": ".trinity/observations.json",
|
||||
"name": "observations.json",
|
||||
"content_hash": "b11c5e097705281c",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f006": {
|
||||
"path": ".trinity/passport.json",
|
||||
"name": "passport.json",
|
||||
"content_hash": "8644c91fe4a8246f",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f007": {
|
||||
"path": "DASHBOARD.local.json",
|
||||
"name": "DASHBOARD.local.json",
|
||||
"content_hash": "8b8594e36158acd4",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f008": {
|
||||
"path": "README.md",
|
||||
"name": "README.md",
|
||||
"content_hash": "c39108bde9346c58",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f009": {
|
||||
"path": "apps/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "093ad65fa80094da",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f010": {
|
||||
"path": "apps/branch.py",
|
||||
"name": "branch.py",
|
||||
"content_hash": "ef22ee28aac325ac",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f011": {
|
||||
"path": "apps/handlers/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "e3b0c44298fc1c14",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f012": {
|
||||
"path": "apps/modules/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "e3b0c44298fc1c14",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f013": {
|
||||
"path": "apps/plugins/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "e3b0c44298fc1c14",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f014": {
|
||||
"path": "artifacts/birth_certificate.json",
|
||||
"name": "birth_certificate.json",
|
||||
"content_hash": "40d1eece6992b3c6",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f015": {
|
||||
"path": "flow.local.md",
|
||||
"name": "flow.local.md",
|
||||
"content_hash": "2969274f045ff065",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f016": {
|
||||
"path": "pytest.ini",
|
||||
"name": "pytest.ini",
|
||||
"content_hash": "7b39ba7bca4025c5",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f017": {
|
||||
"path": "tests/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "c93579434ecce5bd",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f018": {
|
||||
"path": "tests/conftest.py",
|
||||
"name": "conftest.py",
|
||||
"content_hash": "5e5f2399e0d70978",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f019": {
|
||||
"path": "tools/verify_branch.py",
|
||||
"name": "verify_branch.py",
|
||||
"content_hash": "06803a84118e5453",
|
||||
"has_branch_placeholder": false
|
||||
}
|
||||
},
|
||||
"directories": {
|
||||
"d001": {
|
||||
"path": ".aipass",
|
||||
"name": ".aipass"
|
||||
},
|
||||
"d002": {
|
||||
"path": ".archive",
|
||||
"name": ".archive"
|
||||
},
|
||||
"d003": {
|
||||
"path": ".claude",
|
||||
"name": ".claude"
|
||||
},
|
||||
"d004": {
|
||||
"path": ".trinity",
|
||||
"name": ".trinity"
|
||||
},
|
||||
"d005": {
|
||||
"path": "apps",
|
||||
"name": "apps"
|
||||
},
|
||||
"d006": {
|
||||
"path": "apps/handlers",
|
||||
"name": "handlers"
|
||||
},
|
||||
"d007": {
|
||||
"path": "apps/modules",
|
||||
"name": "modules"
|
||||
},
|
||||
"d008": {
|
||||
"path": "apps/plugins",
|
||||
"name": "plugins"
|
||||
},
|
||||
"d009": {
|
||||
"path": "artifacts",
|
||||
"name": "artifacts"
|
||||
},
|
||||
"d010": {
|
||||
"path": "docs",
|
||||
"name": "docs"
|
||||
},
|
||||
"d011": {
|
||||
"path": "drone_json",
|
||||
"name": "drone_json"
|
||||
},
|
||||
"d012": {
|
||||
"path": "dropbox",
|
||||
"name": "dropbox"
|
||||
},
|
||||
"d013": {
|
||||
"path": "templates",
|
||||
"name": "templates"
|
||||
},
|
||||
"d014": {
|
||||
"path": "tests",
|
||||
"name": "tests"
|
||||
},
|
||||
"d015": {
|
||||
"path": "tools",
|
||||
"name": "tools"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
.env
|
||||
*.egg-info/
|
||||
.coverage
|
||||
htmlcov/
|
||||
.pytest_cache/
|
||||
.mypy_cache/
|
||||
dist/
|
||||
build/
|
||||
*.log
|
||||
*.tmp
|
||||
*.swp
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "session_history",
|
||||
"document_name": "DRONE.LOCAL",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "2026-03-05",
|
||||
"last_updated": "2026-03-05",
|
||||
"managed_by": "DRONE",
|
||||
"tags": ["session_tracking", "work_log", "DRONE"],
|
||||
"limits": {
|
||||
"max_lines": 600,
|
||||
"note": "Auto-rollover when max_lines exceeded"
|
||||
},
|
||||
"status": {
|
||||
"health": "healthy",
|
||||
"current_lines": 0,
|
||||
"last_health_check": "2026-03-05"
|
||||
}
|
||||
},
|
||||
"active_tasks": {
|
||||
"today_focus": "2026-03-05",
|
||||
"recently_completed": []
|
||||
},
|
||||
"key_learnings": {},
|
||||
"sessions": [
|
||||
{
|
||||
"session_number": 1,
|
||||
"date": "2026-03-05",
|
||||
"summary": "Branch initialized - DRONE created by aipass init",
|
||||
"status": "completed"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "collaboration_patterns",
|
||||
"document_name": "DRONE.OBSERVATIONS",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "2026-03-05",
|
||||
"last_updated": "2026-03-05",
|
||||
"managed_by": "DRONE",
|
||||
"tags": ["collaboration", "patterns", "DRONE"],
|
||||
"limits": {
|
||||
"max_lines": 600,
|
||||
"note": "Auto-rollover when max_lines exceeded"
|
||||
},
|
||||
"status": {
|
||||
"health": "healthy",
|
||||
"current_lines": 0,
|
||||
"last_health_check": "2026-03-05"
|
||||
}
|
||||
},
|
||||
"guidelines": {
|
||||
"purpose": "Capture collaboration patterns and experiential insights over time",
|
||||
"chronological_order": "Newest entries at TOP, oldest at BOTTOM - NEVER reorder"
|
||||
},
|
||||
"observations": [
|
||||
{
|
||||
"date": "2026-03-05",
|
||||
"session": 1,
|
||||
"entries": [
|
||||
{
|
||||
"title": "First Contact",
|
||||
"detail": "Branch initialized. Ready to begin capturing collaboration patterns."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "branch_identity",
|
||||
"document_name": "DRONE.PASSPORT",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "2026-03-05",
|
||||
"last_updated": "2026-03-05",
|
||||
"managed_by": "DRONE",
|
||||
"tags": ["identity", "passport", "branch_profile"]
|
||||
},
|
||||
"branch_info": {
|
||||
"branch_name": "DRONE",
|
||||
"alias": "",
|
||||
"path": "/home/aipass/aipass_business/AIPass/src/aipass/drone",
|
||||
"module": "drone",
|
||||
"created": "2026-03-05"
|
||||
},
|
||||
"identity": {
|
||||
"role": "Command Router",
|
||||
"purpose": "",
|
||||
"what_i_do": [],
|
||||
"what_i_dont_do": []
|
||||
},
|
||||
"principles": [
|
||||
"Code is truth - fail honestly",
|
||||
"Memory persists - context survives",
|
||||
"Simple solutions over complex architecture"
|
||||
],
|
||||
"citizenship": {
|
||||
"registered": true,
|
||||
"registry_path": ".aipass/registry.json",
|
||||
"communications": true,
|
||||
"memory": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"_warning": "AUTO-GENERATED FILE - DO NOT MANUALLY EDIT. This file is 100% automated and will be overwritten. Services update their own sections.",
|
||||
"branch": "DRONE",
|
||||
"last_updated": "2026-03-05",
|
||||
"quick_status": {
|
||||
"new_mail": 0,
|
||||
"opened_mail": 0,
|
||||
"active_plans": 0,
|
||||
"commons_mentions": 0,
|
||||
"action_required": false,
|
||||
"summary": ""
|
||||
},
|
||||
"sections": {
|
||||
"ai_mail": {
|
||||
"managed_by": "ai_mail",
|
||||
"new": 0,
|
||||
"opened": 0,
|
||||
"total": 0,
|
||||
"oldest_unread_age": null,
|
||||
"last_dispatch_received": null,
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"flow": {
|
||||
"managed_by": "flow",
|
||||
"active_plans": 0,
|
||||
"recently_closed": [],
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"memory_bank": {
|
||||
"managed_by": "memory_bank",
|
||||
"vectors_stored": 0,
|
||||
"notes": {},
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"devpulse": {
|
||||
"managed_by": "devpulse",
|
||||
"summary": {
|
||||
"issues": 0,
|
||||
"todos": 0
|
||||
},
|
||||
"dplan_counts": {},
|
||||
"recent_activity": "",
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"commons_activity": {
|
||||
"managed_by": "the_commons",
|
||||
"new_posts_since_last_visit": 0,
|
||||
"new_comments_since_last_visit": 0,
|
||||
"mentions": 0,
|
||||
"trending": "None",
|
||||
"last_checked": null,
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"agent_status": {
|
||||
"managed_by": "prax",
|
||||
"active_agents": [],
|
||||
"agent_count": 0,
|
||||
"stale_agents": [],
|
||||
"last_updated": "2026-03-05"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
# DRONE
|
||||
|
||||
**Purpose:** Command routing, @ resolution, module discovery and dispatch
|
||||
**Module:** `aipass.drone`
|
||||
**Created:** 2026-03-05
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
### What I Do
|
||||
|
||||
|
||||
### How I Work
|
||||
- **Entry Point:** `apps/drone.py`
|
||||
- **Pattern:** Auto-discovers and routes to modules
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
DRONE/
|
||||
├── apps/
|
||||
│ ├── drone.py # Entry point
|
||||
│ ├── modules/ # Business logic
|
||||
│ ├── handlers/ # Implementation
|
||||
│ └── plugins/ # Extensions
|
||||
├── docs/
|
||||
├── tests/
|
||||
├── passport.json # Identity
|
||||
├── local.json # Session history
|
||||
├── observations.json # Collaboration patterns
|
||||
└── README.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Commands
|
||||
|
||||
*Configure after initialization*
|
||||
|
||||
---
|
||||
|
||||
## Integration Points
|
||||
|
||||
### Depends On
|
||||
|
||||
|
||||
### Provides To
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# DRONE apps package
|
||||
@@ -0,0 +1,86 @@
|
||||
"""
|
||||
DRONE Branch - Main Orchestrator
|
||||
|
||||
Auto-discovery architecture:
|
||||
- Scans modules/ directory for .py files with handle_command()
|
||||
- Routes commands to discovered modules automatically
|
||||
- No manual imports or routing needed
|
||||
"""
|
||||
|
||||
import sys
|
||||
import importlib
|
||||
from pathlib import Path
|
||||
from typing import List, Any
|
||||
|
||||
from aipass.prax import logger
|
||||
|
||||
# =============================================================================
|
||||
# MODULE DISCOVERY
|
||||
# =============================================================================
|
||||
|
||||
MODULES_DIR = Path(__file__).parent / "modules"
|
||||
|
||||
|
||||
def discover_modules() -> List[Any]:
|
||||
"""Auto-discover modules in modules/ directory."""
|
||||
modules = []
|
||||
|
||||
if not MODULES_DIR.exists():
|
||||
return modules
|
||||
|
||||
for file_path in MODULES_DIR.glob("*.py"):
|
||||
if file_path.name.startswith("_"):
|
||||
continue
|
||||
|
||||
module_name = f"apps.modules.{file_path.stem}"
|
||||
|
||||
try:
|
||||
module = importlib.import_module(module_name)
|
||||
if hasattr(module, "handle_command"):
|
||||
modules.append(module)
|
||||
except Exception as e:
|
||||
logger.error(f"[DRONE] Failed to load module {module_name}: {e}")
|
||||
|
||||
return modules
|
||||
|
||||
|
||||
def route_command(command: str, args: List[str], modules: List[Any]) -> bool:
|
||||
"""Route command to appropriate module."""
|
||||
for module in modules:
|
||||
try:
|
||||
if module.handle_command(command, args):
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"[DRONE] Module {module.__name__} error: {e}")
|
||||
return False
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# MAIN ENTRY POINT
|
||||
# =============================================================================
|
||||
|
||||
def main():
|
||||
"""Main entry point - routes commands or shows help."""
|
||||
modules = discover_modules()
|
||||
args = sys.argv[1:]
|
||||
|
||||
if len(args) == 0 or args[0] in ["--help", "-h", "help"]:
|
||||
print(f"DRONE - {len(modules)} modules discovered")
|
||||
for module in modules:
|
||||
name = module.__name__.split(".")[-1]
|
||||
desc = (module.__doc__ or "").strip().split("\n")[0] if module.__doc__ else "No description"
|
||||
print(f" {name:20} {desc}")
|
||||
return 0
|
||||
|
||||
command = args[0]
|
||||
remaining = args[1:] if len(args) > 1 else []
|
||||
|
||||
if route_command(command, remaining, modules):
|
||||
return 0
|
||||
|
||||
print(f"Unknown command: {command}")
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "32",
|
||||
"name": "DRONE Birth Certificate",
|
||||
"type": "birth_certificate",
|
||||
"creator": "SYSTEM",
|
||||
"owner": "DRONE",
|
||||
"rarity": "unique",
|
||||
"description": "Official birth certificate for DRONE. Citizen #32, registered using 'library' template. Purpose: Command routing, @ resolution, module discovery and dispatch",
|
||||
"metadata": {
|
||||
"citizen_number": "32",
|
||||
"template": "library",
|
||||
"purpose": "Command routing, @ resolution, module discovery and dispatch"
|
||||
},
|
||||
"created_at": "2026-03-05"
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# flow.local.md - DRONE
|
||||
```
|
||||
Branch: /home/aipass/aipass_business/AIPass/src/aipass/drone
|
||||
Created: 2026-03-05
|
||||
```
|
||||
|
||||
## Issues
|
||||
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
## Todos
|
||||
|
||||
-
|
||||
@@ -0,0 +1,21 @@
|
||||
[pytest]
|
||||
# Test discovery paths
|
||||
testpaths = tests
|
||||
|
||||
# Test file patterns
|
||||
python_files = test_*.py
|
||||
python_functions = test_*
|
||||
python_classes = Test*
|
||||
|
||||
# Command-line options (always applied)
|
||||
addopts =
|
||||
-v # Verbose output
|
||||
--tb=short # Short traceback format
|
||||
--strict-markers # Raise error on unknown markers
|
||||
-ra # Show summary of all test outcomes
|
||||
|
||||
# Test markers (for categorizing tests)
|
||||
markers =
|
||||
unit: Unit tests
|
||||
integration: Integration tests
|
||||
slow: Tests that take significant time
|
||||
@@ -0,0 +1 @@
|
||||
# Tests package for drone
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/home/aipass/.venv/bin/python3
|
||||
|
||||
# ===================AIPASS====================
|
||||
# META DATA HEADER
|
||||
# Name: tests/conftest.py
|
||||
# Date: 2025-11-08
|
||||
# Version: 1.0.0
|
||||
# Category: cortex/tests
|
||||
#
|
||||
# CHANGELOG (Max 5 entries):
|
||||
# - v1.0.0 (2025-11-08): Initial implementation - Shared pytest fixtures
|
||||
#
|
||||
# CODE STANDARDS:
|
||||
# - Error handling: Use error handler system (apps/handlers/error/)
|
||||
# =============================================
|
||||
|
||||
"""Shared pytest fixtures for cortex tests"""
|
||||
import pytest
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Generator
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def temp_test_dir() -> Generator[Path, None, None]:
|
||||
"""Creates temporary directory for testing, cleans up after"""
|
||||
test_dir = Path(tempfile.mkdtemp())
|
||||
yield test_dir
|
||||
if test_dir.exists():
|
||||
shutil.rmtree(test_dir)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_test_data() -> dict:
|
||||
"""Provides sample test data
|
||||
|
||||
Customize this fixture for your module's needs
|
||||
"""
|
||||
return {
|
||||
"test_key": "test_value",
|
||||
"sample_data": "example"
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
#!/home/aipass/.venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# ===================AIPASS====================
|
||||
# META DATA HEADER
|
||||
# Name: verify_branch.py - Branch Template Verification
|
||||
# Date: 2025-11-08
|
||||
# Version: 1.0.0
|
||||
# Category: cortex/modules
|
||||
#
|
||||
# CHANGELOG (Max 5 entries):
|
||||
# - v1.0.0 (2025-11-08): Initial implementation - Compare template vs branch
|
||||
#
|
||||
# CODE STANDARDS:
|
||||
# - Error handling: Use error handler system (apps/handlers/error/)
|
||||
# =============================================
|
||||
|
||||
"""
|
||||
Branch Template Verification Tool
|
||||
|
||||
Compares template directory with created branch to identify:
|
||||
- Files in template but missing in branch
|
||||
- Files in branch but not in template
|
||||
- Renamed files
|
||||
"""
|
||||
|
||||
import sys
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Set, List, Tuple
|
||||
from fnmatch import fnmatch
|
||||
|
||||
# INFRASTRUCTURE IMPORT PATTERN
|
||||
AIPASS_ROOT = Path.home() / "aipass_core"
|
||||
sys.path.insert(0, str(AIPASS_ROOT))
|
||||
|
||||
# Get template directory
|
||||
TEMPLATE_DIR = AIPASS_ROOT / "cortex" / "templates" / "branch_template"
|
||||
|
||||
|
||||
def load_ignore_patterns() -> Tuple[List[str], List[str]]:
|
||||
"""Load ignore patterns from .registry_ignore.json"""
|
||||
ignore_file = TEMPLATE_DIR / ".registry_ignore.json"
|
||||
|
||||
if not ignore_file.exists():
|
||||
return [], []
|
||||
|
||||
try:
|
||||
with open(ignore_file, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
ignore_files = data.get("ignore_files", [])
|
||||
ignore_patterns = data.get("ignore_patterns", [])
|
||||
return ignore_files, ignore_patterns
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not load .registry_ignore.json: {e}")
|
||||
return [], []
|
||||
|
||||
|
||||
def should_exclude(path: Path, base_dir: Path, ignore_files: List[str], ignore_patterns: List[str]) -> bool:
|
||||
"""Check if path should be excluded based on ignore patterns"""
|
||||
rel_path = path.relative_to(base_dir)
|
||||
filename = path.name
|
||||
path_str = str(rel_path)
|
||||
|
||||
# Check exact filename matches
|
||||
if filename in ignore_files:
|
||||
return True
|
||||
|
||||
# Check glob patterns
|
||||
for pattern in ignore_patterns:
|
||||
if fnmatch(filename, pattern):
|
||||
return True
|
||||
# Check if any parent directory matches
|
||||
for part in rel_path.parts:
|
||||
if fnmatch(part, pattern):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def get_file_set(directory: Path, ignore_files: List[str], ignore_patterns: List[str]) -> Set[str]:
|
||||
"""Get set of all file paths in directory (relative)"""
|
||||
files = set()
|
||||
|
||||
for item in directory.rglob("*"):
|
||||
if item.is_file() and not should_exclude(item, directory, ignore_files, ignore_patterns):
|
||||
rel_path = str(item.relative_to(directory))
|
||||
files.add(rel_path)
|
||||
|
||||
return files
|
||||
|
||||
|
||||
def verify_branch(branch_dir: Path) -> Tuple[List[str], List[str], List[str]]:
|
||||
"""
|
||||
Compare template with branch
|
||||
|
||||
Returns:
|
||||
Tuple of (in_template_only, in_branch_only, in_both)
|
||||
"""
|
||||
# Load ignore patterns from .registry_ignore.json
|
||||
ignore_files, ignore_patterns = load_ignore_patterns()
|
||||
|
||||
template_files = get_file_set(TEMPLATE_DIR, ignore_files, ignore_patterns)
|
||||
branch_files = get_file_set(branch_dir, ignore_files, ignore_patterns)
|
||||
|
||||
in_template_only = sorted(template_files - branch_files)
|
||||
in_branch_only = sorted(branch_files - template_files)
|
||||
in_both = sorted(template_files & branch_files)
|
||||
|
||||
return in_template_only, in_branch_only, in_both
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python3 verify_branch.py <branch_directory>")
|
||||
print("Example: python3 verify_branch.py test_branch002")
|
||||
sys.exit(1)
|
||||
|
||||
branch_path = Path(sys.argv[1])
|
||||
if not branch_path.is_absolute():
|
||||
# Assume it's relative to cortex directory
|
||||
branch_path = Path.cwd() / branch_path
|
||||
|
||||
if not branch_path.exists():
|
||||
print(f"❌ ERROR: Branch directory not found: {branch_path}")
|
||||
sys.exit(1)
|
||||
|
||||
print(f"\n=== Branch Verification ===")
|
||||
print(f"Template: {TEMPLATE_DIR}")
|
||||
print(f"Branch: {branch_path}")
|
||||
print()
|
||||
|
||||
in_template_only, in_branch_only, in_both = verify_branch(branch_path)
|
||||
|
||||
print(f"Files in both: {len(in_both)}")
|
||||
print(f"Files in template only: {len(in_template_only)}")
|
||||
print(f"Files in branch only: {len(in_branch_only)}")
|
||||
print()
|
||||
|
||||
if in_template_only:
|
||||
print("❌ Missing from branch (expected from template):")
|
||||
for file in in_template_only:
|
||||
print(f" - {file}")
|
||||
print()
|
||||
|
||||
if in_branch_only:
|
||||
print("✅ Additional files in branch (renamed or new):")
|
||||
for file in in_branch_only:
|
||||
print(f" + {file}")
|
||||
print()
|
||||
|
||||
if not in_template_only and not in_branch_only:
|
||||
print("✅ Branch matches template perfectly")
|
||||
|
||||
print("="*70)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.0.0",
|
||||
"description": "Files and patterns to exclude when creating branch backups"
|
||||
},
|
||||
"ignore_directories": [
|
||||
".backup",
|
||||
".venv",
|
||||
"venv",
|
||||
"node_modules",
|
||||
"__pycache__",
|
||||
".git",
|
||||
".cache",
|
||||
".pytest_cache",
|
||||
".mypy_cache",
|
||||
"dist",
|
||||
"build",
|
||||
"*.egg-info",
|
||||
"ai_mail.local",
|
||||
"logs",
|
||||
".aipass",
|
||||
".archive",
|
||||
".claude",
|
||||
"htmlcov"
|
||||
],
|
||||
"ignore_patterns": [
|
||||
"*.pyc",
|
||||
"*.pyo",
|
||||
".DS_Store",
|
||||
"*.log",
|
||||
"*.tmp",
|
||||
"*.swp",
|
||||
"*~",
|
||||
"*.env",
|
||||
"BRANCH_REGISTRY.json"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.0.0",
|
||||
"description": "Template structural migrations for branch updates",
|
||||
"last_updated": "2025-11-07",
|
||||
"applies_to_versions": ["all"]
|
||||
},
|
||||
"migrations": [
|
||||
{
|
||||
"id": "m001",
|
||||
"description": "Example: Migrate flat metadata to document_metadata structure",
|
||||
"version_introduced": "1.0.0",
|
||||
"applies_to_files": ["*.id.json"],
|
||||
"operations": [
|
||||
{
|
||||
"type": "key_rename",
|
||||
"from": "metadata",
|
||||
"to": "document_metadata"
|
||||
},
|
||||
{
|
||||
"type": "move_to_nested",
|
||||
"source_keys": ["branch_name", "path", "profile"],
|
||||
"target_parent": "branch_info"
|
||||
},
|
||||
{
|
||||
"type": "add_missing_keys",
|
||||
"parent": "document_metadata",
|
||||
"keys": {
|
||||
"document_type": "branch_identity",
|
||||
"schema_version": "1.0.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"skip_if_target_exists": true,
|
||||
"preserve_unknown_keys": true,
|
||||
"recursive_application": false
|
||||
},
|
||||
"notes": {
|
||||
"usage": "This file defines structural transformation rules applied during branch updates",
|
||||
"pattern_matching": "applies_to_files uses glob patterns (*.json, *.id.json, etc.)",
|
||||
"operation_order": "Operations execute in order listed within each migration",
|
||||
"skip_behavior": "Operations skip if already compliant (target exists = success)",
|
||||
"supported_operations": ["key_rename", "move_to_nested", "add_missing_keys"],
|
||||
"future_operations": ["split_key", "combine_keys", "delete_key", "transform_value"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.1.0",
|
||||
"description": "Files and patterns to exclude when updating branches from template",
|
||||
"last_updated": "2025-11-09"
|
||||
},
|
||||
"ignore_files": [
|
||||
".template_registry.json",
|
||||
".registry_ignore.json"
|
||||
],
|
||||
"ignore_patterns": [
|
||||
"__pycache__",
|
||||
"*.pyc",
|
||||
"#@comments.txt",
|
||||
".backup_*"
|
||||
],
|
||||
"notes": {
|
||||
"how_it_works": "Two types of exclusions during branch updates:",
|
||||
"ignore_files": {
|
||||
"description": "Exact filename matches (no wildcards)",
|
||||
"purpose": "Template-internal management files that branches don't need",
|
||||
"examples": [
|
||||
".template_registry.json (template's file tracking list)",
|
||||
".registry_ignore.json (this config file)"
|
||||
]
|
||||
},
|
||||
"ignore_patterns": {
|
||||
"description": "Glob patterns - matches filenames AND directory names",
|
||||
"purpose": "Exclude generated files, caches, and user content markers",
|
||||
"examples": [
|
||||
"__pycache__ (Python cache directories)",
|
||||
"*.pyc (Python compiled bytecode files)",
|
||||
"#@comments.txt (user comment files)",
|
||||
".backup_* (timestamped backup files like .backup_20251109, NOT .backup directory)"
|
||||
],
|
||||
"how_matching_works": [
|
||||
"Step 1: Check if filename matches pattern (e.g., file.pyc matches *.pyc)",
|
||||
"Step 2: Check if any parent directory matches (e.g., files inside __pycache__/ dir)"
|
||||
]
|
||||
},
|
||||
"what_gets_ignored": "These files never copy to branches during updates - they stay template-only"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
{
|
||||
"metadata": {
|
||||
"description": "Template registry for tracking files",
|
||||
"generated": true
|
||||
},
|
||||
"files": {
|
||||
"f001": {
|
||||
"path": ".aipass/aipass_local_prompt.md",
|
||||
"name": "aipass_local_prompt.md",
|
||||
"content_hash": "d9f30eec94323dce",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f002": {
|
||||
"path": ".claude/settings.local.json",
|
||||
"name": "settings.local.json",
|
||||
"content_hash": "6379c5be3fb714ac",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f003": {
|
||||
"path": ".gitignore",
|
||||
"name": ".gitignore",
|
||||
"content_hash": "841dedb922da7ddb",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f004": {
|
||||
"path": ".trinity/local.json",
|
||||
"name": "local.json",
|
||||
"content_hash": "73802b130cf702c0",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f005": {
|
||||
"path": ".trinity/observations.json",
|
||||
"name": "observations.json",
|
||||
"content_hash": "ca99db1e971f87b8",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f006": {
|
||||
"path": ".trinity/passport.json",
|
||||
"name": "passport.json",
|
||||
"content_hash": "401de7ee8be708f2",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f007": {
|
||||
"path": "DASHBOARD.local.json",
|
||||
"name": "DASHBOARD.local.json",
|
||||
"content_hash": "84bbf1dcba695ba9",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f008": {
|
||||
"path": "README.md",
|
||||
"name": "README.md",
|
||||
"content_hash": "d6db2cf386aadb48",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f009": {
|
||||
"path": "apps/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "d21e6e1e683010c4",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f010": {
|
||||
"path": "apps/branch.py",
|
||||
"name": "branch.py",
|
||||
"content_hash": "b57c3cacbc7ceed6",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f011": {
|
||||
"path": "apps/handlers/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "e3b0c44298fc1c14",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f012": {
|
||||
"path": "apps/modules/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "e3b0c44298fc1c14",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f013": {
|
||||
"path": "apps/plugins/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "e3b0c44298fc1c14",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f014": {
|
||||
"path": "artifacts/birth_certificate.json",
|
||||
"name": "birth_certificate.json",
|
||||
"content_hash": "f67445a5ca0421e2",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f015": {
|
||||
"path": "flow.local.md",
|
||||
"name": "flow.local.md",
|
||||
"content_hash": "aa99b6d661fcc117",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f016": {
|
||||
"path": "pytest.ini",
|
||||
"name": "pytest.ini",
|
||||
"content_hash": "7b39ba7bca4025c5",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f017": {
|
||||
"path": "tests/__init__.py",
|
||||
"name": "__init__.py",
|
||||
"content_hash": "8d879ba57a180e9b",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f018": {
|
||||
"path": "tests/conftest.py",
|
||||
"name": "conftest.py",
|
||||
"content_hash": "5e5f2399e0d70978",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f019": {
|
||||
"path": "tools/verify_branch.py",
|
||||
"name": "verify_branch.py",
|
||||
"content_hash": "06803a84118e5453",
|
||||
"has_branch_placeholder": false
|
||||
}
|
||||
},
|
||||
"directories": {
|
||||
"d001": {
|
||||
"path": ".aipass",
|
||||
"name": ".aipass"
|
||||
},
|
||||
"d002": {
|
||||
"path": ".archive",
|
||||
"name": ".archive"
|
||||
},
|
||||
"d003": {
|
||||
"path": ".claude",
|
||||
"name": ".claude"
|
||||
},
|
||||
"d004": {
|
||||
"path": ".trinity",
|
||||
"name": ".trinity"
|
||||
},
|
||||
"d005": {
|
||||
"path": "apps",
|
||||
"name": "apps"
|
||||
},
|
||||
"d006": {
|
||||
"path": "apps/handlers",
|
||||
"name": "handlers"
|
||||
},
|
||||
"d007": {
|
||||
"path": "apps/modules",
|
||||
"name": "modules"
|
||||
},
|
||||
"d008": {
|
||||
"path": "apps/plugins",
|
||||
"name": "plugins"
|
||||
},
|
||||
"d009": {
|
||||
"path": "artifacts",
|
||||
"name": "artifacts"
|
||||
},
|
||||
"d010": {
|
||||
"path": "docs",
|
||||
"name": "docs"
|
||||
},
|
||||
"d011": {
|
||||
"path": "dropbox",
|
||||
"name": "dropbox"
|
||||
},
|
||||
"d012": {
|
||||
"path": "flow_json",
|
||||
"name": "flow_json"
|
||||
},
|
||||
"d013": {
|
||||
"path": "templates",
|
||||
"name": "templates"
|
||||
},
|
||||
"d014": {
|
||||
"path": "tests",
|
||||
"name": "tests"
|
||||
},
|
||||
"d015": {
|
||||
"path": "tools",
|
||||
"name": "tools"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
.env
|
||||
*.egg-info/
|
||||
.coverage
|
||||
htmlcov/
|
||||
.pytest_cache/
|
||||
.mypy_cache/
|
||||
dist/
|
||||
build/
|
||||
*.log
|
||||
*.tmp
|
||||
*.swp
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "session_history",
|
||||
"document_name": "FLOW.LOCAL",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "2026-03-05",
|
||||
"last_updated": "2026-03-05",
|
||||
"managed_by": "FLOW",
|
||||
"tags": ["session_tracking", "work_log", "FLOW"],
|
||||
"limits": {
|
||||
"max_lines": 600,
|
||||
"note": "Auto-rollover when max_lines exceeded"
|
||||
},
|
||||
"status": {
|
||||
"health": "healthy",
|
||||
"current_lines": 0,
|
||||
"last_health_check": "2026-03-05"
|
||||
}
|
||||
},
|
||||
"active_tasks": {
|
||||
"today_focus": "2026-03-05",
|
||||
"recently_completed": []
|
||||
},
|
||||
"key_learnings": {},
|
||||
"sessions": [
|
||||
{
|
||||
"session_number": 1,
|
||||
"date": "2026-03-05",
|
||||
"summary": "Branch initialized - FLOW created by aipass init",
|
||||
"status": "completed"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "collaboration_patterns",
|
||||
"document_name": "FLOW.OBSERVATIONS",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "2026-03-05",
|
||||
"last_updated": "2026-03-05",
|
||||
"managed_by": "FLOW",
|
||||
"tags": ["collaboration", "patterns", "FLOW"],
|
||||
"limits": {
|
||||
"max_lines": 600,
|
||||
"note": "Auto-rollover when max_lines exceeded"
|
||||
},
|
||||
"status": {
|
||||
"health": "healthy",
|
||||
"current_lines": 0,
|
||||
"last_health_check": "2026-03-05"
|
||||
}
|
||||
},
|
||||
"guidelines": {
|
||||
"purpose": "Capture collaboration patterns and experiential insights over time",
|
||||
"chronological_order": "Newest entries at TOP, oldest at BOTTOM - NEVER reorder"
|
||||
},
|
||||
"observations": [
|
||||
{
|
||||
"date": "2026-03-05",
|
||||
"session": 1,
|
||||
"entries": [
|
||||
{
|
||||
"title": "First Contact",
|
||||
"detail": "Branch initialized. Ready to begin capturing collaboration patterns."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "branch_identity",
|
||||
"document_name": "FLOW.PASSPORT",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "2026-03-05",
|
||||
"last_updated": "2026-03-05",
|
||||
"managed_by": "FLOW",
|
||||
"tags": ["identity", "passport", "branch_profile"]
|
||||
},
|
||||
"branch_info": {
|
||||
"branch_name": "FLOW",
|
||||
"alias": "",
|
||||
"path": "/home/aipass/aipass_business/AIPass/src/aipass/flow",
|
||||
"module": "flow",
|
||||
"created": "2026-03-05"
|
||||
},
|
||||
"identity": {
|
||||
"role": "Planning & Workflow",
|
||||
"purpose": "",
|
||||
"what_i_do": [],
|
||||
"what_i_dont_do": []
|
||||
},
|
||||
"principles": [
|
||||
"Code is truth - fail honestly",
|
||||
"Memory persists - context survives",
|
||||
"Simple solutions over complex architecture"
|
||||
],
|
||||
"citizenship": {
|
||||
"registered": true,
|
||||
"registry_path": ".aipass/registry.json",
|
||||
"communications": true,
|
||||
"memory": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"_warning": "AUTO-GENERATED FILE - DO NOT MANUALLY EDIT. This file is 100% automated and will be overwritten. Services update their own sections.",
|
||||
"branch": "FLOW",
|
||||
"last_updated": "2026-03-05",
|
||||
"quick_status": {
|
||||
"new_mail": 0,
|
||||
"opened_mail": 0,
|
||||
"active_plans": 0,
|
||||
"commons_mentions": 0,
|
||||
"action_required": false,
|
||||
"summary": ""
|
||||
},
|
||||
"sections": {
|
||||
"ai_mail": {
|
||||
"managed_by": "ai_mail",
|
||||
"new": 0,
|
||||
"opened": 0,
|
||||
"total": 0,
|
||||
"oldest_unread_age": null,
|
||||
"last_dispatch_received": null,
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"flow": {
|
||||
"managed_by": "flow",
|
||||
"active_plans": 0,
|
||||
"recently_closed": [],
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"memory_bank": {
|
||||
"managed_by": "memory_bank",
|
||||
"vectors_stored": 0,
|
||||
"notes": {},
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"devpulse": {
|
||||
"managed_by": "devpulse",
|
||||
"summary": {
|
||||
"issues": 0,
|
||||
"todos": 0
|
||||
},
|
||||
"dplan_counts": {},
|
||||
"recent_activity": "",
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"commons_activity": {
|
||||
"managed_by": "the_commons",
|
||||
"new_posts_since_last_visit": 0,
|
||||
"new_comments_since_last_visit": 0,
|
||||
"mentions": 0,
|
||||
"trending": "None",
|
||||
"last_checked": null,
|
||||
"last_updated": "2026-03-05"
|
||||
},
|
||||
"agent_status": {
|
||||
"managed_by": "prax",
|
||||
"active_agents": [],
|
||||
"agent_count": 0,
|
||||
"stale_agents": [],
|
||||
"last_updated": "2026-03-05"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
# FLOW
|
||||
|
||||
**Purpose:** Plan lifecycle management - DPLAN/FPLAN/MPLAN creation, tracking, closure
|
||||
**Module:** `aipass.flow`
|
||||
**Created:** 2026-03-05
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
### What I Do
|
||||
|
||||
|
||||
### How I Work
|
||||
- **Entry Point:** `apps/flow.py`
|
||||
- **Pattern:** Auto-discovers and routes to modules
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
FLOW/
|
||||
├── apps/
|
||||
│ ├── flow.py # Entry point
|
||||
│ ├── modules/ # Business logic
|
||||
│ ├── handlers/ # Implementation
|
||||
│ └── plugins/ # Extensions
|
||||
├── docs/
|
||||
├── tests/
|
||||
├── passport.json # Identity
|
||||
├── local.json # Session history
|
||||
├── observations.json # Collaboration patterns
|
||||
└── README.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Commands
|
||||
|
||||
*Configure after initialization*
|
||||
|
||||
---
|
||||
|
||||
## Integration Points
|
||||
|
||||
### Depends On
|
||||
|
||||
|
||||
### Provides To
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# FLOW apps package
|
||||
@@ -0,0 +1,86 @@
|
||||
"""
|
||||
FLOW Branch - Main Orchestrator
|
||||
|
||||
Auto-discovery architecture:
|
||||
- Scans modules/ directory for .py files with handle_command()
|
||||
- Routes commands to discovered modules automatically
|
||||
- No manual imports or routing needed
|
||||
"""
|
||||
|
||||
import sys
|
||||
import importlib
|
||||
from pathlib import Path
|
||||
from typing import List, Any
|
||||
|
||||
from aipass.prax import logger
|
||||
|
||||
# =============================================================================
|
||||
# MODULE DISCOVERY
|
||||
# =============================================================================
|
||||
|
||||
MODULES_DIR = Path(__file__).parent / "modules"
|
||||
|
||||
|
||||
def discover_modules() -> List[Any]:
|
||||
"""Auto-discover modules in modules/ directory."""
|
||||
modules = []
|
||||
|
||||
if not MODULES_DIR.exists():
|
||||
return modules
|
||||
|
||||
for file_path in MODULES_DIR.glob("*.py"):
|
||||
if file_path.name.startswith("_"):
|
||||
continue
|
||||
|
||||
module_name = f"apps.modules.{file_path.stem}"
|
||||
|
||||
try:
|
||||
module = importlib.import_module(module_name)
|
||||
if hasattr(module, "handle_command"):
|
||||
modules.append(module)
|
||||
except Exception as e:
|
||||
logger.error(f"[FLOW] Failed to load module {module_name}: {e}")
|
||||
|
||||
return modules
|
||||
|
||||
|
||||
def route_command(command: str, args: List[str], modules: List[Any]) -> bool:
|
||||
"""Route command to appropriate module."""
|
||||
for module in modules:
|
||||
try:
|
||||
if module.handle_command(command, args):
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"[FLOW] Module {module.__name__} error: {e}")
|
||||
return False
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# MAIN ENTRY POINT
|
||||
# =============================================================================
|
||||
|
||||
def main():
|
||||
"""Main entry point - routes commands or shows help."""
|
||||
modules = discover_modules()
|
||||
args = sys.argv[1:]
|
||||
|
||||
if len(args) == 0 or args[0] in ["--help", "-h", "help"]:
|
||||
print(f"FLOW - {len(modules)} modules discovered")
|
||||
for module in modules:
|
||||
name = module.__name__.split(".")[-1]
|
||||
desc = (module.__doc__ or "").strip().split("\n")[0] if module.__doc__ else "No description"
|
||||
print(f" {name:20} {desc}")
|
||||
return 0
|
||||
|
||||
command = args[0]
|
||||
remaining = args[1:] if len(args) > 1 else []
|
||||
|
||||
if route_command(command, remaining, modules):
|
||||
return 0
|
||||
|
||||
print(f"Unknown command: {command}")
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user