Files
openclaw-mission-control/backend/scripts/sync_gateway_templates.py

133 lines
4.2 KiB
Python

"""CLI script to sync template files into gateway agent workspaces."""
from __future__ import annotations
import argparse
import asyncio
import sys
from pathlib import Path
from uuid import UUID
BACKEND_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(BACKEND_ROOT))
def _parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Sync templates/ to existing OpenClaw gateway agent workspaces.",
)
parser.add_argument("--gateway-id", type=str, required=True, help="Gateway UUID")
parser.add_argument(
"--board-id",
type=str,
default=None,
help="Optional Board UUID filter",
)
parser.add_argument(
"--user-id",
type=str,
default=None,
help="Optional User UUID for USER.md rendering context",
)
parser.add_argument(
"--include-main",
action=argparse.BooleanOptionalAction,
default=True,
help="Also sync the gateway main agent (default: true)",
)
parser.add_argument(
"--lead-only",
action="store_true",
help="Sync only board lead agents",
)
parser.add_argument(
"--reset-sessions",
action="store_true",
help=("Reset agent sessions after syncing files " "(forces agents to re-read workspace)"),
)
parser.add_argument(
"--rotate-tokens",
action="store_true",
help=(
"Rotate agent tokens when TOOLS.md is missing/unreadable " "or token drift is detected"
),
)
parser.add_argument(
"--force-bootstrap",
action="store_true",
help="Force BOOTSTRAP.md to be rendered during update sync",
)
parser.add_argument(
"--overwrite",
action="store_true",
help="Overwrite editable files (e.g. USER.md, MEMORY.md) during update sync",
)
return parser.parse_args()
async def _run() -> int:
from app.db.session import async_session_maker
from app.models.gateways import Gateway
from app.models.users import User
from app.services.openclaw.provisioning_db import (
GatewayTemplateSyncOptions,
OpenClawProvisioningService,
)
args = _parse_args()
gateway_id = UUID(args.gateway_id)
board_id = UUID(args.board_id) if args.board_id else None
user_id = UUID(args.user_id) if args.user_id else None
async with async_session_maker() as session:
gateway = await session.get(Gateway, gateway_id)
if gateway is None:
message = f"Gateway not found: {gateway_id}"
raise SystemExit(message)
template_user = await session.get(User, user_id) if user_id else None
if user_id and template_user is None:
message = f"User not found: {user_id}"
raise SystemExit(message)
result = await OpenClawProvisioningService(session).sync_gateway_templates(
gateway,
GatewayTemplateSyncOptions(
user=template_user,
include_main=bool(args.include_main),
lead_only=bool(args.lead_only),
reset_sessions=bool(args.reset_sessions),
rotate_tokens=bool(args.rotate_tokens),
force_bootstrap=bool(args.force_bootstrap),
overwrite=bool(args.overwrite),
board_id=board_id,
),
)
sys.stdout.write(f"gateway_id={result.gateway_id}\n")
sys.stdout.write(
f"include_main={result.include_main} " f"reset_sessions={result.reset_sessions}\n",
)
sys.stdout.write(
f"agents_updated={result.agents_updated} "
f"agents_skipped={result.agents_skipped} "
f"main_updated={result.main_updated}\n",
)
if result.errors:
sys.stdout.write("errors:\n")
for err in result.errors:
agent = f"{err.agent_name} ({err.agent_id})" if err.agent_id else "n/a"
sys.stdout.write(
f"- agent={agent} board_id={err.board_id} message={err.message}\n",
)
return 1
return 0
def main() -> None:
"""Run the async CLI workflow and exit with its return code."""
raise SystemExit(asyncio.run(_run()))
if __name__ == "__main__":
main()