From 27d55f91d1de80f82bcbd1997f5031fc52ad1971 Mon Sep 17 00:00:00 2001 From: AIOSAI Date: Sun, 26 Apr 2026 10:48:36 -0700 Subject: [PATCH] =?UTF-8?q?feat(system):=20DPLAN-0154:=20dedicated=20agent?= =?UTF-8?q?=20branches=20=E2=80=94=20passport=20git=5Fbranch=20field=20+?= =?UTF-8?q?=20drone=20routing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: @devpulse --- README.md | 7 ++++--- .../drone/apps/handlers/git/pr_handler.py | 16 +++++++++++++++- .../apps/plugins/devpulse_ops/pr_plugin.py | 19 ++++++++++++++++++- .../birthright/.trinity/passport.json | 3 ++- .../templates/builder/.trinity/passport.json | 3 ++- 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8dd0db63..2ee01893 100644 --- a/README.md +++ b/README.md @@ -229,9 +229,10 @@ setup.sh auto-detects which CLIs are installed and configures hooks for each. | Version | 2.1.0 | | Agents | 11 | | Quality standards | 33 automated checks | -| Tests | 3,500+ (across all agents) | -| PRs merged | 260+ (created by agents, reviewed by human) | -| External projects | Full cross-project access (Vera Studio) | +| Tests | 6,500+ (across all agents) | +| PRs merged | 470+ (created by agents, reviewed by human) | +| Code coverage | 75% ([codecov](https://codecov.io/gh/AIOSAI/AIPass)) | +| CI | Green (0 failures) | Each agent documents its own operational status in its branch README — what works, what doesn't, and why. diff --git a/src/aipass/drone/apps/handlers/git/pr_handler.py b/src/aipass/drone/apps/handlers/git/pr_handler.py index 9d7ad61d..f5b7d058 100644 --- a/src/aipass/drone/apps/handlers/git/pr_handler.py +++ b/src/aipass/drone/apps/handlers/git/pr_handler.py @@ -29,6 +29,20 @@ from aipass.drone.apps.handlers.git.lock_handler import ( ) +def _resolve_git_branch(branch_name: str, branch_dir: Path) -> str: + """Read git_branch from passport if available, else fall back to citizen/{name}.""" + passport_path = branch_dir / ".trinity" / "passport.json" + if passport_path.is_file(): + try: + data = _json.loads(passport_path.read_text()) + git_branch = data.get("branch_info", {}).get("git_branch", "") + if git_branch: + return git_branch + except (ValueError, OSError) as exc: + logger.warning("Failed to read git_branch from passport %s: %s", passport_path, exc) + return f"citizen/{branch_name}" + + def create_pr(branch_name: str, description: str, branch_dir: Path) -> dict: """Execute the full PR creation workflow. @@ -57,7 +71,7 @@ def create_pr(branch_name: str, description: str, branch_dir: Path) -> dict: Dict with success, pr_url, feature_branch, and message. """ repo_root = find_repo_root() - feature_branch = f"citizen/{branch_name}" + feature_branch = _resolve_git_branch(branch_name, branch_dir) lock_acquired = False result = { diff --git a/src/aipass/drone/apps/plugins/devpulse_ops/pr_plugin.py b/src/aipass/drone/apps/plugins/devpulse_ops/pr_plugin.py index 80ef34be..2a590c66 100644 --- a/src/aipass/drone/apps/plugins/devpulse_ops/pr_plugin.py +++ b/src/aipass/drone/apps/plugins/devpulse_ops/pr_plugin.py @@ -20,8 +20,10 @@ Only authorized callers (verified via :mod:`auth`) may invoke this. from __future__ import annotations +import json as _json import re import subprocess +from pathlib import Path from aipass.prax import logger from aipass.drone.apps.handlers.json import json_handler @@ -52,6 +54,20 @@ def slugify(description: str) -> str: return slug[:50] +def _resolve_system_git_branch(caller: str, repo_root: Path) -> str: + """Read git_branch from the caller's passport, else fall back to system/{caller}-{slug}.""" + for trinity_dir in repo_root.rglob(f"src/aipass/{caller}/.trinity/passport.json"): + try: + data = _json.loads(trinity_dir.read_text()) + git_branch = data.get("branch_info", {}).get("git_branch", "") + if git_branch: + return git_branch + except (ValueError, OSError) as exc: + logger.warning("Failed to read git_branch from %s: %s", trinity_dir, exc) + break + return "" + + def create_system_pr(description: str, caller: str) -> dict: """Execute the system-wide PR creation workflow. @@ -72,7 +88,8 @@ def create_system_pr(description: str, caller: str) -> dict: """ repo_root = find_repo_root() slug = slugify(description) - feature_branch = f"system/{caller}-{slug}" + passport_branch = _resolve_system_git_branch(caller, repo_root) + feature_branch = passport_branch if passport_branch else f"system/{caller}-{slug}" lock_acquired = False result: dict = { diff --git a/src/aipass/spawn/templates/birthright/.trinity/passport.json b/src/aipass/spawn/templates/birthright/.trinity/passport.json index a54ee676..5e9955de 100644 --- a/src/aipass/spawn/templates/birthright/.trinity/passport.json +++ b/src/aipass/spawn/templates/birthright/.trinity/passport.json @@ -14,7 +14,8 @@ "alias": "", "path": "{{CWD}}", "module": "{{MODULE}}", - "created": "{{DATE}}" + "created": "{{DATE}}", + "git_branch": "work/{{branchname}}" }, "identity": { "citizen_class": "birthright", diff --git a/src/aipass/spawn/templates/builder/.trinity/passport.json b/src/aipass/spawn/templates/builder/.trinity/passport.json index 049ec7d2..128be9f3 100644 --- a/src/aipass/spawn/templates/builder/.trinity/passport.json +++ b/src/aipass/spawn/templates/builder/.trinity/passport.json @@ -14,7 +14,8 @@ "alias": "", "path": "{{CWD}}", "module": "{{MODULE}}", - "created": "{{DATE}}" + "created": "{{DATE}}", + "git_branch": "work/{{branchname}}" }, "identity": { "citizen_class": "builder",