Add claude-task-chunker: break large tasks into efficient Claude Code sessions
CLI tool that decomposes big coding tasks into self-contained chunks, each with a ready-to-paste prompt including codebase context, targeted instructions, and dependency tracking. Supports phase, component, and manual decomposition strategies. https://claude.ai/code/session_01Fzv8baXnEVVhnrffAb3Ucc
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
"""Codebase analyzer - gathers structure and context for task decomposition."""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@dataclass
|
||||
class CodebaseInfo:
|
||||
"""Summary of a codebase's structure and key files."""
|
||||
root: Path
|
||||
languages: dict[str, int] = field(default_factory=dict) # extension -> file count
|
||||
total_files: int = 0
|
||||
total_lines: int = 0
|
||||
tree: list[str] = field(default_factory=list) # directory tree (paths)
|
||||
key_files: list[str] = field(default_factory=list) # config, entry points, etc.
|
||||
git_branch: str = ""
|
||||
recent_commits: list[str] = field(default_factory=list)
|
||||
|
||||
def summary(self) -> str:
|
||||
lines = [f"Codebase: {self.root.name}"]
|
||||
if self.git_branch:
|
||||
lines.append(f"Branch: {self.git_branch}")
|
||||
lines.append(f"Files: {self.total_files} | Lines: ~{self.total_lines}")
|
||||
if self.languages:
|
||||
top = sorted(self.languages.items(), key=lambda x: -x[1])[:5]
|
||||
lines.append("Languages: " + ", ".join(f"{ext} ({n})" for ext, n in top))
|
||||
if self.key_files:
|
||||
lines.append("Key files: " + ", ".join(self.key_files[:10]))
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
IGNORE_DIRS = {
|
||||
".git", "node_modules", "__pycache__", ".venv", "venv", "dist", "build",
|
||||
".next", ".nuxt", "target", "vendor", ".tox", ".mypy_cache", ".pytest_cache",
|
||||
"coverage", ".cache", "env", ".env", ".eggs", "*.egg-info",
|
||||
}
|
||||
|
||||
KEY_FILE_NAMES = {
|
||||
"package.json", "pyproject.toml", "setup.py", "setup.cfg", "Cargo.toml",
|
||||
"go.mod", "Makefile", "CMakeLists.txt", "Dockerfile", "docker-compose.yml",
|
||||
"docker-compose.yaml", ".env.example", "requirements.txt", "tsconfig.json",
|
||||
"webpack.config.js", "vite.config.ts", "vite.config.js", "next.config.js",
|
||||
"tailwind.config.js", "CLAUDE.md",
|
||||
}
|
||||
|
||||
|
||||
def analyze_codebase(root: Path) -> CodebaseInfo:
|
||||
"""Walk the codebase and gather structural info."""
|
||||
info = CodebaseInfo(root=root.resolve())
|
||||
|
||||
# Git info
|
||||
try:
|
||||
info.git_branch = subprocess.check_output(
|
||||
["git", "rev-parse", "--abbrev-ref", "HEAD"],
|
||||
cwd=root, stderr=subprocess.DEVNULL, text=True,
|
||||
).strip()
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
pass
|
||||
|
||||
try:
|
||||
log = subprocess.check_output(
|
||||
["git", "log", "--oneline", "-10"],
|
||||
cwd=root, stderr=subprocess.DEVNULL, text=True,
|
||||
).strip()
|
||||
if log:
|
||||
info.recent_commits = log.splitlines()
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
pass
|
||||
|
||||
# Walk files
|
||||
languages: dict[str, int] = {}
|
||||
total_lines = 0
|
||||
|
||||
for dirpath, dirnames, filenames in os.walk(root):
|
||||
# Prune ignored directories
|
||||
dirnames[:] = [d for d in dirnames if d not in IGNORE_DIRS]
|
||||
|
||||
rel_dir = os.path.relpath(dirpath, root)
|
||||
|
||||
for fname in filenames:
|
||||
full = os.path.join(dirpath, fname)
|
||||
rel = os.path.join(rel_dir, fname) if rel_dir != "." else fname
|
||||
info.tree.append(rel)
|
||||
info.total_files += 1
|
||||
|
||||
# Check key files
|
||||
if fname in KEY_FILE_NAMES:
|
||||
info.key_files.append(rel)
|
||||
|
||||
# Language stats
|
||||
ext = Path(fname).suffix.lower()
|
||||
if ext:
|
||||
languages[ext] = languages.get(ext, 0) + 1
|
||||
|
||||
# Line count (skip binary)
|
||||
try:
|
||||
with open(full, "r", errors="ignore") as f:
|
||||
total_lines += sum(1 for _ in f)
|
||||
except (OSError, UnicodeDecodeError):
|
||||
pass
|
||||
|
||||
info.languages = languages
|
||||
info.total_lines = total_lines
|
||||
return info
|
||||
Reference in New Issue
Block a user