""" Knowledge loader for the markitect helper. Reads markitect's own documentation files and returns them as a concatenated string for use as LLM context. """ import importlib from pathlib import Path from typing import List # Docs to load relative to the project root, in priority order. _DOC_PATHS: List[str] = [ "INTRODUCTION.md", "docs/CLI_TUTORIAL.md", "docs/PROJECT_STRUCTURE.md", "docs/SCHEMA_MANAGEMENT_GUIDE.md", "docs/PLUGIN_SYSTEM.md", "docs/ERROR_HANDLING_STRATEGY.md", "docs/architecture/CAPABILITIES_ARCHITECTURE.md", "docs/architecture/caching-system.md", "docs/ASSET_MANAGEMENT_USER_GUIDE.md", "docs/graphql_interface.md", "examples/content-generator/TUTORIAL.md", "examples/infospace-with-history/TUTORIAL.md", ] # Glob patterns (relative to project root) for additional docs. _DOC_GLOBS: List[str] = [ "docs/user-guides/*.md", ] # Modules whose docstrings to include. _MODULE_DOCSTRINGS: List[str] = [ "markitect.prompts", "markitect.llm", ] def _find_project_root() -> Path: """Return the markitect project root directory. Walks up from this file (markitect/helper/knowledge.py) to find the directory that contains ``markitect/`` as a package *and* has a ``pyproject.toml`` or ``INTRODUCTION.md``. """ candidate = Path(__file__).resolve().parent.parent.parent # Verify we landed in the right place. if (candidate / "pyproject.toml").exists() or (candidate / "INTRODUCTION.md").exists(): return candidate # Fallback: try CWD. cwd = Path.cwd() if (cwd / "markitect").is_dir(): return cwd return candidate def collect_knowledge() -> str: """Load markitect documentation and return as a single string. Reads documentation files from the project root, concatenates them with section headers, and appends relevant module docstrings. Missing files are silently skipped. """ root = _find_project_root() sections: List[str] = [] # Fixed-path documents. for rel_path in _DOC_PATHS: filepath = root / rel_path if filepath.is_file(): try: content = filepath.read_text(encoding="utf-8") sections.append(f"## {rel_path}\n\n{content}") except OSError: continue # Glob-pattern documents. for pattern in _DOC_GLOBS: for filepath in sorted(root.glob(pattern)): if filepath.is_file(): rel = filepath.relative_to(root) try: content = filepath.read_text(encoding="utf-8") sections.append(f"## {rel}\n\n{content}") except OSError: continue # Module docstrings. for mod_name in _MODULE_DOCSTRINGS: try: mod = importlib.import_module(mod_name) if mod.__doc__: sections.append(f"## Module: {mod_name}\n\n{mod.__doc__.strip()}") except ImportError: continue return "\n\n---\n\n".join(sections)