@prateek_ai/agents-maker 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +659 -0
- package/agents/architect_agent.md +175 -0
- package/agents/code_agent.md +178 -0
- package/agents/compression_agent.md +226 -0
- package/agents/execution_agent.md +157 -0
- package/agents/orchestrator.md +406 -0
- package/agents/reviewer_agent.md +134 -0
- package/agents/ui_agent.md +147 -0
- package/agents/ux_agent.md +144 -0
- package/bin/cli.js +79 -0
- package/config/agents.yaml +388 -0
- package/config/domain_profiles.yaml +394 -0
- package/config/project.yaml.example +16 -0
- package/config/token_policies.yaml +325 -0
- package/context_loaders/__init__.py +15 -0
- package/context_loaders/__pycache__/__init__.cpython-314.pyc +0 -0
- package/context_loaders/__pycache__/file_chunker.cpython-314.pyc +0 -0
- package/context_loaders/__pycache__/project_summary.cpython-314.pyc +0 -0
- package/context_loaders/__pycache__/repo_tree.cpython-314.pyc +0 -0
- package/context_loaders/file_chunker.py +252 -0
- package/context_loaders/project_summary.py +369 -0
- package/context_loaders/repo_tree.py +203 -0
- package/package.json +46 -0
- package/quickstart.ps1 +252 -0
- package/quickstart.sh +232 -0
- package/requirements.txt +3 -0
- package/skills/analyze_repo.md +86 -0
- package/skills/animated_website.md +285 -0
- package/skills/compare_approaches.md +86 -0
- package/skills/define_data_schema.md +99 -0
- package/skills/design_api.md +126 -0
- package/skills/improve_copy.md +69 -0
- package/skills/review_code.md +83 -0
- package/skills/review_layout.md +89 -0
- package/skills/suggest_next.md +105 -0
- package/skills/summarize_history.md +89 -0
- package/skills/write_process_map.md +105 -0
- package/skills/write_tests.md +97 -0
- package/token_optimization/__pycache__/compressor.cpython-314.pyc +0 -0
- package/token_optimization/compressor.py +502 -0
- package/token_optimization/output_styles.md +80 -0
- package/tools/__pycache__/domain_utils.cpython-314.pyc +0 -0
- package/tools/__pycache__/generate_claude_md.cpython-314.pyc +0 -0
- package/tools/__pycache__/validate_kit.cpython-314.pyc +0 -0
- package/tools/domain_utils.py +141 -0
- package/tools/generate_claude_md.py +269 -0
- package/tools/generate_platform_configs.py +467 -0
- package/tools/generate_prompt.py +461 -0
- package/tools/init_project.py +454 -0
- package/tools/test_kit.py +363 -0
- package/tools/validate_kit.py +504 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
"""
|
|
2
|
+
context_loaders/project_summary.py
|
|
3
|
+
|
|
4
|
+
Produce a compact, structured project summary for agent context.
|
|
5
|
+
Detects the tech stack, primary services/modules, main entrypoints,
|
|
6
|
+
test structure, and key config files by inspecting the repository.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python context_loaders/project_summary.py --path /your/repo
|
|
10
|
+
python context_loaders/project_summary.py --path /your/repo --output summary.txt
|
|
11
|
+
|
|
12
|
+
Output: paste directly as the "## Project State" section in your agent session.
|
|
13
|
+
|
|
14
|
+
The summary is intentionally compact (300–600 tokens) — it is the basis
|
|
15
|
+
for all agent context and should not be summarized further.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import argparse
|
|
21
|
+
import sys
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
__version__ = "1.0.0"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# ---------------------------------------------------------------------------
|
|
28
|
+
# Stack detection rules
|
|
29
|
+
# Each entry: (indicator_file_or_dir, language, framework_or_runtime)
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
STACK_INDICATORS: list[tuple[str, str, str]] = [
|
|
33
|
+
# Python
|
|
34
|
+
("pyproject.toml", "Python", ""),
|
|
35
|
+
("setup.py", "Python", ""),
|
|
36
|
+
("requirements.txt", "Python", ""),
|
|
37
|
+
("Pipfile", "Python", "Pipenv"),
|
|
38
|
+
("manage.py", "Python", "Django"),
|
|
39
|
+
("wsgi.py", "Python", "WSGI/Django"),
|
|
40
|
+
("asgi.py", "Python", "ASGI"),
|
|
41
|
+
# Node / JS / TS
|
|
42
|
+
("package.json", "Node.js", ""),
|
|
43
|
+
("tsconfig.json", "TypeScript", ""),
|
|
44
|
+
("next.config.js", "TypeScript", "Next.js"),
|
|
45
|
+
("next.config.ts", "TypeScript", "Next.js"),
|
|
46
|
+
("nuxt.config.ts", "TypeScript", "Nuxt.js"),
|
|
47
|
+
("vite.config.ts", "TypeScript", "Vite"),
|
|
48
|
+
("angular.json", "TypeScript", "Angular"),
|
|
49
|
+
# Go
|
|
50
|
+
("go.mod", "Go", ""),
|
|
51
|
+
# Java / Kotlin
|
|
52
|
+
("pom.xml", "Java", "Maven"),
|
|
53
|
+
("build.gradle", "Java/Kotlin", "Gradle"),
|
|
54
|
+
("build.gradle.kts", "Kotlin", "Gradle"),
|
|
55
|
+
# Rust
|
|
56
|
+
("Cargo.toml", "Rust", "Cargo"),
|
|
57
|
+
# Ruby
|
|
58
|
+
("Gemfile", "Ruby", "Bundler"),
|
|
59
|
+
("config/routes.rb", "Ruby", "Rails"),
|
|
60
|
+
# Infra
|
|
61
|
+
("docker-compose.yml", "", "Docker Compose"),
|
|
62
|
+
("docker-compose.yaml", "", "Docker Compose"),
|
|
63
|
+
("Dockerfile", "", "Docker"),
|
|
64
|
+
("k8s/", "", "Kubernetes"),
|
|
65
|
+
("helm/", "", "Helm"),
|
|
66
|
+
("terraform/", "", "Terraform"),
|
|
67
|
+
(".tf", "", "Terraform"),
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
FRAMEWORK_INDICATORS: list[tuple[str, str]] = [
|
|
71
|
+
("fastapi", "FastAPI"),
|
|
72
|
+
("flask", "Flask"),
|
|
73
|
+
("django", "Django"),
|
|
74
|
+
("starlette", "Starlette"),
|
|
75
|
+
("tornado", "Tornado"),
|
|
76
|
+
("express", "Express"),
|
|
77
|
+
("koa", "Koa"),
|
|
78
|
+
("nestjs", "NestJS"),
|
|
79
|
+
("spring", "Spring"),
|
|
80
|
+
("gin", "Gin"),
|
|
81
|
+
("fiber", "Fiber"),
|
|
82
|
+
("actix", "Actix"),
|
|
83
|
+
("axum", "Axum"),
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
TEST_FRAMEWORK_INDICATORS: list[tuple[str, str]] = [
|
|
87
|
+
("pytest", "pytest"),
|
|
88
|
+
("unittest", "unittest"),
|
|
89
|
+
("jest", "Jest"),
|
|
90
|
+
("vitest", "Vitest"),
|
|
91
|
+
("mocha", "Mocha"),
|
|
92
|
+
("jasmine", "Jasmine"),
|
|
93
|
+
("rspec", "RSpec"),
|
|
94
|
+
("minitest", "Minitest"),
|
|
95
|
+
("junit", "JUnit"),
|
|
96
|
+
("testng", "TestNG"),
|
|
97
|
+
("go test", "go test"),
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
ENTRYPOINT_NAMES = frozenset({
|
|
101
|
+
"main.py", "app.py", "server.py", "wsgi.py", "asgi.py", "run.py",
|
|
102
|
+
"index.js", "index.ts", "server.js", "server.ts", "app.js", "app.ts",
|
|
103
|
+
"main.go", "main.java", "main.rs", "main.rb",
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
SERVICE_DIR_PATTERNS = ("service", "services", "api", "routes", "handlers", "controllers", "workers")
|
|
107
|
+
MODEL_DIR_PATTERNS = ("model", "models", "schema", "schemas", "entities", "domain")
|
|
108
|
+
TEST_DIR_PATTERNS = ("test", "tests", "spec", "specs", "__tests__")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _read_text_safe(path: Path) -> str:
|
|
112
|
+
try:
|
|
113
|
+
return path.read_text(encoding="utf-8", errors="replace")
|
|
114
|
+
except (OSError, PermissionError):
|
|
115
|
+
return ""
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def detect_stack(root: Path) -> tuple[list[str], list[str], str | None]:
|
|
119
|
+
"""Returns (languages, frameworks, build_tool)."""
|
|
120
|
+
languages: list[str] = []
|
|
121
|
+
frameworks: list[str] = []
|
|
122
|
+
build_tool: str | None = None
|
|
123
|
+
|
|
124
|
+
for indicator, lang, framework in STACK_INDICATORS:
|
|
125
|
+
target = root / indicator
|
|
126
|
+
if target.exists():
|
|
127
|
+
if lang and lang not in languages:
|
|
128
|
+
languages.append(lang)
|
|
129
|
+
if framework and framework not in frameworks:
|
|
130
|
+
frameworks.append(framework)
|
|
131
|
+
if indicator in ("pyproject.toml", "setup.py", "requirements.txt"):
|
|
132
|
+
build_tool = build_tool or "pip"
|
|
133
|
+
elif indicator == "package.json":
|
|
134
|
+
pkg = _read_text_safe(target).lower()
|
|
135
|
+
build_tool = build_tool or ("pnpm" if "pnpm" in pkg else "npm/yarn")
|
|
136
|
+
elif indicator in ("pom.xml",):
|
|
137
|
+
build_tool = "Maven"
|
|
138
|
+
elif indicator.startswith("build.gradle"):
|
|
139
|
+
build_tool = "Gradle"
|
|
140
|
+
elif indicator == "Cargo.toml":
|
|
141
|
+
build_tool = "Cargo"
|
|
142
|
+
elif indicator == "Gemfile":
|
|
143
|
+
build_tool = "Bundler"
|
|
144
|
+
elif indicator == "go.mod":
|
|
145
|
+
build_tool = "go"
|
|
146
|
+
|
|
147
|
+
# Detect framework from dependency files
|
|
148
|
+
dep_files = ["requirements.txt", "pyproject.toml", "package.json", "Pipfile", "Gemfile"]
|
|
149
|
+
for dep_file in dep_files:
|
|
150
|
+
content = _read_text_safe(root / dep_file).lower()
|
|
151
|
+
for key, name in FRAMEWORK_INDICATORS:
|
|
152
|
+
if key in content and name not in frameworks:
|
|
153
|
+
frameworks.append(name)
|
|
154
|
+
|
|
155
|
+
return languages, frameworks, build_tool
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def detect_test_framework(root: Path) -> str | None:
|
|
159
|
+
dep_files = ["requirements.txt", "pyproject.toml", "package.json", "setup.cfg"]
|
|
160
|
+
for dep_file in dep_files:
|
|
161
|
+
content = _read_text_safe(root / dep_file).lower()
|
|
162
|
+
for key, name in TEST_FRAMEWORK_INDICATORS:
|
|
163
|
+
if key in content:
|
|
164
|
+
return name
|
|
165
|
+
# Go: detect by go.mod existence
|
|
166
|
+
if (root / "go.mod").exists():
|
|
167
|
+
return "go test"
|
|
168
|
+
return None
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def detect_containerization(root: Path) -> str:
|
|
172
|
+
if (root / "k8s").is_dir() or (root / "kubernetes").is_dir():
|
|
173
|
+
return "Kubernetes"
|
|
174
|
+
if (root / "docker-compose.yml").exists() or (root / "docker-compose.yaml").exists():
|
|
175
|
+
return "Docker Compose"
|
|
176
|
+
if (root / "Dockerfile").exists():
|
|
177
|
+
return "Docker"
|
|
178
|
+
return "none"
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def find_services(root: Path, max_depth: int = 3) -> list[tuple[str, str]]:
|
|
182
|
+
"""Return list of (path, description) for service/module directories."""
|
|
183
|
+
results = []
|
|
184
|
+
|
|
185
|
+
def _scan(directory: Path, depth: int) -> None:
|
|
186
|
+
if depth > max_depth:
|
|
187
|
+
return
|
|
188
|
+
try:
|
|
189
|
+
entries = list(directory.iterdir())
|
|
190
|
+
except PermissionError:
|
|
191
|
+
return
|
|
192
|
+
for entry in entries:
|
|
193
|
+
if not entry.is_dir():
|
|
194
|
+
continue
|
|
195
|
+
name_lower = entry.name.lower()
|
|
196
|
+
if any(p in name_lower for p in ("__pycache__", ".git", "node_modules", ".venv")):
|
|
197
|
+
continue
|
|
198
|
+
rel = str(entry.relative_to(root)).replace("\\", "/")
|
|
199
|
+
for pattern in SERVICE_DIR_PATTERNS:
|
|
200
|
+
if pattern in name_lower:
|
|
201
|
+
results.append((rel + "/", "service/handler layer"))
|
|
202
|
+
break
|
|
203
|
+
for pattern in MODEL_DIR_PATTERNS:
|
|
204
|
+
if pattern in name_lower:
|
|
205
|
+
results.append((rel + "/", "data models / schemas"))
|
|
206
|
+
break
|
|
207
|
+
_scan(entry, depth + 1)
|
|
208
|
+
|
|
209
|
+
_scan(root, 0)
|
|
210
|
+
return results[:10]
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def find_entrypoints(root: Path) -> list[tuple[str, str]]:
|
|
214
|
+
results = []
|
|
215
|
+
for name in ENTRYPOINT_NAMES:
|
|
216
|
+
p = root / name
|
|
217
|
+
if p.exists():
|
|
218
|
+
results.append((name, "application entrypoint"))
|
|
219
|
+
# Also search one level deep
|
|
220
|
+
for child in root.iterdir():
|
|
221
|
+
if child.is_dir() and child.name not in ("__pycache__", "node_modules", ".git", ".venv"):
|
|
222
|
+
for name in ENTRYPOINT_NAMES:
|
|
223
|
+
p = child / name
|
|
224
|
+
if p.exists():
|
|
225
|
+
rel = str(p.relative_to(root)).replace("\\", "/")
|
|
226
|
+
results.append((rel, "application entrypoint"))
|
|
227
|
+
return results[:8]
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def find_test_dirs(root: Path) -> list[tuple[str, str]]:
|
|
231
|
+
results = []
|
|
232
|
+
|
|
233
|
+
def _scan(directory: Path, depth: int = 0) -> None:
|
|
234
|
+
if depth > 3:
|
|
235
|
+
return
|
|
236
|
+
try:
|
|
237
|
+
for entry in directory.iterdir():
|
|
238
|
+
if not entry.is_dir():
|
|
239
|
+
continue
|
|
240
|
+
name_lower = entry.name.lower()
|
|
241
|
+
if any(p in name_lower for p in TEST_DIR_PATTERNS):
|
|
242
|
+
rel = str(entry.relative_to(root)).replace("\\", "/")
|
|
243
|
+
results.append((rel + "/", "test suite"))
|
|
244
|
+
_scan(entry, depth + 1)
|
|
245
|
+
except PermissionError:
|
|
246
|
+
pass
|
|
247
|
+
|
|
248
|
+
_scan(root)
|
|
249
|
+
return results[:6]
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def find_key_configs(root: Path) -> list[tuple[str, str]]:
|
|
253
|
+
config_map = {
|
|
254
|
+
"pyproject.toml": "Python project config + dependencies",
|
|
255
|
+
"setup.py": "Python package setup",
|
|
256
|
+
"requirements.txt": "Python dependencies",
|
|
257
|
+
"requirements-dev.txt": "Python dev dependencies",
|
|
258
|
+
"package.json": "Node.js dependencies + scripts",
|
|
259
|
+
"tsconfig.json": "TypeScript compiler config",
|
|
260
|
+
"go.mod": "Go module definition",
|
|
261
|
+
"Cargo.toml": "Rust crate config",
|
|
262
|
+
"Gemfile": "Ruby dependencies",
|
|
263
|
+
"pom.xml": "Java Maven config",
|
|
264
|
+
"build.gradle": "Java/Kotlin Gradle config",
|
|
265
|
+
"Dockerfile": "Container build definition",
|
|
266
|
+
"docker-compose.yml": "Multi-service container config",
|
|
267
|
+
"docker-compose.yaml": "Multi-service container config",
|
|
268
|
+
"Makefile": "Build / task runner",
|
|
269
|
+
".env.example": "Required environment variables",
|
|
270
|
+
"alembic.ini": "Database migration config (Alembic)",
|
|
271
|
+
"migrate.go": "Database migration entrypoint",
|
|
272
|
+
"schema.prisma": "Prisma ORM schema",
|
|
273
|
+
"schema.graphql": "GraphQL schema",
|
|
274
|
+
}
|
|
275
|
+
results = []
|
|
276
|
+
for filename, description in config_map.items():
|
|
277
|
+
if (root / filename).exists():
|
|
278
|
+
results.append((filename, description))
|
|
279
|
+
return results
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def build_summary(root: Path) -> str:
|
|
283
|
+
languages, frameworks, build_tool = detect_stack(root)
|
|
284
|
+
test_framework = detect_test_framework(root)
|
|
285
|
+
containerization = detect_containerization(root)
|
|
286
|
+
services = find_services(root)
|
|
287
|
+
entrypoints = find_entrypoints(root)
|
|
288
|
+
test_dirs = find_test_dirs(root)
|
|
289
|
+
configs = find_key_configs(root)
|
|
290
|
+
|
|
291
|
+
stack_str = ", ".join(languages) if languages else "Unknown"
|
|
292
|
+
frameworks_str = ", ".join(frameworks) if frameworks else "none detected"
|
|
293
|
+
|
|
294
|
+
lines: list[str] = [
|
|
295
|
+
"## Project Summary",
|
|
296
|
+
"",
|
|
297
|
+
f"**Stack**: {stack_str}",
|
|
298
|
+
f"**Frameworks**: {frameworks_str}",
|
|
299
|
+
f"**Build tool**: {build_tool or 'unknown'}",
|
|
300
|
+
f"**Test framework**: {test_framework or 'unknown'}",
|
|
301
|
+
f"**Containerization**: {containerization}",
|
|
302
|
+
"",
|
|
303
|
+
]
|
|
304
|
+
|
|
305
|
+
if services:
|
|
306
|
+
lines.append("## Services / Modules")
|
|
307
|
+
lines.append("")
|
|
308
|
+
lines.append("| Path | Responsibility |")
|
|
309
|
+
lines.append("|---|---|")
|
|
310
|
+
for path, desc in services:
|
|
311
|
+
lines.append(f"| `{path}` | {desc} |")
|
|
312
|
+
lines.append("")
|
|
313
|
+
|
|
314
|
+
if entrypoints:
|
|
315
|
+
lines.append("## Main Entrypoints")
|
|
316
|
+
lines.append("")
|
|
317
|
+
lines.append("| File | Purpose |")
|
|
318
|
+
lines.append("|---|---|")
|
|
319
|
+
for path, desc in entrypoints:
|
|
320
|
+
lines.append(f"| `{path}` | {desc} |")
|
|
321
|
+
lines.append("")
|
|
322
|
+
|
|
323
|
+
if configs:
|
|
324
|
+
lines.append("## Key Config Files")
|
|
325
|
+
lines.append("")
|
|
326
|
+
lines.append("| File | Purpose |")
|
|
327
|
+
lines.append("|---|---|")
|
|
328
|
+
for path, desc in configs:
|
|
329
|
+
lines.append(f"| `{path}` | {desc} |")
|
|
330
|
+
lines.append("")
|
|
331
|
+
|
|
332
|
+
if test_dirs:
|
|
333
|
+
lines.append("## Test Structure")
|
|
334
|
+
lines.append("")
|
|
335
|
+
lines.append("| Path | Type |")
|
|
336
|
+
lines.append("|---|---|")
|
|
337
|
+
for path, desc in test_dirs:
|
|
338
|
+
lines.append(f"| `{path}` | {desc} |")
|
|
339
|
+
lines.append("")
|
|
340
|
+
|
|
341
|
+
lines.append(f"_Summary generated from: `{root}`_")
|
|
342
|
+
return "\n".join(lines)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def main() -> None:
|
|
346
|
+
parser = argparse.ArgumentParser(
|
|
347
|
+
description="Generate a compact project summary for agent context."
|
|
348
|
+
)
|
|
349
|
+
parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
|
|
350
|
+
parser.add_argument("--path", required=True, help="Repository root directory.")
|
|
351
|
+
parser.add_argument("--output", help="Write output to this file instead of stdout.")
|
|
352
|
+
args = parser.parse_args()
|
|
353
|
+
|
|
354
|
+
root = Path(args.path).resolve()
|
|
355
|
+
if not root.is_dir():
|
|
356
|
+
print(f"Error: {root} is not a directory.", file=sys.stderr)
|
|
357
|
+
sys.exit(1)
|
|
358
|
+
|
|
359
|
+
summary = build_summary(root)
|
|
360
|
+
|
|
361
|
+
if args.output:
|
|
362
|
+
Path(args.output).write_text(summary, encoding="utf-8")
|
|
363
|
+
print(f"Written to {args.output}")
|
|
364
|
+
else:
|
|
365
|
+
sys.stdout.buffer.write(summary.encode("utf-8"))
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
if __name__ == "__main__":
|
|
369
|
+
main()
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"""
|
|
2
|
+
context_loaders/repo_tree.py
|
|
3
|
+
|
|
4
|
+
Walk a repository and emit a filtered, indented file tree with one-line
|
|
5
|
+
descriptions for key files. Output is designed to be pasted directly into
|
|
6
|
+
an agent session as the "Relevant Files" section of the context block.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python context_loaders/repo_tree.py --path /your/repo
|
|
10
|
+
python context_loaders/repo_tree.py --path /your/repo --filter src/ app/ components/
|
|
11
|
+
python context_loaders/repo_tree.py --path /your/repo --max-depth 3 --output tree.txt
|
|
12
|
+
|
|
13
|
+
Output format:
|
|
14
|
+
src/
|
|
15
|
+
services/
|
|
16
|
+
user_service.py # UserService: CRUD + auth helpers
|
|
17
|
+
order_service.py # OrderService: order lifecycle management
|
|
18
|
+
models/
|
|
19
|
+
user.py # User ORM model
|
|
20
|
+
tests/
|
|
21
|
+
test_user_service.py # Unit tests for UserService
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
__version__ = "1.0.0"
|
|
27
|
+
|
|
28
|
+
import argparse
|
|
29
|
+
import sys
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
|
|
32
|
+
# Files to always exclude from the tree
|
|
33
|
+
DEFAULT_EXCLUDES = frozenset({
|
|
34
|
+
".git", "__pycache__", "node_modules", ".venv", "venv", "env",
|
|
35
|
+
".mypy_cache", ".pytest_cache", ".ruff_cache", "dist", "build",
|
|
36
|
+
".next", ".nuxt", "coverage", ".coverage", "*.pyc", "*.pyo",
|
|
37
|
+
"*.egg-info", ".DS_Store", "Thumbs.db",
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
# Extensions considered "key" files worth showing even in dense trees
|
|
41
|
+
KEY_EXTENSIONS = frozenset({
|
|
42
|
+
".py", ".ts", ".tsx", ".js", ".jsx", ".go", ".java", ".rb", ".rs",
|
|
43
|
+
".yaml", ".yml", ".toml", ".json", ".env.example", ".md",
|
|
44
|
+
".sql", ".proto", ".graphql", ".gql",
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
# File-level description heuristics: (pattern, description)
|
|
48
|
+
DESCRIPTION_HINTS: list[tuple[str, str]] = [
|
|
49
|
+
("test_", "unit/integration tests"),
|
|
50
|
+
("_test.", "unit/integration tests"),
|
|
51
|
+
(".test.", "unit/integration tests"),
|
|
52
|
+
("spec.", "unit/integration tests"),
|
|
53
|
+
("router", "route definitions"),
|
|
54
|
+
("routes", "route definitions"),
|
|
55
|
+
("controller", "request handler"),
|
|
56
|
+
("handler", "request handler"),
|
|
57
|
+
("service", "business logic"),
|
|
58
|
+
("repository", "data access layer"),
|
|
59
|
+
("repo.", "data access layer"),
|
|
60
|
+
("model", "data model / ORM"),
|
|
61
|
+
("schema", "schema definition"),
|
|
62
|
+
("migration", "database migration"),
|
|
63
|
+
("config", "configuration"),
|
|
64
|
+
("settings", "configuration"),
|
|
65
|
+
("middleware", "middleware"),
|
|
66
|
+
("utils", "utility helpers"),
|
|
67
|
+
("helpers", "utility helpers"),
|
|
68
|
+
("constants", "constants / enums"),
|
|
69
|
+
("types", "type definitions"),
|
|
70
|
+
("index.", "module entrypoint"),
|
|
71
|
+
("main.", "application entrypoint"),
|
|
72
|
+
("app.", "application entrypoint"),
|
|
73
|
+
("__init__", "package init"),
|
|
74
|
+
("Dockerfile", "container build definition"),
|
|
75
|
+
("docker-compose", "multi-service container config"),
|
|
76
|
+
("Makefile", "build/task runner"),
|
|
77
|
+
("pyproject.toml", "Python project config"),
|
|
78
|
+
("package.json", "Node.js project config"),
|
|
79
|
+
("requirements", "Python dependencies"),
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _should_exclude(name: str) -> bool:
|
|
84
|
+
name_lower = name.lower()
|
|
85
|
+
for excl in DEFAULT_EXCLUDES:
|
|
86
|
+
if excl.startswith("*"):
|
|
87
|
+
if name_lower.endswith(excl[1:]):
|
|
88
|
+
return True
|
|
89
|
+
elif name_lower == excl.lower():
|
|
90
|
+
return True
|
|
91
|
+
return False
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _describe_file(filename: str) -> str:
|
|
95
|
+
lower = filename.lower()
|
|
96
|
+
for pattern, description in DESCRIPTION_HINTS:
|
|
97
|
+
if pattern.lower() in lower:
|
|
98
|
+
return description
|
|
99
|
+
return ""
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _is_key_file(path: Path) -> bool:
|
|
103
|
+
return path.suffix in KEY_EXTENSIONS
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def walk_tree(
|
|
107
|
+
root: Path,
|
|
108
|
+
filter_paths: list[str] | None = None,
|
|
109
|
+
max_depth: int = 5,
|
|
110
|
+
show_all: bool = False,
|
|
111
|
+
) -> list[tuple[int, Path, bool]]:
|
|
112
|
+
"""
|
|
113
|
+
Walk the directory tree and return (depth, path, is_dir) tuples.
|
|
114
|
+
filter_paths: if set, only include subtrees whose prefix matches one of these strings.
|
|
115
|
+
"""
|
|
116
|
+
results: list[tuple[int, Path, bool]] = []
|
|
117
|
+
|
|
118
|
+
def _walk(directory: Path, depth: int) -> None:
|
|
119
|
+
if depth > max_depth:
|
|
120
|
+
return
|
|
121
|
+
try:
|
|
122
|
+
entries = sorted(
|
|
123
|
+
(p for p in directory.iterdir() if not p.is_symlink()),
|
|
124
|
+
key=lambda p: (p.is_file(), p.name.lower()),
|
|
125
|
+
)
|
|
126
|
+
except PermissionError:
|
|
127
|
+
return
|
|
128
|
+
|
|
129
|
+
for entry in entries:
|
|
130
|
+
if _should_exclude(entry.name):
|
|
131
|
+
continue
|
|
132
|
+
rel = entry.relative_to(root)
|
|
133
|
+
|
|
134
|
+
if filter_paths:
|
|
135
|
+
rel_str = str(rel).replace("\\", "/")
|
|
136
|
+
if entry.is_dir():
|
|
137
|
+
if not any(
|
|
138
|
+
rel_str.startswith(fp.rstrip("/")) or fp.rstrip("/").startswith(rel_str)
|
|
139
|
+
for fp in filter_paths
|
|
140
|
+
):
|
|
141
|
+
continue
|
|
142
|
+
else:
|
|
143
|
+
if not any(rel_str.startswith(fp.rstrip("/")) for fp in filter_paths):
|
|
144
|
+
continue
|
|
145
|
+
|
|
146
|
+
if entry.is_dir():
|
|
147
|
+
results.append((depth, entry, True))
|
|
148
|
+
_walk(entry, depth + 1)
|
|
149
|
+
elif entry.is_file():
|
|
150
|
+
if show_all or _is_key_file(entry):
|
|
151
|
+
results.append((depth, entry, False))
|
|
152
|
+
|
|
153
|
+
_walk(root, 0)
|
|
154
|
+
return results
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def format_tree(entries: list[tuple[int, Path, bool]], root: Path | None = None) -> str:
|
|
158
|
+
lines: list[str] = []
|
|
159
|
+
for depth, path, is_dir in entries:
|
|
160
|
+
indent = " " * depth
|
|
161
|
+
name = path.name + ("/" if is_dir else "")
|
|
162
|
+
if not is_dir:
|
|
163
|
+
desc = _describe_file(path.name)
|
|
164
|
+
comment = f" # {desc}" if desc else ""
|
|
165
|
+
lines.append(f"{indent}{name}{comment}")
|
|
166
|
+
else:
|
|
167
|
+
lines.append(f"{indent}{name}")
|
|
168
|
+
return "\n".join(lines)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def main() -> None:
|
|
172
|
+
parser = argparse.ArgumentParser(
|
|
173
|
+
description="Emit a filtered, annotated file tree for agent context."
|
|
174
|
+
)
|
|
175
|
+
parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
|
|
176
|
+
parser.add_argument("--path", required=True, help="Root directory of the repository.")
|
|
177
|
+
parser.add_argument(
|
|
178
|
+
"--filter", nargs="*", metavar="PREFIX",
|
|
179
|
+
help="Only include subtrees matching these path prefixes (e.g., src/ app/)."
|
|
180
|
+
)
|
|
181
|
+
parser.add_argument("--max-depth", type=int, default=5, help="Maximum directory depth (default: 5).")
|
|
182
|
+
parser.add_argument("--all", action="store_true", help="Include all files, not just key extensions.")
|
|
183
|
+
parser.add_argument("--output", help="Write output to this file instead of stdout.")
|
|
184
|
+
args = parser.parse_args()
|
|
185
|
+
|
|
186
|
+
root = Path(args.path).resolve()
|
|
187
|
+
if not root.is_dir():
|
|
188
|
+
print(f"Error: {root} is not a directory.", file=sys.stderr)
|
|
189
|
+
sys.exit(1)
|
|
190
|
+
|
|
191
|
+
entries = walk_tree(root, filter_paths=args.filter, max_depth=args.max_depth, show_all=args.all)
|
|
192
|
+
output = f"## Repository Tree: {root.name}/\n\n```\n{format_tree(entries, root)}\n```\n"
|
|
193
|
+
output += f"\n({len([e for e in entries if not e[2]])} files shown)\n"
|
|
194
|
+
|
|
195
|
+
if args.output:
|
|
196
|
+
Path(args.output).write_text(output, encoding="utf-8")
|
|
197
|
+
print(f"Written to {args.output}")
|
|
198
|
+
else:
|
|
199
|
+
sys.stdout.buffer.write(output.encode("utf-8"))
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
if __name__ == "__main__":
|
|
203
|
+
main()
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@prateek_ai/agents-maker",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Multi-LLM multi-agent assistant kit — structured AI sessions for any project, any LLM",
|
|
5
|
+
"bin": {
|
|
6
|
+
"agents-maker": "bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/",
|
|
10
|
+
"agents/",
|
|
11
|
+
"skills/",
|
|
12
|
+
"config/agents.yaml",
|
|
13
|
+
"config/domain_profiles.yaml",
|
|
14
|
+
"config/token_policies.yaml",
|
|
15
|
+
"config/project.yaml.example",
|
|
16
|
+
"tools/",
|
|
17
|
+
"context_loaders/",
|
|
18
|
+
"token_optimization/",
|
|
19
|
+
"quickstart.sh",
|
|
20
|
+
"quickstart.ps1",
|
|
21
|
+
"requirements.txt"
|
|
22
|
+
],
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=16"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"ai",
|
|
28
|
+
"agents",
|
|
29
|
+
"llm",
|
|
30
|
+
"multi-agent",
|
|
31
|
+
"prompt-engineering",
|
|
32
|
+
"claude",
|
|
33
|
+
"openai",
|
|
34
|
+
"cursor",
|
|
35
|
+
"copilot"
|
|
36
|
+
],
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://github.com/Prateek-N/Multi-Agent-Stack"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/Prateek-N/Multi-Agent-Stack#readme",
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/Prateek-N/Multi-Agent-Stack/issues"
|
|
45
|
+
}
|
|
46
|
+
}
|