@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.
Files changed (124) hide show
  1. package/CHANGELOG.md +526 -0
  2. package/LICENSE +21 -0
  3. package/README.md +620 -0
  4. package/bin/devflow-checkpoint.js +10 -0
  5. package/bin/devflow-collab.js +10 -0
  6. package/bin/devflow-cost.js +10 -0
  7. package/bin/devflow-create-persona.js +10 -0
  8. package/bin/devflow-init.js +10 -0
  9. package/bin/devflow-memory.js +10 -0
  10. package/bin/devflow-new-doc.js +10 -0
  11. package/bin/devflow-personalize.js +10 -0
  12. package/bin/devflow-setup-checkpoint.js +10 -0
  13. package/bin/devflow-story.js +10 -0
  14. package/bin/devflow-tech-debt.js +10 -0
  15. package/bin/devflow-validate-overrides.js +10 -0
  16. package/bin/devflow-validate.js +10 -0
  17. package/bin/devflow-version.js +10 -0
  18. package/lib/constants.js +30 -0
  19. package/lib/exec-python.js +78 -0
  20. package/lib/python-check.js +178 -0
  21. package/package.json +64 -0
  22. package/tooling/.automation/agents/architect.md +135 -0
  23. package/tooling/.automation/agents/ba.md +70 -0
  24. package/tooling/.automation/agents/dev.md +79 -0
  25. package/tooling/.automation/agents/maintainer.md +97 -0
  26. package/tooling/.automation/agents/pm.md +116 -0
  27. package/tooling/.automation/agents/reviewer.md +141 -0
  28. package/tooling/.automation/agents/sm.md +61 -0
  29. package/tooling/.automation/agents/writer.md +193 -0
  30. package/tooling/.automation/config.ps1.template +61 -0
  31. package/tooling/.automation/config.sh.template +48 -0
  32. package/tooling/.automation/memory/.gitkeep +6 -0
  33. package/tooling/.automation/memory/knowledge/kg_integration-test.json +94 -0
  34. package/tooling/.automation/memory/knowledge/kg_test-story.json +300 -0
  35. package/tooling/.automation/memory/shared/shared_integration-test.json +30 -0
  36. package/tooling/.automation/memory/shared/shared_test-story.json +78 -0
  37. package/tooling/.automation/overrides/templates/README.md +113 -0
  38. package/tooling/.automation/overrides/templates/architect/README.md +27 -0
  39. package/tooling/.automation/overrides/templates/architect/cloud-native.yaml +92 -0
  40. package/tooling/.automation/overrides/templates/architect/enterprise-architect.yaml +85 -0
  41. package/tooling/.automation/overrides/templates/architect/pragmatic-minimalist.yaml +88 -0
  42. package/tooling/.automation/overrides/templates/ba/README.md +27 -0
  43. package/tooling/.automation/overrides/templates/ba/agile-storyteller.yaml +86 -0
  44. package/tooling/.automation/overrides/templates/ba/domain-expert.yaml +91 -0
  45. package/tooling/.automation/overrides/templates/ba/requirements-engineer.yaml +89 -0
  46. package/tooling/.automation/overrides/templates/dev/README.md +32 -0
  47. package/tooling/.automation/overrides/templates/dev/junior-mentored.yaml +39 -0
  48. package/tooling/.automation/overrides/templates/dev/performance-engineer.yaml +43 -0
  49. package/tooling/.automation/overrides/templates/dev/rapid-prototyper.yaml +52 -0
  50. package/tooling/.automation/overrides/templates/dev/security-focused.yaml +43 -0
  51. package/tooling/.automation/overrides/templates/dev/senior-fullstack.yaml +39 -0
  52. package/tooling/.automation/overrides/templates/maintainer/README.md +27 -0
  53. package/tooling/.automation/overrides/templates/maintainer/devops-maintainer.yaml +113 -0
  54. package/tooling/.automation/overrides/templates/maintainer/legacy-steward.yaml +94 -0
  55. package/tooling/.automation/overrides/templates/maintainer/oss-maintainer.yaml +94 -0
  56. package/tooling/.automation/overrides/templates/pm/README.md +27 -0
  57. package/tooling/.automation/overrides/templates/pm/agile-pm.yaml +91 -0
  58. package/tooling/.automation/overrides/templates/pm/hybrid-delivery.yaml +87 -0
  59. package/tooling/.automation/overrides/templates/pm/traditional-pm.yaml +91 -0
  60. package/tooling/.automation/overrides/templates/reviewer/README.md +11 -0
  61. package/tooling/.automation/overrides/templates/reviewer/mentoring-reviewer.yaml +45 -0
  62. package/tooling/.automation/overrides/templates/reviewer/quick-sanity.yaml +50 -0
  63. package/tooling/.automation/overrides/templates/reviewer/thorough-critic.yaml +48 -0
  64. package/tooling/.automation/overrides/templates/sm/README.md +11 -0
  65. package/tooling/.automation/overrides/templates/sm/agile-coach.yaml +52 -0
  66. package/tooling/.automation/overrides/templates/sm/startup-pm.yaml +50 -0
  67. package/tooling/.automation/overrides/templates/sm/technical-lead.yaml +47 -0
  68. package/tooling/.automation/overrides/templates/user-profile.template.yaml +62 -0
  69. package/tooling/.automation/overrides/templates/writer/README.md +27 -0
  70. package/tooling/.automation/overrides/templates/writer/api-documentarian.yaml +99 -0
  71. package/tooling/.automation/overrides/templates/writer/docs-as-code.yaml +108 -0
  72. package/tooling/.automation/overrides/templates/writer/user-guide-author.yaml +100 -0
  73. package/tooling/completions/DevflowCompletion.ps1 +213 -0
  74. package/tooling/completions/_run-story +116 -0
  75. package/tooling/completions/run-story-completion.bash +136 -0
  76. package/tooling/docs/DOC-STANDARD.md +717 -0
  77. package/tooling/docs/sprint-status.yaml.template +24 -0
  78. package/tooling/docs/templates/bug-report.md +234 -0
  79. package/tooling/docs/templates/migration-spec.md +274 -0
  80. package/tooling/docs/templates/refactor-spec.md +86 -0
  81. package/tooling/docs/templates/tech-debt.md +86 -0
  82. package/tooling/scripts/context_checkpoint.py +556 -0
  83. package/tooling/scripts/cost_dashboard.py +617 -0
  84. package/tooling/scripts/create-persona.py +690 -0
  85. package/tooling/scripts/create-persona.sh +435 -0
  86. package/tooling/scripts/init-project-workflow.ps1 +651 -0
  87. package/tooling/scripts/init-project-workflow.py +70 -0
  88. package/tooling/scripts/init-project-workflow.sh +746 -0
  89. package/tooling/scripts/lib/__init__.py +35 -0
  90. package/tooling/scripts/lib/agent_handoff.py +526 -0
  91. package/tooling/scripts/lib/agent_router.py +698 -0
  92. package/tooling/scripts/lib/checkpoint-integration.ps1 +245 -0
  93. package/tooling/scripts/lib/checkpoint-integration.sh +191 -0
  94. package/tooling/scripts/lib/claude-cli.ps1 +952 -0
  95. package/tooling/scripts/lib/claude-cli.sh +1293 -0
  96. package/tooling/scripts/lib/cost_config.py +222 -0
  97. package/tooling/scripts/lib/cost_display.py +443 -0
  98. package/tooling/scripts/lib/cost_tracker.py +710 -0
  99. package/tooling/scripts/lib/currency_converter.py +328 -0
  100. package/tooling/scripts/lib/errors.py +438 -0
  101. package/tooling/scripts/lib/override-loader.sh +286 -0
  102. package/tooling/scripts/lib/pair_programming.py +589 -0
  103. package/tooling/scripts/lib/shared_memory.py +637 -0
  104. package/tooling/scripts/lib/swarm_orchestrator.py +689 -0
  105. package/tooling/scripts/memory_summarize.py +324 -0
  106. package/tooling/scripts/new-doc.ps1 +405 -0
  107. package/tooling/scripts/new-doc.py +93 -0
  108. package/tooling/scripts/new-doc.sh +534 -0
  109. package/tooling/scripts/personalize_agent.py +385 -0
  110. package/tooling/scripts/rollback-migration.sh +540 -0
  111. package/tooling/scripts/run-collab.ps1 +251 -0
  112. package/tooling/scripts/run-collab.py +605 -0
  113. package/tooling/scripts/run-collab.sh +110 -0
  114. package/tooling/scripts/run-story.ps1 +490 -0
  115. package/tooling/scripts/run-story.py +387 -0
  116. package/tooling/scripts/run-story.sh +467 -0
  117. package/tooling/scripts/setup-checkpoint-service.ps1 +219 -0
  118. package/tooling/scripts/setup-checkpoint-service.py +87 -0
  119. package/tooling/scripts/setup-checkpoint-service.sh +236 -0
  120. package/tooling/scripts/tech-debt-tracker.py +608 -0
  121. package/tooling/scripts/update_version.py +244 -0
  122. package/tooling/scripts/validate-overrides.py +511 -0
  123. package/tooling/scripts/validate-overrides.sh +432 -0
  124. 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)