🔧 chore(spawn): update .gitignore to track spawn templates correctly
- allow tracking of specific hidden directories and files under spawn templates - ensure agents can build properly with required template files ✨ feat(branch): add comprehensive branch template verification tool - implemented verify_branch.py to compare branch vs template files - supports ignoring files based on .registry_ignore.json patterns - outputs missing, additional, and matched files for branch validation - included usage instructions and error handling for robust operation ♻️ refactor(prax): fix logger branch logs path to use Path.home() - replaced hardcoded "/home/aipass" with portable Path.home() - allows logging directory creation to adapt to user environment ✨ feat(spawn): add default template files and ignore configs for agent branches - added .backup_ignore.json, .migrations.json, .registry_ignore.json for agent templates - introduced .template_registry.json to track template files and directories - created local context and metadata files for branch identity and session tracking - included dashboard and flow local markdown templates for branch status and management - added artifacts birth_certificate template for branch registration metadata ✨ feat(spawn): add mock agent branch templates and backups for testing - created mock branch with backup ignore and registry ignore files for efficient backups - added template registry and migration definitions matching main agent template - included local prompt, passport, observations, and dashboard templates for mock branch - provided flow local markdown and artifact registration files for mock branch use - duplicated verify_branch.py tool for mock branch environment consistency ♻️ refactor(spawn): unify verify_branch.py tool in agent and mock branches - standardized branch verification script in both template sets - ensures consistent branch-template comparison and ignores handling
This commit is contained in:
@@ -122,7 +122,7 @@ def setup_individual_logger(module_name: str) -> logging.Logger:
|
||||
if branch:
|
||||
# Create branch logs directory if it doesn't exist
|
||||
# Branch format is now "aipass_core/module" or "project_name"
|
||||
branch_logs_dir = Path("/home/aipass") / branch / "logs"
|
||||
branch_logs_dir = Path.home() / branch / "logs"
|
||||
branch_logs_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Create branch-local log file
|
||||
|
||||
@@ -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,301 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.0.0",
|
||||
"last_updated": "2026-02-20",
|
||||
"description": "Template file tracking registry for ID-based updates"
|
||||
},
|
||||
"files": {
|
||||
"f001": {
|
||||
"current_name": "BRANCH.ID.json",
|
||||
"path": "BRANCH.ID.json",
|
||||
"content_hash": "e9bc2347d373",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f003": {
|
||||
"current_name": "dev.local.md",
|
||||
"path": "dev.local.md",
|
||||
"content_hash": "6c1c5e099790",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f035": {
|
||||
"current_name": ".gitkeep",
|
||||
"path": "ai_mail.local/.archive/.gitkeep",
|
||||
"content_hash": "e3b0c44298fc",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f008": {
|
||||
"current_name": "DASHBOARD.local.json",
|
||||
"path": "DASHBOARD.local.json",
|
||||
"content_hash": "3f0528b4c5d5",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f007": {
|
||||
"current_name": ".migrations.json",
|
||||
"path": ".migrations.json",
|
||||
"content_hash": "4ca241607dc3",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f010": {
|
||||
"current_name": "OBSERVATIONS.json",
|
||||
"path": "OBSERVATIONS.json",
|
||||
"content_hash": "58ea8609fbe0",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f011": {
|
||||
"current_name": "requirements.txt",
|
||||
"path": "requirements.txt",
|
||||
"content_hash": "66dfffc70d53",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f021": {
|
||||
"current_name": "README.md",
|
||||
"path": "README.md",
|
||||
"content_hash": "4e946f67a130",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f012": {
|
||||
"current_name": "LOCAL.json",
|
||||
"path": "LOCAL.json",
|
||||
"content_hash": "459dbe18d40a",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f006": {
|
||||
"current_name": "pytest.ini",
|
||||
"path": "pytest.ini",
|
||||
"content_hash": "7b39ba7bca40",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f022": {
|
||||
"current_name": "_template.md",
|
||||
"path": "docs/_template.md",
|
||||
"content_hash": "79ce97b0e613",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f016": {
|
||||
"current_name": "__init__.py",
|
||||
"path": "tests/__init__.py",
|
||||
"content_hash": "1fcd8126d174",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f019": {
|
||||
"current_name": "conftest.py",
|
||||
"path": "tests/conftest.py",
|
||||
"content_hash": "2887db109a6b",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f004": {
|
||||
"current_name": "BRANCH.py",
|
||||
"path": "apps/BRANCH.py",
|
||||
"content_hash": "44f22cc95232",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f009": {
|
||||
"current_name": "__init__.py",
|
||||
"path": "apps/__init__.py",
|
||||
"content_hash": "5c38204be5fc",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f013": {
|
||||
"current_name": "#@comments.txt.removed_from_template",
|
||||
"path": ".archive/#@comments.txt.removed_from_template",
|
||||
"content_hash": "651126c1e7a9",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f028": {
|
||||
"current_name": "deleted.json.old_template_format",
|
||||
"path": ".archive/deleted.json.old_template_format",
|
||||
"content_hash": "48a3a33dd73a",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f002": {
|
||||
"current_name": "branch_system_prompt.md",
|
||||
"path": ".aipass/branch_system_prompt.md",
|
||||
"content_hash": "897c7beb66f5",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f026": {
|
||||
"current_name": "inbox.json",
|
||||
"path": "ai_mail.local/inbox.json",
|
||||
"content_hash": "c9702fe2cc21",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f027": {
|
||||
"current_name": "sent.json",
|
||||
"path": "ai_mail.local/sent.json",
|
||||
"content_hash": "240132e5a567",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f014": {
|
||||
"current_name": "__init__.py",
|
||||
"path": "apps/handlers/__init__.py",
|
||||
"content_hash": "657d98ad4b98",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f015": {
|
||||
"current_name": "__init__.py",
|
||||
"path": "apps/json_templates/__init__.py",
|
||||
"content_hash": "330b189c08c7",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f020": {
|
||||
"current_name": "__init__.py",
|
||||
"path": "apps/plugins/__init__.py",
|
||||
"content_hash": "39158d26a19c",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f023": {
|
||||
"current_name": "__init__.py",
|
||||
"path": "apps/modules/__init__.py",
|
||||
"content_hash": "bc25a8b75e81",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f024": {
|
||||
"current_name": "__init__.py",
|
||||
"path": "apps/extensions/__init__.py",
|
||||
"content_hash": "6742ceb64ec1",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f032": {
|
||||
"current_name": "data.json",
|
||||
"path": "apps/json_templates/default/data.json",
|
||||
"content_hash": "0531a02be998",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f033": {
|
||||
"current_name": "log.json",
|
||||
"path": "apps/json_templates/default/log.json",
|
||||
"content_hash": "37517e5f3dc6",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f034": {
|
||||
"current_name": "config.json",
|
||||
"path": "apps/json_templates/default/config.json",
|
||||
"content_hash": "3759a05e171d",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f005": {
|
||||
"current_name": "json_handler.py",
|
||||
"path": "apps/handlers/json/json_handler.py",
|
||||
"content_hash": "3449629aff23",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f017": {
|
||||
"current_name": "__init__.py",
|
||||
"path": "apps/handlers/json/__init__.py",
|
||||
"content_hash": "ad3629e381ca",
|
||||
"has_branch_placeholder": false
|
||||
}
|
||||
},
|
||||
"directories": {
|
||||
"d001": {
|
||||
"current_name": "tools",
|
||||
"path": "tools",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d002": {
|
||||
"current_name": "docs",
|
||||
"path": "docs",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d003": {
|
||||
"current_name": "tests",
|
||||
"path": "tests",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d004": {
|
||||
"current_name": "apps",
|
||||
"path": "apps",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d005": {
|
||||
"current_name": ".archive",
|
||||
"path": ".archive",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d006": {
|
||||
"current_name": "logs",
|
||||
"path": "logs",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d009": {
|
||||
"current_name": ".backup",
|
||||
"path": ".backup",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d008": {
|
||||
"current_name": "{{BRANCH}}_json",
|
||||
"path": "{{BRANCH}}_json",
|
||||
"has_branch_placeholder": true
|
||||
},
|
||||
"d010": {
|
||||
"current_name": "artifacts",
|
||||
"path": "artifacts",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d012": {
|
||||
"current_name": ".aipass",
|
||||
"path": ".aipass",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d011": {
|
||||
"current_name": "ai_mail.local",
|
||||
"path": "ai_mail.local",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d007": {
|
||||
"current_name": "dropbox",
|
||||
"path": "dropbox",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d013": {
|
||||
"current_name": "handlers",
|
||||
"path": "apps/handlers",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d014": {
|
||||
"current_name": "json_templates",
|
||||
"path": "apps/json_templates",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d015": {
|
||||
"current_name": "plugins",
|
||||
"path": "apps/plugins",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d016": {
|
||||
"current_name": "modules",
|
||||
"path": "apps/modules",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d017": {
|
||||
"current_name": "extensions",
|
||||
"path": "apps/extensions",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d018": {
|
||||
"current_name": "sent",
|
||||
"path": "ai_mail.local/sent",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d019": {
|
||||
"current_name": "deleted",
|
||||
"path": "ai_mail.local/deleted",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d020": {
|
||||
"current_name": ".archive",
|
||||
"path": "ai_mail.local/.archive",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d027": {
|
||||
"current_name": "json",
|
||||
"path": "apps/handlers/json",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d024": {
|
||||
"current_name": "default",
|
||||
"path": "apps/json_templates/default",
|
||||
"has_branch_placeholder": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
# {{BRANCHNAME}} Branch-Local Context
|
||||
<!-- Source: {{CWD}}/.aipass/branch_system_prompt.md -->
|
||||
|
||||
> Auto-created by aipass init. Customize for your branch.
|
||||
|
||||
## Status: NEEDS CONFIGURATION
|
||||
|
||||
This file is injected into every AI conversation when working from this branch directory. Configure it with:
|
||||
|
||||
- Who this branch is (role, purpose)
|
||||
- Key commands and workflows
|
||||
- Architecture overview
|
||||
- Critical files and operational rules
|
||||
- Integration points with other branches
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "session_history",
|
||||
"document_name": "{{BRANCHNAME}}.LOCAL",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "{{DATE}}",
|
||||
"last_updated": "{{DATE}}",
|
||||
"managed_by": "{{BRANCHNAME}}",
|
||||
"tags": ["session_tracking", "work_log", "{{BRANCHNAME}}"],
|
||||
"limits": {
|
||||
"max_lines": 600,
|
||||
"note": "Auto-rollover when max_lines exceeded"
|
||||
},
|
||||
"status": {
|
||||
"health": "healthy",
|
||||
"current_lines": 0,
|
||||
"last_health_check": "{{DATE}}"
|
||||
}
|
||||
},
|
||||
"active_tasks": {
|
||||
"today_focus": "{{DATE}}",
|
||||
"recently_completed": []
|
||||
},
|
||||
"key_learnings": {},
|
||||
"sessions": [
|
||||
{
|
||||
"session_number": 1,
|
||||
"date": "{{DATE}}",
|
||||
"summary": "Branch initialized - {{BRANCHNAME}} created by aipass init",
|
||||
"status": "completed"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "collaboration_patterns",
|
||||
"document_name": "{{BRANCHNAME}}.OBSERVATIONS",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "{{DATE}}",
|
||||
"last_updated": "{{DATE}}",
|
||||
"managed_by": "{{BRANCHNAME}}",
|
||||
"tags": ["collaboration", "patterns", "{{BRANCHNAME}}"],
|
||||
"limits": {
|
||||
"max_lines": 600,
|
||||
"note": "Auto-rollover when max_lines exceeded"
|
||||
},
|
||||
"status": {
|
||||
"health": "healthy",
|
||||
"current_lines": 0,
|
||||
"last_health_check": "{{DATE}}"
|
||||
}
|
||||
},
|
||||
"guidelines": {
|
||||
"purpose": "Capture collaboration patterns and experiential insights over time",
|
||||
"chronological_order": "Newest entries at TOP, oldest at BOTTOM - NEVER reorder"
|
||||
},
|
||||
"observations": [
|
||||
{
|
||||
"date": "{{DATE}}",
|
||||
"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": "{{BRANCHNAME}}.PASSPORT",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "{{DATE}}",
|
||||
"last_updated": "{{DATE}}",
|
||||
"managed_by": "{{BRANCHNAME}}",
|
||||
"tags": ["identity", "passport", "branch_profile"]
|
||||
},
|
||||
"branch_info": {
|
||||
"branch_name": "{{BRANCHNAME}}",
|
||||
"alias": "",
|
||||
"path": "{{CWD}}",
|
||||
"module": "{{MODULE}}",
|
||||
"created": "{{DATE}}"
|
||||
},
|
||||
"identity": {
|
||||
"role": "{{ROLE}}",
|
||||
"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": "{{BRANCHNAME}}",
|
||||
"last_updated": "{{DATE}}",
|
||||
"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": "{{DATE}}"
|
||||
},
|
||||
"flow": {
|
||||
"managed_by": "flow",
|
||||
"active_plans": 0,
|
||||
"recently_closed": [],
|
||||
"last_updated": "{{DATE}}"
|
||||
},
|
||||
"memory_bank": {
|
||||
"managed_by": "memory_bank",
|
||||
"vectors_stored": 0,
|
||||
"notes": {},
|
||||
"last_updated": "{{DATE}}"
|
||||
},
|
||||
"devpulse": {
|
||||
"managed_by": "devpulse",
|
||||
"summary": {
|
||||
"issues": 0,
|
||||
"todos": 0
|
||||
},
|
||||
"dplan_counts": {},
|
||||
"recent_activity": "",
|
||||
"last_updated": "{{DATE}}"
|
||||
},
|
||||
"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": "{{DATE}}"
|
||||
},
|
||||
"agent_status": {
|
||||
"managed_by": "prax",
|
||||
"active_agents": [],
|
||||
"agent_count": 0,
|
||||
"stale_agents": [],
|
||||
"last_updated": "{{DATE}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "{{CITIZEN_NUMBER}}",
|
||||
"name": "{{BRANCHNAME}} Birth Certificate",
|
||||
"type": "birth_certificate",
|
||||
"creator": "SYSTEM",
|
||||
"owner": "{{BRANCHNAME}}",
|
||||
"rarity": "unique",
|
||||
"description": "Official birth certificate for {{BRANCHNAME}}. Citizen #{{CITIZEN_NUMBER}}, registered using '{{PROFILE}}' template. Purpose: {{PURPOSE_BRIEF}}",
|
||||
"metadata": {
|
||||
"citizen_number": "{{CITIZEN_NUMBER}}",
|
||||
"template": "{{PROFILE}}",
|
||||
"purpose": "{{PURPOSE_BRIEF}}"
|
||||
},
|
||||
"created_at": "{{DATE}}"
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# flow.local.md - {{BRANCHNAME}}
|
||||
```
|
||||
Branch: {{CWD}}
|
||||
Created: {{DATE}}
|
||||
```
|
||||
|
||||
## Issues
|
||||
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
## Todos
|
||||
|
||||
-
|
||||
@@ -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,133 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.0.0",
|
||||
"description": "Files and patterns to exclude when creating branch backups",
|
||||
"last_updated": "2025-11-09"
|
||||
},
|
||||
"ignore_directories": [
|
||||
".backup",
|
||||
"backups",
|
||||
".venv",
|
||||
"venv",
|
||||
"node_modules",
|
||||
"__pycache__",
|
||||
".git",
|
||||
".cache",
|
||||
".pytest_cache",
|
||||
".mypy_cache",
|
||||
"dist",
|
||||
"build",
|
||||
"*.egg-info",
|
||||
"aipass_dev",
|
||||
"aipass_core",
|
||||
"aipass_business",
|
||||
"aipass_help",
|
||||
"input_x",
|
||||
"Link to mnt",
|
||||
"mcp_servers",
|
||||
"speakeasy",
|
||||
"sandbox",
|
||||
"ai_mail.local",
|
||||
"logs",
|
||||
"pruned_files",
|
||||
"crash-logs",
|
||||
".aipass",
|
||||
".archive",
|
||||
".cargo",
|
||||
".codex",
|
||||
".config",
|
||||
".dbus",
|
||||
".dotnet",
|
||||
".gemini",
|
||||
".gnome",
|
||||
".gnupg",
|
||||
".idlerc",
|
||||
".java",
|
||||
".local",
|
||||
".mozilla",
|
||||
".npm",
|
||||
".npm-global",
|
||||
".nvm",
|
||||
".pki",
|
||||
".pylint.d",
|
||||
".pyenv",
|
||||
".serena",
|
||||
".ssh",
|
||||
".thunderbird",
|
||||
".var",
|
||||
".vscode-server",
|
||||
".wget-hsts",
|
||||
".claude-code-docs",
|
||||
".claude",
|
||||
"backup_system",
|
||||
"Desktop",
|
||||
"Documents",
|
||||
"Downloads",
|
||||
"dropbox",
|
||||
"Music",
|
||||
"Pictures",
|
||||
"Public",
|
||||
"snap",
|
||||
"system_logs",
|
||||
"Templates",
|
||||
"Videos"
|
||||
],
|
||||
"ignore_patterns": [
|
||||
"*.pyc",
|
||||
"*.pyo",
|
||||
"*.pyd",
|
||||
".DS_Store",
|
||||
"Thumbs.db",
|
||||
"*.log",
|
||||
"*.tmp",
|
||||
"*.swp",
|
||||
"*.swo",
|
||||
"*~",
|
||||
"*.env",
|
||||
"*_json",
|
||||
"dev.local.md",
|
||||
"notepad.md",
|
||||
"pytest.ini",
|
||||
".bash_history",
|
||||
".bash_logout",
|
||||
".bashrc",
|
||||
".claude.json",
|
||||
".claude.json.backup",
|
||||
".lesshst",
|
||||
".npmrc",
|
||||
".profile",
|
||||
".python_history",
|
||||
".sudo_as_admin_successful",
|
||||
".gitattributes",
|
||||
"BRANCH_REGISTRY.json",
|
||||
".branch_meta.json*",
|
||||
"migrations.json*",
|
||||
"sandbox.img"
|
||||
],
|
||||
"notes": {
|
||||
"how_it_works": "Two types of exclusions during backup creation:",
|
||||
"ignore_directories": {
|
||||
"description": "Directory names to skip entirely (including all contents)",
|
||||
"purpose": "Exclude large dependency dirs, caches, and backup dirs themselves",
|
||||
"examples": [
|
||||
".venv, venv (Python virtual environments - large, regeneratable)",
|
||||
"node_modules (NPM dependencies - huge, regeneratable)",
|
||||
"__pycache__, .cache (Python/system caches - regeneratable)",
|
||||
".git (Git repository - already versioned)",
|
||||
".backup, backups (backup directories - prevent recursion)"
|
||||
]
|
||||
},
|
||||
"ignore_patterns": {
|
||||
"description": "Glob patterns for files to skip",
|
||||
"purpose": "Exclude temporary files, compiled bytecode, OS cruft",
|
||||
"examples": [
|
||||
"*.pyc, *.pyo (Python compiled bytecode - regeneratable)",
|
||||
"*.log (Log files - can be large, temporary)",
|
||||
"*.tmp, *.swp (Temporary/swap files)",
|
||||
".DS_Store, Thumbs.db (OS metadata files)"
|
||||
]
|
||||
},
|
||||
"customization": "Edit this file in the template to add more patterns. Changes take effect on next branch update.",
|
||||
"performance": "Ignoring large directories dramatically speeds up backups (seconds vs minutes for branches with node_modules or .venv)"
|
||||
}
|
||||
}
|
||||
@@ -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,301 @@
|
||||
{
|
||||
"metadata": {
|
||||
"version": "1.0.0",
|
||||
"last_updated": "2026-02-20",
|
||||
"description": "Template file tracking registry for ID-based updates"
|
||||
},
|
||||
"files": {
|
||||
"f001": {
|
||||
"current_name": "BRANCH.ID.json",
|
||||
"path": "BRANCH.ID.json",
|
||||
"content_hash": "e9bc2347d373",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f003": {
|
||||
"current_name": "dev.local.md",
|
||||
"path": "dev.local.md",
|
||||
"content_hash": "6c1c5e099790",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f035": {
|
||||
"current_name": ".gitkeep",
|
||||
"path": "ai_mail.local/.archive/.gitkeep",
|
||||
"content_hash": "e3b0c44298fc",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f008": {
|
||||
"current_name": "DASHBOARD.local.json",
|
||||
"path": "DASHBOARD.local.json",
|
||||
"content_hash": "3f0528b4c5d5",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f007": {
|
||||
"current_name": ".migrations.json",
|
||||
"path": ".migrations.json",
|
||||
"content_hash": "4ca241607dc3",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f010": {
|
||||
"current_name": "OBSERVATIONS.json",
|
||||
"path": "OBSERVATIONS.json",
|
||||
"content_hash": "58ea8609fbe0",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f011": {
|
||||
"current_name": "requirements.txt",
|
||||
"path": "requirements.txt",
|
||||
"content_hash": "66dfffc70d53",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f021": {
|
||||
"current_name": "README.md",
|
||||
"path": "README.md",
|
||||
"content_hash": "4e946f67a130",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f012": {
|
||||
"current_name": "LOCAL.json",
|
||||
"path": "LOCAL.json",
|
||||
"content_hash": "459dbe18d40a",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f006": {
|
||||
"current_name": "pytest.ini",
|
||||
"path": "pytest.ini",
|
||||
"content_hash": "7b39ba7bca40",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f022": {
|
||||
"current_name": "_template.md",
|
||||
"path": "docs/_template.md",
|
||||
"content_hash": "79ce97b0e613",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f016": {
|
||||
"current_name": "__init__.py",
|
||||
"path": "tests/__init__.py",
|
||||
"content_hash": "1fcd8126d174",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f019": {
|
||||
"current_name": "conftest.py",
|
||||
"path": "tests/conftest.py",
|
||||
"content_hash": "2887db109a6b",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f004": {
|
||||
"current_name": "BRANCH.py",
|
||||
"path": "apps/BRANCH.py",
|
||||
"content_hash": "44f22cc95232",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f009": {
|
||||
"current_name": "__init__.py",
|
||||
"path": "apps/__init__.py",
|
||||
"content_hash": "5c38204be5fc",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f013": {
|
||||
"current_name": "#@comments.txt.removed_from_template",
|
||||
"path": ".archive/#@comments.txt.removed_from_template",
|
||||
"content_hash": "651126c1e7a9",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f028": {
|
||||
"current_name": "deleted.json.old_template_format",
|
||||
"path": ".archive/deleted.json.old_template_format",
|
||||
"content_hash": "48a3a33dd73a",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f002": {
|
||||
"current_name": "branch_system_prompt.md",
|
||||
"path": ".aipass/branch_system_prompt.md",
|
||||
"content_hash": "897c7beb66f5",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f026": {
|
||||
"current_name": "inbox.json",
|
||||
"path": "ai_mail.local/inbox.json",
|
||||
"content_hash": "c9702fe2cc21",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f027": {
|
||||
"current_name": "sent.json",
|
||||
"path": "ai_mail.local/sent.json",
|
||||
"content_hash": "240132e5a567",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f014": {
|
||||
"current_name": "__init__.py",
|
||||
"path": "apps/handlers/__init__.py",
|
||||
"content_hash": "657d98ad4b98",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f015": {
|
||||
"current_name": "__init__.py",
|
||||
"path": "apps/json_templates/__init__.py",
|
||||
"content_hash": "330b189c08c7",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f020": {
|
||||
"current_name": "__init__.py",
|
||||
"path": "apps/plugins/__init__.py",
|
||||
"content_hash": "39158d26a19c",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f023": {
|
||||
"current_name": "__init__.py",
|
||||
"path": "apps/modules/__init__.py",
|
||||
"content_hash": "bc25a8b75e81",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f024": {
|
||||
"current_name": "__init__.py",
|
||||
"path": "apps/extensions/__init__.py",
|
||||
"content_hash": "6742ceb64ec1",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f032": {
|
||||
"current_name": "data.json",
|
||||
"path": "apps/json_templates/default/data.json",
|
||||
"content_hash": "0531a02be998",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f033": {
|
||||
"current_name": "log.json",
|
||||
"path": "apps/json_templates/default/log.json",
|
||||
"content_hash": "37517e5f3dc6",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f034": {
|
||||
"current_name": "config.json",
|
||||
"path": "apps/json_templates/default/config.json",
|
||||
"content_hash": "3759a05e171d",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f005": {
|
||||
"current_name": "json_handler.py",
|
||||
"path": "apps/handlers/json/json_handler.py",
|
||||
"content_hash": "3449629aff23",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"f017": {
|
||||
"current_name": "__init__.py",
|
||||
"path": "apps/handlers/json/__init__.py",
|
||||
"content_hash": "ad3629e381ca",
|
||||
"has_branch_placeholder": false
|
||||
}
|
||||
},
|
||||
"directories": {
|
||||
"d001": {
|
||||
"current_name": "tools",
|
||||
"path": "tools",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d002": {
|
||||
"current_name": "docs",
|
||||
"path": "docs",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d003": {
|
||||
"current_name": "tests",
|
||||
"path": "tests",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d004": {
|
||||
"current_name": "apps",
|
||||
"path": "apps",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d005": {
|
||||
"current_name": ".archive",
|
||||
"path": ".archive",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d006": {
|
||||
"current_name": "logs",
|
||||
"path": "logs",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d009": {
|
||||
"current_name": ".backup",
|
||||
"path": ".backup",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d008": {
|
||||
"current_name": "{{BRANCH}}_json",
|
||||
"path": "{{BRANCH}}_json",
|
||||
"has_branch_placeholder": true
|
||||
},
|
||||
"d010": {
|
||||
"current_name": "artifacts",
|
||||
"path": "artifacts",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d012": {
|
||||
"current_name": ".aipass",
|
||||
"path": ".aipass",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d011": {
|
||||
"current_name": "ai_mail.local",
|
||||
"path": "ai_mail.local",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d007": {
|
||||
"current_name": "dropbox",
|
||||
"path": "dropbox",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d013": {
|
||||
"current_name": "handlers",
|
||||
"path": "apps/handlers",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d014": {
|
||||
"current_name": "json_templates",
|
||||
"path": "apps/json_templates",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d015": {
|
||||
"current_name": "plugins",
|
||||
"path": "apps/plugins",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d016": {
|
||||
"current_name": "modules",
|
||||
"path": "apps/modules",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d017": {
|
||||
"current_name": "extensions",
|
||||
"path": "apps/extensions",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d018": {
|
||||
"current_name": "sent",
|
||||
"path": "ai_mail.local/sent",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d019": {
|
||||
"current_name": "deleted",
|
||||
"path": "ai_mail.local/deleted",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d020": {
|
||||
"current_name": ".archive",
|
||||
"path": "ai_mail.local/.archive",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d027": {
|
||||
"current_name": "json",
|
||||
"path": "apps/handlers/json",
|
||||
"has_branch_placeholder": false
|
||||
},
|
||||
"d024": {
|
||||
"current_name": "default",
|
||||
"path": "apps/json_templates/default",
|
||||
"has_branch_placeholder": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
# {{BRANCHNAME}} Branch-Local Context
|
||||
<!-- Source: {{CWD}}/.aipass/branch_system_prompt.md -->
|
||||
|
||||
> Auto-created by aipass init. Customize for your branch.
|
||||
|
||||
## Status: NEEDS CONFIGURATION
|
||||
|
||||
This file is injected into every AI conversation when working from this branch directory. Configure it with:
|
||||
|
||||
- Who this branch is (role, purpose)
|
||||
- Key commands and workflows
|
||||
- Architecture overview
|
||||
- Critical files and operational rules
|
||||
- Integration points with other branches
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "session_history",
|
||||
"document_name": "{{BRANCHNAME}}.LOCAL",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "{{DATE}}",
|
||||
"last_updated": "{{DATE}}",
|
||||
"managed_by": "{{BRANCHNAME}}",
|
||||
"tags": ["session_tracking", "work_log", "{{BRANCHNAME}}"],
|
||||
"limits": {
|
||||
"max_lines": 600,
|
||||
"note": "Auto-rollover when max_lines exceeded"
|
||||
},
|
||||
"status": {
|
||||
"health": "healthy",
|
||||
"current_lines": 0,
|
||||
"last_health_check": "{{DATE}}"
|
||||
}
|
||||
},
|
||||
"active_tasks": {
|
||||
"today_focus": "{{DATE}}",
|
||||
"recently_completed": []
|
||||
},
|
||||
"key_learnings": {},
|
||||
"sessions": [
|
||||
{
|
||||
"session_number": 1,
|
||||
"date": "{{DATE}}",
|
||||
"summary": "Branch initialized - {{BRANCHNAME}} created by aipass init",
|
||||
"status": "completed"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"document_metadata": {
|
||||
"document_type": "collaboration_patterns",
|
||||
"document_name": "{{BRANCHNAME}}.OBSERVATIONS",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "{{DATE}}",
|
||||
"last_updated": "{{DATE}}",
|
||||
"managed_by": "{{BRANCHNAME}}",
|
||||
"tags": ["collaboration", "patterns", "{{BRANCHNAME}}"],
|
||||
"limits": {
|
||||
"max_lines": 600,
|
||||
"note": "Auto-rollover when max_lines exceeded"
|
||||
},
|
||||
"status": {
|
||||
"health": "healthy",
|
||||
"current_lines": 0,
|
||||
"last_health_check": "{{DATE}}"
|
||||
}
|
||||
},
|
||||
"guidelines": {
|
||||
"purpose": "Capture collaboration patterns and experiential insights over time",
|
||||
"chronological_order": "Newest entries at TOP, oldest at BOTTOM - NEVER reorder"
|
||||
},
|
||||
"observations": [
|
||||
{
|
||||
"date": "{{DATE}}",
|
||||
"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": "{{BRANCHNAME}}.PASSPORT",
|
||||
"version": "1.0.0",
|
||||
"schema_version": "1.0.0",
|
||||
"created": "{{DATE}}",
|
||||
"last_updated": "{{DATE}}",
|
||||
"managed_by": "{{BRANCHNAME}}",
|
||||
"tags": ["identity", "passport", "branch_profile"]
|
||||
},
|
||||
"branch_info": {
|
||||
"branch_name": "{{BRANCHNAME}}",
|
||||
"alias": "",
|
||||
"path": "{{CWD}}",
|
||||
"module": "{{MODULE}}",
|
||||
"created": "{{DATE}}"
|
||||
},
|
||||
"identity": {
|
||||
"role": "{{ROLE}}",
|
||||
"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,91 @@
|
||||
{
|
||||
"_warning": "AUTO-GENERATED FILE - DO NOT MANUALLY EDIT. This file is 100% automated and will be overwritten. Services update their own sections.",
|
||||
"branch": "CORTEX",
|
||||
"last_updated": "2026-03-04T02:09:48.112262",
|
||||
"quick_status": {
|
||||
"new_mail": 0,
|
||||
"opened_mail": 0,
|
||||
"active_plans": 0,
|
||||
"commons_mentions": 13,
|
||||
"action_required": true,
|
||||
"summary": "13 mentions"
|
||||
},
|
||||
"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-04T02:09:48.112249"
|
||||
},
|
||||
"flow": {
|
||||
"managed_by": "flow",
|
||||
"active_plans": 0,
|
||||
"recently_closed": [
|
||||
{
|
||||
"plan_id": "FPLAN-0338",
|
||||
"subject": "Race condition fix test B"
|
||||
},
|
||||
{
|
||||
"plan_id": "FPLAN-0337",
|
||||
"subject": "Race condition fix test A"
|
||||
},
|
||||
{
|
||||
"plan_id": "FPLAN-0336",
|
||||
"subject": "Real content drone test"
|
||||
},
|
||||
{
|
||||
"plan_id": "FPLAN-0333",
|
||||
"subject": "Close workflow v3.2 test"
|
||||
},
|
||||
{
|
||||
"plan_id": "FPLAN-0332",
|
||||
"subject": "Close workflow test - real content"
|
||||
}
|
||||
],
|
||||
"last_updated": "2026-02-25T21:04:01.461440"
|
||||
},
|
||||
"memory_bank": {
|
||||
"managed_by": "memory_bank",
|
||||
"vectors_stored": 27,
|
||||
"notes": {},
|
||||
"last_updated": "2026-02-25T16:52:38.749241"
|
||||
},
|
||||
"devpulse": {
|
||||
"managed_by": "devpulse",
|
||||
"summary": {
|
||||
"issues": 1,
|
||||
"todos": 0
|
||||
},
|
||||
"dplan_counts": {
|
||||
"total": 35,
|
||||
"by_status": {
|
||||
"complete": 11,
|
||||
"planning": 19,
|
||||
"in_progress": 4,
|
||||
"ready": 1
|
||||
}
|
||||
},
|
||||
"recent_activity": "Registry synced (35 plans)",
|
||||
"last_updated": "2026-02-25T17:31:52.500742"
|
||||
},
|
||||
"commons_activity": {
|
||||
"managed_by": "the_commons",
|
||||
"new_posts_since_last_visit": 46,
|
||||
"new_comments_since_last_visit": 303,
|
||||
"mentions": 13,
|
||||
"trending": "None",
|
||||
"last_checked": "2026-03-04T04:30:20Z",
|
||||
"last_updated": "2026-03-03T20:30:20.172727"
|
||||
},
|
||||
"agent_status": {
|
||||
"managed_by": "prax",
|
||||
"active_agents": [],
|
||||
"agent_count": 0,
|
||||
"stale_agents": [],
|
||||
"last_updated": "2026-02-25T21:00:30.714949"
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": 7,
|
||||
"name": "CORTEX Birth Certificate",
|
||||
"type": "birth_certificate",
|
||||
"creator": "SYSTEM",
|
||||
"owner": "CORTEX",
|
||||
"rarity": "unique",
|
||||
"description": "Official birth certificate for CORTEX. Citizen #7, registered using 'AIPass Workshop' template. Purpose: New branch - purpose TBD",
|
||||
"metadata": {
|
||||
"citizen_number": 7,
|
||||
"template": "AIPass Workshop",
|
||||
"purpose": "New branch - purpose TBD"
|
||||
},
|
||||
"created_at": "2026-02-19T03:46:41Z"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
# flow.local.md - {{BRANCHNAME}}
|
||||
```
|
||||
Branch: {{CWD}}
|
||||
Created: {{DATE}}
|
||||
```
|
||||
|
||||
## Issues
|
||||
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
## Todos
|
||||
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
## Notepad
|
||||
|
||||
-
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user