diff --git a/aggregate.py b/aggregate.py index 4da1133..6473875 100644 --- a/aggregate.py +++ b/aggregate.py @@ -64,9 +64,14 @@ def build_discussion_section(history: list[str]) -> str: sections.append(f"### Discussion Excerpt {i}\n\n{paste.strip()}") return "\n\n---\n\n".join(sections) -def build_files_section(base_dir: Path, files: list[str]) -> str: +def build_files_section(base_dir: Path, files: list[str | dict]) -> str: sections = [] - for entry in files: + for entry_raw in files: + if isinstance(entry_raw, dict): + entry = entry_raw.get("path") + else: + entry = entry_raw + paths = resolve_paths(base_dir, entry) if not paths: sections.append(f"### `{entry}`\n\n```text\nERROR: no files matched: {entry}\n```") @@ -100,7 +105,7 @@ def build_screenshots_section(base_dir: Path, screenshots: list[str]) -> str: return "\n\n---\n\n".join(sections) -def build_file_items(base_dir: Path, files: list[str]) -> list[dict]: +def build_file_items(base_dir: Path, files: list[str | dict]) -> list[dict]: """ Return a list of dicts describing each file, for use by ai_client when it wants to upload individual files rather than inline everything as markdown. @@ -111,12 +116,20 @@ def build_file_items(base_dir: Path, files: list[str]) -> list[dict]: content : str (file text, or error string) error : bool mtime : float (last modification time, for skip-if-unchanged optimization) + tier : int | None (optional tier for context management) """ items = [] - for entry in files: + for entry_raw in files: + if isinstance(entry_raw, dict): + entry = entry_raw.get("path") + tier = entry_raw.get("tier") + else: + entry = entry_raw + tier = None + paths = resolve_paths(base_dir, entry) if not paths: - items.append({"path": None, "entry": entry, "content": f"ERROR: no files matched: {entry}", "error": True, "mtime": 0.0}) + items.append({"path": None, "entry": entry, "content": f"ERROR: no files matched: {entry}", "error": True, "mtime": 0.0, "tier": tier}) continue for path in paths: try: @@ -131,10 +144,10 @@ def build_file_items(base_dir: Path, files: list[str]) -> list[dict]: content = f"ERROR: {e}" mtime = 0.0 error = True - items.append({"path": path, "entry": entry, "content": content, "error": error, "mtime": mtime}) + items.append({"path": path, "entry": entry, "content": content, "error": error, "mtime": mtime, "tier": tier}) return items -def build_summary_section(base_dir: Path, files: list[str]) -> str: +def build_summary_section(base_dir: Path, files: list[str | dict]) -> str: """ Build a compact summary section using summarize.py — one short block per file. Used as the initial block instead of full file contents. @@ -279,7 +292,7 @@ def build_tier3_context(file_items: list[dict], screenshot_base_dir: Path, scree return "\n\n---\n\n".join(parts) -def build_markdown(base_dir: Path, files: list[str], screenshot_base_dir: Path, screenshots: list[str], history: list[str], summary_only: bool = False) -> str: +def build_markdown(base_dir: Path, files: list[str | dict], screenshot_base_dir: Path, screenshots: list[str], history: list[str], summary_only: bool = False) -> str: parts = [] # STATIC PREFIX: Files and Screenshots must go first to maximize Cache Hits if files: diff --git a/tests/test_tiered_context.py b/tests/test_tiered_context.py index c673095..630af1e 100644 --- a/tests/test_tiered_context.py +++ b/tests/test_tiered_context.py @@ -66,3 +66,44 @@ def test_build_tier3_context_exists(): # Let's check for the header assert "other.py" in result assert "AST Skeleton" in result + +def test_build_file_items_with_tiers(tmp_path): + from aggregate import build_file_items + + # Create some dummy files + file1 = tmp_path / "file1.txt" + file1.write_text("content1") + file2 = tmp_path / "file2.txt" + file2.write_text("content2") + + files_config = [ + "file1.txt", + {"path": "file2.txt", "tier": 3} + ] + + items = build_file_items(tmp_path, files_config) + + assert len(items) == 2 + + item1 = next(i for i in items if i["entry"] == "file1.txt") + assert item1["content"] == "content1" + assert "tier" in item1 + assert item1["tier"] is None + + item2 = next(i for i in items if i["entry"] == "file2.txt") + assert item2["content"] == "content2" + assert item2["tier"] == 3 + +def test_build_files_section_with_dicts(tmp_path): + from aggregate import build_files_section + + file1 = tmp_path / "file1.txt" + file1.write_text("content1") + + files_config = [ + {"path": str(file1)} + ] + + result = build_files_section(tmp_path, files_config) + assert "content1" in result + assert "file1.txt" in result