@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,387 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Cross-Platform Story Runner with Cost Tracking
4
+
5
+ Automatically detects the operating system and runs the appropriate script.
6
+ Works on Windows, macOS, and Linux. Includes real-time cost monitoring.
7
+
8
+ Usage:
9
+ python run-story.py <story-key> [options]
10
+
11
+ Options:
12
+ --develop, -d Run development phase only
13
+ --review, -r Run review phase only
14
+ --context, -c Run context phase only
15
+ --no-commit Disable auto-commit
16
+ --with-pr Create PR after commit
17
+ --model MODEL Model to use (sonnet, opus, haiku)
18
+ --budget AMOUNT Budget limit in USD (default: 15.00)
19
+ --show-costs Show cost dashboard after run
20
+ --native Run natively with Python (enables cost tracking)
21
+
22
+ Examples:
23
+ python run-story.py 3-5
24
+ python run-story.py 3-5 --develop
25
+ python run-story.py 3-5 --model opus --budget 20.00
26
+ python run-story.py 3-5 --native --show-costs
27
+ """
28
+
29
+ import argparse
30
+ import os
31
+ import subprocess
32
+ import sys
33
+ import threading
34
+ import time
35
+ from pathlib import Path
36
+
37
+ SCRIPT_DIR = Path(__file__).parent
38
+
39
+ # Add lib directory for imports
40
+ sys.path.insert(0, str(SCRIPT_DIR / "lib"))
41
+
42
+
43
+ def get_platform():
44
+ """Detect the current platform."""
45
+ if sys.platform == "win32":
46
+ return "windows"
47
+ elif sys.platform == "darwin":
48
+ return "macos"
49
+ else:
50
+ return "linux"
51
+
52
+
53
+ def run_windows(args):
54
+ """Run PowerShell script on Windows."""
55
+ script = SCRIPT_DIR / "run-story.ps1"
56
+
57
+ if not script.exists():
58
+ print(f"Error: PowerShell script not found: {script}")
59
+ return 1
60
+
61
+ # Convert args to PowerShell format
62
+ ps_args = []
63
+ i = 0
64
+ while i < len(args):
65
+ arg = args[i]
66
+ if arg.startswith("--"):
67
+ # Convert --develop to -Develop
68
+ param_name = arg[2:].title()
69
+ ps_args.append(f"-{param_name}")
70
+ elif arg.startswith("-") and len(arg) == 2:
71
+ ps_args.append(arg)
72
+ else:
73
+ ps_args.append(arg)
74
+ i += 1
75
+
76
+ cmd = ["powershell", "-ExecutionPolicy", "Bypass", "-File", str(script)] + ps_args
77
+ return subprocess.call(cmd)
78
+
79
+
80
+ def run_unix(args):
81
+ """Run shell script on macOS/Linux."""
82
+ script = SCRIPT_DIR / "run-story.sh"
83
+
84
+ if not script.exists():
85
+ print(f"Error: Shell script not found: {script}")
86
+ return 1
87
+
88
+ # Ensure script is executable
89
+ os.chmod(script, 0o755)
90
+
91
+ cmd = [str(script)] + args
92
+ return subprocess.call(cmd)
93
+
94
+
95
+ def parse_args():
96
+ """Parse command line arguments."""
97
+ parser = argparse.ArgumentParser(
98
+ description="Run story automation with cost tracking",
99
+ formatter_class=argparse.RawDescriptionHelpFormatter,
100
+ epilog="""
101
+ Examples:
102
+ python run-story.py 3-5 # Full pipeline
103
+ python run-story.py 3-5 --develop # Development only
104
+ python run-story.py 3-5 --native # Native Python with cost tracking
105
+ python run-story.py 3-5 --budget 20.00 # Custom budget
106
+ """,
107
+ )
108
+
109
+ parser.add_argument("story_key", help="Story key (e.g., 3-5)")
110
+ parser.add_argument("--develop", "-d", action="store_true", help="Development phase only")
111
+ parser.add_argument("--review", "-r", action="store_true", help="Review phase only")
112
+ parser.add_argument("--context", "-c", action="store_true", help="Context phase only")
113
+ parser.add_argument("--no-commit", action="store_true", help="Disable auto-commit")
114
+ parser.add_argument("--with-pr", action="store_true", help="Create PR after commit")
115
+ parser.add_argument(
116
+ "--model", choices=["sonnet", "opus", "haiku"], default="sonnet", help="Model to use"
117
+ )
118
+ parser.add_argument("--budget", type=float, default=15.00, help="Budget limit in USD")
119
+ parser.add_argument("--show-costs", action="store_true", help="Show cost dashboard after run")
120
+ parser.add_argument(
121
+ "--native", action="store_true", help="Run natively with Python (enables cost tracking)"
122
+ )
123
+ parser.add_argument("--no-monitor", action="store_true", help="Disable live monitoring display")
124
+
125
+ return parser.parse_args()
126
+
127
+
128
+ class NativeRunner:
129
+ """Native Python runner with cost tracking."""
130
+
131
+ def __init__(self, args):
132
+ self.args = args
133
+ self.tracker = None
134
+ self.display = None
135
+ self.monitor_thread = None
136
+ self.running = False
137
+
138
+ # Import cost modules
139
+ try:
140
+ from cost_display import CompactCostDisplay, CostDisplay
141
+ from cost_tracker import CostTracker
142
+
143
+ self.CostTracker = CostTracker
144
+ self.CostDisplay = CostDisplay
145
+ self.CompactCostDisplay = CompactCostDisplay
146
+ self.cost_available = True
147
+ except ImportError as e:
148
+ print(f"Warning: Cost tracking not available: {e}")
149
+ self.cost_available = False
150
+
151
+ def start_tracking(self):
152
+ """Initialize cost tracking."""
153
+ if not self.cost_available:
154
+ return
155
+
156
+ self.tracker = self.CostTracker(
157
+ story_key=self.args.story_key, budget_limit_usd=self.args.budget
158
+ )
159
+ self.display = self.CompactCostDisplay(self.tracker)
160
+
161
+ def start_monitor(self):
162
+ """Start the monitoring display thread."""
163
+ if not self.cost_available or self.args.no_monitor:
164
+ return
165
+
166
+ self.running = True
167
+ self.monitor_thread = threading.Thread(target=self._monitor_loop, daemon=True)
168
+ self.monitor_thread.start()
169
+
170
+ def _monitor_loop(self):
171
+ """Monitor loop for live display updates."""
172
+ while self.running:
173
+ if self.tracker:
174
+ self.display.print()
175
+ time.sleep(2)
176
+
177
+ def stop_monitor(self):
178
+ """Stop the monitoring display."""
179
+ self.running = False
180
+ if self.monitor_thread:
181
+ self.monitor_thread.join(timeout=1)
182
+
183
+ def run_claude(self, agent: str, model: str, prompt: str, timeout: int = 300) -> tuple:
184
+ """Run Claude CLI and capture output."""
185
+ cli = "claude.cmd" if sys.platform == "win32" else "claude"
186
+
187
+ cmd = [cli, "--print", "--model", model, "-p", prompt]
188
+
189
+ # Set current agent for display
190
+ if self.tracker:
191
+ self.tracker.set_current_agent(agent, model)
192
+
193
+ try:
194
+ result = subprocess.run(
195
+ cmd,
196
+ capture_output=True,
197
+ text=True,
198
+ timeout=timeout,
199
+ cwd=str(SCRIPT_DIR.parent.parent), # Project root
200
+ )
201
+
202
+ output = result.stdout + result.stderr
203
+
204
+ # Parse token usage from output (if available)
205
+ if self.tracker:
206
+ tokens = self._parse_tokens(output)
207
+ if tokens:
208
+ self.tracker.log_usage(agent, model, tokens[0], tokens[1])
209
+
210
+ return (result.returncode == 0, output)
211
+
212
+ except subprocess.TimeoutExpired:
213
+ return (False, "Timeout expired")
214
+ except Exception as e:
215
+ return (False, str(e))
216
+
217
+ def _parse_tokens(self, output: str) -> tuple:
218
+ """Parse token usage from Claude output."""
219
+ import re
220
+
221
+ # Try to find token patterns
222
+ # Pattern: "Token usage: X/Y"
223
+ match = re.search(r"Token usage:\s*(\d+)/(\d+)", output)
224
+ if match:
225
+ total = int(match.group(1))
226
+ return (int(total * 0.8), int(total * 0.2))
227
+
228
+ # Pattern: "X in / Y out"
229
+ match = re.search(r"(\d+)\s*in\s*/\s*(\d+)\s*out", output, re.IGNORECASE)
230
+ if match:
231
+ return (int(match.group(1)), int(match.group(2)))
232
+
233
+ # Default estimate based on output length
234
+ output_tokens = len(output.split()) * 1.3
235
+ input_tokens = output_tokens * 0.3
236
+ return (int(input_tokens), int(output_tokens))
237
+
238
+ def check_budget(self) -> bool:
239
+ """Check if budget is OK to continue."""
240
+ if not self.tracker:
241
+ return True
242
+
243
+ ok, level, msg = self.tracker.check_budget()
244
+
245
+ if level == "critical":
246
+ print(f"\n\033[91m{msg}\033[0m")
247
+ elif level == "warning":
248
+ print(f"\n\033[93m{msg}\033[0m")
249
+
250
+ return ok
251
+
252
+ def run(self) -> int:
253
+ """Run the story automation."""
254
+ print(f"Starting story: {self.args.story_key}")
255
+ print(f"Model: {self.args.model}")
256
+ print(f"Budget: ${self.args.budget:.2f}")
257
+ print()
258
+
259
+ self.start_tracking()
260
+ self.start_monitor()
261
+
262
+ try:
263
+ # Determine which phases to run
264
+ run_context = self.args.context or (not self.args.develop and not self.args.review)
265
+ run_develop = self.args.develop or (not self.args.context and not self.args.review)
266
+ run_review = self.args.review or (not self.args.context and not self.args.develop)
267
+
268
+ # Context phase
269
+ if run_context:
270
+ print("\n[1/3] Context Phase...")
271
+ success, output = self.run_claude(
272
+ "SM",
273
+ "sonnet",
274
+ f"Analyze story {self.args.story_key} and prepare context for development",
275
+ )
276
+ if not success:
277
+ print(f"Context phase failed: {output[:200]}")
278
+ return 1
279
+
280
+ if not self.check_budget():
281
+ return 1
282
+
283
+ # Development phase
284
+ if run_develop:
285
+ print("\n[2/3] Development Phase...")
286
+ success, output = self.run_claude(
287
+ "DEV",
288
+ self.args.model,
289
+ f"Implement story {self.args.story_key} following the context and specifications",
290
+ )
291
+ if not success:
292
+ print(f"Development phase failed: {output[:200]}")
293
+ return 1
294
+
295
+ if not self.check_budget():
296
+ return 1
297
+
298
+ # Review phase
299
+ if run_review and not self.args.context and not self.args.develop:
300
+ print("\n[3/3] Review Phase...")
301
+ success, output = self.run_claude(
302
+ "SM", "sonnet", f"Review the implementation of story {self.args.story_key}"
303
+ )
304
+ if not success:
305
+ print(f"Review phase failed: {output[:200]}")
306
+ return 1
307
+
308
+ print("\n✓ Story automation complete!")
309
+
310
+ # Show final costs
311
+ if self.tracker:
312
+ print()
313
+ self.display.print()
314
+ print()
315
+
316
+ summary = self.tracker.get_session_summary()
317
+ print(f"Final Cost: ${summary['totals']['cost_usd']:.2f}")
318
+ print(f"Tokens Used: {summary['totals']['total_tokens']:,}")
319
+
320
+ return 0
321
+
322
+ finally:
323
+ self.stop_monitor()
324
+
325
+ # Save session
326
+ if self.tracker:
327
+ self.tracker.end_session()
328
+
329
+ # Show cost dashboard if requested
330
+ if self.args.show_costs:
331
+ print("\n" + "=" * 60)
332
+ try:
333
+ from cost_dashboard import CostDashboard
334
+
335
+ dashboard = CostDashboard()
336
+ if self.tracker:
337
+ dashboard.show_session(self.tracker.session)
338
+ except ImportError:
339
+ print("Cost dashboard not available")
340
+
341
+
342
+ def main():
343
+ if len(sys.argv) < 2:
344
+ print(__doc__)
345
+ print("\nDetected platform:", get_platform())
346
+ return 1
347
+
348
+ args = parse_args()
349
+ platform = get_platform()
350
+
351
+ print(f"Platform: {platform}")
352
+
353
+ # Use native runner if --native flag is set
354
+ if args.native:
355
+ print("Mode: Native Python with cost tracking")
356
+ print()
357
+ runner = NativeRunner(args)
358
+ return runner.run()
359
+
360
+ # Otherwise, delegate to platform-specific scripts
361
+ # Build args list for subprocess
362
+ script_args = [args.story_key]
363
+
364
+ if args.develop:
365
+ script_args.append("--develop")
366
+ if args.review:
367
+ script_args.append("--review")
368
+ if args.context:
369
+ script_args.append("--context")
370
+ if args.no_commit:
371
+ script_args.append("--no-commit")
372
+ if args.with_pr:
373
+ script_args.append("--with-pr")
374
+ if args.model != "sonnet":
375
+ script_args.extend(["--model", args.model])
376
+
377
+ print(f"Running: run-story with args: {' '.join(script_args)}")
378
+ print()
379
+
380
+ if platform == "windows":
381
+ return run_windows(script_args)
382
+ else:
383
+ return run_unix(script_args)
384
+
385
+
386
+ if __name__ == "__main__":
387
+ sys.exit(main())