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.
- tapps_agents/__init__.py +2 -2
- tapps_agents/agents/cleanup/__init__.py +7 -0
- tapps_agents/agents/cleanup/agent.py +445 -0
- tapps_agents/agents/enhancer/agent.py +2 -2
- 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/cleanup_agent.py +92 -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 +15 -2
- tapps_agents/cli/parsers/cleanup_agent.py +228 -0
- tapps_agents/cli/parsers/top_level.py +1978 -1881
- tapps_agents/core/config.py +43 -0
- tapps_agents/core/init_project.py +3012 -2896
- 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 +723 -723
- 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/enforcer.py +36 -23
- tapps_agents/workflow/message_formatter.py +188 -0
- tapps_agents/workflow/parallel_executor.py +43 -4
- tapps_agents/workflow/parser.py +375 -357
- tapps_agents/workflow/rules_generator.py +337 -331
- tapps_agents/workflow/skill_invoker.py +9 -3
- {tapps_agents-3.5.38.dist-info → tapps_agents-3.5.40.dist-info}/METADATA +9 -5
- {tapps_agents-3.5.38.dist-info → tapps_agents-3.5.40.dist-info}/RECORD +62 -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.38.dist-info → tapps_agents-3.5.40.dist-info}/WHEEL +0 -0
- {tapps_agents-3.5.38.dist-info → tapps_agents-3.5.40.dist-info}/entry_points.txt +0 -0
- {tapps_agents-3.5.38.dist-info → tapps_agents-3.5.40.dist-info}/licenses/LICENSE +0 -0
- {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
|
+
)
|