tapps-agents 3.5.39__py3-none-any.whl → 3.5.41__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 +227 -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 +2337 -2118
- tapps_agents/workflow/direct_execution_fallback.py +16 -3
- tapps_agents/workflow/message_formatter.py +2 -1
- tapps_agents/workflow/models.py +38 -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.41.dist-info}/METADATA +5 -1
- {tapps_agents-3.5.39.dist-info → tapps_agents-3.5.41.dist-info}/RECORD +58 -54
- 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.41.dist-info}/WHEEL +0 -0
- {tapps_agents-3.5.39.dist-info → tapps_agents-3.5.41.dist-info}/entry_points.txt +0 -0
- {tapps_agents-3.5.39.dist-info → tapps_agents-3.5.41.dist-info}/licenses/LICENSE +0 -0
- {tapps_agents-3.5.39.dist-info → tapps_agents-3.5.41.dist-info}/top_level.txt +0 -0
tapps_agents/cli/main.py
CHANGED
|
@@ -1,651 +1,658 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Main CLI entry point
|
|
3
|
-
"""
|
|
4
|
-
import argparse
|
|
5
|
-
import asyncio
|
|
6
|
-
import os
|
|
7
|
-
import sys
|
|
8
|
-
from collections.abc import Callable
|
|
9
|
-
|
|
10
|
-
# Try to import version, with fallback to importlib.metadata
|
|
11
|
-
try:
|
|
12
|
-
from .. import __version__ as PACKAGE_VERSION
|
|
13
|
-
except (ImportError, AttributeError):
|
|
14
|
-
# Fallback: use importlib.metadata (standard library, Python 3.8+)
|
|
15
|
-
try:
|
|
16
|
-
from importlib.metadata import version
|
|
17
|
-
PACKAGE_VERSION = version("tapps-agents")
|
|
18
|
-
except Exception:
|
|
19
|
-
# Last resort: try reading from __init__.py directly
|
|
20
|
-
try:
|
|
21
|
-
import importlib.util
|
|
22
|
-
import pathlib
|
|
23
|
-
init_path = pathlib.Path(__file__).parent.parent / "__init__.py"
|
|
24
|
-
if init_path.exists():
|
|
25
|
-
spec = importlib.util.spec_from_file_location("tapps_agents_init", init_path)
|
|
26
|
-
if spec and spec.loader:
|
|
27
|
-
module = importlib.util.module_from_spec(spec)
|
|
28
|
-
spec.loader.exec_module(module)
|
|
29
|
-
PACKAGE_VERSION = getattr(module, "__version__", "unknown")
|
|
30
|
-
else:
|
|
31
|
-
PACKAGE_VERSION = "unknown"
|
|
32
|
-
else:
|
|
33
|
-
PACKAGE_VERSION = "unknown"
|
|
34
|
-
except Exception:
|
|
35
|
-
PACKAGE_VERSION = "unknown"
|
|
36
|
-
from .commands import (
|
|
37
|
-
analyst,
|
|
38
|
-
architect,
|
|
39
|
-
cleanup_agent,
|
|
40
|
-
debugger,
|
|
41
|
-
designer,
|
|
42
|
-
documenter,
|
|
43
|
-
enhancer,
|
|
44
|
-
evaluator,
|
|
45
|
-
implementer,
|
|
46
|
-
improver,
|
|
47
|
-
learning,
|
|
48
|
-
observability,
|
|
49
|
-
ops,
|
|
50
|
-
orchestrator,
|
|
51
|
-
planner,
|
|
52
|
-
reviewer,
|
|
53
|
-
simple_mode,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if
|
|
138
|
-
|
|
139
|
-
i
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
>>> parser
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
•
|
|
176
|
-
•
|
|
177
|
-
•
|
|
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
|
-
tapps-agents <
|
|
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
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
"
|
|
356
|
-
"
|
|
357
|
-
"
|
|
358
|
-
"
|
|
359
|
-
"
|
|
360
|
-
"
|
|
361
|
-
"
|
|
362
|
-
"
|
|
363
|
-
"
|
|
364
|
-
"
|
|
365
|
-
"
|
|
366
|
-
"skill
|
|
367
|
-
"
|
|
368
|
-
"
|
|
369
|
-
"
|
|
370
|
-
"
|
|
371
|
-
"
|
|
372
|
-
"
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
top_level.
|
|
383
|
-
elif cleanup_type == "
|
|
384
|
-
top_level.
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
sys.
|
|
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
|
-
from
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
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
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
config
|
|
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
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
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
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
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
|
-
|
|
1
|
+
"""
|
|
2
|
+
Main CLI entry point
|
|
3
|
+
"""
|
|
4
|
+
import argparse
|
|
5
|
+
import asyncio
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
from collections.abc import Callable
|
|
9
|
+
|
|
10
|
+
# Try to import version, with fallback to importlib.metadata
|
|
11
|
+
try:
|
|
12
|
+
from .. import __version__ as PACKAGE_VERSION
|
|
13
|
+
except (ImportError, AttributeError):
|
|
14
|
+
# Fallback: use importlib.metadata (standard library, Python 3.8+)
|
|
15
|
+
try:
|
|
16
|
+
from importlib.metadata import version
|
|
17
|
+
PACKAGE_VERSION = version("tapps-agents")
|
|
18
|
+
except Exception:
|
|
19
|
+
# Last resort: try reading from __init__.py directly
|
|
20
|
+
try:
|
|
21
|
+
import importlib.util
|
|
22
|
+
import pathlib
|
|
23
|
+
init_path = pathlib.Path(__file__).parent.parent / "__init__.py"
|
|
24
|
+
if init_path.exists():
|
|
25
|
+
spec = importlib.util.spec_from_file_location("tapps_agents_init", init_path)
|
|
26
|
+
if spec and spec.loader:
|
|
27
|
+
module = importlib.util.module_from_spec(spec)
|
|
28
|
+
spec.loader.exec_module(module)
|
|
29
|
+
PACKAGE_VERSION = getattr(module, "__version__", "unknown")
|
|
30
|
+
else:
|
|
31
|
+
PACKAGE_VERSION = "unknown"
|
|
32
|
+
else:
|
|
33
|
+
PACKAGE_VERSION = "unknown"
|
|
34
|
+
except Exception:
|
|
35
|
+
PACKAGE_VERSION = "unknown"
|
|
36
|
+
from .commands import (
|
|
37
|
+
analyst,
|
|
38
|
+
architect,
|
|
39
|
+
cleanup_agent,
|
|
40
|
+
debugger,
|
|
41
|
+
designer,
|
|
42
|
+
documenter,
|
|
43
|
+
enhancer,
|
|
44
|
+
evaluator,
|
|
45
|
+
implementer,
|
|
46
|
+
improver,
|
|
47
|
+
learning,
|
|
48
|
+
observability,
|
|
49
|
+
ops,
|
|
50
|
+
orchestrator,
|
|
51
|
+
planner,
|
|
52
|
+
reviewer,
|
|
53
|
+
simple_mode,
|
|
54
|
+
task as task_cmd,
|
|
55
|
+
tester,
|
|
56
|
+
top_level,
|
|
57
|
+
)
|
|
58
|
+
from .feedback import FeedbackManager, ProgressMode, VerbosityLevel
|
|
59
|
+
|
|
60
|
+
# Import all parser registration functions
|
|
61
|
+
from .parsers import (
|
|
62
|
+
analyst as analyst_parsers,
|
|
63
|
+
)
|
|
64
|
+
from .parsers import (
|
|
65
|
+
cleanup_agent as cleanup_agent_parsers,
|
|
66
|
+
)
|
|
67
|
+
from .parsers import (
|
|
68
|
+
architect as architect_parsers,
|
|
69
|
+
)
|
|
70
|
+
from .parsers import (
|
|
71
|
+
debugger as debugger_parsers,
|
|
72
|
+
)
|
|
73
|
+
from .parsers import (
|
|
74
|
+
designer as designer_parsers,
|
|
75
|
+
)
|
|
76
|
+
from .parsers import (
|
|
77
|
+
documenter as documenter_parsers,
|
|
78
|
+
)
|
|
79
|
+
from .parsers import (
|
|
80
|
+
enhancer as enhancer_parsers,
|
|
81
|
+
)
|
|
82
|
+
from .parsers import (
|
|
83
|
+
evaluator as evaluator_parsers,
|
|
84
|
+
)
|
|
85
|
+
from .parsers import (
|
|
86
|
+
implementer as implementer_parsers,
|
|
87
|
+
)
|
|
88
|
+
from .parsers import (
|
|
89
|
+
improver as improver_parsers,
|
|
90
|
+
)
|
|
91
|
+
from .parsers import (
|
|
92
|
+
ops as ops_parsers,
|
|
93
|
+
)
|
|
94
|
+
from .parsers import (
|
|
95
|
+
orchestrator as orchestrator_parsers,
|
|
96
|
+
)
|
|
97
|
+
from .parsers import (
|
|
98
|
+
planner as planner_parsers,
|
|
99
|
+
)
|
|
100
|
+
from .parsers import (
|
|
101
|
+
reviewer as reviewer_parsers,
|
|
102
|
+
)
|
|
103
|
+
from .parsers import (
|
|
104
|
+
tester as tester_parsers,
|
|
105
|
+
)
|
|
106
|
+
from .parsers import (
|
|
107
|
+
top_level as top_level_parsers,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _reorder_global_flags(argv: list[str]) -> list[str]:
|
|
112
|
+
"""
|
|
113
|
+
Allow global flags to appear anywhere (common modern CLI UX).
|
|
114
|
+
|
|
115
|
+
Argparse only supports global flags before the subcommand. Users frequently type:
|
|
116
|
+
tapps-agents doctor --no-progress
|
|
117
|
+
so we hoist known global flags to the front before parsing.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
hoisted: list[str] = []
|
|
121
|
+
rest: list[str] = []
|
|
122
|
+
i = 0
|
|
123
|
+
while i < len(argv):
|
|
124
|
+
a = argv[i]
|
|
125
|
+
|
|
126
|
+
if a in {"--quiet", "-q", "--verbose", "-v", "--no-progress"}:
|
|
127
|
+
hoisted.append(a)
|
|
128
|
+
i += 1
|
|
129
|
+
continue
|
|
130
|
+
|
|
131
|
+
if a.startswith("--progress="):
|
|
132
|
+
hoisted.append(a)
|
|
133
|
+
i += 1
|
|
134
|
+
continue
|
|
135
|
+
|
|
136
|
+
if a == "--progress":
|
|
137
|
+
# Keep the value if present; argparse will validate choices later.
|
|
138
|
+
if i + 1 < len(argv):
|
|
139
|
+
hoisted.extend([a, argv[i + 1]])
|
|
140
|
+
i += 2
|
|
141
|
+
else:
|
|
142
|
+
hoisted.append(a)
|
|
143
|
+
i += 1
|
|
144
|
+
continue
|
|
145
|
+
|
|
146
|
+
rest.append(a)
|
|
147
|
+
i += 1
|
|
148
|
+
|
|
149
|
+
return hoisted + rest
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def create_root_parser() -> argparse.ArgumentParser:
|
|
153
|
+
"""
|
|
154
|
+
Create the root ArgumentParser for the TappsCodingAgents CLI.
|
|
155
|
+
|
|
156
|
+
Sets up the main parser with version information and helpful epilog
|
|
157
|
+
showing common usage examples and shortcuts.
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
Configured ArgumentParser instance ready for subparser registration.
|
|
161
|
+
|
|
162
|
+
Example:
|
|
163
|
+
>>> parser = create_root_parser()
|
|
164
|
+
>>> parser.parse_args(['--version'])
|
|
165
|
+
"""
|
|
166
|
+
parser = argparse.ArgumentParser(
|
|
167
|
+
description="""TappsCodingAgents CLI - AI Coding Agents Framework
|
|
168
|
+
|
|
169
|
+
A comprehensive framework for defining, configuring, and orchestrating AI coding agents
|
|
170
|
+
with 14 workflow agents, industry experts, and full Cursor AI integration.
|
|
171
|
+
|
|
172
|
+
Key Features:
|
|
173
|
+
• 14 Workflow Agents: Analyst, Architect, Debugger, Designer, Documenter, Enhancer,
|
|
174
|
+
Evaluator, Implementer, Improver, Ops, Orchestrator, Planner, Reviewer, Tester
|
|
175
|
+
• Industry Experts: Domain-specific knowledge with weighted decision-making
|
|
176
|
+
• Workflow Presets: Rapid development, full SDLC, bug fixes, quality improvement
|
|
177
|
+
• Code Quality Tools: Scoring, linting, type checking, duplication detection
|
|
178
|
+
• Cursor Integration: Skills and natural language commands
|
|
179
|
+
|
|
180
|
+
For detailed documentation, visit: https://github.com/your-repo/docs""",
|
|
181
|
+
epilog="""QUICK START COMMANDS:
|
|
182
|
+
create <description> Create a new project from description (PRIMARY USE CASE)
|
|
183
|
+
score <file> Score a code file (shortcut for 'reviewer score')
|
|
184
|
+
init Initialize project (Cursor Rules + workflow presets)
|
|
185
|
+
workflow <preset> Run preset workflows (rapid, full, fix, quality, hotfix)
|
|
186
|
+
doctor Validate local environment and tools
|
|
187
|
+
setup-experts Interactive expert setup wizard
|
|
188
|
+
|
|
189
|
+
ALSO: simple-mode status | cleanup workflow-docs | health check | health overview | health usage dashboard | beads ready | cursor verify
|
|
190
|
+
|
|
191
|
+
WORKFLOW PRESETS:
|
|
192
|
+
rapid / feature Rapid development for sprint work and features
|
|
193
|
+
full / enterprise Full SDLC pipeline for complete lifecycle management
|
|
194
|
+
fix / refactor Maintenance and bug fixing workflows
|
|
195
|
+
quality / improve Quality improvement and code review cycles
|
|
196
|
+
hotfix / urgent Quick fixes for urgent production bugs
|
|
197
|
+
|
|
198
|
+
AGENT COMMANDS:
|
|
199
|
+
Use 'tapps-agents <agent> help' to see available commands for each agent:
|
|
200
|
+
• analyst - Requirements gathering, stakeholder analysis, tech research
|
|
201
|
+
• architect - System design, architecture diagrams, tech selection
|
|
202
|
+
• debugger - Error debugging, stack trace analysis, code tracing
|
|
203
|
+
• designer - API design, data models, UI/UX design, wireframes
|
|
204
|
+
• documenter - Generate documentation, update README, docstrings
|
|
205
|
+
• enhancer - Transform simple prompts into comprehensive specifications
|
|
206
|
+
• evaluator - Framework effectiveness evaluation and usage analysis
|
|
207
|
+
• implementer - Code generation, refactoring, file writing
|
|
208
|
+
• improver - Code refactoring, performance optimization, quality improvement
|
|
209
|
+
• ops - Security scanning, compliance checks, deployment
|
|
210
|
+
• orchestrator - Workflow management, step coordination, gate decisions
|
|
211
|
+
• planner - Create plans, user stories, task breakdowns
|
|
212
|
+
• reviewer - Code review, scoring, linting, type checking, reports
|
|
213
|
+
• tester - Generate and run tests, test coverage
|
|
214
|
+
|
|
215
|
+
EXAMPLES:
|
|
216
|
+
# Create a new project
|
|
217
|
+
tapps-agents create "Build a task management web app with React and FastAPI"
|
|
218
|
+
|
|
219
|
+
# Score code quality
|
|
220
|
+
tapps-agents score src/main.py
|
|
221
|
+
|
|
222
|
+
# Initialize project setup
|
|
223
|
+
tapps-agents init
|
|
224
|
+
|
|
225
|
+
# Run rapid development workflow
|
|
226
|
+
tapps-agents workflow rapid --prompt "Add user authentication"
|
|
227
|
+
|
|
228
|
+
# Review code with detailed analysis
|
|
229
|
+
tapps-agents reviewer review src/app.py --format json
|
|
230
|
+
|
|
231
|
+
# Generate tests
|
|
232
|
+
tapps-agents tester test src/utils.py
|
|
233
|
+
|
|
234
|
+
# Get workflow recommendation
|
|
235
|
+
tapps-agents workflow recommend
|
|
236
|
+
|
|
237
|
+
# Check environment
|
|
238
|
+
tapps-agents doctor
|
|
239
|
+
|
|
240
|
+
For more information on a specific command, use:
|
|
241
|
+
tapps-agents <command> --help
|
|
242
|
+
tapps-agents <agent> help""",
|
|
243
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
244
|
+
)
|
|
245
|
+
parser.add_argument(
|
|
246
|
+
"--version",
|
|
247
|
+
action="version",
|
|
248
|
+
version=f"%(prog)s {PACKAGE_VERSION}",
|
|
249
|
+
help="Show version and exit",
|
|
250
|
+
)
|
|
251
|
+
parser.add_argument(
|
|
252
|
+
"--quiet",
|
|
253
|
+
"-q",
|
|
254
|
+
action="store_const",
|
|
255
|
+
const="quiet",
|
|
256
|
+
dest="verbosity",
|
|
257
|
+
help="Quiet mode: only show errors and final results",
|
|
258
|
+
)
|
|
259
|
+
parser.add_argument(
|
|
260
|
+
"--verbose",
|
|
261
|
+
"-v",
|
|
262
|
+
action="store_const",
|
|
263
|
+
const="verbose",
|
|
264
|
+
dest="verbosity",
|
|
265
|
+
help="Verbose mode: show detailed debugging information",
|
|
266
|
+
)
|
|
267
|
+
parser.add_argument(
|
|
268
|
+
"--progress",
|
|
269
|
+
choices=[m.value for m in ProgressMode],
|
|
270
|
+
default=None,
|
|
271
|
+
help=(
|
|
272
|
+
"Progress UI mode: auto (default), rich (animated), plain (single-line), off (disabled). "
|
|
273
|
+
"You can also set TAPPS_PROGRESS=auto|rich|plain|off or TAPPS_NO_PROGRESS=1."
|
|
274
|
+
),
|
|
275
|
+
)
|
|
276
|
+
parser.add_argument(
|
|
277
|
+
"--no-progress",
|
|
278
|
+
action="store_true",
|
|
279
|
+
help="Disable progress UI (same as --progress off)",
|
|
280
|
+
)
|
|
281
|
+
return parser
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def register_all_parsers(parser: argparse.ArgumentParser) -> None:
|
|
285
|
+
"""
|
|
286
|
+
Register all agent and top-level command subparsers.
|
|
287
|
+
|
|
288
|
+
This function sets up the complete command structure by registering:
|
|
289
|
+
- Agent parsers (reviewer, planner, implementer, tester, etc.)
|
|
290
|
+
- Top-level command parsers (create, init, workflow, score, etc.)
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
parser: Root ArgumentParser to attach subparsers to.
|
|
294
|
+
|
|
295
|
+
Note:
|
|
296
|
+
This must be called after create_root_parser() and before parsing arguments.
|
|
297
|
+
"""
|
|
298
|
+
subparsers = parser.add_subparsers(dest="agent", help="Agent or command to use")
|
|
299
|
+
|
|
300
|
+
# Register agent parsers
|
|
301
|
+
reviewer_parsers.add_reviewer_parser(subparsers)
|
|
302
|
+
planner_parsers.add_planner_parser(subparsers)
|
|
303
|
+
implementer_parsers.add_implementer_parser(subparsers)
|
|
304
|
+
tester_parsers.add_tester_parser(subparsers)
|
|
305
|
+
debugger_parsers.add_debugger_parser(subparsers)
|
|
306
|
+
documenter_parsers.add_documenter_parser(subparsers)
|
|
307
|
+
orchestrator_parsers.add_orchestrator_parser(subparsers)
|
|
308
|
+
analyst_parsers.add_analyst_parser(subparsers)
|
|
309
|
+
architect_parsers.add_architect_parser(subparsers)
|
|
310
|
+
designer_parsers.add_designer_parser(subparsers)
|
|
311
|
+
improver_parsers.add_improver_parser(subparsers)
|
|
312
|
+
ops_parsers.add_ops_parser(subparsers)
|
|
313
|
+
enhancer_parsers.add_enhancer_parser(subparsers)
|
|
314
|
+
evaluator_parsers.add_evaluator_parser(subparsers)
|
|
315
|
+
cleanup_agent_parsers.add_cleanup_agent_parser(subparsers)
|
|
316
|
+
|
|
317
|
+
# Register top-level parsers
|
|
318
|
+
top_level_parsers.add_top_level_parsers(subparsers)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def _get_agent_command_handlers() -> dict[str, Callable[[argparse.Namespace], None]]:
|
|
322
|
+
"""
|
|
323
|
+
Get dictionary mapping agent names to their command handlers.
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
Dictionary mapping agent names to handler functions
|
|
327
|
+
"""
|
|
328
|
+
return {
|
|
329
|
+
"reviewer": reviewer.handle_reviewer_command,
|
|
330
|
+
"planner": planner.handle_planner_command,
|
|
331
|
+
"implementer": implementer.handle_implementer_command,
|
|
332
|
+
"tester": tester.handle_tester_command,
|
|
333
|
+
"debugger": debugger.handle_debugger_command,
|
|
334
|
+
"documenter": documenter.handle_documenter_command,
|
|
335
|
+
"orchestrator": orchestrator.handle_orchestrator_command,
|
|
336
|
+
"analyst": analyst.handle_analyst_command,
|
|
337
|
+
"architect": architect.handle_architect_command,
|
|
338
|
+
"designer": designer.handle_designer_command,
|
|
339
|
+
"improver": improver.handle_improver_command,
|
|
340
|
+
"ops": ops.handle_ops_command,
|
|
341
|
+
"enhancer": enhancer.handle_enhancer_command,
|
|
342
|
+
"evaluator": evaluator.handle_evaluator_command,
|
|
343
|
+
"cleanup-agent": cleanup_agent.handle_cleanup_agent_command,
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def _get_top_level_command_handlers() -> dict[str, Callable[[argparse.Namespace], None]]:
|
|
348
|
+
"""
|
|
349
|
+
Get dictionary mapping top-level command names to their handlers.
|
|
350
|
+
|
|
351
|
+
Returns:
|
|
352
|
+
Dictionary mapping command names to handler functions
|
|
353
|
+
"""
|
|
354
|
+
return {
|
|
355
|
+
"create": top_level.handle_create_command,
|
|
356
|
+
"init": top_level.handle_init_command,
|
|
357
|
+
"generate-rules": top_level.handle_generate_rules_command,
|
|
358
|
+
"workflow": top_level.handle_workflow_command,
|
|
359
|
+
"score": top_level.handle_score_command,
|
|
360
|
+
"status": top_level.handle_status_command,
|
|
361
|
+
"doctor": top_level.handle_doctor_command,
|
|
362
|
+
"docs": top_level.handle_docs_command,
|
|
363
|
+
"install-dev": top_level.handle_install_dev_command,
|
|
364
|
+
"customize": top_level.handle_customize_command,
|
|
365
|
+
"commands": top_level.handle_commands_command,
|
|
366
|
+
"skill": top_level.handle_skill_command,
|
|
367
|
+
"skill-template": top_level.handle_skill_template_command,
|
|
368
|
+
"setup-experts": top_level.handle_setup_experts_command,
|
|
369
|
+
"cursor": top_level.handle_cursor_command,
|
|
370
|
+
"beads": top_level.handle_beads_command,
|
|
371
|
+
"task": task_cmd.handle_task_command,
|
|
372
|
+
"continuous-bug-fix": top_level.handle_continuous_bug_fix_command,
|
|
373
|
+
"bug-fix-continuous": top_level.handle_continuous_bug_fix_command,
|
|
374
|
+
"brownfield": top_level.handle_brownfield_command,
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def _handle_cleanup_command(args: argparse.Namespace) -> None:
|
|
379
|
+
"""Handle cleanup command with sub-commands."""
|
|
380
|
+
cleanup_type = getattr(args, "cleanup_type", None)
|
|
381
|
+
if cleanup_type == "workflow-docs":
|
|
382
|
+
top_level.handle_cleanup_workflow_docs_command(args)
|
|
383
|
+
elif cleanup_type == "sessions":
|
|
384
|
+
top_level.handle_cleanup_sessions_command(args)
|
|
385
|
+
elif cleanup_type == "all":
|
|
386
|
+
top_level.handle_cleanup_all_command(args)
|
|
387
|
+
else:
|
|
388
|
+
print(f"Unknown cleanup type: {cleanup_type}", file=sys.stderr)
|
|
389
|
+
print("Use 'tapps-agents cleanup --help' for available cleanup operations", file=sys.stderr)
|
|
390
|
+
sys.exit(1)
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
def _handle_observability_command(args: argparse.Namespace) -> None:
|
|
394
|
+
"""Handle observability command with sub-commands."""
|
|
395
|
+
from pathlib import Path
|
|
396
|
+
|
|
397
|
+
project_root = Path.cwd()
|
|
398
|
+
command = getattr(args, "observability_command", None)
|
|
399
|
+
|
|
400
|
+
observability_handlers = {
|
|
401
|
+
"dashboard": lambda: observability.handle_observability_dashboard_command(
|
|
402
|
+
workflow_id=getattr(args, "workflow_id", None),
|
|
403
|
+
output_format=getattr(args, "format", "text"),
|
|
404
|
+
output_file=getattr(args, "output", None),
|
|
405
|
+
project_root=project_root,
|
|
406
|
+
),
|
|
407
|
+
"graph": lambda: observability.handle_observability_graph_command(
|
|
408
|
+
workflow_id=args.workflow_id,
|
|
409
|
+
output_format=getattr(args, "format", "dot"),
|
|
410
|
+
output_file=getattr(args, "output", None),
|
|
411
|
+
project_root=project_root,
|
|
412
|
+
),
|
|
413
|
+
"otel": lambda: observability.handle_observability_otel_command(
|
|
414
|
+
workflow_id=args.workflow_id,
|
|
415
|
+
output_file=getattr(args, "output", None),
|
|
416
|
+
project_root=project_root,
|
|
417
|
+
),
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
handler = observability_handlers.get(command)
|
|
421
|
+
if handler:
|
|
422
|
+
handler()
|
|
423
|
+
else:
|
|
424
|
+
print(f"Unknown observability subcommand: {command}")
|
|
425
|
+
sys.exit(1)
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def _handle_health_command(args: argparse.Namespace) -> None:
|
|
429
|
+
"""Handle health command with sub-commands."""
|
|
430
|
+
from pathlib import Path
|
|
431
|
+
|
|
432
|
+
from .commands import health
|
|
433
|
+
|
|
434
|
+
if not hasattr(args, "command"):
|
|
435
|
+
return
|
|
436
|
+
|
|
437
|
+
health_handlers = {
|
|
438
|
+
"check": lambda: health.handle_health_check_command(
|
|
439
|
+
check_name=getattr(args, "check", None),
|
|
440
|
+
output_format=getattr(args, "format", "text"),
|
|
441
|
+
save=getattr(args, "save", True),
|
|
442
|
+
),
|
|
443
|
+
"dashboard": lambda: health.handle_health_dashboard_command(
|
|
444
|
+
output_format=getattr(args, "format", "text"),
|
|
445
|
+
),
|
|
446
|
+
"show": lambda: health.handle_health_dashboard_command(
|
|
447
|
+
output_format=getattr(args, "format", "text"),
|
|
448
|
+
),
|
|
449
|
+
"metrics": lambda: health.handle_health_metrics_command(
|
|
450
|
+
check_name=getattr(args, "check_name", None),
|
|
451
|
+
status=getattr(args, "status", None),
|
|
452
|
+
days=getattr(args, "days", 30),
|
|
453
|
+
output_format=getattr(args, "format", "text"),
|
|
454
|
+
),
|
|
455
|
+
"trends": lambda: health.handle_health_trends_command(
|
|
456
|
+
check_name=getattr(args, "check_name", None) or "",
|
|
457
|
+
days=getattr(args, "days", 7),
|
|
458
|
+
output_format=getattr(args, "format", "text"),
|
|
459
|
+
),
|
|
460
|
+
"usage": lambda: health.handle_health_usage_command(args),
|
|
461
|
+
"overview": lambda: health.handle_health_overview_command(
|
|
462
|
+
output_format=getattr(args, "format", "text"),
|
|
463
|
+
project_root=Path.cwd(),
|
|
464
|
+
),
|
|
465
|
+
"summary": lambda: health.handle_health_overview_command(
|
|
466
|
+
output_format=getattr(args, "format", "text"),
|
|
467
|
+
project_root=Path.cwd(),
|
|
468
|
+
),
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
handler = health_handlers.get(args.command)
|
|
472
|
+
if handler:
|
|
473
|
+
handler()
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
def route_command(args: argparse.Namespace) -> None:
|
|
477
|
+
"""
|
|
478
|
+
Route parsed command arguments to the appropriate handler function.
|
|
479
|
+
|
|
480
|
+
This function acts as the central dispatcher, examining the 'agent' attribute
|
|
481
|
+
from parsed arguments and calling the corresponding handler function.
|
|
482
|
+
|
|
483
|
+
Supported routes:
|
|
484
|
+
- Agent commands: reviewer, planner, implementer, tester, debugger, etc.
|
|
485
|
+
- Top-level commands: create, init, workflow, score, doctor, etc.
|
|
486
|
+
- Special commands: customize, skill, etc.
|
|
487
|
+
|
|
488
|
+
Args:
|
|
489
|
+
args: Parsed command-line arguments with 'agent' attribute indicating the command.
|
|
490
|
+
|
|
491
|
+
Note:
|
|
492
|
+
If no agent is specified, prints the main help message.
|
|
493
|
+
"""
|
|
494
|
+
# Apply prompt enhancement middleware if enabled
|
|
495
|
+
from ..cli.utils.prompt_enhancer import enhance_prompt_if_needed
|
|
496
|
+
from ..core.config import load_config
|
|
497
|
+
|
|
498
|
+
config = load_config()
|
|
499
|
+
if config.auto_enhancement.enabled:
|
|
500
|
+
args = enhance_prompt_if_needed(args, config.auto_enhancement)
|
|
501
|
+
|
|
502
|
+
agent = args.agent
|
|
503
|
+
|
|
504
|
+
# Handle None case (show help)
|
|
505
|
+
if agent is None:
|
|
506
|
+
help_parser = create_root_parser()
|
|
507
|
+
register_all_parsers(help_parser)
|
|
508
|
+
_safe_print_help(help_parser)
|
|
509
|
+
return
|
|
510
|
+
|
|
511
|
+
# Session lifecycle: start on first CLI command, SessionEnd via atexit
|
|
512
|
+
from pathlib import Path
|
|
513
|
+
from ..session import ensure_session_started
|
|
514
|
+
ensure_session_started(Path.cwd())
|
|
515
|
+
|
|
516
|
+
# Try agent command handlers first
|
|
517
|
+
agent_handlers = _get_agent_command_handlers()
|
|
518
|
+
if agent in agent_handlers:
|
|
519
|
+
agent_handlers[agent](args)
|
|
520
|
+
return
|
|
521
|
+
|
|
522
|
+
# Try top-level command handlers
|
|
523
|
+
top_level_handlers = _get_top_level_command_handlers()
|
|
524
|
+
if agent in top_level_handlers:
|
|
525
|
+
top_level_handlers[agent](args)
|
|
526
|
+
return
|
|
527
|
+
|
|
528
|
+
# Handle special cases with sub-commands or aliases
|
|
529
|
+
special_handlers = {
|
|
530
|
+
"cleanup": _handle_cleanup_command,
|
|
531
|
+
"health": _handle_health_command,
|
|
532
|
+
"observability": _handle_observability_command,
|
|
533
|
+
"simple-mode": simple_mode.handle_simple_mode_command,
|
|
534
|
+
"learning": learning.handle_learning_command,
|
|
535
|
+
"knowledge": top_level.handle_knowledge_command,
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if agent in special_handlers:
|
|
539
|
+
special_handlers[agent](args)
|
|
540
|
+
return
|
|
541
|
+
|
|
542
|
+
# Unknown command - show help
|
|
543
|
+
help_parser = create_root_parser()
|
|
544
|
+
register_all_parsers(help_parser)
|
|
545
|
+
_safe_print_help(help_parser)
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
def _setup_windows_encoding() -> None:
|
|
549
|
+
"""
|
|
550
|
+
Set up UTF-8 encoding for Windows console to prevent encoding errors.
|
|
551
|
+
|
|
552
|
+
This must be called before any argparse operations or help text printing.
|
|
553
|
+
"""
|
|
554
|
+
if sys.platform == "win32":
|
|
555
|
+
# Set environment variable for subprocess encoding
|
|
556
|
+
os.environ.setdefault("PYTHONIOENCODING", "utf-8")
|
|
557
|
+
|
|
558
|
+
# Reconfigure stdout/stderr to UTF-8 if possible (Python 3.7+)
|
|
559
|
+
try:
|
|
560
|
+
if hasattr(sys.stdout, 'reconfigure'):
|
|
561
|
+
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
|
562
|
+
if hasattr(sys.stderr, 'reconfigure'):
|
|
563
|
+
sys.stderr.reconfigure(encoding='utf-8', errors='replace')
|
|
564
|
+
except (AttributeError, ValueError, OSError):
|
|
565
|
+
# Fallback: use environment variable only
|
|
566
|
+
# Some terminals may not support reconfiguration
|
|
567
|
+
pass
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
def _safe_print_help(parser: argparse.ArgumentParser) -> None:
|
|
571
|
+
"""
|
|
572
|
+
Safely print argparse help text with Windows encoding handling.
|
|
573
|
+
|
|
574
|
+
Args:
|
|
575
|
+
parser: ArgumentParser instance to print help for
|
|
576
|
+
"""
|
|
577
|
+
try:
|
|
578
|
+
parser.print_help()
|
|
579
|
+
except (UnicodeEncodeError, OSError) as e:
|
|
580
|
+
# If encoding fails, try to print ASCII-safe version
|
|
581
|
+
try:
|
|
582
|
+
# Get help text and encode safely
|
|
583
|
+
help_text = parser.format_help()
|
|
584
|
+
# Replace any problematic Unicode characters with ASCII equivalents
|
|
585
|
+
safe_text = help_text.encode('ascii', 'replace').decode('ascii')
|
|
586
|
+
print(safe_text, file=sys.stdout)
|
|
587
|
+
except Exception:
|
|
588
|
+
# Last resort: print basic error message
|
|
589
|
+
print("Help text unavailable due to encoding issues.", file=sys.stderr)
|
|
590
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
591
|
+
sys.exit(1)
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
def main() -> None:
|
|
595
|
+
"""Main CLI entry point - supports both *command and command formats"""
|
|
596
|
+
# Set up Windows encoding FIRST, before any argparse operations
|
|
597
|
+
_setup_windows_encoding()
|
|
598
|
+
|
|
599
|
+
# Run startup routines (documentation refresh) before main
|
|
600
|
+
from ..core.startup import startup_routines
|
|
601
|
+
|
|
602
|
+
async def startup():
|
|
603
|
+
"""Run startup routines in background."""
|
|
604
|
+
try:
|
|
605
|
+
await startup_routines(refresh_docs=True, background_refresh=True)
|
|
606
|
+
except Exception:
|
|
607
|
+
# Don't fail if startup routines fail
|
|
608
|
+
return
|
|
609
|
+
|
|
610
|
+
# Start startup routines in background
|
|
611
|
+
asyncio.run(startup())
|
|
612
|
+
|
|
613
|
+
# Create parser and register all subparsers
|
|
614
|
+
parser = create_root_parser()
|
|
615
|
+
register_all_parsers(parser)
|
|
616
|
+
|
|
617
|
+
# Parse arguments
|
|
618
|
+
argv = _reorder_global_flags(sys.argv[1:])
|
|
619
|
+
try:
|
|
620
|
+
args = parser.parse_args(argv)
|
|
621
|
+
except SystemExit as e:
|
|
622
|
+
# argparse raises SystemExit(0) for --help, SystemExit(2) for errors
|
|
623
|
+
# We need to handle this gracefully with encoding safety
|
|
624
|
+
if e.code == 0:
|
|
625
|
+
# --help was used, argparse already printed help, but we need to ensure encoding
|
|
626
|
+
# If we get here, argparse.print_help() was called internally
|
|
627
|
+
# The encoding setup at the start should have handled it, but exit cleanly
|
|
628
|
+
sys.exit(0)
|
|
629
|
+
else:
|
|
630
|
+
# Parse error - argparse already printed error message
|
|
631
|
+
# Ensure encoding was set up, then exit with error code
|
|
632
|
+
sys.exit(e.code)
|
|
633
|
+
|
|
634
|
+
# Set verbosity level from arguments
|
|
635
|
+
verbosity_str = getattr(args, "verbosity", None)
|
|
636
|
+
if verbosity_str == "quiet":
|
|
637
|
+
FeedbackManager.set_verbosity(VerbosityLevel.QUIET)
|
|
638
|
+
elif verbosity_str == "verbose":
|
|
639
|
+
FeedbackManager.set_verbosity(VerbosityLevel.VERBOSE)
|
|
640
|
+
else:
|
|
641
|
+
FeedbackManager.set_verbosity(VerbosityLevel.NORMAL)
|
|
642
|
+
|
|
643
|
+
# Set progress mode (CLI flags override env; env is handled by FeedbackManager.AUTO)
|
|
644
|
+
if getattr(args, "no_progress", False):
|
|
645
|
+
FeedbackManager.set_progress_mode(ProgressMode.OFF)
|
|
646
|
+
else:
|
|
647
|
+
progress_str = getattr(args, "progress", None)
|
|
648
|
+
if progress_str:
|
|
649
|
+
FeedbackManager.set_progress_mode(ProgressMode(progress_str))
|
|
650
|
+
|
|
651
|
+
# Set format type if specified (for commands that support it)
|
|
652
|
+
format_type = getattr(args, "format", None)
|
|
653
|
+
if format_type:
|
|
654
|
+
FeedbackManager.set_format(format_type)
|
|
655
|
+
|
|
656
|
+
# Route to appropriate handler
|
|
657
|
+
route_command(args)
|
|
658
|
+
|