diff --git a/src/aggregate.py b/src/aggregate.py index 46f3f82..8bb5e08 100644 --- a/src/aggregate.py +++ b/src/aggregate.py @@ -189,16 +189,14 @@ def _build_files_section_from_items(file_items: list[dict[str, Any]]) -> str: if not item.get("auto_aggregate", True): continue path = item.get("path") - entry = cast(str, item.get("entry", "unknown")) - content = cast(str, item.get("content", "")) + entry = item.get("entry", "unknown") + content = item.get("content", "") if path is None: sections.append(f"### `{entry}`\n\n```text\n{content}\n```") - continue - p = cast(Path, path) - suffix = p.suffix.lstrip(".") if hasattr(p, "suffix") else "text" - lang = suffix if suffix else "text" - original = entry if "*" not in entry else str(p) - sections.append(f"### `{original}`\n\n```{lang}\n{content}\n```") + else: + suffix = path.suffix.lstrip(".") if path.suffix else "text" + original = entry if "*" not in entry else str(path) + sections.append(f"### `{original}`\n\n```{suffix}\n{content}\n```") return "\n\n---\n\n".join(sections) def build_beads_section(base_dir: Path) -> str: @@ -263,24 +261,24 @@ def build_tier1_context(file_items: list[dict[str, Any]], screenshot_base_dir: P Full content for core conductor files and files with tier=1, summaries for others. """ core_files = {"product.md", "tech-stack.md", "workflow.md", "tracks.md"} + sections = [] + for item in file_items: + if not item.get("auto_aggregate", True): + continue + path = item.get("path") + if not path: continue + entry = item.get("entry") + display_name = entry or str(path) + tier = item.get("tier") + force_full = item.get("force_full") + content = item.get("content", "") + if path.name in core_files or tier == 1 or force_full: + suffix = path.suffix.lstrip(".") if path.suffix else "text" + sections.append(f"### `{display_name}`\n\n```{suffix}\n{content}\n```") + else: + sections.append(f"### `{display_name}`\n\n{summarize.summarise_file(path, content)}") parts = [] - # Files section - if file_items: - sections = [] - for item in file_items: - if not item.get("auto_aggregate", True): - continue - path = item.get("path") - name = path.name if path and isinstance(path, Path) else "" - if name in core_files or item.get("tier") == 1 or item.get("force_full"): - # Include in full - sections.append("### `" + (cast(str, item.get("entry")) or str(path)) + "`\n\n" + - f"```{path.suffix.lstrip('.') if path and isinstance(path, Path) and path.suffix else 'text'}\n{item.get('content', '')}\n```") - else: - # Summarize - if path and isinstance(path, Path): - sections.append("### `" + (cast(str, item.get("entry")) or str(path)) + "`\n\n" + - summarize.summarise_file(path, cast(str, item.get("content", "")))) + if sections: parts.append("## Files (Tier 1 - Mixed)\n\n" + "\n\n---\n\n".join(sections)) if screenshots: parts.append("## Screenshots\n\n" + build_screenshots_section(screenshot_base_dir, screenshots)) @@ -301,37 +299,40 @@ def build_tier3_context(file_items: list[dict[str, Any]], screenshot_base_dir: P Full content for focus_files and files with tier=3, summaries/skeletons for others. """ with get_monitor().scope("build_tier3_context"): - parts = [] - if file_items: - sections = [] - for item in file_items: - if not item.get("auto_aggregate", True): - continue - path = cast(Path, item.get("path")) - entry = cast(str, item.get("entry", "")) - path_str = str(path) if path else "" - # Check if this file is in focus_files (by name or path) - is_focus = False - for focus in focus_files: - if focus == entry or (path and focus == path.name) or (path_str and focus in path_str): + focus_set = set(focus_files) + parser = ASTParser("python") + sections = [] + for item in file_items: + if not item.get("auto_aggregate", True): + continue + path = item.get("path") + entry = item.get("entry", "") + path_str = str(path) if path else "" + name = path.name if path else "" + tier = item.get("tier") + force_full = item.get("force_full") + content = item.get("content", "") + is_focus = entry in focus_set or (name and name in focus_set) or (path_str and path_str in focus_set) + if not is_focus and path_str: + for focus in focus_set: + if focus in path_str: is_focus = True break - if is_focus or item.get("tier") == 3 or item.get("force_full"): - sections.append("### `" + (entry or path_str) + "`\n\n" + - f"```{path.suffix.lstrip('.') if path and path.suffix else 'text'}\n{item.get('content', '')}\n```") + display_name = entry or path_str + if is_focus or tier == 3 or force_full: + suffix = path.suffix.lstrip(".") if path and path.suffix else "text" + sections.append(f"### `{display_name}`\n\n```{suffix}\n{content}\n```") + elif path: + if path.suffix == ".py" and not item.get("error"): + try: + skeleton = parser.get_skeleton(content) + sections.append(f"### `{display_name}` (AST Skeleton)\n\n```python\n{skeleton}\n```") + except Exception: + sections.append(f"### `{display_name}`\n\n{summarize.summarise_file(path, content)}") else: - content = cast(str, item.get("content", "")) - if path and path.suffix == ".py" and not item.get("error"): - try: - parser = ASTParser("python") - skeleton = parser.get_skeleton(content) - sections.append(f"### `{entry or path_str}` (AST Skeleton)\n\n```python\n{skeleton}\n```") - except Exception: - # Fallback to summary if AST parsing fails - sections.append(f"### `{entry or path_str}`\n\n" + summarize.summarise_file(path, content)) - else: - if path: - sections.append(f"### `{entry or path_str}`\n\n" + summarize.summarise_file(path, content)) + sections.append(f"### `{display_name}`\n\n{summarize.summarise_file(path, content)}") + parts = [] + if sections: parts.append("## Files (Tier 3 - Focused)\n\n" + "\n\n---\n\n".join(sections)) if screenshots: parts.append("## Screenshots\n\n" + build_screenshots_section(screenshot_base_dir, screenshots))