tapps-agents 3.5.39__py3-none-any.whl → 3.5.40__py3-none-any.whl
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.
- tapps_agents/__init__.py +2 -2
- tapps_agents/agents/enhancer/agent.py +2728 -2728
- tapps_agents/agents/implementer/agent.py +35 -13
- tapps_agents/agents/reviewer/agent.py +43 -10
- tapps_agents/agents/reviewer/scoring.py +59 -68
- tapps_agents/agents/reviewer/tools/__init__.py +24 -0
- tapps_agents/agents/reviewer/tools/ruff_grouping.py +250 -0
- tapps_agents/agents/reviewer/tools/scoped_mypy.py +284 -0
- tapps_agents/beads/__init__.py +11 -0
- tapps_agents/beads/hydration.py +213 -0
- tapps_agents/beads/specs.py +206 -0
- tapps_agents/cli/commands/health.py +19 -3
- tapps_agents/cli/commands/simple_mode.py +842 -676
- tapps_agents/cli/commands/task.py +219 -0
- tapps_agents/cli/commands/top_level.py +13 -0
- tapps_agents/cli/main.py +658 -651
- tapps_agents/cli/parsers/top_level.py +1978 -1881
- tapps_agents/core/config.py +1622 -1622
- tapps_agents/core/init_project.py +3012 -2897
- tapps_agents/epic/markdown_sync.py +105 -0
- tapps_agents/epic/orchestrator.py +1 -2
- tapps_agents/epic/parser.py +427 -423
- tapps_agents/experts/adaptive_domain_detector.py +0 -2
- tapps_agents/experts/knowledge/api-design-integration/api-security-patterns.md +15 -15
- tapps_agents/experts/knowledge/api-design-integration/external-api-integration.md +19 -44
- tapps_agents/health/checks/outcomes.backup_20260204_064058.py +324 -0
- tapps_agents/health/checks/outcomes.backup_20260204_064256.py +324 -0
- tapps_agents/health/checks/outcomes.backup_20260204_064600.py +324 -0
- tapps_agents/health/checks/outcomes.py +134 -46
- tapps_agents/health/orchestrator.py +12 -4
- tapps_agents/hooks/__init__.py +33 -0
- tapps_agents/hooks/config.py +140 -0
- tapps_agents/hooks/events.py +135 -0
- tapps_agents/hooks/executor.py +128 -0
- tapps_agents/hooks/manager.py +143 -0
- tapps_agents/session/__init__.py +19 -0
- tapps_agents/session/manager.py +256 -0
- tapps_agents/simple_mode/code_snippet_handler.py +382 -0
- tapps_agents/simple_mode/intent_parser.py +29 -4
- tapps_agents/simple_mode/orchestrators/base.py +185 -59
- tapps_agents/simple_mode/orchestrators/build_orchestrator.py +2667 -2642
- tapps_agents/simple_mode/orchestrators/fix_orchestrator.py +2 -2
- tapps_agents/simple_mode/workflow_suggester.py +37 -3
- tapps_agents/workflow/agent_handlers/implementer_handler.py +18 -3
- tapps_agents/workflow/cursor_executor.py +2196 -2118
- tapps_agents/workflow/direct_execution_fallback.py +16 -3
- tapps_agents/workflow/message_formatter.py +2 -1
- tapps_agents/workflow/parallel_executor.py +43 -4
- tapps_agents/workflow/parser.py +375 -357
- tapps_agents/workflow/rules_generator.py +337 -337
- tapps_agents/workflow/skill_invoker.py +9 -3
- {tapps_agents-3.5.39.dist-info → tapps_agents-3.5.40.dist-info}/METADATA +5 -1
- {tapps_agents-3.5.39.dist-info → tapps_agents-3.5.40.dist-info}/RECORD +57 -53
- tapps_agents/agents/analyst/SKILL.md +0 -85
- tapps_agents/agents/architect/SKILL.md +0 -80
- tapps_agents/agents/debugger/SKILL.md +0 -66
- tapps_agents/agents/designer/SKILL.md +0 -78
- tapps_agents/agents/documenter/SKILL.md +0 -95
- tapps_agents/agents/enhancer/SKILL.md +0 -189
- tapps_agents/agents/implementer/SKILL.md +0 -117
- tapps_agents/agents/improver/SKILL.md +0 -55
- tapps_agents/agents/ops/SKILL.md +0 -64
- tapps_agents/agents/orchestrator/SKILL.md +0 -238
- tapps_agents/agents/planner/story_template.md +0 -37
- tapps_agents/agents/reviewer/templates/quality-dashboard.html.j2 +0 -150
- tapps_agents/agents/tester/SKILL.md +0 -71
- {tapps_agents-3.5.39.dist-info → tapps_agents-3.5.40.dist-info}/WHEEL +0 -0
- {tapps_agents-3.5.39.dist-info → tapps_agents-3.5.40.dist-info}/entry_points.txt +0 -0
- {tapps_agents-3.5.39.dist-info → tapps_agents-3.5.40.dist-info}/licenses/LICENSE +0 -0
- {tapps_agents-3.5.39.dist-info → tapps_agents-3.5.40.dist-info}/top_level.txt +0 -0
|
@@ -1,676 +1,842 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Simple Mode command handlers.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import sys
|
|
6
|
-
import yaml
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
|
|
9
|
-
from ...core.config import ProjectConfig, load_config, save_config
|
|
10
|
-
from ...simple_mode.error_handling import SimpleModeErrorHandler
|
|
11
|
-
from ...simple_mode.learning_progression import LearningProgressionTracker
|
|
12
|
-
from ...simple_mode.onboarding import OnboardingWizard
|
|
13
|
-
from ...simple_mode.zero_config import ZeroConfigMode
|
|
14
|
-
from ...workflow.executor import WorkflowExecutor
|
|
15
|
-
from ...workflow.preset_loader import PresetLoader
|
|
16
|
-
from ..feedback import get_feedback
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def handle_simple_mode_command(args: object) -> None:
|
|
20
|
-
"""Handle simple-mode command."""
|
|
21
|
-
command = getattr(args, "command", None)
|
|
22
|
-
|
|
23
|
-
if command == "on":
|
|
24
|
-
handle_simple_mode_on()
|
|
25
|
-
elif command == "off":
|
|
26
|
-
handle_simple_mode_off()
|
|
27
|
-
elif command == "status":
|
|
28
|
-
handle_simple_mode_status(args)
|
|
29
|
-
elif command == "init":
|
|
30
|
-
handle_simple_mode_init()
|
|
31
|
-
elif command == "configure" or command == "config":
|
|
32
|
-
handle_simple_mode_configure()
|
|
33
|
-
elif command == "progress":
|
|
34
|
-
handle_simple_mode_progress()
|
|
35
|
-
elif command == "full":
|
|
36
|
-
handle_simple_mode_full(args)
|
|
37
|
-
elif command == "build":
|
|
38
|
-
handle_simple_mode_build(args)
|
|
39
|
-
elif command == "resume":
|
|
40
|
-
handle_simple_mode_resume(args)
|
|
41
|
-
elif command == "enhance":
|
|
42
|
-
handle_simple_mode_enhance(args)
|
|
43
|
-
elif command == "breakdown":
|
|
44
|
-
handle_simple_mode_breakdown(args)
|
|
45
|
-
elif command == "todo":
|
|
46
|
-
handle_simple_mode_todo(args)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
"No config file found",
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
feedback.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
print("
|
|
97
|
-
print("
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
"
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
"No config file found",
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
#
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
print("
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
"
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
feedback
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
config
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
"
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
print(
|
|
175
|
-
print(
|
|
176
|
-
print(
|
|
177
|
-
if status["
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
)
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
print(f"
|
|
350
|
-
print(f"
|
|
351
|
-
print(f"
|
|
352
|
-
print("
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
from ...
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
#
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
print(
|
|
477
|
-
print("
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
(
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
(
|
|
491
|
-
(
|
|
492
|
-
(
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
def
|
|
525
|
-
"""Callback when a step
|
|
526
|
-
status_reporter.
|
|
527
|
-
|
|
528
|
-
def
|
|
529
|
-
"""Callback when a step
|
|
530
|
-
status_reporter.complete_step(step_num, step_name,
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
print(f"
|
|
596
|
-
print("
|
|
597
|
-
print("
|
|
598
|
-
print("
|
|
599
|
-
print("
|
|
600
|
-
print("
|
|
601
|
-
print(" •
|
|
602
|
-
print(" •
|
|
603
|
-
print()
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
#
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
1
|
+
"""
|
|
2
|
+
Simple Mode command handlers.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
import yaml
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from ...core.config import ProjectConfig, load_config, save_config
|
|
10
|
+
from ...simple_mode.error_handling import SimpleModeErrorHandler
|
|
11
|
+
from ...simple_mode.learning_progression import LearningProgressionTracker
|
|
12
|
+
from ...simple_mode.onboarding import OnboardingWizard
|
|
13
|
+
from ...simple_mode.zero_config import ZeroConfigMode
|
|
14
|
+
from ...workflow.executor import WorkflowExecutor
|
|
15
|
+
from ...workflow.preset_loader import PresetLoader
|
|
16
|
+
from ..feedback import get_feedback
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def handle_simple_mode_command(args: object) -> None:
|
|
20
|
+
"""Handle simple-mode command."""
|
|
21
|
+
command = getattr(args, "command", None)
|
|
22
|
+
|
|
23
|
+
if command == "on":
|
|
24
|
+
handle_simple_mode_on()
|
|
25
|
+
elif command == "off":
|
|
26
|
+
handle_simple_mode_off()
|
|
27
|
+
elif command == "status":
|
|
28
|
+
handle_simple_mode_status(args)
|
|
29
|
+
elif command == "init":
|
|
30
|
+
handle_simple_mode_init()
|
|
31
|
+
elif command == "configure" or command == "config":
|
|
32
|
+
handle_simple_mode_configure()
|
|
33
|
+
elif command == "progress":
|
|
34
|
+
handle_simple_mode_progress()
|
|
35
|
+
elif command == "full":
|
|
36
|
+
handle_simple_mode_full(args)
|
|
37
|
+
elif command == "build":
|
|
38
|
+
handle_simple_mode_build(args)
|
|
39
|
+
elif command == "resume":
|
|
40
|
+
handle_simple_mode_resume(args)
|
|
41
|
+
elif command == "enhance":
|
|
42
|
+
handle_simple_mode_enhance(args)
|
|
43
|
+
elif command == "breakdown":
|
|
44
|
+
handle_simple_mode_breakdown(args)
|
|
45
|
+
elif command == "todo":
|
|
46
|
+
handle_simple_mode_todo(args)
|
|
47
|
+
elif command == "epic":
|
|
48
|
+
handle_simple_mode_epic(args)
|
|
49
|
+
elif command == "epic-status":
|
|
50
|
+
handle_simple_mode_epic_status(args)
|
|
51
|
+
else:
|
|
52
|
+
feedback = get_feedback()
|
|
53
|
+
available_commands = ["on", "off", "status", "init", "configure", "progress", "full", "build", "resume", "enhance", "breakdown", "todo", "epic", "epic-status"]
|
|
54
|
+
command_list = ", ".join(available_commands)
|
|
55
|
+
feedback.error(
|
|
56
|
+
f"Invalid simple-mode command: {command or '(none provided)'}",
|
|
57
|
+
error_code="invalid_command",
|
|
58
|
+
context={"command": command, "available_commands": available_commands},
|
|
59
|
+
remediation=f"Use one of: {command_list}",
|
|
60
|
+
exit_code=2,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def handle_simple_mode_on() -> None:
|
|
65
|
+
"""Enable Simple Mode."""
|
|
66
|
+
feedback = get_feedback()
|
|
67
|
+
error_handler = SimpleModeErrorHandler()
|
|
68
|
+
feedback.start_operation("Enabling Simple Mode")
|
|
69
|
+
|
|
70
|
+
# Find config file
|
|
71
|
+
config_path = find_config_file()
|
|
72
|
+
if not config_path:
|
|
73
|
+
error_handler.handle_error(
|
|
74
|
+
"config_not_found",
|
|
75
|
+
error_message="No config file found",
|
|
76
|
+
context={"suggestion": "Run 'tapps-agents init' first"},
|
|
77
|
+
)
|
|
78
|
+
feedback.error(
|
|
79
|
+
"No config file found",
|
|
80
|
+
error_code="config_not_found",
|
|
81
|
+
remediation="Run 'tapps-agents init' first",
|
|
82
|
+
exit_code=2,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Load config
|
|
86
|
+
feedback.running("Loading configuration...", step=2, total_steps=3)
|
|
87
|
+
config = load_config(config_path)
|
|
88
|
+
config.simple_mode.enabled = True
|
|
89
|
+
|
|
90
|
+
# Save config
|
|
91
|
+
feedback.running("Saving configuration...", step=3, total_steps=3)
|
|
92
|
+
save_config(config_path, config)
|
|
93
|
+
|
|
94
|
+
feedback.clear_progress()
|
|
95
|
+
feedback.success("Simple Mode enabled")
|
|
96
|
+
print("\nSimple Mode is now enabled.")
|
|
97
|
+
print("You can use natural language commands like:")
|
|
98
|
+
print(" • 'Build a user authentication feature'")
|
|
99
|
+
print(" • 'Review my authentication code'")
|
|
100
|
+
print(" • 'Fix the error in auth.py'")
|
|
101
|
+
print(" • 'Add tests for service.py'")
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def handle_simple_mode_off() -> None:
|
|
105
|
+
"""Disable Simple Mode."""
|
|
106
|
+
feedback = get_feedback()
|
|
107
|
+
error_handler = SimpleModeErrorHandler()
|
|
108
|
+
feedback.start_operation("Disable Simple Mode", "Disabling Simple Mode in configuration")
|
|
109
|
+
|
|
110
|
+
# Find config file
|
|
111
|
+
feedback.running("Locating configuration file...", step=1, total_steps=3)
|
|
112
|
+
config_path = find_config_file()
|
|
113
|
+
if not config_path:
|
|
114
|
+
error_handler.handle_error(
|
|
115
|
+
"config_not_found",
|
|
116
|
+
error_message="No config file found",
|
|
117
|
+
context={"suggestion": "Run 'tapps-agents init' first"},
|
|
118
|
+
)
|
|
119
|
+
feedback.error(
|
|
120
|
+
"No config file found",
|
|
121
|
+
error_code="config_not_found",
|
|
122
|
+
remediation="Run 'tapps-agents init' first",
|
|
123
|
+
exit_code=2,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
# Load config
|
|
127
|
+
config = load_config(config_path)
|
|
128
|
+
config.simple_mode.enabled = False
|
|
129
|
+
|
|
130
|
+
# Save config
|
|
131
|
+
save_config(config_path, config)
|
|
132
|
+
|
|
133
|
+
feedback.clear_progress()
|
|
134
|
+
feedback.success("Simple Mode disabled")
|
|
135
|
+
print("\nSimple Mode is now disabled.")
|
|
136
|
+
print("You can use agent-specific commands like:")
|
|
137
|
+
print(" • @reviewer *review")
|
|
138
|
+
print(" • @implementer *implement")
|
|
139
|
+
print(" • @tester *test")
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def handle_simple_mode_status(args: object) -> None:
|
|
143
|
+
"""Check Simple Mode status."""
|
|
144
|
+
feedback = get_feedback()
|
|
145
|
+
output_format = getattr(args, "format", "text")
|
|
146
|
+
feedback.format_type = output_format
|
|
147
|
+
|
|
148
|
+
feedback.start_operation("Simple Mode Status", "Checking Simple Mode configuration status")
|
|
149
|
+
feedback.running("Loading configuration...", step=1, total_steps=2)
|
|
150
|
+
|
|
151
|
+
# Find config file
|
|
152
|
+
config_path = find_config_file()
|
|
153
|
+
if not config_path:
|
|
154
|
+
# No config file - use defaults
|
|
155
|
+
config = ProjectConfig()
|
|
156
|
+
else:
|
|
157
|
+
feedback.running("Loading configuration...", step=2, total_steps=2)
|
|
158
|
+
config = load_config(config_path)
|
|
159
|
+
|
|
160
|
+
feedback.clear_progress()
|
|
161
|
+
|
|
162
|
+
status = {
|
|
163
|
+
"enabled": config.simple_mode.enabled,
|
|
164
|
+
"auto_detect": config.simple_mode.auto_detect,
|
|
165
|
+
"show_advanced": config.simple_mode.show_advanced,
|
|
166
|
+
"natural_language": config.simple_mode.natural_language,
|
|
167
|
+
"config_file": str(config_path) if config_path else None,
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if output_format == "json":
|
|
171
|
+
feedback.output_result(status, message="Simple Mode status retrieved")
|
|
172
|
+
else:
|
|
173
|
+
feedback.success("Simple Mode status retrieved")
|
|
174
|
+
print("\n" + "=" * 60)
|
|
175
|
+
print("Simple Mode Status")
|
|
176
|
+
print("=" * 60)
|
|
177
|
+
print(f"\nEnabled: {'Yes' if status['enabled'] else 'No'}")
|
|
178
|
+
print(f"Auto-detect: {'Yes' if status['auto_detect'] else 'No'}")
|
|
179
|
+
print(f"Show advanced: {'Yes' if status['show_advanced'] else 'No'}")
|
|
180
|
+
print(f"Natural language: {'Yes' if status['natural_language'] else 'No'}")
|
|
181
|
+
if status["config_file"]:
|
|
182
|
+
print(f"\nConfig file: {status['config_file']}")
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def find_config_file() -> Path | None:
|
|
186
|
+
"""Find .tapps-agents/config.yaml in current or parent directories."""
|
|
187
|
+
current = Path.cwd()
|
|
188
|
+
for parent in [current] + list(current.parents):
|
|
189
|
+
candidate = parent / ".tapps-agents" / "config.yaml"
|
|
190
|
+
if candidate.exists():
|
|
191
|
+
return candidate
|
|
192
|
+
return None
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def handle_simple_mode_init() -> None:
|
|
196
|
+
"""Run the Simple Mode onboarding wizard."""
|
|
197
|
+
wizard = OnboardingWizard()
|
|
198
|
+
wizard.run()
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def handle_simple_mode_configure() -> None:
|
|
202
|
+
"""Run the Simple Mode configuration wizard."""
|
|
203
|
+
zero_config = ZeroConfigMode()
|
|
204
|
+
zero_config.run_configuration_wizard()
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def handle_simple_mode_progress() -> None:
|
|
208
|
+
"""Show Simple Mode learning progression."""
|
|
209
|
+
tracker = LearningProgressionTracker()
|
|
210
|
+
tracker.show_progression_indicator()
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def handle_simple_mode_todo(args: object) -> None:
|
|
214
|
+
"""Handle simple-mode todo - forwards to bd. §3.5."""
|
|
215
|
+
from ...beads import is_available, run_bd
|
|
216
|
+
|
|
217
|
+
root = Path.cwd()
|
|
218
|
+
if not is_available(root):
|
|
219
|
+
get_feedback().error(
|
|
220
|
+
"bd not found. Install to tools/bd or add bd to PATH. See docs/BEADS_INTEGRATION.md.",
|
|
221
|
+
error_code="bd_not_found",
|
|
222
|
+
exit_code=1,
|
|
223
|
+
)
|
|
224
|
+
return
|
|
225
|
+
bd_args = list(getattr(args, "args", None) or [])
|
|
226
|
+
r = run_bd(root, bd_args, capture_output=False)
|
|
227
|
+
sys.exit(r.returncode if r.returncode is not None else 0)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def handle_simple_mode_enhance(args: object) -> None:
|
|
231
|
+
"""Handle simple-mode enhance - @simple-mode *enhance. §3.4."""
|
|
232
|
+
feedback = get_feedback()
|
|
233
|
+
prompt = getattr(args, "prompt", None) or ""
|
|
234
|
+
if not str(prompt).strip():
|
|
235
|
+
feedback.error("Prompt required", error_code="prompt_required", remediation='Use: tapps-agents simple-mode enhance --prompt "your prompt"', exit_code=2)
|
|
236
|
+
return
|
|
237
|
+
feedback.start_operation("Enhance prompt")
|
|
238
|
+
from ...simple_mode.intent_parser import Intent, IntentType
|
|
239
|
+
from ...simple_mode.orchestrators.enhance_orchestrator import EnhanceOrchestrator
|
|
240
|
+
from ...core.config import load_config
|
|
241
|
+
import asyncio
|
|
242
|
+
|
|
243
|
+
config = load_config()
|
|
244
|
+
intent = Intent(type=IntentType.ENHANCE, confidence=1.0, parameters={"prompt": str(prompt).strip(), "quick": getattr(args, "quick", False)}, original_input=prompt)
|
|
245
|
+
orch = EnhanceOrchestrator(project_root=Path.cwd(), config=config)
|
|
246
|
+
try:
|
|
247
|
+
r = asyncio.run(orch.execute(intent, intent.parameters))
|
|
248
|
+
feedback.clear_progress()
|
|
249
|
+
if r.get("success"):
|
|
250
|
+
feedback.success("Enhancement complete")
|
|
251
|
+
print(r.get("enhanced_prompt", str(r)))
|
|
252
|
+
else:
|
|
253
|
+
feedback.error(r.get("error", "Unknown error"), error_code="enhance_failed", exit_code=1)
|
|
254
|
+
except Exception as e:
|
|
255
|
+
feedback.error(str(e), error_code="enhance_error", exit_code=1)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def handle_simple_mode_breakdown(args: object) -> None:
|
|
259
|
+
"""Handle simple-mode breakdown - @simple-mode *breakdown. §3.4."""
|
|
260
|
+
feedback = get_feedback()
|
|
261
|
+
prompt = getattr(args, "prompt", None) or ""
|
|
262
|
+
if not str(prompt).strip():
|
|
263
|
+
feedback.error("Prompt required", error_code="prompt_required", remediation='Use: tapps-agents simple-mode breakdown --prompt "your goal"', exit_code=2)
|
|
264
|
+
return
|
|
265
|
+
feedback.start_operation("Breakdown tasks")
|
|
266
|
+
from ...simple_mode.intent_parser import Intent, IntentType
|
|
267
|
+
from ...simple_mode.orchestrators.breakdown_orchestrator import BreakdownOrchestrator
|
|
268
|
+
from ...core.config import load_config
|
|
269
|
+
import asyncio
|
|
270
|
+
|
|
271
|
+
config = load_config()
|
|
272
|
+
intent = Intent(type=IntentType.BREAKDOWN, confidence=1.0, parameters={"prompt": str(prompt).strip()}, original_input=prompt)
|
|
273
|
+
orch = BreakdownOrchestrator(project_root=Path.cwd(), config=config)
|
|
274
|
+
try:
|
|
275
|
+
r = asyncio.run(orch.execute(intent, intent.parameters))
|
|
276
|
+
feedback.clear_progress()
|
|
277
|
+
if r.get("success"):
|
|
278
|
+
feedback.success("Breakdown complete")
|
|
279
|
+
print(r.get("plan", r))
|
|
280
|
+
else:
|
|
281
|
+
feedback.error(r.get("error", "Unknown error"), error_code="breakdown_failed", exit_code=1)
|
|
282
|
+
except Exception as e:
|
|
283
|
+
feedback.error(str(e), error_code="breakdown_error", exit_code=1)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def handle_simple_mode_resume(args: object) -> None:
|
|
287
|
+
"""Handle simple-mode resume command."""
|
|
288
|
+
feedback = get_feedback()
|
|
289
|
+
feedback.start_operation("Resuming Workflow")
|
|
290
|
+
|
|
291
|
+
from ...simple_mode.orchestrators.resume_orchestrator import ResumeOrchestrator
|
|
292
|
+
from ...simple_mode.intent_parser import IntentParser
|
|
293
|
+
|
|
294
|
+
# Check for --list flag
|
|
295
|
+
list_workflows = getattr(args, "list", False)
|
|
296
|
+
if list_workflows:
|
|
297
|
+
orchestrator = ResumeOrchestrator(project_root=Path.cwd())
|
|
298
|
+
workflows = orchestrator.list_available_workflows()
|
|
299
|
+
|
|
300
|
+
if not workflows:
|
|
301
|
+
feedback.success("No workflows available to resume")
|
|
302
|
+
print("\nNo workflows found with checkpoints.")
|
|
303
|
+
return
|
|
304
|
+
|
|
305
|
+
feedback.success(f"Found {len(workflows)} workflow(s) available to resume")
|
|
306
|
+
print(f"\n{'='*60}")
|
|
307
|
+
print("Available Workflows to Resume")
|
|
308
|
+
print(f"{'='*60}\n")
|
|
309
|
+
|
|
310
|
+
for wf in workflows:
|
|
311
|
+
print(f"Workflow ID: {wf['workflow_id']}")
|
|
312
|
+
print(f" Last Step: {wf['last_step']} (Step {wf['last_step_number']})")
|
|
313
|
+
print(f" Completed: {wf['completed_at']}")
|
|
314
|
+
print()
|
|
315
|
+
|
|
316
|
+
return
|
|
317
|
+
|
|
318
|
+
# Get workflow_id
|
|
319
|
+
workflow_id = getattr(args, "workflow_id", None)
|
|
320
|
+
if not workflow_id:
|
|
321
|
+
feedback.error(
|
|
322
|
+
"Workflow ID required",
|
|
323
|
+
error_code="workflow_id_required",
|
|
324
|
+
remediation="Provide workflow_id or use --list to see available workflows",
|
|
325
|
+
exit_code=2,
|
|
326
|
+
)
|
|
327
|
+
return
|
|
328
|
+
|
|
329
|
+
# Validate if requested
|
|
330
|
+
validate = getattr(args, "validate", False)
|
|
331
|
+
if validate:
|
|
332
|
+
feedback.running("Validating workflow state...", step=1, total_steps=2)
|
|
333
|
+
|
|
334
|
+
# Resume workflow
|
|
335
|
+
feedback.running(f"Resuming workflow: {workflow_id}...", step=2, total_steps=2)
|
|
336
|
+
|
|
337
|
+
try:
|
|
338
|
+
orchestrator = ResumeOrchestrator(project_root=Path.cwd())
|
|
339
|
+
parser = IntentParser()
|
|
340
|
+
intent = parser.parse(f"resume {workflow_id}")
|
|
341
|
+
|
|
342
|
+
import asyncio
|
|
343
|
+
|
|
344
|
+
result = asyncio.run(orchestrator.execute(intent, {"workflow_id": workflow_id}))
|
|
345
|
+
|
|
346
|
+
feedback.clear_progress()
|
|
347
|
+
feedback.success(f"Workflow {workflow_id} ready to resume")
|
|
348
|
+
|
|
349
|
+
print(f"\n{'='*60}")
|
|
350
|
+
print(f"Resume Workflow: {workflow_id}")
|
|
351
|
+
print(f"{'='*60}")
|
|
352
|
+
print(f"Resume from: Step {result['resume_step']}")
|
|
353
|
+
print(f"Completed steps: {', '.join(map(str, result['completed_steps']))}")
|
|
354
|
+
print(f"Last checkpoint: {result['checkpoint']['step_name']}")
|
|
355
|
+
print(f"\n{result['message']}")
|
|
356
|
+
print("\nNote: Resume execution logic will be integrated with BuildOrchestrator")
|
|
357
|
+
|
|
358
|
+
except Exception as e:
|
|
359
|
+
feedback.clear_progress()
|
|
360
|
+
feedback.error(
|
|
361
|
+
f"Failed to resume workflow: {e}",
|
|
362
|
+
error_code="resume_failed",
|
|
363
|
+
context={"workflow_id": workflow_id},
|
|
364
|
+
remediation="Check that workflow_id exists and checkpoints are valid",
|
|
365
|
+
exit_code=1,
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def handle_simple_mode_build(args: object) -> None:
|
|
370
|
+
"""Handle simple-mode build command - runs build workflow for new features."""
|
|
371
|
+
feedback = get_feedback()
|
|
372
|
+
feedback.start_operation("Starting Simple Mode Build Workflow")
|
|
373
|
+
|
|
374
|
+
# Validate arguments before execution
|
|
375
|
+
from ..validators.command_validator import CommandValidator
|
|
376
|
+
from ..utils.error_formatter import ErrorFormatter
|
|
377
|
+
|
|
378
|
+
validator = CommandValidator()
|
|
379
|
+
validation_result = validator.validate_build_command(args)
|
|
380
|
+
|
|
381
|
+
if not validation_result.valid:
|
|
382
|
+
formatter = ErrorFormatter()
|
|
383
|
+
error_msg = formatter.format_validation_error(validation_result)
|
|
384
|
+
feedback.error(
|
|
385
|
+
"Command validation failed",
|
|
386
|
+
error_code="validation_error",
|
|
387
|
+
context={"errors": validation_result.errors},
|
|
388
|
+
remediation=validation_result.suggestions[0] if validation_result.suggestions else "Check command arguments",
|
|
389
|
+
exit_code=2,
|
|
390
|
+
)
|
|
391
|
+
# Print detailed error message
|
|
392
|
+
print("\n" + error_msg, file=sys.stderr)
|
|
393
|
+
return
|
|
394
|
+
|
|
395
|
+
# Get arguments (validated)
|
|
396
|
+
user_prompt = getattr(args, "prompt", None)
|
|
397
|
+
target_file = getattr(args, "file", None)
|
|
398
|
+
fast_mode = getattr(args, "fast", False)
|
|
399
|
+
preset_arg = getattr(args, "preset", None)
|
|
400
|
+
auto_mode = getattr(args, "auto", False)
|
|
401
|
+
no_auto_checkpoint = getattr(args, "no_auto_checkpoint", False)
|
|
402
|
+
checkpoint_debug = getattr(args, "checkpoint_debug", False)
|
|
403
|
+
|
|
404
|
+
# Auto-suggest preset from scope when neither --fast nor --preset set (SIMPLE_MODE_FEEDBACK_REVIEW)
|
|
405
|
+
if not fast_mode and preset_arg is None and user_prompt:
|
|
406
|
+
from ...simple_mode.workflow_suggester import WorkflowSuggester
|
|
407
|
+
suggester = WorkflowSuggester()
|
|
408
|
+
suggested = suggester.suggest_build_preset(user_prompt)
|
|
409
|
+
if suggested == "minimal":
|
|
410
|
+
fast_mode = True
|
|
411
|
+
preset_arg = "minimal"
|
|
412
|
+
else:
|
|
413
|
+
preset_arg = suggested
|
|
414
|
+
# Log without prompting user
|
|
415
|
+
if preset_arg:
|
|
416
|
+
feedback.info(f"Preset auto-selected from scope: {preset_arg}")
|
|
417
|
+
|
|
418
|
+
# Explicit --preset overrides: minimal => fast_mode
|
|
419
|
+
if preset_arg == "minimal" and not getattr(args, "fast", False):
|
|
420
|
+
fast_mode = True
|
|
421
|
+
|
|
422
|
+
print(f"\n{'='*60}")
|
|
423
|
+
print("Simple Mode Build Workflow")
|
|
424
|
+
print(f"{'='*60}")
|
|
425
|
+
print(f"Feature: {user_prompt}")
|
|
426
|
+
if fast_mode:
|
|
427
|
+
print("Mode: Fast (skipping documentation steps 1-4)")
|
|
428
|
+
else:
|
|
429
|
+
print("Mode: Complete (all 7 steps)")
|
|
430
|
+
print()
|
|
431
|
+
|
|
432
|
+
# Load config
|
|
433
|
+
from ...core.config import load_config
|
|
434
|
+
from ...core.path_normalizer import normalize_for_cli, normalize_project_root
|
|
435
|
+
from ...core.runtime_mode import detect_runtime_mode, is_cursor_mode
|
|
436
|
+
from ...simple_mode.intent_parser import Intent, IntentParser, IntentType
|
|
437
|
+
from ...simple_mode.orchestrators.build_orchestrator import BuildOrchestrator
|
|
438
|
+
|
|
439
|
+
config = load_config()
|
|
440
|
+
project_root = normalize_project_root(Path.cwd())
|
|
441
|
+
|
|
442
|
+
# Normalize target file path if provided
|
|
443
|
+
if target_file:
|
|
444
|
+
try:
|
|
445
|
+
target_file = normalize_for_cli(target_file, project_root)
|
|
446
|
+
except Exception as e:
|
|
447
|
+
feedback.warning(f"Path normalization warning: {e}. Using path as-is.")
|
|
448
|
+
# Continue with original path - let workflow executor handle it
|
|
449
|
+
|
|
450
|
+
# Create intent
|
|
451
|
+
parser = IntentParser()
|
|
452
|
+
intent = Intent(
|
|
453
|
+
type=IntentType.BUILD,
|
|
454
|
+
confidence=1.0,
|
|
455
|
+
parameters={
|
|
456
|
+
"description": user_prompt,
|
|
457
|
+
"file": target_file,
|
|
458
|
+
"no_auto_checkpoint": no_auto_checkpoint,
|
|
459
|
+
"checkpoint_debug": checkpoint_debug,
|
|
460
|
+
},
|
|
461
|
+
original_input=user_prompt,
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
# Initialize orchestrator
|
|
465
|
+
orchestrator = BuildOrchestrator(
|
|
466
|
+
project_root=project_root,
|
|
467
|
+
config=config,
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
# Check runtime mode
|
|
471
|
+
runtime_mode = detect_runtime_mode()
|
|
472
|
+
feedback.clear_progress()
|
|
473
|
+
|
|
474
|
+
# Workflow preview (if not auto mode)
|
|
475
|
+
if not auto_mode:
|
|
476
|
+
print("\n" + "=" * 60)
|
|
477
|
+
print("Workflow Preview")
|
|
478
|
+
print("=" * 60)
|
|
479
|
+
print(f"Feature: {user_prompt}")
|
|
480
|
+
print(f"Mode: {'Fast' if fast_mode else 'Complete'} ({'4' if fast_mode else '7'} steps)")
|
|
481
|
+
print("\nSteps to Execute:")
|
|
482
|
+
if fast_mode:
|
|
483
|
+
steps = [
|
|
484
|
+
(5, "Implement code", "~5s"),
|
|
485
|
+
(6, "Review code quality", "~2s"),
|
|
486
|
+
(7, "Generate tests", "~2s"),
|
|
487
|
+
]
|
|
488
|
+
else:
|
|
489
|
+
steps = [
|
|
490
|
+
(1, "Enhance prompt (requirements analysis)", "~2s"),
|
|
491
|
+
(2, "Create user stories", "~2s"),
|
|
492
|
+
(3, "Design architecture", "~3s"),
|
|
493
|
+
(4, "Design API/data models", "~3s"),
|
|
494
|
+
(5, "Implement code", "~5s"),
|
|
495
|
+
(6, "Review code quality", "~2s"),
|
|
496
|
+
(7, "Generate tests", "~2s"),
|
|
497
|
+
]
|
|
498
|
+
for step_num, step_name, est_time in steps:
|
|
499
|
+
print(f" {step_num}. {step_name:<45} {est_time}")
|
|
500
|
+
total_est = sum(float(s[2].replace("~", "").replace("s", "")) for s in steps)
|
|
501
|
+
print(f"\nEstimated Total Time: ~{total_est:.0f}s")
|
|
502
|
+
print(f"Configuration: automation.level=2, fast_mode={str(fast_mode).lower()}")
|
|
503
|
+
print("\n" + "=" * 60)
|
|
504
|
+
sys.stdout.flush()
|
|
505
|
+
|
|
506
|
+
print("\nExecuting build workflow...")
|
|
507
|
+
print(f"Runtime mode: {runtime_mode.value}")
|
|
508
|
+
print(f"Auto-execution: {'enabled' if auto_mode else 'disabled'}")
|
|
509
|
+
|
|
510
|
+
from ...core.unicode_safe import safe_print
|
|
511
|
+
if is_cursor_mode():
|
|
512
|
+
safe_print("[OK] Running in Cursor mode - using direct execution\n")
|
|
513
|
+
else:
|
|
514
|
+
safe_print("[OK] Running in headless mode - direct execution with terminal output\n")
|
|
515
|
+
|
|
516
|
+
sys.stdout.flush()
|
|
517
|
+
|
|
518
|
+
# Initialize status reporter
|
|
519
|
+
from ..utils.status_reporter import StatusReporter
|
|
520
|
+
total_steps = 4 if fast_mode else 7
|
|
521
|
+
status_reporter = StatusReporter(total_steps=total_steps)
|
|
522
|
+
|
|
523
|
+
# Define callbacks for real-time status reporting
|
|
524
|
+
def on_step_start(step_num: int, step_name: str) -> None:
|
|
525
|
+
"""Callback when a step starts."""
|
|
526
|
+
status_reporter.start_step(step_num, step_name)
|
|
527
|
+
|
|
528
|
+
def on_step_complete(step_num: int, step_name: str, status: str) -> None:
|
|
529
|
+
"""Callback when a step completes."""
|
|
530
|
+
status_reporter.complete_step(step_num, step_name, status)
|
|
531
|
+
|
|
532
|
+
def on_step_error(step_num: int, step_name: str, error: Exception) -> None:
|
|
533
|
+
"""Callback when a step errors."""
|
|
534
|
+
status_reporter.complete_step(step_num, step_name, "failed")
|
|
535
|
+
|
|
536
|
+
try:
|
|
537
|
+
import asyncio
|
|
538
|
+
|
|
539
|
+
result = asyncio.run(
|
|
540
|
+
orchestrator.execute(
|
|
541
|
+
intent=intent,
|
|
542
|
+
parameters=intent.parameters,
|
|
543
|
+
fast_mode=fast_mode,
|
|
544
|
+
on_step_start=on_step_start,
|
|
545
|
+
on_step_complete=on_step_complete,
|
|
546
|
+
on_step_error=on_step_error,
|
|
547
|
+
)
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
# Print execution summary
|
|
551
|
+
status_reporter.print_summary()
|
|
552
|
+
|
|
553
|
+
if result.get("success", False):
|
|
554
|
+
feedback.success("Simple Mode Build Workflow completed successfully")
|
|
555
|
+
print("\n✅ Build workflow completed successfully!")
|
|
556
|
+
if "workflow_id" in result:
|
|
557
|
+
print(f"\nWorkflow ID: {result['workflow_id']}")
|
|
558
|
+
if "steps_executed" in result:
|
|
559
|
+
print(f"Steps executed: {len(result['steps_executed'])}")
|
|
560
|
+
else:
|
|
561
|
+
feedback.error(
|
|
562
|
+
"Build workflow execution failed",
|
|
563
|
+
error_code="build_workflow_failed",
|
|
564
|
+
context={"error": result.get("error", "Unknown error")},
|
|
565
|
+
exit_code=1,
|
|
566
|
+
)
|
|
567
|
+
except Exception as e:
|
|
568
|
+
feedback.error(
|
|
569
|
+
"Build workflow execution error",
|
|
570
|
+
error_code="build_workflow_error",
|
|
571
|
+
context={"error": str(e)},
|
|
572
|
+
exit_code=1,
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
def handle_simple_mode_full(args: object) -> None:
|
|
577
|
+
"""Handle simple-mode full command - runs the Full SDLC workflow (requirements -> security -> docs)."""
|
|
578
|
+
feedback = get_feedback()
|
|
579
|
+
feedback.start_operation("Starting Full SDLC Workflow")
|
|
580
|
+
|
|
581
|
+
# Load the full SDLC workflow preset (matches docs: @simple-mode *full)
|
|
582
|
+
loader = PresetLoader()
|
|
583
|
+
workflow = loader.load_preset("full-sdlc")
|
|
584
|
+
|
|
585
|
+
if not workflow:
|
|
586
|
+
feedback.error(
|
|
587
|
+
"Workflow not found",
|
|
588
|
+
error_code="workflow_not_found",
|
|
589
|
+
context={"preset": "full-sdlc"},
|
|
590
|
+
remediation="Ensure full-sdlc.yaml exists in workflows/presets/",
|
|
591
|
+
exit_code=1,
|
|
592
|
+
)
|
|
593
|
+
return
|
|
594
|
+
|
|
595
|
+
print(f"\n{'='*60}")
|
|
596
|
+
print(f"Starting: {workflow.name}")
|
|
597
|
+
print(f"{'='*60}")
|
|
598
|
+
print(f"Description: {workflow.description}")
|
|
599
|
+
print(f"Steps: {len(workflow.steps)}")
|
|
600
|
+
print("\nThis workflow includes:")
|
|
601
|
+
print(" • Full SDLC lifecycle (requirements -> implementation -> testing)")
|
|
602
|
+
print(" • Automatic quality gates with scoring")
|
|
603
|
+
print(" • Development loopbacks if scores aren't good enough")
|
|
604
|
+
print(" • Test execution and validation")
|
|
605
|
+
print(" • Security scanning")
|
|
606
|
+
print(" • Documentation generation")
|
|
607
|
+
print()
|
|
608
|
+
|
|
609
|
+
# Get optional arguments
|
|
610
|
+
target_file = getattr(args, "file", None)
|
|
611
|
+
user_prompt = getattr(args, "prompt", None)
|
|
612
|
+
auto_mode = getattr(args, "auto", False)
|
|
613
|
+
no_auto_checkpoint = getattr(args, "no_auto_checkpoint", False)
|
|
614
|
+
checkpoint_debug = getattr(args, "checkpoint_debug", False)
|
|
615
|
+
|
|
616
|
+
# Execute with auto_mode
|
|
617
|
+
executor = WorkflowExecutor(auto_detect=False, auto_mode=auto_mode)
|
|
618
|
+
|
|
619
|
+
# Pass checkpoint flags to executor
|
|
620
|
+
if no_auto_checkpoint or checkpoint_debug:
|
|
621
|
+
executor.parameters = executor.parameters or {}
|
|
622
|
+
if no_auto_checkpoint:
|
|
623
|
+
executor.parameters["no_auto_checkpoint"] = True
|
|
624
|
+
if checkpoint_debug:
|
|
625
|
+
executor.parameters["checkpoint_debug"] = True
|
|
626
|
+
|
|
627
|
+
if user_prompt:
|
|
628
|
+
executor.user_prompt = user_prompt
|
|
629
|
+
|
|
630
|
+
# Check runtime mode
|
|
631
|
+
from ...core.runtime_mode import is_cursor_mode, detect_runtime_mode
|
|
632
|
+
runtime_mode = detect_runtime_mode()
|
|
633
|
+
|
|
634
|
+
# Stop spinner before async execution (spinner may interfere with async)
|
|
635
|
+
feedback.clear_progress()
|
|
636
|
+
|
|
637
|
+
print("Executing workflow steps...")
|
|
638
|
+
print(f"Runtime mode: {runtime_mode.value}")
|
|
639
|
+
print(f"Auto-execution: {'enabled' if auto_mode else 'disabled'}")
|
|
640
|
+
|
|
641
|
+
from ...core.unicode_safe import safe_print
|
|
642
|
+
if is_cursor_mode():
|
|
643
|
+
safe_print("[OK] Running in Cursor mode - using direct execution and Cursor Skills\n")
|
|
644
|
+
else:
|
|
645
|
+
safe_print("[OK] Running in headless mode - direct execution with terminal output\n")
|
|
646
|
+
|
|
647
|
+
sys.stdout.flush()
|
|
648
|
+
|
|
649
|
+
try:
|
|
650
|
+
import asyncio
|
|
651
|
+
state = asyncio.run(executor.execute(workflow=workflow, target_file=target_file))
|
|
652
|
+
|
|
653
|
+
if state.status == "completed":
|
|
654
|
+
feedback.success("Full SDLC Workflow completed successfully")
|
|
655
|
+
print("\n✅ Workflow completed successfully!")
|
|
656
|
+
print(f"\nWorkflow ID: {state.workflow_id}")
|
|
657
|
+
print(f"Steps completed: {len(state.completed_steps)}/{len(workflow.steps)}")
|
|
658
|
+
else:
|
|
659
|
+
feedback.error(
|
|
660
|
+
"Workflow execution failed",
|
|
661
|
+
error_code="workflow_execution_failed",
|
|
662
|
+
context={"status": state.status, "error": state.error if hasattr(state, 'error') else "Unknown error"},
|
|
663
|
+
exit_code=1,
|
|
664
|
+
)
|
|
665
|
+
except TimeoutError as e:
|
|
666
|
+
feedback.error(
|
|
667
|
+
"Workflow timeout",
|
|
668
|
+
error_code="workflow_timeout",
|
|
669
|
+
context={"error": str(e)},
|
|
670
|
+
remediation="Increase timeout in config (workflow.timeout_seconds) or check for blocking operations",
|
|
671
|
+
exit_code=1,
|
|
672
|
+
)
|
|
673
|
+
except Exception as e:
|
|
674
|
+
feedback.error(
|
|
675
|
+
"Workflow execution error",
|
|
676
|
+
error_code="workflow_execution_error",
|
|
677
|
+
context={"error": str(e)},
|
|
678
|
+
exit_code=1,
|
|
679
|
+
)
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
def handle_simple_mode_epic(args: object) -> None:
|
|
683
|
+
"""Handle simple-mode epic command - execute Epic document (all stories in dependency order)."""
|
|
684
|
+
feedback = get_feedback()
|
|
685
|
+
epic_path = getattr(args, "epic_path", None)
|
|
686
|
+
|
|
687
|
+
if not epic_path:
|
|
688
|
+
feedback.error(
|
|
689
|
+
"Epic path required",
|
|
690
|
+
error_code="epic_path_required",
|
|
691
|
+
remediation="Use: tapps-agents simple-mode epic <path> (e.g. stories/enh-002-critical-enhancements.md)",
|
|
692
|
+
exit_code=2,
|
|
693
|
+
)
|
|
694
|
+
return
|
|
695
|
+
|
|
696
|
+
feedback.start_operation("Executing Epic")
|
|
697
|
+
project_root = Path.cwd()
|
|
698
|
+
epic_path_resolved = Path(epic_path)
|
|
699
|
+
if not epic_path_resolved.is_absolute():
|
|
700
|
+
if (project_root / epic_path_resolved).exists():
|
|
701
|
+
epic_path_resolved = project_root / epic_path_resolved
|
|
702
|
+
elif (project_root / "docs" / "prd" / epic_path_resolved.name).exists():
|
|
703
|
+
epic_path_resolved = project_root / "docs" / "prd" / epic_path_resolved.name
|
|
704
|
+
else:
|
|
705
|
+
epic_path_resolved = project_root / epic_path_resolved
|
|
706
|
+
|
|
707
|
+
if not epic_path_resolved.exists():
|
|
708
|
+
feedback.error(
|
|
709
|
+
"Epic document not found",
|
|
710
|
+
error_code="epic_not_found",
|
|
711
|
+
context={"path": str(epic_path_resolved)},
|
|
712
|
+
remediation="Provide a valid path to an Epic markdown file",
|
|
713
|
+
exit_code=2,
|
|
714
|
+
)
|
|
715
|
+
return
|
|
716
|
+
|
|
717
|
+
quality_threshold = getattr(args, "quality_threshold", 70.0)
|
|
718
|
+
critical_threshold = getattr(args, "critical_service_threshold", 80.0)
|
|
719
|
+
auto_mode = getattr(args, "auto", False)
|
|
720
|
+
enforce_quality_gates = not getattr(args, "no_quality_gates", False)
|
|
721
|
+
|
|
722
|
+
from ...core.config import load_config
|
|
723
|
+
from ...simple_mode.intent_parser import Intent, IntentType
|
|
724
|
+
from ...simple_mode.orchestrators.epic_orchestrator import EpicOrchestrator
|
|
725
|
+
|
|
726
|
+
config = load_config()
|
|
727
|
+
orchestrator = EpicOrchestrator(
|
|
728
|
+
project_root=project_root,
|
|
729
|
+
config=config,
|
|
730
|
+
)
|
|
731
|
+
|
|
732
|
+
intent = Intent(
|
|
733
|
+
type=IntentType.EPIC,
|
|
734
|
+
confidence=1.0,
|
|
735
|
+
parameters={
|
|
736
|
+
"epic_path": str(epic_path_resolved),
|
|
737
|
+
"quality_threshold": quality_threshold,
|
|
738
|
+
"critical_service_threshold": critical_threshold,
|
|
739
|
+
"auto_mode": auto_mode,
|
|
740
|
+
"enforce_quality_gates": enforce_quality_gates,
|
|
741
|
+
},
|
|
742
|
+
original_input=str(epic_path_resolved),
|
|
743
|
+
)
|
|
744
|
+
|
|
745
|
+
feedback.clear_progress()
|
|
746
|
+
print(f"\n{'='*60}")
|
|
747
|
+
print("Epic Execution")
|
|
748
|
+
print(f"{'='*60}")
|
|
749
|
+
print(f"Epic: {epic_path_resolved}")
|
|
750
|
+
print(f"Quality threshold: {quality_threshold}")
|
|
751
|
+
print(f"Auto mode: {auto_mode}")
|
|
752
|
+
print()
|
|
753
|
+
|
|
754
|
+
try:
|
|
755
|
+
import asyncio
|
|
756
|
+
result = asyncio.run(orchestrator.execute(intent, intent.parameters))
|
|
757
|
+
|
|
758
|
+
if result.get("success", False):
|
|
759
|
+
feedback.success("Epic execution completed")
|
|
760
|
+
print("\n[OK] Epic execution completed!")
|
|
761
|
+
print(f" Epic: {result.get('epic_number')} - {result.get('epic_title', '')}")
|
|
762
|
+
print(f" Completion: {result.get('completion_percentage', 0):.1f}%")
|
|
763
|
+
print(f" Done: {result.get('done_stories', 0)}/{result.get('total_stories', 0)} stories")
|
|
764
|
+
if result.get("failed_stories", 0) > 0:
|
|
765
|
+
print(f" Failed: {result.get('failed_stories', 0)} stories")
|
|
766
|
+
report_path = result.get("report_path")
|
|
767
|
+
if report_path:
|
|
768
|
+
print(f"\nReport saved to: {report_path}")
|
|
769
|
+
else:
|
|
770
|
+
feedback.error(
|
|
771
|
+
"Epic execution failed",
|
|
772
|
+
error_code="epic_execution_failed",
|
|
773
|
+
context={"error": result.get("error", "Unknown error")},
|
|
774
|
+
exit_code=1,
|
|
775
|
+
)
|
|
776
|
+
except Exception as e:
|
|
777
|
+
feedback.error(
|
|
778
|
+
"Epic execution error",
|
|
779
|
+
error_code="epic_execution_error",
|
|
780
|
+
context={"error": str(e)},
|
|
781
|
+
exit_code=1,
|
|
782
|
+
)
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
def handle_simple_mode_epic_status(args: object) -> None:
|
|
786
|
+
"""Update epic markdown with execution status from report JSON."""
|
|
787
|
+
feedback = get_feedback()
|
|
788
|
+
epic_path = getattr(args, "epic_path", None)
|
|
789
|
+
report_path = getattr(args, "report", None)
|
|
790
|
+
|
|
791
|
+
if not epic_path:
|
|
792
|
+
feedback.error(
|
|
793
|
+
"Epic path required",
|
|
794
|
+
error_code="epic_path_required",
|
|
795
|
+
remediation="Use: tapps-agents simple-mode epic-status <path> (e.g. stories/enh-002-critical-enhancements.md)",
|
|
796
|
+
exit_code=2,
|
|
797
|
+
)
|
|
798
|
+
return
|
|
799
|
+
|
|
800
|
+
project_root = Path.cwd()
|
|
801
|
+
epic_path_resolved = Path(epic_path)
|
|
802
|
+
if not epic_path_resolved.is_absolute():
|
|
803
|
+
if (project_root / epic_path_resolved).exists():
|
|
804
|
+
epic_path_resolved = project_root / epic_path_resolved
|
|
805
|
+
elif (project_root / "docs" / "prd" / epic_path_resolved.name).exists():
|
|
806
|
+
epic_path_resolved = project_root / "docs" / "prd" / epic_path_resolved.name
|
|
807
|
+
else:
|
|
808
|
+
epic_path_resolved = project_root / epic_path_resolved
|
|
809
|
+
|
|
810
|
+
try:
|
|
811
|
+
from ...epic.markdown_sync import update_epic_markdown_from_report
|
|
812
|
+
|
|
813
|
+
update_epic_markdown_from_report(
|
|
814
|
+
epic_path_resolved,
|
|
815
|
+
report_path=report_path,
|
|
816
|
+
project_root=project_root,
|
|
817
|
+
)
|
|
818
|
+
feedback.success("Epic markdown updated with execution status")
|
|
819
|
+
print(f"\n[OK] Updated {epic_path_resolved} with status from report.")
|
|
820
|
+
except FileNotFoundError as e:
|
|
821
|
+
feedback.error(
|
|
822
|
+
"File not found",
|
|
823
|
+
error_code="epic_status_file_not_found",
|
|
824
|
+
context={"error": str(e)},
|
|
825
|
+
remediation="Run 'simple-mode epic <path>' first to generate the report, or pass --report <path>.",
|
|
826
|
+
exit_code=2,
|
|
827
|
+
)
|
|
828
|
+
except ValueError as e:
|
|
829
|
+
feedback.error(
|
|
830
|
+
"Invalid epic or report",
|
|
831
|
+
error_code="epic_status_invalid",
|
|
832
|
+
context={"error": str(e)},
|
|
833
|
+
exit_code=2,
|
|
834
|
+
)
|
|
835
|
+
except Exception as e:
|
|
836
|
+
feedback.error(
|
|
837
|
+
"Epic status update failed",
|
|
838
|
+
error_code="epic_status_update_failed",
|
|
839
|
+
context={"error": str(e)},
|
|
840
|
+
exit_code=1,
|
|
841
|
+
)
|
|
842
|
+
|