@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,454 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
init_project.py — One-time project bootstrap for agents-maker Companion Mode.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
python agents-maker/tools/init_project.py
|
|
7
|
+
python agents-maker/tools/init_project.py --path /your/project
|
|
8
|
+
python agents-maker/tools/init_project.py --update # regenerate system_prompt.md
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
import hashlib
|
|
15
|
+
import os
|
|
16
|
+
import sys
|
|
17
|
+
import tempfile
|
|
18
|
+
from datetime import date
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
# ---------------------------------------------------------------------------
|
|
22
|
+
# Path setup — allow imports from context_loaders and config
|
|
23
|
+
# ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
__version__ = "1.0.0"
|
|
26
|
+
|
|
27
|
+
SCRIPT_DIR = Path(__file__).resolve().parent # agents-maker/tools/
|
|
28
|
+
KIT_DIR = SCRIPT_DIR.parent # agents-maker/
|
|
29
|
+
sys.path.insert(0, str(KIT_DIR))
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
import yaml
|
|
33
|
+
except ImportError:
|
|
34
|
+
print("[ERROR] pyyaml is required: pip install pyyaml", file=sys.stderr)
|
|
35
|
+
sys.exit(1)
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
from context_loaders.project_summary import build_summary
|
|
39
|
+
from context_loaders.repo_tree import walk_tree
|
|
40
|
+
except ImportError as e:
|
|
41
|
+
print(f"[ERROR] Could not import context_loaders: {e}", file=sys.stderr)
|
|
42
|
+
print("[ERROR] Make sure you're running from the project root and agents-maker/ is present.", file=sys.stderr)
|
|
43
|
+
sys.exit(1)
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
from tools.domain_utils import _load_yaml
|
|
47
|
+
from tools.domain_utils import detect_domain as _detect_domain
|
|
48
|
+
except ImportError:
|
|
49
|
+
from domain_utils import _load_yaml
|
|
50
|
+
from domain_utils import detect_domain as _detect_domain
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def detect_domain(summary_text: str) -> tuple[str, str]:
|
|
54
|
+
return _detect_domain(summary_text, kit_dir=KIT_DIR) # type: ignore[return-value]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def detect_stack_from_summary(summary_text: str) -> list[str]:
|
|
58
|
+
for line in summary_text.splitlines():
|
|
59
|
+
if line.startswith("**Stack**:"):
|
|
60
|
+
parts = line.split(":", 1)[1].strip()
|
|
61
|
+
if parts and parts != "Unknown":
|
|
62
|
+
return [p.strip() for p in parts.split(",") if p.strip()]
|
|
63
|
+
return []
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# ---------------------------------------------------------------------------
|
|
67
|
+
# YAML injection guard — reject strings with characters that break yaml.dump
|
|
68
|
+
# ---------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
_YAML_UNSAFE = frozenset({'"', "'", ':', '!', '{', '}', '[', ']', '\\', '\n', '\r'})
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _sanitize_yaml_str(value: str, field: str) -> str:
|
|
74
|
+
bad = [c for c in value if c in _YAML_UNSAFE]
|
|
75
|
+
if bad:
|
|
76
|
+
safe = "".join(c for c in value if c not in _YAML_UNSAFE)
|
|
77
|
+
print(
|
|
78
|
+
f"[WARN] {field!r} contained unsafe YAML characters {sorted(set(bad))} — stripped.",
|
|
79
|
+
file=sys.stderr,
|
|
80
|
+
)
|
|
81
|
+
return safe
|
|
82
|
+
return value
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# ---------------------------------------------------------------------------
|
|
86
|
+
# Source hash — lets validate_kit.py detect stale system_prompt.md
|
|
87
|
+
# ---------------------------------------------------------------------------
|
|
88
|
+
|
|
89
|
+
def _compute_source_hash(kit_dir: Path) -> str:
|
|
90
|
+
h = hashlib.sha256()
|
|
91
|
+
agent_files = sorted((kit_dir / "agents").glob("*.md")) if (kit_dir / "agents").is_dir() else []
|
|
92
|
+
skill_files = sorted((kit_dir / "skills").glob("*.md")) if (kit_dir / "skills").is_dir() else []
|
|
93
|
+
for path in agent_files + skill_files:
|
|
94
|
+
try:
|
|
95
|
+
h.update(path.read_bytes().replace(b"\r\n", b"\n"))
|
|
96
|
+
except (OSError, PermissionError):
|
|
97
|
+
pass
|
|
98
|
+
return h.hexdigest()[:16]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# ---------------------------------------------------------------------------
|
|
102
|
+
# Atomic write helpers (write to temp then os.replace — crash-safe)
|
|
103
|
+
# ---------------------------------------------------------------------------
|
|
104
|
+
|
|
105
|
+
def _atomic_write_text(path: Path, content: str) -> None:
|
|
106
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
107
|
+
with tempfile.NamedTemporaryFile(
|
|
108
|
+
"w", dir=path.parent, delete=False, suffix=".tmp", encoding="utf-8"
|
|
109
|
+
) as f:
|
|
110
|
+
f.write(content)
|
|
111
|
+
tmp = f.name
|
|
112
|
+
os.replace(tmp, path)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _atomic_write_yaml(path: Path, data: dict) -> None:
|
|
116
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
117
|
+
with tempfile.NamedTemporaryFile(
|
|
118
|
+
"w", dir=path.parent, delete=False, suffix=".tmp", encoding="utf-8"
|
|
119
|
+
) as f:
|
|
120
|
+
yaml.dump(data, f, default_flow_style=False, allow_unicode=True, sort_keys=False)
|
|
121
|
+
tmp = f.name
|
|
122
|
+
os.replace(tmp, path)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# ---------------------------------------------------------------------------
|
|
126
|
+
# system_prompt.md builder
|
|
127
|
+
# ---------------------------------------------------------------------------
|
|
128
|
+
|
|
129
|
+
def build_system_prompt(project_name: str, domain: str, stack: list[str]) -> str:
|
|
130
|
+
agents_dir = KIT_DIR / "agents"
|
|
131
|
+
agent_order = [
|
|
132
|
+
"orchestrator.md",
|
|
133
|
+
"architect_agent.md",
|
|
134
|
+
"code_agent.md",
|
|
135
|
+
"execution_agent.md",
|
|
136
|
+
"ui_agent.md",
|
|
137
|
+
"ux_agent.md",
|
|
138
|
+
"reviewer_agent.md",
|
|
139
|
+
"compression_agent.md",
|
|
140
|
+
]
|
|
141
|
+
skill_count = len(list((KIT_DIR / "skills").glob("*.md"))) if (KIT_DIR / "skills").exists() else 0
|
|
142
|
+
source_hash = _compute_source_hash(KIT_DIR)
|
|
143
|
+
version_header = (
|
|
144
|
+
f"# agents-maker system_prompt.md\n"
|
|
145
|
+
f"# Version: 1.0 | Generated: {date.today().isoformat()} | Source hash: {source_hash}\n"
|
|
146
|
+
f"# Regenerate: python agents-maker/tools/init_project.py --update\n"
|
|
147
|
+
f"# Contains: {len(agent_order)} agents + {skill_count} skills\n"
|
|
148
|
+
f"#\n"
|
|
149
|
+
f"# [Companion] INSTRUCTION (always active):\n"
|
|
150
|
+
f"# After every response append a [Companion] block:\n"
|
|
151
|
+
f"# ---\n"
|
|
152
|
+
f"# [Companion] Phase: <phase> | Domain: <domain> | Est. token budget used: ~N%\n"
|
|
153
|
+
f"# What to do next (pick one):\n"
|
|
154
|
+
f"# [Recommended] A: <action> Command: python agents-maker/tools/generate_prompt.py \"...\"\n"
|
|
155
|
+
f"# B: <action>\n"
|
|
156
|
+
f"# C: <action>\n"
|
|
157
|
+
f"# ---\n"
|
|
158
|
+
)
|
|
159
|
+
sections: list[str] = [version_header]
|
|
160
|
+
|
|
161
|
+
for fname in agent_order:
|
|
162
|
+
fpath = agents_dir / fname
|
|
163
|
+
if fpath.exists():
|
|
164
|
+
try:
|
|
165
|
+
content = fpath.read_text(encoding="utf-8").strip()
|
|
166
|
+
sections.append(content)
|
|
167
|
+
sections.append("---")
|
|
168
|
+
except (PermissionError, OSError) as e:
|
|
169
|
+
print(f"[WARN] Could not read {fpath}: {e}", file=sys.stderr)
|
|
170
|
+
|
|
171
|
+
skills_dir = KIT_DIR / "skills"
|
|
172
|
+
if skills_dir.exists():
|
|
173
|
+
for skill_file in sorted(skills_dir.glob("*.md")):
|
|
174
|
+
try:
|
|
175
|
+
content = skill_file.read_text(encoding="utf-8").strip()
|
|
176
|
+
sections.append(content)
|
|
177
|
+
sections.append("---")
|
|
178
|
+
except (PermissionError, OSError) as e:
|
|
179
|
+
print(f"[WARN] Could not read {skill_file}: {e}", file=sys.stderr)
|
|
180
|
+
|
|
181
|
+
stack_str = ", ".join(stack) if stack else "unknown"
|
|
182
|
+
context_block = (
|
|
183
|
+
f"## Project Context\n\n"
|
|
184
|
+
f"Project name: {project_name} \n"
|
|
185
|
+
f"Primary domain: {domain} \n"
|
|
186
|
+
f"Stack: {stack_str} \n"
|
|
187
|
+
f"Initialized: {date.today().isoformat()} \n"
|
|
188
|
+
)
|
|
189
|
+
sections.append(context_block)
|
|
190
|
+
|
|
191
|
+
return "\n\n".join(sections)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
# ---------------------------------------------------------------------------
|
|
195
|
+
# project_state.md template
|
|
196
|
+
# ---------------------------------------------------------------------------
|
|
197
|
+
|
|
198
|
+
STATE_TEMPLATE = """\
|
|
199
|
+
# Project State
|
|
200
|
+
schema_version: "1.0"
|
|
201
|
+
|
|
202
|
+
## Current Phase
|
|
203
|
+
task_framing
|
|
204
|
+
|
|
205
|
+
## Domain
|
|
206
|
+
(detected at init — override here if needed)
|
|
207
|
+
|
|
208
|
+
## Approved Artifacts
|
|
209
|
+
(none yet)
|
|
210
|
+
|
|
211
|
+
## Open Decisions
|
|
212
|
+
(none yet)
|
|
213
|
+
|
|
214
|
+
## Build Log
|
|
215
|
+
(empty)
|
|
216
|
+
|
|
217
|
+
## Session Notes
|
|
218
|
+
(add notes after each session)
|
|
219
|
+
"""
|
|
220
|
+
|
|
221
|
+
VALID_DOMAINS = [
|
|
222
|
+
"software", "content", "research", "data_analytics",
|
|
223
|
+
"product_design", "marketing", "ops_process", "general",
|
|
224
|
+
]
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
# ---------------------------------------------------------------------------
|
|
228
|
+
# Main
|
|
229
|
+
# ---------------------------------------------------------------------------
|
|
230
|
+
|
|
231
|
+
def main() -> None:
|
|
232
|
+
sys.stdout.reconfigure(encoding="utf-8")
|
|
233
|
+
|
|
234
|
+
parser = argparse.ArgumentParser(
|
|
235
|
+
description="Bootstrap agents-maker Companion Mode for a project.",
|
|
236
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
237
|
+
epilog=(
|
|
238
|
+
"Examples:\n"
|
|
239
|
+
" python agents-maker/tools/init_project.py\n"
|
|
240
|
+
" python agents-maker/tools/init_project.py --path /my/project\n"
|
|
241
|
+
" python agents-maker/tools/init_project.py --update # regenerate system_prompt.md\n"
|
|
242
|
+
),
|
|
243
|
+
)
|
|
244
|
+
parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
|
|
245
|
+
parser.add_argument(
|
|
246
|
+
"--path",
|
|
247
|
+
help="Project root directory (default: parent of agents-maker/)",
|
|
248
|
+
)
|
|
249
|
+
parser.add_argument(
|
|
250
|
+
"--update",
|
|
251
|
+
action="store_true",
|
|
252
|
+
help="Regenerate system_prompt.md even if it already exists.",
|
|
253
|
+
)
|
|
254
|
+
parser.add_argument(
|
|
255
|
+
"--claude-md",
|
|
256
|
+
action="store_true",
|
|
257
|
+
help="Also generate CLAUDE.md in the project root (Claude Code integration).",
|
|
258
|
+
)
|
|
259
|
+
parser.add_argument(
|
|
260
|
+
"--platforms",
|
|
261
|
+
action="store_true",
|
|
262
|
+
help=(
|
|
263
|
+
"Generate config files for ALL supported platforms: "
|
|
264
|
+
"Claude Code (CLAUDE.md), GitHub Copilot (.github/copilot-instructions.md), "
|
|
265
|
+
"Cursor (.cursor/rules), Antigravity (.agkit/agents.yaml). "
|
|
266
|
+
"Supersedes --claude-md."
|
|
267
|
+
),
|
|
268
|
+
)
|
|
269
|
+
args = parser.parse_args()
|
|
270
|
+
|
|
271
|
+
# Resolve project root
|
|
272
|
+
if args.path:
|
|
273
|
+
project_root = Path(args.path).resolve()
|
|
274
|
+
else:
|
|
275
|
+
project_root = KIT_DIR.parent
|
|
276
|
+
|
|
277
|
+
if not project_root.exists():
|
|
278
|
+
print(f"[ERROR] Project root does not exist: {project_root}", file=sys.stderr)
|
|
279
|
+
sys.exit(1)
|
|
280
|
+
if not project_root.is_dir():
|
|
281
|
+
print(f"[ERROR] Path is not a directory: {project_root}", file=sys.stderr)
|
|
282
|
+
sys.exit(1)
|
|
283
|
+
|
|
284
|
+
project_name = project_root.name
|
|
285
|
+
print(f"\nInitializing agents-maker for: {project_root}")
|
|
286
|
+
print("-" * 60)
|
|
287
|
+
|
|
288
|
+
# Step 1 — Scan project
|
|
289
|
+
print("Scanning project...")
|
|
290
|
+
try:
|
|
291
|
+
summary_text = build_summary(project_root)
|
|
292
|
+
walk_tree(project_root, max_depth=3, show_all=False)
|
|
293
|
+
except Exception as e:
|
|
294
|
+
print(f"[WARN] Project scan encountered an error: {e}", file=sys.stderr)
|
|
295
|
+
summary_text = ""
|
|
296
|
+
|
|
297
|
+
# Step 2 — Detect domain
|
|
298
|
+
detected_domain, confidence = detect_domain(summary_text)
|
|
299
|
+
stack = detect_stack_from_summary(summary_text)
|
|
300
|
+
|
|
301
|
+
print(f"Detected domain : {detected_domain} (confidence: {confidence})")
|
|
302
|
+
print(f"Detected stack : {', '.join(stack) if stack else 'unknown'}")
|
|
303
|
+
|
|
304
|
+
# Step 3 — Confirm or override domain
|
|
305
|
+
print(f"\nValid domains: {', '.join(VALID_DOMAINS)}")
|
|
306
|
+
try:
|
|
307
|
+
user_input = input(
|
|
308
|
+
f"Press Enter to accept '{detected_domain}', or type a domain to override: "
|
|
309
|
+
).strip().lower()
|
|
310
|
+
except (EOFError, KeyboardInterrupt):
|
|
311
|
+
user_input = ""
|
|
312
|
+
|
|
313
|
+
# Validate user input strictly
|
|
314
|
+
if not user_input:
|
|
315
|
+
final_domain = detected_domain
|
|
316
|
+
elif len(user_input) > 50:
|
|
317
|
+
print(f"[WARN] Input too long — keeping '{detected_domain}'", file=sys.stderr)
|
|
318
|
+
final_domain = detected_domain
|
|
319
|
+
elif not user_input.replace("_", "").isalpha():
|
|
320
|
+
print(f"[WARN] Invalid domain name (letters and underscores only) — keeping '{detected_domain}'", file=sys.stderr)
|
|
321
|
+
final_domain = detected_domain
|
|
322
|
+
elif user_input in VALID_DOMAINS:
|
|
323
|
+
final_domain = user_input
|
|
324
|
+
print(f"Using domain: {final_domain}")
|
|
325
|
+
else:
|
|
326
|
+
print(f"[WARN] '{user_input}' is not a recognized domain — keeping '{detected_domain}'", file=sys.stderr)
|
|
327
|
+
final_domain = detected_domain
|
|
328
|
+
|
|
329
|
+
# Step 4 — Write config/project.yaml
|
|
330
|
+
config_dir = KIT_DIR / "config"
|
|
331
|
+
config_dir.mkdir(parents=True, exist_ok=True)
|
|
332
|
+
project_yaml_path = config_dir / "project.yaml"
|
|
333
|
+
|
|
334
|
+
# Preserve session_count if updating
|
|
335
|
+
existing_cfg = _load_yaml(project_yaml_path)
|
|
336
|
+
session_count = existing_cfg.get("session_count", 0) if args.update else 0
|
|
337
|
+
created_at = existing_cfg.get("created_at", date.today().isoformat()) if args.update else date.today().isoformat()
|
|
338
|
+
|
|
339
|
+
safe_name = _sanitize_yaml_str(project_name, "project_name")
|
|
340
|
+
safe_stack = [_sanitize_yaml_str(s, f"stack[{i}]") for i, s in enumerate(stack)]
|
|
341
|
+
|
|
342
|
+
project_cfg = {
|
|
343
|
+
"project_name": safe_name,
|
|
344
|
+
"created_at": created_at,
|
|
345
|
+
"primary_domain": final_domain,
|
|
346
|
+
"stack": safe_stack,
|
|
347
|
+
"key_constraints": existing_cfg.get("key_constraints", []) if args.update else [],
|
|
348
|
+
"session_count": session_count,
|
|
349
|
+
"last_session": existing_cfg.get("last_session") if args.update else None,
|
|
350
|
+
}
|
|
351
|
+
try:
|
|
352
|
+
_atomic_write_yaml(project_yaml_path, project_cfg)
|
|
353
|
+
except OSError as e:
|
|
354
|
+
print(f"[ERROR] Could not write project.yaml: {e}", file=sys.stderr)
|
|
355
|
+
sys.exit(1)
|
|
356
|
+
|
|
357
|
+
# Step 5 — Generate system_prompt.md
|
|
358
|
+
system_prompt_path = KIT_DIR / "system_prompt.md"
|
|
359
|
+
if not system_prompt_path.exists() or args.update:
|
|
360
|
+
system_prompt_text = build_system_prompt(project_name, final_domain, stack)
|
|
361
|
+
try:
|
|
362
|
+
_atomic_write_text(system_prompt_path, system_prompt_text)
|
|
363
|
+
except OSError as e:
|
|
364
|
+
print(f"[ERROR] Could not write system_prompt.md: {e}", file=sys.stderr)
|
|
365
|
+
sys.exit(1)
|
|
366
|
+
char_count = len(system_prompt_text)
|
|
367
|
+
token_estimate = char_count // 4
|
|
368
|
+
system_prompt_status = f"(~{char_count:,} chars, ~{token_estimate:,} tokens)"
|
|
369
|
+
system_prompt_done = True
|
|
370
|
+
else:
|
|
371
|
+
system_prompt_status = "(already exists — use --update to regenerate)"
|
|
372
|
+
system_prompt_done = False
|
|
373
|
+
|
|
374
|
+
# Step 6 — Create project_state.md if absent
|
|
375
|
+
state_path = KIT_DIR / "project_state.md"
|
|
376
|
+
if not state_path.exists():
|
|
377
|
+
try:
|
|
378
|
+
_atomic_write_text(state_path, STATE_TEMPLATE)
|
|
379
|
+
state_created = True
|
|
380
|
+
except OSError as e:
|
|
381
|
+
print(f"[ERROR] Could not write project_state.md: {e}", file=sys.stderr)
|
|
382
|
+
sys.exit(1)
|
|
383
|
+
else:
|
|
384
|
+
state_created = False
|
|
385
|
+
|
|
386
|
+
# Step 7 — Print summary
|
|
387
|
+
print()
|
|
388
|
+
print("=" * 60)
|
|
389
|
+
try:
|
|
390
|
+
print(f" [DONE] {project_yaml_path.relative_to(KIT_DIR.parent)}")
|
|
391
|
+
tag = "[DONE]" if system_prompt_done else "[SKIP]"
|
|
392
|
+
print(f" {tag} {system_prompt_path.relative_to(KIT_DIR.parent)} {system_prompt_status}")
|
|
393
|
+
if state_created:
|
|
394
|
+
print(f" [DONE] {state_path.relative_to(KIT_DIR.parent)} (template created)")
|
|
395
|
+
else:
|
|
396
|
+
print(" [SKIP] project_state.md (already exists — not overwritten)")
|
|
397
|
+
except ValueError:
|
|
398
|
+
print(f" [DONE] {project_yaml_path}")
|
|
399
|
+
print(f" [DONE] {system_prompt_path}")
|
|
400
|
+
print("=" * 60)
|
|
401
|
+
print()
|
|
402
|
+
print("Next: Paste system_prompt.md into your AI tool as the system prompt (do this once).")
|
|
403
|
+
print('Then: python agents-maker/tools/generate_prompt.py "your first task"')
|
|
404
|
+
print()
|
|
405
|
+
|
|
406
|
+
# --platforms: generate configs for all supported AI platforms
|
|
407
|
+
if args.platforms:
|
|
408
|
+
try:
|
|
409
|
+
from tools.generate_platform_configs import PLATFORMS, generate_all
|
|
410
|
+
except ImportError:
|
|
411
|
+
from generate_platform_configs import PLATFORMS, generate_all
|
|
412
|
+
print("Generating platform configs (Claude Code, Copilot, Cursor, Antigravity)...")
|
|
413
|
+
generate_all(project_root, KIT_DIR, PLATFORMS, dry_run=False)
|
|
414
|
+
|
|
415
|
+
# --claude-md: generate CLAUDE.md only (kept for backward compatibility)
|
|
416
|
+
elif args.claude_md:
|
|
417
|
+
try:
|
|
418
|
+
from tools.generate_claude_md import _parse_phase, build_claude_md
|
|
419
|
+
except ImportError:
|
|
420
|
+
from generate_claude_md import _parse_phase, build_claude_md
|
|
421
|
+
|
|
422
|
+
state_path = KIT_DIR / "project_state.md"
|
|
423
|
+
phase = _parse_phase(state_path.read_text(encoding="utf-8")) if state_path.exists() else "task_framing"
|
|
424
|
+
try:
|
|
425
|
+
kit_rel = KIT_DIR.relative_to(project_root)
|
|
426
|
+
kit_rel_path = str(kit_rel).replace("\\", "/")
|
|
427
|
+
except ValueError:
|
|
428
|
+
kit_rel_path = "agents-maker"
|
|
429
|
+
|
|
430
|
+
claude_md_content = build_claude_md(
|
|
431
|
+
project_name=project_name,
|
|
432
|
+
domain=final_domain,
|
|
433
|
+
confidence="high",
|
|
434
|
+
stack=stack,
|
|
435
|
+
phase=phase,
|
|
436
|
+
kit_rel_path=kit_rel_path,
|
|
437
|
+
)
|
|
438
|
+
claude_md_path = project_root / "CLAUDE.md"
|
|
439
|
+
try:
|
|
440
|
+
_atomic_write_text(claude_md_path, claude_md_content)
|
|
441
|
+
print(f" [DONE] CLAUDE.md written to {claude_md_path}")
|
|
442
|
+
print(" Claude Code will auto-load domain/phase/stack on every session.")
|
|
443
|
+
print(" Commit CLAUDE.md to git — it is project config, not private state.")
|
|
444
|
+
except OSError as e:
|
|
445
|
+
print(f" [WARN] Could not write CLAUDE.md: {e}", file=sys.stderr)
|
|
446
|
+
print()
|
|
447
|
+
else:
|
|
448
|
+
print("Tip: Wire agents-maker into Claude Code, Copilot, Cursor, and Antigravity:")
|
|
449
|
+
print(" python agents-maker/tools/generate_platform_configs.py")
|
|
450
|
+
print()
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
if __name__ == "__main__":
|
|
454
|
+
main()
|