@pjmendonca/devflow 1.9.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/CHANGELOG.md +526 -0
- package/LICENSE +21 -0
- package/README.md +620 -0
- package/bin/devflow-checkpoint.js +10 -0
- package/bin/devflow-collab.js +10 -0
- package/bin/devflow-cost.js +10 -0
- package/bin/devflow-create-persona.js +10 -0
- package/bin/devflow-init.js +10 -0
- package/bin/devflow-memory.js +10 -0
- package/bin/devflow-new-doc.js +10 -0
- package/bin/devflow-personalize.js +10 -0
- package/bin/devflow-setup-checkpoint.js +10 -0
- package/bin/devflow-story.js +10 -0
- package/bin/devflow-tech-debt.js +10 -0
- package/bin/devflow-validate-overrides.js +10 -0
- package/bin/devflow-validate.js +10 -0
- package/bin/devflow-version.js +10 -0
- package/lib/constants.js +30 -0
- package/lib/exec-python.js +78 -0
- package/lib/python-check.js +178 -0
- package/package.json +64 -0
- package/tooling/.automation/agents/architect.md +135 -0
- package/tooling/.automation/agents/ba.md +70 -0
- package/tooling/.automation/agents/dev.md +79 -0
- package/tooling/.automation/agents/maintainer.md +97 -0
- package/tooling/.automation/agents/pm.md +116 -0
- package/tooling/.automation/agents/reviewer.md +141 -0
- package/tooling/.automation/agents/sm.md +61 -0
- package/tooling/.automation/agents/writer.md +193 -0
- package/tooling/.automation/config.ps1.template +61 -0
- package/tooling/.automation/config.sh.template +48 -0
- package/tooling/.automation/memory/.gitkeep +6 -0
- package/tooling/.automation/memory/knowledge/kg_integration-test.json +94 -0
- package/tooling/.automation/memory/knowledge/kg_test-story.json +300 -0
- package/tooling/.automation/memory/shared/shared_integration-test.json +30 -0
- package/tooling/.automation/memory/shared/shared_test-story.json +78 -0
- package/tooling/.automation/overrides/templates/README.md +113 -0
- package/tooling/.automation/overrides/templates/architect/README.md +27 -0
- package/tooling/.automation/overrides/templates/architect/cloud-native.yaml +92 -0
- package/tooling/.automation/overrides/templates/architect/enterprise-architect.yaml +85 -0
- package/tooling/.automation/overrides/templates/architect/pragmatic-minimalist.yaml +88 -0
- package/tooling/.automation/overrides/templates/ba/README.md +27 -0
- package/tooling/.automation/overrides/templates/ba/agile-storyteller.yaml +86 -0
- package/tooling/.automation/overrides/templates/ba/domain-expert.yaml +91 -0
- package/tooling/.automation/overrides/templates/ba/requirements-engineer.yaml +89 -0
- package/tooling/.automation/overrides/templates/dev/README.md +32 -0
- package/tooling/.automation/overrides/templates/dev/junior-mentored.yaml +39 -0
- package/tooling/.automation/overrides/templates/dev/performance-engineer.yaml +43 -0
- package/tooling/.automation/overrides/templates/dev/rapid-prototyper.yaml +52 -0
- package/tooling/.automation/overrides/templates/dev/security-focused.yaml +43 -0
- package/tooling/.automation/overrides/templates/dev/senior-fullstack.yaml +39 -0
- package/tooling/.automation/overrides/templates/maintainer/README.md +27 -0
- package/tooling/.automation/overrides/templates/maintainer/devops-maintainer.yaml +113 -0
- package/tooling/.automation/overrides/templates/maintainer/legacy-steward.yaml +94 -0
- package/tooling/.automation/overrides/templates/maintainer/oss-maintainer.yaml +94 -0
- package/tooling/.automation/overrides/templates/pm/README.md +27 -0
- package/tooling/.automation/overrides/templates/pm/agile-pm.yaml +91 -0
- package/tooling/.automation/overrides/templates/pm/hybrid-delivery.yaml +87 -0
- package/tooling/.automation/overrides/templates/pm/traditional-pm.yaml +91 -0
- package/tooling/.automation/overrides/templates/reviewer/README.md +11 -0
- package/tooling/.automation/overrides/templates/reviewer/mentoring-reviewer.yaml +45 -0
- package/tooling/.automation/overrides/templates/reviewer/quick-sanity.yaml +50 -0
- package/tooling/.automation/overrides/templates/reviewer/thorough-critic.yaml +48 -0
- package/tooling/.automation/overrides/templates/sm/README.md +11 -0
- package/tooling/.automation/overrides/templates/sm/agile-coach.yaml +52 -0
- package/tooling/.automation/overrides/templates/sm/startup-pm.yaml +50 -0
- package/tooling/.automation/overrides/templates/sm/technical-lead.yaml +47 -0
- package/tooling/.automation/overrides/templates/user-profile.template.yaml +62 -0
- package/tooling/.automation/overrides/templates/writer/README.md +27 -0
- package/tooling/.automation/overrides/templates/writer/api-documentarian.yaml +99 -0
- package/tooling/.automation/overrides/templates/writer/docs-as-code.yaml +108 -0
- package/tooling/.automation/overrides/templates/writer/user-guide-author.yaml +100 -0
- package/tooling/completions/DevflowCompletion.ps1 +213 -0
- package/tooling/completions/_run-story +116 -0
- package/tooling/completions/run-story-completion.bash +136 -0
- package/tooling/docs/DOC-STANDARD.md +717 -0
- package/tooling/docs/sprint-status.yaml.template +24 -0
- package/tooling/docs/templates/bug-report.md +234 -0
- package/tooling/docs/templates/migration-spec.md +274 -0
- package/tooling/docs/templates/refactor-spec.md +86 -0
- package/tooling/docs/templates/tech-debt.md +86 -0
- package/tooling/scripts/context_checkpoint.py +556 -0
- package/tooling/scripts/cost_dashboard.py +617 -0
- package/tooling/scripts/create-persona.py +690 -0
- package/tooling/scripts/create-persona.sh +435 -0
- package/tooling/scripts/init-project-workflow.ps1 +651 -0
- package/tooling/scripts/init-project-workflow.py +70 -0
- package/tooling/scripts/init-project-workflow.sh +746 -0
- package/tooling/scripts/lib/__init__.py +35 -0
- package/tooling/scripts/lib/agent_handoff.py +526 -0
- package/tooling/scripts/lib/agent_router.py +698 -0
- package/tooling/scripts/lib/checkpoint-integration.ps1 +245 -0
- package/tooling/scripts/lib/checkpoint-integration.sh +191 -0
- package/tooling/scripts/lib/claude-cli.ps1 +952 -0
- package/tooling/scripts/lib/claude-cli.sh +1293 -0
- package/tooling/scripts/lib/cost_config.py +222 -0
- package/tooling/scripts/lib/cost_display.py +443 -0
- package/tooling/scripts/lib/cost_tracker.py +710 -0
- package/tooling/scripts/lib/currency_converter.py +328 -0
- package/tooling/scripts/lib/errors.py +438 -0
- package/tooling/scripts/lib/override-loader.sh +286 -0
- package/tooling/scripts/lib/pair_programming.py +589 -0
- package/tooling/scripts/lib/shared_memory.py +637 -0
- package/tooling/scripts/lib/swarm_orchestrator.py +689 -0
- package/tooling/scripts/memory_summarize.py +324 -0
- package/tooling/scripts/new-doc.ps1 +405 -0
- package/tooling/scripts/new-doc.py +93 -0
- package/tooling/scripts/new-doc.sh +534 -0
- package/tooling/scripts/personalize_agent.py +385 -0
- package/tooling/scripts/rollback-migration.sh +540 -0
- package/tooling/scripts/run-collab.ps1 +251 -0
- package/tooling/scripts/run-collab.py +605 -0
- package/tooling/scripts/run-collab.sh +110 -0
- package/tooling/scripts/run-story.ps1 +490 -0
- package/tooling/scripts/run-story.py +387 -0
- package/tooling/scripts/run-story.sh +467 -0
- package/tooling/scripts/setup-checkpoint-service.ps1 +219 -0
- package/tooling/scripts/setup-checkpoint-service.py +87 -0
- package/tooling/scripts/setup-checkpoint-service.sh +236 -0
- package/tooling/scripts/tech-debt-tracker.py +608 -0
- package/tooling/scripts/update_version.py +244 -0
- package/tooling/scripts/validate-overrides.py +511 -0
- package/tooling/scripts/validate-overrides.sh +432 -0
- package/tooling/scripts/validate_setup.py +539 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Agent Personalization Wizard
|
|
4
|
+
|
|
5
|
+
Interactive wizard to customize agent personas and create override files.
|
|
6
|
+
Guides users through selecting templates and customizing settings.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
python3 personalize_agent.py [agent_name]
|
|
10
|
+
python3 personalize_agent.py # Interactive selection
|
|
11
|
+
python3 personalize_agent.py dev # Personalize dev agent
|
|
12
|
+
python3 personalize_agent.py --all # Personalize all agents
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import shutil
|
|
17
|
+
import sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Optional
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# Colors for terminal output
|
|
23
|
+
class Colors:
|
|
24
|
+
HEADER = "\033[95m"
|
|
25
|
+
BLUE = "\033[94m"
|
|
26
|
+
CYAN = "\033[96m"
|
|
27
|
+
GREEN = "\033[92m"
|
|
28
|
+
YELLOW = "\033[93m"
|
|
29
|
+
RED = "\033[91m"
|
|
30
|
+
END = "\033[0m"
|
|
31
|
+
BOLD = "\033[1m"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# Find project paths
|
|
35
|
+
SCRIPT_DIR = Path(__file__).parent.resolve()
|
|
36
|
+
PROJECT_ROOT = SCRIPT_DIR.parent.parent
|
|
37
|
+
OVERRIDES_DIR = PROJECT_ROOT / ".automation" / "overrides"
|
|
38
|
+
TEMPLATES_DIR = OVERRIDES_DIR / "templates"
|
|
39
|
+
AGENTS_DIR = PROJECT_ROOT / ".automation" / "agents"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def print_banner():
|
|
43
|
+
"""Print the wizard banner."""
|
|
44
|
+
print(f"""
|
|
45
|
+
{Colors.CYAN}╔═══════════════════════════════════════════════════════════════╗
|
|
46
|
+
║ AGENT PERSONALIZATION WIZARD ║
|
|
47
|
+
╠═══════════════════════════════════════════════════════════════╣
|
|
48
|
+
║ Customize your AI agents for your project and preferences ║
|
|
49
|
+
╚═══════════════════════════════════════════════════════════════╝{Colors.END}
|
|
50
|
+
""")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def print_step(step_num: int, title: str):
|
|
54
|
+
"""Print a step header."""
|
|
55
|
+
print(f"\n{Colors.BOLD}{Colors.BLUE}═══ Step {step_num}: {title} ═══{Colors.END}\n")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def get_available_agents() -> list[str]:
|
|
59
|
+
"""Get list of available agents."""
|
|
60
|
+
agents = []
|
|
61
|
+
if AGENTS_DIR.exists():
|
|
62
|
+
for file in AGENTS_DIR.glob("*.md"):
|
|
63
|
+
agents.append(file.stem)
|
|
64
|
+
return sorted(agents)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def get_agent_templates(agent_name: str) -> list[dict]:
|
|
68
|
+
"""Get available templates for an agent."""
|
|
69
|
+
templates = []
|
|
70
|
+
agent_template_dir = TEMPLATES_DIR / agent_name
|
|
71
|
+
|
|
72
|
+
if agent_template_dir.exists():
|
|
73
|
+
for file in agent_template_dir.glob("*.yaml"):
|
|
74
|
+
if file.name != "README.md":
|
|
75
|
+
# Read first few lines to get description
|
|
76
|
+
content = file.read_text()
|
|
77
|
+
first_line = content.split("\n")[0].replace("#", "").strip()
|
|
78
|
+
templates.append({"name": file.stem, "path": file, "description": first_line})
|
|
79
|
+
|
|
80
|
+
return templates
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def prompt_choice(prompt: str, options: list[str], default: int = 0) -> int:
|
|
84
|
+
"""Prompt user to choose from options."""
|
|
85
|
+
print(f"{Colors.YELLOW}{prompt}{Colors.END}")
|
|
86
|
+
for i, opt in enumerate(options):
|
|
87
|
+
marker = "→" if i == default else " "
|
|
88
|
+
print(f" {marker} [{i + 1}] {opt}")
|
|
89
|
+
|
|
90
|
+
while True:
|
|
91
|
+
try:
|
|
92
|
+
response = input(
|
|
93
|
+
f"\nEnter choice [1-{len(options)}] (default: {default + 1}): "
|
|
94
|
+
).strip()
|
|
95
|
+
if not response:
|
|
96
|
+
return default
|
|
97
|
+
choice = int(response) - 1
|
|
98
|
+
if 0 <= choice < len(options):
|
|
99
|
+
return choice
|
|
100
|
+
print(f"{Colors.RED}Please enter a number between 1 and {len(options)}{Colors.END}")
|
|
101
|
+
except ValueError:
|
|
102
|
+
print(f"{Colors.RED}Please enter a valid number{Colors.END}")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def prompt_yes_no(prompt: str, default: bool = True) -> bool:
|
|
106
|
+
"""Prompt for yes/no answer."""
|
|
107
|
+
default_str = "Y/n" if default else "y/N"
|
|
108
|
+
response = input(f"{Colors.YELLOW}{prompt} [{default_str}]: {Colors.END}").strip().lower()
|
|
109
|
+
if not response:
|
|
110
|
+
return default
|
|
111
|
+
return response in ("y", "yes")
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def prompt_input(prompt: str, default: str = "") -> str:
|
|
115
|
+
"""Prompt for text input."""
|
|
116
|
+
if default:
|
|
117
|
+
response = input(
|
|
118
|
+
f"{Colors.YELLOW}{prompt}{Colors.END} [{Colors.BLUE}{default}{Colors.END}]: "
|
|
119
|
+
).strip()
|
|
120
|
+
return response if response else default
|
|
121
|
+
return input(f"{Colors.YELLOW}{prompt}: {Colors.END}").strip()
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def prompt_list(prompt: str, existing: list[str] = None) -> list[str]:
|
|
125
|
+
"""Prompt for a list of items."""
|
|
126
|
+
print(f"{Colors.YELLOW}{prompt}{Colors.END}")
|
|
127
|
+
print(f"{Colors.CYAN}(Enter items one per line, empty line to finish){Colors.END}")
|
|
128
|
+
|
|
129
|
+
if existing:
|
|
130
|
+
print("\nCurrent items:")
|
|
131
|
+
for item in existing:
|
|
132
|
+
print(f" - {item}")
|
|
133
|
+
if not prompt_yes_no("Keep these items?", default=True):
|
|
134
|
+
existing = []
|
|
135
|
+
|
|
136
|
+
items = existing or []
|
|
137
|
+
print("\nEnter new items:")
|
|
138
|
+
while True:
|
|
139
|
+
item = input(" - ").strip()
|
|
140
|
+
if not item:
|
|
141
|
+
break
|
|
142
|
+
items.append(item)
|
|
143
|
+
|
|
144
|
+
return items
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def get_user_profile() -> dict:
|
|
148
|
+
"""Get or create user profile."""
|
|
149
|
+
profile_path = OVERRIDES_DIR / "user-profile.yaml"
|
|
150
|
+
|
|
151
|
+
if profile_path.exists():
|
|
152
|
+
print(f"{Colors.GREEN}Found existing user profile{Colors.END}")
|
|
153
|
+
if not prompt_yes_no("Update user profile?", default=False):
|
|
154
|
+
return {}
|
|
155
|
+
|
|
156
|
+
print_step(1, "User Profile")
|
|
157
|
+
|
|
158
|
+
profile = {
|
|
159
|
+
"name": prompt_input("Your name", "Developer"),
|
|
160
|
+
"technical_level": prompt_choice(
|
|
161
|
+
"Your technical level:", ["Junior", "Mid-level", "Senior", "Principal/Staff"], default=2
|
|
162
|
+
),
|
|
163
|
+
"communication_style": prompt_choice(
|
|
164
|
+
"Preferred communication style:",
|
|
165
|
+
[
|
|
166
|
+
"Concise - brief and to the point",
|
|
167
|
+
"Balanced - moderate detail",
|
|
168
|
+
"Detailed - thorough explanations",
|
|
169
|
+
],
|
|
170
|
+
default=1,
|
|
171
|
+
),
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
level_map = ["junior", "mid", "senior", "principal"]
|
|
175
|
+
style_map = ["concise", "balanced", "detailed"]
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
"user": {
|
|
179
|
+
"name": profile["name"],
|
|
180
|
+
"technical_level": level_map[profile["technical_level"]],
|
|
181
|
+
"communication_style": style_map[profile["communication_style"]],
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def customize_agent(agent_name: str) -> Optional[dict]:
|
|
187
|
+
"""Run customization wizard for a single agent."""
|
|
188
|
+
print(f"\n{Colors.BOLD}Personalizing: {agent_name.upper()} Agent{Colors.END}")
|
|
189
|
+
print("=" * 50)
|
|
190
|
+
|
|
191
|
+
# Check for templates
|
|
192
|
+
templates = get_agent_templates(agent_name)
|
|
193
|
+
|
|
194
|
+
override = {}
|
|
195
|
+
|
|
196
|
+
# Step 1: Template selection
|
|
197
|
+
if templates:
|
|
198
|
+
print_step(1, "Select Base Template")
|
|
199
|
+
print(f"Found {len(templates)} pre-built persona(s) for {agent_name}:\n")
|
|
200
|
+
|
|
201
|
+
options = ["Start from scratch (no template)"]
|
|
202
|
+
for t in templates:
|
|
203
|
+
options.append(f"{t['name']}: {t['description']}")
|
|
204
|
+
|
|
205
|
+
choice = prompt_choice("Choose a starting point:", options, default=1)
|
|
206
|
+
|
|
207
|
+
if choice > 0:
|
|
208
|
+
template = templates[choice - 1]
|
|
209
|
+
print(f"\n{Colors.GREEN}Using template: {template['name']}{Colors.END}")
|
|
210
|
+
# Copy template content (in a real implementation, parse YAML)
|
|
211
|
+
shutil.copy(template["path"], OVERRIDES_DIR / f"{agent_name}.override.yaml")
|
|
212
|
+
print(f"Template copied to: {agent_name}.override.yaml")
|
|
213
|
+
|
|
214
|
+
if not prompt_yes_no("Customize further?", default=True):
|
|
215
|
+
return None
|
|
216
|
+
|
|
217
|
+
# Step 2: Persona customization
|
|
218
|
+
print_step(2, "Persona Definition")
|
|
219
|
+
|
|
220
|
+
if prompt_yes_no("Define a custom persona?", default=True):
|
|
221
|
+
override["persona"] = {
|
|
222
|
+
"role": prompt_input("Role title", f"Senior {agent_name.title()} Specialist"),
|
|
223
|
+
"identity": prompt_input(
|
|
224
|
+
"Identity description", "A focused professional who delivers quality work"
|
|
225
|
+
),
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
print("\nDefine your core principles (what guides your decisions):")
|
|
229
|
+
principles = prompt_list("Principles:")
|
|
230
|
+
if principles:
|
|
231
|
+
override["persona"]["principles"] = principles
|
|
232
|
+
|
|
233
|
+
# Step 3: Rules
|
|
234
|
+
print_step(3, "Additional Rules")
|
|
235
|
+
|
|
236
|
+
if prompt_yes_no("Add custom coding/working rules?", default=True):
|
|
237
|
+
rules = prompt_list("Enter rules the agent should follow:")
|
|
238
|
+
if rules:
|
|
239
|
+
override["additional_rules"] = rules
|
|
240
|
+
|
|
241
|
+
# Step 4: Memories
|
|
242
|
+
print_step(4, "Project Context (Memories)")
|
|
243
|
+
|
|
244
|
+
if prompt_yes_no("Add project-specific knowledge?", default=True):
|
|
245
|
+
memories = prompt_list("Enter facts the agent should always remember:")
|
|
246
|
+
if memories:
|
|
247
|
+
override["memories"] = memories
|
|
248
|
+
|
|
249
|
+
# Step 5: Critical actions
|
|
250
|
+
print_step(5, "Critical Actions")
|
|
251
|
+
|
|
252
|
+
if prompt_yes_no("Define actions that must happen before completing tasks?", default=True):
|
|
253
|
+
actions = prompt_list("Enter critical verification steps:")
|
|
254
|
+
if actions:
|
|
255
|
+
override["critical_actions"] = actions
|
|
256
|
+
|
|
257
|
+
# Step 6: Model and budget
|
|
258
|
+
print_step(6, "Model & Budget")
|
|
259
|
+
|
|
260
|
+
if prompt_yes_no("Configure model and budget?", default=False):
|
|
261
|
+
model_choice = prompt_choice(
|
|
262
|
+
"Preferred model:",
|
|
263
|
+
["Sonnet (faster, cheaper)", "Opus (smarter, more expensive)"],
|
|
264
|
+
default=0,
|
|
265
|
+
)
|
|
266
|
+
override["model"] = "sonnet" if model_choice == 0 else "opus"
|
|
267
|
+
|
|
268
|
+
budget = prompt_input("Max budget per task (USD)", "15.00")
|
|
269
|
+
try:
|
|
270
|
+
override["max_budget_usd"] = float(budget)
|
|
271
|
+
except ValueError:
|
|
272
|
+
pass
|
|
273
|
+
|
|
274
|
+
return override if override else None
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def save_override(agent_name: str, override: dict):
|
|
278
|
+
"""Save override to YAML file."""
|
|
279
|
+
|
|
280
|
+
override_path = OVERRIDES_DIR / f"{agent_name}.override.yaml"
|
|
281
|
+
|
|
282
|
+
# Add header comment
|
|
283
|
+
content = f"# {agent_name.title()} Agent Override\n"
|
|
284
|
+
content += "# Generated by Personalization Wizard\n"
|
|
285
|
+
content += "# Customize further as needed\n\n"
|
|
286
|
+
|
|
287
|
+
# Simple YAML-like output (avoiding yaml dependency issues)
|
|
288
|
+
def write_yaml(data, indent=0):
|
|
289
|
+
result = ""
|
|
290
|
+
prefix = " " * indent
|
|
291
|
+
for key, value in data.items():
|
|
292
|
+
if isinstance(value, dict):
|
|
293
|
+
result += f"{prefix}{key}:\n"
|
|
294
|
+
result += write_yaml(value, indent + 1)
|
|
295
|
+
elif isinstance(value, list):
|
|
296
|
+
result += f"{prefix}{key}:\n"
|
|
297
|
+
for item in value:
|
|
298
|
+
result += f'{prefix} - "{item}"\n'
|
|
299
|
+
elif isinstance(value, (int, float)):
|
|
300
|
+
result += f"{prefix}{key}: {value}\n"
|
|
301
|
+
else:
|
|
302
|
+
result += f'{prefix}{key}: "{value}"\n'
|
|
303
|
+
return result
|
|
304
|
+
|
|
305
|
+
content += write_yaml(override)
|
|
306
|
+
|
|
307
|
+
override_path.write_text(content)
|
|
308
|
+
print(f"\n{Colors.GREEN}✅ Saved: {override_path}{Colors.END}")
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def main():
|
|
312
|
+
parser = argparse.ArgumentParser(
|
|
313
|
+
description="Interactive wizard to personalize AI agent behavior"
|
|
314
|
+
)
|
|
315
|
+
parser.add_argument("agent", nargs="?", help="Agent name to personalize")
|
|
316
|
+
parser.add_argument("--all", action="store_true", help="Personalize all agents")
|
|
317
|
+
parser.add_argument("--list", action="store_true", help="List available agents and templates")
|
|
318
|
+
|
|
319
|
+
args = parser.parse_args()
|
|
320
|
+
|
|
321
|
+
print_banner()
|
|
322
|
+
|
|
323
|
+
# Ensure directories exist
|
|
324
|
+
OVERRIDES_DIR.mkdir(parents=True, exist_ok=True)
|
|
325
|
+
|
|
326
|
+
# List mode
|
|
327
|
+
if args.list:
|
|
328
|
+
print(f"{Colors.BOLD}Available Agents:{Colors.END}")
|
|
329
|
+
for agent in get_available_agents():
|
|
330
|
+
templates = get_agent_templates(agent)
|
|
331
|
+
template_count = len(templates)
|
|
332
|
+
print(f" • {agent} ({template_count} template(s))")
|
|
333
|
+
for t in templates:
|
|
334
|
+
print(f" - {t['name']}: {t['description']}")
|
|
335
|
+
return
|
|
336
|
+
|
|
337
|
+
# Get user profile first
|
|
338
|
+
profile = get_user_profile()
|
|
339
|
+
if profile:
|
|
340
|
+
# Save user profile
|
|
341
|
+
profile_path = OVERRIDES_DIR / "user-profile.yaml"
|
|
342
|
+
content = "# User Profile\n# Global preferences for all agents\n\n"
|
|
343
|
+
for section, values in profile.items():
|
|
344
|
+
content += f"{section}:\n"
|
|
345
|
+
for key, value in values.items():
|
|
346
|
+
content += f' {key}: "{value}"\n'
|
|
347
|
+
profile_path.write_text(content)
|
|
348
|
+
print(f"\n{Colors.GREEN}✅ User profile saved{Colors.END}")
|
|
349
|
+
|
|
350
|
+
# Determine agents to personalize
|
|
351
|
+
agents = get_available_agents()
|
|
352
|
+
|
|
353
|
+
if args.all:
|
|
354
|
+
agents_to_personalize = agents
|
|
355
|
+
elif args.agent:
|
|
356
|
+
if args.agent not in agents:
|
|
357
|
+
print(f"{Colors.RED}Unknown agent: {args.agent}{Colors.END}")
|
|
358
|
+
print(f"Available: {', '.join(agents)}")
|
|
359
|
+
return 1
|
|
360
|
+
agents_to_personalize = [args.agent]
|
|
361
|
+
else:
|
|
362
|
+
# Interactive agent selection
|
|
363
|
+
print_step(2, "Select Agent to Personalize")
|
|
364
|
+
options = agents + ["All agents"]
|
|
365
|
+
choice = prompt_choice("Which agent would you like to personalize?", options)
|
|
366
|
+
|
|
367
|
+
if choice == len(agents):
|
|
368
|
+
agents_to_personalize = agents
|
|
369
|
+
else:
|
|
370
|
+
agents_to_personalize = [agents[choice]]
|
|
371
|
+
|
|
372
|
+
# Personalize each agent
|
|
373
|
+
for agent in agents_to_personalize:
|
|
374
|
+
override = customize_agent(agent)
|
|
375
|
+
if override:
|
|
376
|
+
save_override(agent, override)
|
|
377
|
+
|
|
378
|
+
print(f"\n{Colors.GREEN}{Colors.BOLD}✨ Personalization complete!{Colors.END}")
|
|
379
|
+
print(f"\nYour overrides are in: {OVERRIDES_DIR}")
|
|
380
|
+
print("They will be applied automatically when running agents.")
|
|
381
|
+
print("\nTo modify later, edit the .override.yaml files directly.")
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
if __name__ == "__main__":
|
|
385
|
+
sys.exit(main() or 0)
|