Files
variet-agent/core/docs_manager.py

141 lines
4.9 KiB
Python

"""Docs Manager — 작업 기록 + Wiki 문서 관리.
모든 작업은 docs/에 기록되며, Gemini 호출 시
문서 경로와 기존 문서 목록을 프롬프트에 주입합니다.
"""
import logging
from datetime import datetime
from pathlib import Path
logger = logging.getLogger("variet.docs")
class DocsManager:
"""프로젝트 문서 관리자."""
def __init__(self, project_path: str, docs_subpath: str = "docs/wiki"):
self.project_path = Path(project_path)
self.docs_path = self.project_path / docs_subpath
self.sessions_path = self.project_path / "docs" / "sessions"
self.changelog_path = self.project_path / "docs" / "changelog.md"
# 디렉토리 생성
self.docs_path.mkdir(parents=True, exist_ok=True)
self.sessions_path.mkdir(parents=True, exist_ok=True)
def get_docs_index(self) -> str:
"""docs/wiki 내 문서 목록을 문자열로 반환 (프롬프트 주입용)."""
if not self.docs_path.exists():
return "문서 없음"
files = sorted(self.docs_path.glob("*.md"))
if not files:
return "문서 없음"
lines = ["=== PROJECT DOCS ==="]
for f in files:
size = f.stat().st_size
lines.append(f" - {f.name} ({size}B)")
lines.append(f"경로: {self.docs_path}")
lines.append("=== END DOCS ===")
return "\n".join(lines)
def get_doc_content(self, filename: str) -> str:
"""특정 문서 내용 반환."""
path = self.docs_path / filename
if path.exists():
return path.read_text(encoding="utf-8", errors="ignore")
return ""
def get_all_docs_content(self, max_total_bytes: int = 30000) -> str:
"""전체 문서 내용 반환 (예산 내에서)."""
files = sorted(self.docs_path.glob("*.md"))
parts = ["=== PROJECT KNOWLEDGE BASE ===\n"]
total = 0
for f in files:
content = f.read_text(encoding="utf-8", errors="ignore")
if total + len(content.encode("utf-8")) > max_total_bytes:
parts.append(f"\n--- {f.name} (예산 초과, 생략) ---")
continue
parts.append(f"\n--- {f.name} ---\n{content}")
total += len(content.encode("utf-8"))
parts.append("\n=== END KNOWLEDGE BASE ===")
return "\n".join(parts)
def record_session(self, request: str, summary: dict, plan: dict = None) -> str:
"""작업 세션을 기록."""
try:
self.sessions_path.mkdir(parents=True, exist_ok=True)
now = datetime.now()
filename = f"{now.strftime('%Y-%m-%d_%H%M%S')}.md"
filepath = self.sessions_path / filename
lines = [
f"# 작업 기록 - {now.strftime('%Y-%m-%d %H:%M')}",
"",
f"## 요청",
f"{request}",
"",
]
if plan:
lines.extend([
f"## 계획",
f"{plan.get('summary', str(plan)[:300])}",
"",
])
if isinstance(summary, dict):
lines.extend([
f"## 결과",
f"{summary.get('summary', str(summary)[:300])}",
"",
])
changes = summary.get("changes", [])
if changes:
lines.append("## 변경 파일")
for c in changes:
if isinstance(c, dict):
lines.append(f"- `{c.get('file', '?')}` - {c.get('description', '')}")
else:
lines.append(f"- {c}")
lines.append("")
warnings = summary.get("warnings", [])
if warnings:
lines.append("## 주의사항")
for w in warnings:
lines.append(f"- {w}")
lines.append("")
filepath.write_text("\n".join(lines), encoding="utf-8")
logger.info(f"세션 기록: {filepath}")
return str(filepath)
except Exception as e:
logger.warning(f"세션 기록 실패 (무시): {e}")
return ""
def append_changelog(self, entry: str):
"""Changelog에 항목 추가."""
now = datetime.now().strftime("%Y-%m-%d %H:%M")
line = f"\n- [{now}] {entry}"
if self.changelog_path.exists():
content = self.changelog_path.read_text(encoding="utf-8")
else:
content = "# Changelog\n"
content += line
self.changelog_path.write_text(content, encoding="utf-8")
def update_wiki(self, filename: str, content: str):
"""Wiki 문서 생성/수정."""
path = self.docs_path / filename
path.write_text(content, encoding="utf-8")
logger.info(f"Wiki 업데이트: {path}")