tapps-agents 3.5.38__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.
Files changed (75) hide show
  1. tapps_agents/__init__.py +2 -2
  2. tapps_agents/agents/cleanup/__init__.py +7 -0
  3. tapps_agents/agents/cleanup/agent.py +445 -0
  4. tapps_agents/agents/enhancer/agent.py +2 -2
  5. tapps_agents/agents/implementer/agent.py +35 -13
  6. tapps_agents/agents/reviewer/agent.py +43 -10
  7. tapps_agents/agents/reviewer/scoring.py +59 -68
  8. tapps_agents/agents/reviewer/tools/__init__.py +24 -0
  9. tapps_agents/agents/reviewer/tools/ruff_grouping.py +250 -0
  10. tapps_agents/agents/reviewer/tools/scoped_mypy.py +284 -0
  11. tapps_agents/beads/__init__.py +11 -0
  12. tapps_agents/beads/hydration.py +213 -0
  13. tapps_agents/beads/specs.py +206 -0
  14. tapps_agents/cli/commands/cleanup_agent.py +92 -0
  15. tapps_agents/cli/commands/health.py +19 -3
  16. tapps_agents/cli/commands/simple_mode.py +842 -676
  17. tapps_agents/cli/commands/task.py +219 -0
  18. tapps_agents/cli/commands/top_level.py +13 -0
  19. tapps_agents/cli/main.py +15 -2
  20. tapps_agents/cli/parsers/cleanup_agent.py +228 -0
  21. tapps_agents/cli/parsers/top_level.py +1978 -1881
  22. tapps_agents/core/config.py +43 -0
  23. tapps_agents/core/init_project.py +3012 -2896
  24. tapps_agents/epic/markdown_sync.py +105 -0
  25. tapps_agents/epic/orchestrator.py +1 -2
  26. tapps_agents/epic/parser.py +427 -423
  27. tapps_agents/experts/adaptive_domain_detector.py +0 -2
  28. tapps_agents/experts/knowledge/api-design-integration/api-security-patterns.md +15 -15
  29. tapps_agents/experts/knowledge/api-design-integration/external-api-integration.md +19 -44
  30. tapps_agents/health/checks/outcomes.backup_20260204_064058.py +324 -0
  31. tapps_agents/health/checks/outcomes.backup_20260204_064256.py +324 -0
  32. tapps_agents/health/checks/outcomes.backup_20260204_064600.py +324 -0
  33. tapps_agents/health/checks/outcomes.py +134 -46
  34. tapps_agents/health/orchestrator.py +12 -4
  35. tapps_agents/hooks/__init__.py +33 -0
  36. tapps_agents/hooks/config.py +140 -0
  37. tapps_agents/hooks/events.py +135 -0
  38. tapps_agents/hooks/executor.py +128 -0
  39. tapps_agents/hooks/manager.py +143 -0
  40. tapps_agents/session/__init__.py +19 -0
  41. tapps_agents/session/manager.py +256 -0
  42. tapps_agents/simple_mode/code_snippet_handler.py +382 -0
  43. tapps_agents/simple_mode/intent_parser.py +29 -4
  44. tapps_agents/simple_mode/orchestrators/base.py +185 -59
  45. tapps_agents/simple_mode/orchestrators/build_orchestrator.py +2667 -2642
  46. tapps_agents/simple_mode/orchestrators/fix_orchestrator.py +723 -723
  47. tapps_agents/simple_mode/workflow_suggester.py +37 -3
  48. tapps_agents/workflow/agent_handlers/implementer_handler.py +18 -3
  49. tapps_agents/workflow/cursor_executor.py +2196 -2118
  50. tapps_agents/workflow/direct_execution_fallback.py +16 -3
  51. tapps_agents/workflow/enforcer.py +36 -23
  52. tapps_agents/workflow/message_formatter.py +188 -0
  53. tapps_agents/workflow/parallel_executor.py +43 -4
  54. tapps_agents/workflow/parser.py +375 -357
  55. tapps_agents/workflow/rules_generator.py +337 -331
  56. tapps_agents/workflow/skill_invoker.py +9 -3
  57. {tapps_agents-3.5.38.dist-info → tapps_agents-3.5.40.dist-info}/METADATA +9 -5
  58. {tapps_agents-3.5.38.dist-info → tapps_agents-3.5.40.dist-info}/RECORD +62 -53
  59. tapps_agents/agents/analyst/SKILL.md +0 -85
  60. tapps_agents/agents/architect/SKILL.md +0 -80
  61. tapps_agents/agents/debugger/SKILL.md +0 -66
  62. tapps_agents/agents/designer/SKILL.md +0 -78
  63. tapps_agents/agents/documenter/SKILL.md +0 -95
  64. tapps_agents/agents/enhancer/SKILL.md +0 -189
  65. tapps_agents/agents/implementer/SKILL.md +0 -117
  66. tapps_agents/agents/improver/SKILL.md +0 -55
  67. tapps_agents/agents/ops/SKILL.md +0 -64
  68. tapps_agents/agents/orchestrator/SKILL.md +0 -238
  69. tapps_agents/agents/planner/story_template.md +0 -37
  70. tapps_agents/agents/reviewer/templates/quality-dashboard.html.j2 +0 -150
  71. tapps_agents/agents/tester/SKILL.md +0 -71
  72. {tapps_agents-3.5.38.dist-info → tapps_agents-3.5.40.dist-info}/WHEEL +0 -0
  73. {tapps_agents-3.5.38.dist-info → tapps_agents-3.5.40.dist-info}/entry_points.txt +0 -0
  74. {tapps_agents-3.5.38.dist-info → tapps_agents-3.5.40.dist-info}/licenses/LICENSE +0 -0
  75. {tapps_agents-3.5.38.dist-info → tapps_agents-3.5.40.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,219 @@
1
+ """
2
+ Task management CLI: create, list, show, update, close, hydrate, dehydrate, run.
3
+
4
+ Manages task specs in .tapps-agents/task-specs/ and sync with Beads (bd).
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import sys
10
+ from pathlib import Path
11
+
12
+ from ..feedback import get_feedback
13
+ from .common import format_json_output
14
+
15
+
16
+ def handle_task_command(args: object) -> None:
17
+ """Dispatch to task subcommand handler."""
18
+ cmd = getattr(args, "task_command", None)
19
+ if not cmd:
20
+ print("task: subcommand required (create, list, show, update, close, hydrate, dehydrate, run)", file=sys.stderr)
21
+ sys.exit(2)
22
+ handlers = {
23
+ "create": _handle_create,
24
+ "list": _handle_list,
25
+ "show": _handle_show,
26
+ "update": _handle_update,
27
+ "close": _handle_close,
28
+ "hydrate": _handle_hydrate,
29
+ "dehydrate": _handle_dehydrate,
30
+ "run": _handle_run,
31
+ }
32
+ handler = handlers.get(cmd)
33
+ if not handler:
34
+ print(f"task: unknown subcommand {cmd!r}", file=sys.stderr)
35
+ sys.exit(2)
36
+ handler(args)
37
+
38
+
39
+ def _project_root() -> Path:
40
+ return Path.cwd()
41
+
42
+
43
+ def _handle_create(args: object) -> None:
44
+ from ...beads.specs import TaskSpec, save_task_spec
45
+ from ...beads.hydration import hydrate_to_beads
46
+
47
+ task_id = getattr(args, "id", "").strip()
48
+ title = getattr(args, "title", "").strip()
49
+ if not task_id or not title:
50
+ print("task create: id and --title are required", file=sys.stderr)
51
+ sys.exit(2)
52
+ root = _project_root()
53
+ spec = TaskSpec(
54
+ id=task_id,
55
+ title=title,
56
+ description=getattr(args, "description", "") or "",
57
+ workflow=getattr(args, "workflow", "build") or "build",
58
+ )
59
+ save_task_spec(spec, root)
60
+ print(f"Created task spec: {spec.id} ({root / '.tapps-agents' / 'task-specs' / f'{spec.id}.yaml'})")
61
+ if getattr(args, "beads", False):
62
+ report = hydrate_to_beads(project_root=root)
63
+ if report.bd_unavailable:
64
+ print("Beads (bd) not available; spec created without Beads issue.", file=sys.stderr)
65
+ else:
66
+ print(f"Hydration: created={report.created}, skipped={report.skipped}")
67
+
68
+
69
+ def _handle_list(args: object) -> None:
70
+ from ...beads.specs import load_task_specs
71
+
72
+ root = _project_root()
73
+ specs = load_task_specs(root)
74
+ status_filter = getattr(args, "status", None)
75
+ if status_filter:
76
+ specs = [s for s in specs if s.status == status_filter]
77
+ out_fmt = getattr(args, "format", "text")
78
+ if out_fmt == "json":
79
+ format_json_output([s.model_dump() for s in specs])
80
+ return
81
+ if not specs:
82
+ print("No task specs found.")
83
+ return
84
+ for s in specs:
85
+ beads = f" [bd:{s.beads_issue}]" if s.beads_issue else ""
86
+ print(f" {s.id} {s.status} {s.title or ''}{beads}")
87
+
88
+
89
+ def _handle_show(args: object) -> None:
90
+ from ...beads.specs import load_task_spec
91
+
92
+ task_id = getattr(args, "id", "").strip()
93
+ if not task_id:
94
+ print("task show: id required", file=sys.stderr)
95
+ sys.exit(2)
96
+ root = _project_root()
97
+ spec = load_task_spec(task_id, root)
98
+ if not spec:
99
+ print(f"Task not found: {task_id}", file=sys.stderr)
100
+ sys.exit(1)
101
+ print(f"id: {spec.id}")
102
+ print(f"title: {spec.title}")
103
+ print(f"status: {spec.status}")
104
+ print(f"workflow: {spec.workflow or 'build'}")
105
+ if spec.beads_issue:
106
+ print(f"beads_issue: {spec.beads_issue}")
107
+ if spec.description:
108
+ print(f"description: {spec.description}")
109
+
110
+
111
+ def _handle_update(args: object) -> None:
112
+ from ...beads.specs import load_task_spec, save_task_spec
113
+
114
+ task_id = getattr(args, "id", "").strip()
115
+ status = getattr(args, "status", None)
116
+ if not task_id:
117
+ print("task update: id required", file=sys.stderr)
118
+ sys.exit(2)
119
+ if not status:
120
+ print("task update: --status required", file=sys.stderr)
121
+ sys.exit(2)
122
+ root = _project_root()
123
+ spec = load_task_spec(task_id, root)
124
+ if not spec:
125
+ print(f"Task not found: {task_id}", file=sys.stderr)
126
+ sys.exit(1)
127
+ spec = spec.model_copy(update={"status": status})
128
+ save_task_spec(spec, root)
129
+ print(f"Updated {task_id} status to {status}")
130
+
131
+
132
+ def _handle_close(args: object) -> None:
133
+ from ...beads.specs import load_task_spec, save_task_spec
134
+
135
+ task_id = getattr(args, "id", "").strip()
136
+ if not task_id:
137
+ print("task close: id required", file=sys.stderr)
138
+ sys.exit(2)
139
+ root = _project_root()
140
+ spec = load_task_spec(task_id, root)
141
+ if not spec:
142
+ print(f"Task not found: {task_id}", file=sys.stderr)
143
+ sys.exit(1)
144
+ spec = spec.model_copy(update={"status": "done"})
145
+ save_task_spec(spec, root)
146
+ print(f"Closed {task_id}")
147
+
148
+
149
+ def _handle_hydrate(args: object) -> None:
150
+ from ...beads.hydration import hydrate_to_beads
151
+
152
+ root = _project_root()
153
+ report = hydrate_to_beads(project_root=root)
154
+ if report.bd_unavailable:
155
+ print("Beads (bd) not available. Install to tools/bd or add bd to PATH.", file=sys.stderr)
156
+ sys.exit(1)
157
+ print(f"created={report.created} skipped={report.skipped} failed={report.failed} deps_added={report.deps_added}")
158
+
159
+
160
+ def _handle_dehydrate(args: object) -> None:
161
+ from ...beads.hydration import dehydrate_from_beads
162
+
163
+ root = _project_root()
164
+ updated = dehydrate_from_beads(project_root=root)
165
+ print(f"Updated {updated} spec(s) from Beads.")
166
+
167
+
168
+ def _handle_run(args: object) -> None:
169
+ from ...beads.specs import load_task_spec, save_task_spec
170
+
171
+ task_id = getattr(args, "id", "").strip()
172
+ if not task_id:
173
+ print("task run: id required", file=sys.stderr)
174
+ sys.exit(2)
175
+ root = _project_root()
176
+ spec = load_task_spec(task_id, root)
177
+ if not spec:
178
+ print(f"Task not found: {task_id}", file=sys.stderr)
179
+ sys.exit(1)
180
+ workflow_name = (spec.workflow or "build").strip().lower()
181
+ # Map task workflow name to preset
182
+ preset_map = {"build": "rapid", "fix": "fix", "review": "quality", "test": "quality", "full": "full"}
183
+ preset = preset_map.get(workflow_name, "rapid")
184
+ # Update spec to in-progress
185
+ spec = spec.model_copy(update={"status": "in-progress"})
186
+ save_task_spec(spec, root)
187
+ # Run workflow via CLI workflow path (simplified: invoke workflow preset)
188
+ try:
189
+ from ...workflow.executor import WorkflowExecutor
190
+ from ...workflow.preset_loader import PresetLoader
191
+ from ..base import run_async_command
192
+
193
+ loader = PresetLoader()
194
+ workflow = loader.load_preset(preset)
195
+ if not workflow:
196
+ print(f"Workflow preset not found: {preset}", file=sys.stderr)
197
+ spec = spec.model_copy(update={"status": "todo"})
198
+ save_task_spec(spec, root)
199
+ sys.exit(1)
200
+ executor = WorkflowExecutor(auto_detect=False, auto_mode=True)
201
+ executor.user_prompt = spec.title or spec.description or spec.id
202
+ target_file = (spec.files or [None])[0] if spec.files else None
203
+ final_state = run_async_command(
204
+ executor.execute(workflow=workflow, target_file=target_file)
205
+ )
206
+ if final_state.status == "completed":
207
+ spec = spec.model_copy(update={"status": "done"})
208
+ save_task_spec(spec, root)
209
+ print(f"Task {task_id} completed.")
210
+ else:
211
+ spec = spec.model_copy(update={"status": "todo"})
212
+ save_task_spec(spec, root)
213
+ print(f"Workflow ended with status: {final_state.status}", file=sys.stderr)
214
+ sys.exit(1)
215
+ except Exception as e:
216
+ spec = spec.model_copy(update={"status": "todo"})
217
+ save_task_spec(spec, root)
218
+ print(f"Error running workflow: {e}", file=sys.stderr)
219
+ sys.exit(1)
@@ -1454,6 +1454,18 @@ def _print_init_results(results: dict[str, Any]) -> None:
1454
1454
  print(" - .cursorignore")
1455
1455
  else:
1456
1456
  print(" .cursorignore: Skipped or already exists")
1457
+
1458
+ if results.get("hooks"):
1459
+ if results.get("hooks_templates"):
1460
+ print(" Hooks: Created from templates (all disabled)")
1461
+ print(" - .tapps-agents/hooks.yaml")
1462
+ if results.get("context_created"):
1463
+ print(" - .tapps-agents/context/")
1464
+ else:
1465
+ print(" Hooks: Minimal hooks.yaml created")
1466
+ print(" - .tapps-agents/hooks.yaml")
1467
+ else:
1468
+ print(" Hooks: Skipped or already exists")
1457
1469
 
1458
1470
  # Show MCP config (will be shown in dedicated section)
1459
1471
  # MCP status is now shown in _print_mcp_status() function
@@ -2194,6 +2206,7 @@ def handle_init_command(args: object) -> None:
2194
2206
  backup_before_reset=not getattr(args, "no_backup", False),
2195
2207
  reset_mcp=getattr(args, "reset_mcp", False),
2196
2208
  preserve_custom=getattr(args, "preserve_custom", True),
2209
+ include_hooks_templates=getattr(args, "hooks", False),
2197
2210
  )
2198
2211
 
2199
2212
  # Offer interactive Context7 setup if API key is missing
tapps_agents/cli/main.py CHANGED
@@ -36,6 +36,7 @@ except (ImportError, AttributeError):
36
36
  from .commands import (
37
37
  analyst,
38
38
  architect,
39
+ cleanup_agent,
39
40
  debugger,
40
41
  designer,
41
42
  documenter,
@@ -50,6 +51,7 @@ from .commands import (
50
51
  planner,
51
52
  reviewer,
52
53
  simple_mode,
54
+ task as task_cmd,
53
55
  tester,
54
56
  top_level,
55
57
  )
@@ -59,6 +61,9 @@ from .feedback import FeedbackManager, ProgressMode, VerbosityLevel
59
61
  from .parsers import (
60
62
  analyst as analyst_parsers,
61
63
  )
64
+ from .parsers import (
65
+ cleanup_agent as cleanup_agent_parsers,
66
+ )
62
67
  from .parsers import (
63
68
  architect as architect_parsers,
64
69
  )
@@ -307,6 +312,7 @@ def register_all_parsers(parser: argparse.ArgumentParser) -> None:
307
312
  ops_parsers.add_ops_parser(subparsers)
308
313
  enhancer_parsers.add_enhancer_parser(subparsers)
309
314
  evaluator_parsers.add_evaluator_parser(subparsers)
315
+ cleanup_agent_parsers.add_cleanup_agent_parser(subparsers)
310
316
 
311
317
  # Register top-level parsers
312
318
  top_level_parsers.add_top_level_parsers(subparsers)
@@ -334,6 +340,7 @@ def _get_agent_command_handlers() -> dict[str, Callable[[argparse.Namespace], No
334
340
  "ops": ops.handle_ops_command,
335
341
  "enhancer": enhancer.handle_enhancer_command,
336
342
  "evaluator": evaluator.handle_evaluator_command,
343
+ "cleanup-agent": cleanup_agent.handle_cleanup_agent_command,
337
344
  }
338
345
 
339
346
 
@@ -361,6 +368,7 @@ def _get_top_level_command_handlers() -> dict[str, Callable[[argparse.Namespace]
361
368
  "setup-experts": top_level.handle_setup_experts_command,
362
369
  "cursor": top_level.handle_cursor_command,
363
370
  "beads": top_level.handle_beads_command,
371
+ "task": task_cmd.handle_task_command,
364
372
  "continuous-bug-fix": top_level.handle_continuous_bug_fix_command,
365
373
  "bug-fix-continuous": top_level.handle_continuous_bug_fix_command,
366
374
  "brownfield": top_level.handle_brownfield_command,
@@ -492,14 +500,19 @@ def route_command(args: argparse.Namespace) -> None:
492
500
  args = enhance_prompt_if_needed(args, config.auto_enhancement)
493
501
 
494
502
  agent = args.agent
495
-
503
+
496
504
  # Handle None case (show help)
497
505
  if agent is None:
498
506
  help_parser = create_root_parser()
499
507
  register_all_parsers(help_parser)
500
508
  _safe_print_help(help_parser)
501
509
  return
502
-
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
+
503
516
  # Try agent command handlers first
504
517
  agent_handlers = _get_agent_command_handlers()
505
518
  if agent in agent_handlers:
@@ -0,0 +1,228 @@
1
+ """
2
+ Cleanup Agent parser definitions
3
+ """
4
+ import argparse
5
+
6
+
7
+ def add_cleanup_agent_parser(subparsers: argparse._SubParsersAction) -> None:
8
+ """Add cleanup-agent parser and subparsers."""
9
+ cleanup_agent_parser = subparsers.add_parser(
10
+ "cleanup-agent",
11
+ help="Project Cleanup Agent commands",
12
+ description="""Project structure analysis and intelligent cleanup agent.
13
+
14
+ The Cleanup Agent helps keep projects clean by:
15
+ - Analyzing project structure for cleanup opportunities
16
+ - Detecting duplicate files and content
17
+ - Identifying outdated documentation
18
+ - Enforcing naming conventions (kebab-case)
19
+ - Generating cleanup plans with rationale
20
+ - Executing cleanup operations safely with backups
21
+
22
+ Use this agent for guided project and docs cleanup after heavy development.""",
23
+ )
24
+ cleanup_subparsers = cleanup_agent_parser.add_subparsers(
25
+ dest="command",
26
+ help="Cleanup agent subcommand (use 'help' to see all available commands)",
27
+ )
28
+
29
+ # Analyze command
30
+ analyze_parser = cleanup_subparsers.add_parser(
31
+ "analyze",
32
+ aliases=["*analyze"],
33
+ help="Analyze project structure for cleanup opportunities",
34
+ description="""Analyze project structure to identify cleanup opportunities.
35
+
36
+ Scans the specified path and detects:
37
+ - Duplicate files (by content hash)
38
+ - Outdated files (not modified in 90+ days)
39
+ - Naming convention violations
40
+ - Files with no references
41
+
42
+ Example:
43
+ tapps-agents cleanup-agent analyze --path ./docs --pattern "*.md"
44
+ tapps-agents cleanup-agent analyze --output analysis.json""",
45
+ )
46
+ analyze_parser.add_argument(
47
+ "--path",
48
+ help="Path to analyze (defaults to ./docs). Can be any directory in the project.",
49
+ )
50
+ analyze_parser.add_argument(
51
+ "--pattern",
52
+ default="*.md",
53
+ help="File pattern to match (default: *.md). Supports glob patterns.",
54
+ )
55
+ analyze_parser.add_argument(
56
+ "--output",
57
+ help="Output file for analysis report (JSON format). If not specified, displays summary.",
58
+ )
59
+ analyze_parser.add_argument(
60
+ "--format",
61
+ choices=["json", "text", "markdown"],
62
+ default="json",
63
+ help="Output format: 'json' for structured data (default), 'text' for human-readable, 'markdown' for markdown",
64
+ )
65
+
66
+ # Plan command
67
+ plan_parser = cleanup_subparsers.add_parser(
68
+ "plan",
69
+ aliases=["*plan"],
70
+ help="Generate cleanup plan from analysis",
71
+ description="""Generate a cleanup plan with prioritized actions.
72
+
73
+ Creates a plan based on analysis that includes:
74
+ - File categorization (keep, archive, delete, merge, rename)
75
+ - Priority levels (high, medium, low)
76
+ - Safety levels (safe, moderate, risky)
77
+ - Rationale for each action
78
+ - Estimated space savings
79
+
80
+ Example:
81
+ tapps-agents cleanup-agent plan --analysis-file analysis.json
82
+ tapps-agents cleanup-agent plan --path ./docs --output cleanup-plan.json""",
83
+ )
84
+ plan_parser.add_argument(
85
+ "--analysis-file",
86
+ help="Path to analysis report JSON. If not provided, runs fresh analysis.",
87
+ )
88
+ plan_parser.add_argument(
89
+ "--path",
90
+ help="Path to analyze if no analysis file provided (defaults to ./docs).",
91
+ )
92
+ plan_parser.add_argument(
93
+ "--pattern",
94
+ default="*.md",
95
+ help="File pattern if running fresh analysis (default: *.md).",
96
+ )
97
+ plan_parser.add_argument(
98
+ "--output",
99
+ help="Output file for cleanup plan (JSON format).",
100
+ )
101
+ plan_parser.add_argument(
102
+ "--format",
103
+ choices=["json", "text", "markdown"],
104
+ default="json",
105
+ help="Output format (default: json).",
106
+ )
107
+
108
+ # Execute command
109
+ execute_parser = cleanup_subparsers.add_parser(
110
+ "execute",
111
+ aliases=["*execute"],
112
+ help="Execute cleanup plan (dry-run by default)",
113
+ description="""Execute cleanup operations from a plan.
114
+
115
+ Performs cleanup actions with safety measures:
116
+ - Dry-run mode by default (preview changes)
117
+ - Optional backup creation before execution
118
+ - Reference updating for renamed/moved files
119
+ - Transaction logging for rollback capability
120
+
121
+ Example:
122
+ tapps-agents cleanup-agent execute --plan-file cleanup-plan.json --dry-run
123
+ tapps-agents cleanup-agent execute --plan-file cleanup-plan.json --no-dry-run --backup""",
124
+ )
125
+ execute_parser.add_argument(
126
+ "--plan-file",
127
+ help="Path to cleanup plan JSON. If not provided, generates plan from analysis.",
128
+ )
129
+ execute_parser.add_argument(
130
+ "--path",
131
+ help="Path to analyze if no plan file provided (defaults to ./docs).",
132
+ )
133
+ execute_parser.add_argument(
134
+ "--pattern",
135
+ default="*.md",
136
+ help="File pattern if running fresh (default: *.md).",
137
+ )
138
+ execute_parser.add_argument(
139
+ "--dry-run",
140
+ action="store_true",
141
+ default=True,
142
+ help="Preview changes without executing (default: True).",
143
+ )
144
+ execute_parser.add_argument(
145
+ "--no-dry-run",
146
+ action="store_true",
147
+ help="Execute changes for real (disables dry-run).",
148
+ )
149
+ execute_parser.add_argument(
150
+ "--backup",
151
+ action="store_true",
152
+ default=True,
153
+ help="Create backup before execution (default: True).",
154
+ )
155
+ execute_parser.add_argument(
156
+ "--no-backup",
157
+ action="store_true",
158
+ help="Skip backup creation (not recommended).",
159
+ )
160
+ execute_parser.add_argument(
161
+ "--format",
162
+ choices=["json", "text", "markdown"],
163
+ default="json",
164
+ help="Output format (default: json).",
165
+ )
166
+
167
+ # Run command (full workflow)
168
+ run_parser = cleanup_subparsers.add_parser(
169
+ "run",
170
+ aliases=["*run"],
171
+ help="Run full cleanup workflow (analyze, plan, execute)",
172
+ description="""Run the complete cleanup workflow in one command.
173
+
174
+ Executes all steps:
175
+ 1. Analyze project structure
176
+ 2. Generate cleanup plan
177
+ 3. Execute cleanup operations
178
+
179
+ By default runs in dry-run mode with backups enabled.
180
+
181
+ Example:
182
+ tapps-agents cleanup-agent run --path ./docs --dry-run
183
+ tapps-agents cleanup-agent run --path ./docs --no-dry-run --backup""",
184
+ )
185
+ run_parser.add_argument(
186
+ "--path",
187
+ help="Path to analyze (defaults to ./docs).",
188
+ )
189
+ run_parser.add_argument(
190
+ "--pattern",
191
+ default="*.md",
192
+ help="File pattern to match (default: *.md).",
193
+ )
194
+ run_parser.add_argument(
195
+ "--dry-run",
196
+ action="store_true",
197
+ default=True,
198
+ help="Preview changes without executing (default: True).",
199
+ )
200
+ run_parser.add_argument(
201
+ "--no-dry-run",
202
+ action="store_true",
203
+ help="Execute changes for real (disables dry-run).",
204
+ )
205
+ run_parser.add_argument(
206
+ "--backup",
207
+ action="store_true",
208
+ default=True,
209
+ help="Create backup before execution (default: True).",
210
+ )
211
+ run_parser.add_argument(
212
+ "--no-backup",
213
+ action="store_true",
214
+ help="Skip backup creation (not recommended).",
215
+ )
216
+ run_parser.add_argument(
217
+ "--format",
218
+ choices=["json", "text", "markdown"],
219
+ default="json",
220
+ help="Output format (default: json).",
221
+ )
222
+
223
+ # Help command
224
+ cleanup_subparsers.add_parser(
225
+ "help",
226
+ aliases=["*help"],
227
+ help="Show cleanup agent commands",
228
+ )