@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,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())
|