"""Wiki.js Debate Tool — AG용 Wiki.js 읽기/쓰기 CLI. 사용법: python tools/wiki_debate.py read python tools/wiki_debate.py write python tools/wiki_debate.py write-file 예시: python tools/wiki_debate.py read debates/frtb/input-gemini python tools/wiki_debate.py write debates/frtb/response-gemini "SA 방식을 제안합니다..." python tools/wiki_debate.py write-file debates/frtb/response-gemini response_draft.md """ import asyncio import httpx import io import os import sys from pathlib import Path # .env 로드 (여러 후보 경로에서 탐색) _candidates = [ Path(__file__).parent.parent / ".env", # tools/../.env (배포 위치) Path.cwd() / ".env", # CWD/.env Path.cwd().parent / ".env", # CWD/../.env ] for _env_path in _candidates: if _env_path.exists(): for line in _env_path.read_text(encoding="utf-8").splitlines(): line = line.strip() if not line or line.startswith("#"): continue if "=" in line: key, _, value = line.partition("=") value = value.strip() if len(value) >= 2 and value[0] == value[-1] and value[0] in ('"', "'"): value = value[1:-1] os.environ.setdefault(key.strip(), value) break # 첫 번째 .env만 사용 WIKI_URL = os.getenv("WIKI_URL", "https://wiki.variet.net") WIKI_API_KEY = os.getenv("WIKI_API_KEY", "") GRAPHQL_ENDPOINT = f"{WIKI_URL}/graphql" async def _query(query: str, variables: dict = None) -> dict: """GraphQL 쿼리 실행.""" headers = { "Authorization": f"Bearer {WIKI_API_KEY}", "Content-Type": "application/json", } payload = {"query": query} if variables: payload["variables"] = variables async with httpx.AsyncClient(timeout=15.0) as client: resp = await client.post(GRAPHQL_ENDPOINT, json=payload, headers=headers) resp.raise_for_status() data = resp.json() if "errors" in data and data["errors"]: raise RuntimeError(f"Wiki.js 오류: {data['errors'][0].get('message', data['errors'])}") return data.get("data", {}) async def read_page(path: str) -> str: """경로로 페이지 읽기 (singleByPath).""" query = """ query ($path: String!) { pages { singleByPath(path: $path, locale: "ko") { id, path, title, content }} } """ data = await _query(query, {"path": path}) page = data.get("pages", {}).get("singleByPath") if not page: return f"[오류] 페이지를 찾을 수 없습니다: {path}" return page.get("content", "") async def write_page(path: str, content: str) -> str: """경로에 페이지 쓰기 (upsert).""" # 기존 페이지 확인 find_query = """ query ($path: String!) { pages { singleByPath(path: $path, locale: "ko") { id, tags { tag } }} } """ data = await _query(find_query, {"path": path}) existing = data.get("pages", {}).get("singleByPath") if existing: # 수정 tags = [t["tag"] for t in existing.get("tags", [])] update_query = """ mutation ($id: Int!, $content: String!, $tags: [String!]) { pages { update(id: $id, content: $content, tags: $tags) { responseResult { succeeded, message } }} } """ result = await _query(update_query, { "id": existing["id"], "content": content, "tags": tags, }) ok = result["pages"]["update"]["responseResult"]["succeeded"] msg = result["pages"]["update"]["responseResult"]["message"] return f"✅ 수정 완료 (id: {existing['id']})" if ok else f"❌ 수정 실패: {msg}" else: # 생성 title = path.split("/")[-1].replace("-", " ").title() create_query = """ mutation ($content: String!, $path: String!, $title: String!, $description: String!, $tags: [String!]!) { pages { create( content: $content, description: $description, editor: "markdown", isPublished: true, isPrivate: false, locale: "ko", path: $path, tags: $tags, title: $title ) { responseResult { succeeded, message } page { id } }} } """ result = await _query(create_query, { "content": content, "path": path, "title": title, "description": title, "tags": ["debate"], }) ok = result["pages"]["create"]["responseResult"]["succeeded"] if ok: pid = result["pages"]["create"]["page"]["id"] return f"✅ 생성 완료 (id: {pid})" return f"❌ 생성 실패: {result['pages']['create']['responseResult']['message']}" async def main(): if sys.stdout.encoding != "utf-8": sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace") args = sys.argv[1:] if len(args) < 2: print(__doc__) return cmd, path = args[0], args[1] if cmd == "read": content = await read_page(path) print(content) elif cmd == "write" and len(args) > 2: content = " ".join(args[2:]) result = await write_page(path, content) print(result) elif cmd == "write-file" and len(args) > 2: file_path = Path(args[2]) if not file_path.exists(): print(f"❌ 파일을 찾을 수 없습니다: {file_path}") return content = file_path.read_text(encoding="utf-8") result = await write_page(path, content) print(result) else: print(__doc__) if __name__ == "__main__": asyncio.run(main())