2026-02-09 15:49:50 +05:30
|
|
|
"""CLI script to sync template files into gateway agent workspaces."""
|
|
|
|
|
|
2026-02-07 04:24:06 +05:30
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import argparse
|
|
|
|
|
import asyncio
|
2026-02-07 16:21:21 +05:30
|
|
|
import sys
|
|
|
|
|
from pathlib import Path
|
2026-02-07 04:24:06 +05:30
|
|
|
from uuid import UUID
|
|
|
|
|
|
2026-02-07 16:21:21 +05:30
|
|
|
BACKEND_ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
sys.path.insert(0, str(BACKEND_ROOT))
|
|
|
|
|
|
2026-02-07 04:24:06 +05:30
|
|
|
|
|
|
|
|
def _parse_args() -> argparse.Namespace:
|
|
|
|
|
parser = argparse.ArgumentParser(
|
2026-02-09 15:49:50 +05:30
|
|
|
description="Sync templates/ to existing OpenClaw gateway agent workspaces.",
|
2026-02-07 04:24:06 +05:30
|
|
|
)
|
|
|
|
|
parser.add_argument("--gateway-id", type=str, required=True, help="Gateway UUID")
|
2026-02-09 15:49:50 +05:30
|
|
|
parser.add_argument(
|
|
|
|
|
"--board-id",
|
|
|
|
|
type=str,
|
|
|
|
|
default=None,
|
|
|
|
|
help="Optional Board UUID filter",
|
|
|
|
|
)
|
2026-02-07 04:24:06 +05:30
|
|
|
parser.add_argument(
|
|
|
|
|
"--include-main",
|
|
|
|
|
action=argparse.BooleanOptionalAction,
|
|
|
|
|
default=True,
|
|
|
|
|
help="Also sync the gateway main agent (default: true)",
|
|
|
|
|
)
|
|
|
|
|
parser.add_argument(
|
|
|
|
|
"--reset-sessions",
|
|
|
|
|
action="store_true",
|
2026-02-09 15:49:50 +05:30
|
|
|
help=(
|
|
|
|
|
"Reset agent sessions after syncing files "
|
|
|
|
|
"(forces agents to re-read workspace)"
|
|
|
|
|
),
|
2026-02-07 04:24:06 +05:30
|
|
|
)
|
|
|
|
|
parser.add_argument(
|
|
|
|
|
"--rotate-tokens",
|
|
|
|
|
action="store_true",
|
2026-02-09 15:49:50 +05:30
|
|
|
help=(
|
|
|
|
|
"Rotate agent tokens when TOOLS.md is missing/unreadable "
|
|
|
|
|
"or token drift is detected"
|
|
|
|
|
),
|
2026-02-07 04:24:06 +05:30
|
|
|
)
|
|
|
|
|
parser.add_argument(
|
|
|
|
|
"--force-bootstrap",
|
|
|
|
|
action="store_true",
|
|
|
|
|
help="Force BOOTSTRAP.md to be provisioned during sync",
|
|
|
|
|
)
|
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def _run() -> int:
|
2026-02-09 17:24:21 +05:30
|
|
|
from app.db.session import async_session_maker
|
|
|
|
|
from app.models.gateways import Gateway
|
|
|
|
|
from app.services.template_sync import (
|
|
|
|
|
GatewayTemplateSyncOptions,
|
|
|
|
|
sync_gateway_templates,
|
|
|
|
|
)
|
|
|
|
|
|
2026-02-07 04:24:06 +05:30
|
|
|
args = _parse_args()
|
|
|
|
|
gateway_id = UUID(args.gateway_id)
|
|
|
|
|
board_id = UUID(args.board_id) if args.board_id else None
|
|
|
|
|
|
|
|
|
|
async with async_session_maker() as session:
|
|
|
|
|
gateway = await session.get(Gateway, gateway_id)
|
|
|
|
|
if gateway is None:
|
2026-02-09 15:49:50 +05:30
|
|
|
message = f"Gateway not found: {gateway_id}"
|
|
|
|
|
raise SystemExit(message)
|
2026-02-07 04:24:06 +05:30
|
|
|
|
|
|
|
|
result = await sync_gateway_templates(
|
|
|
|
|
session,
|
|
|
|
|
gateway,
|
2026-02-09 17:24:21 +05:30
|
|
|
options=GatewayTemplateSyncOptions(
|
|
|
|
|
user=None,
|
|
|
|
|
include_main=bool(args.include_main),
|
|
|
|
|
reset_sessions=bool(args.reset_sessions),
|
|
|
|
|
rotate_tokens=bool(args.rotate_tokens),
|
|
|
|
|
force_bootstrap=bool(args.force_bootstrap),
|
|
|
|
|
board_id=board_id,
|
|
|
|
|
),
|
2026-02-07 04:24:06 +05:30
|
|
|
)
|
|
|
|
|
|
2026-02-09 15:49:50 +05:30
|
|
|
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",
|
2026-02-07 04:24:06 +05:30
|
|
|
)
|
|
|
|
|
if result.errors:
|
2026-02-09 15:49:50 +05:30
|
|
|
sys.stdout.write("errors:\n")
|
2026-02-07 04:24:06 +05:30
|
|
|
for err in result.errors:
|
|
|
|
|
agent = f"{err.agent_name} ({err.agent_id})" if err.agent_id else "n/a"
|
2026-02-09 15:49:50 +05:30
|
|
|
sys.stdout.write(
|
|
|
|
|
f"- agent={agent} board_id={err.board_id} message={err.message}\n",
|
|
|
|
|
)
|
2026-02-07 04:24:06 +05:30
|
|
|
return 1
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main() -> None:
|
2026-02-09 15:49:50 +05:30
|
|
|
"""Run the async CLI workflow and exit with its return code."""
|
2026-02-07 04:24:06 +05:30
|
|
|
raise SystemExit(asyncio.run(_run()))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
main()
|