Updated repo onboarding

This commit is contained in:
2026-05-04 19:18:10 +02:00
parent 5429340f21
commit 47f6971c56
4 changed files with 213 additions and 12 deletions

View File

@@ -1,5 +1,7 @@
import asyncio
import json
import os
import re
import socket
import subprocess
import sys
@@ -34,6 +36,8 @@ from api.schemas.managed_repo import (
PendingInterfaceChange,
RepoCreate,
RepoDispatch,
RepoOnboardRequest,
RepoOnboardResult,
RepoPathRegister,
RepoRead,
RepoScopeHealth,
@@ -90,6 +94,77 @@ async def register_repo(
return repo
@router.post("/onboard", response_model=RepoOnboardResult)
async def onboard_repo(body: RepoOnboardRequest) -> RepoOnboardResult:
"""Run the local repo onboarding script for an accessible working copy.
The dashboard uses this for the "Add Repo" action. The path must be visible
from the State Hub host, either as a local checkout or through an ops-bridge
mounted/exposed working copy. Keep the API agent-profile based so future
native coding agents can gain their own profiles without changing callers.
"""
project_path = Path(body.project_path).expanduser()
if not project_path.exists() or not project_path.is_dir():
raise HTTPException(
status_code=400,
detail=f"project_path is not an accessible directory: {body.project_path}",
)
if not (project_path / ".git").exists():
raise HTTPException(
status_code=400,
detail=f"project_path does not look like a git working copy: {body.project_path}",
)
script = Path(__file__).parent.parent.parent / "scripts" / "register_project.sh"
cmd = ["bash", str(script), body.domain_slug, str(project_path)]
if body.agent_profile == "codex":
cmd.append("--codex")
if body.additional:
cmd.append("--additional")
env = {
**os.environ,
"API_BASE": settings.api_base,
"CUSTODIAN_SKIP_SBOM_PROMPT": "true",
}
result = await asyncio.to_thread(
subprocess.run,
cmd,
cwd=str(script.parent.parent),
env=env,
stdin=subprocess.DEVNULL,
capture_output=True,
text=True,
timeout=180,
)
stdout = result.stdout or ""
stderr = result.stderr or ""
if result.returncode != 0:
raise HTTPException(
status_code=500,
detail={
"message": "Repo onboarding failed.",
"command": cmd,
"stdout": stdout,
"stderr": stderr,
},
)
repo_slug = None
match = re.search(r"Repo slug:\s+([a-z0-9][a-z0-9-]*)", stdout)
if match:
repo_slug = match.group(1)
return RepoOnboardResult(
ok=True,
repo_slug=repo_slug,
agent_profile=body.agent_profile,
command=cmd,
stdout=stdout,
stderr=stderr,
)
@router.get("/by-fingerprint", response_model=list[RepoRead])
async def get_repo_by_fingerprint(
hash: str,

View File

@@ -1,6 +1,6 @@
import uuid
from datetime import date, datetime
from typing import Any
from typing import Any, Literal
from pydantic import BaseModel, ConfigDict, Field
@@ -32,6 +32,23 @@ class RepoPathRegister(BaseModel):
path: str
class RepoOnboardRequest(BaseModel):
"""Start scripted onboarding for a working copy that is visible to State Hub."""
domain_slug: str
project_path: str
agent_profile: Literal["claude-code", "codex"] = "codex"
additional: bool = False
class RepoOnboardResult(BaseModel):
ok: bool
repo_slug: str | None = None
agent_profile: str
command: list[str]
stdout: str = ""
stderr: str = ""
class RepoRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID