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.
Files changed (71) hide show
  1. tapps_agents/__init__.py +2 -2
  2. tapps_agents/agents/enhancer/agent.py +2728 -2728
  3. tapps_agents/agents/implementer/agent.py +35 -13
  4. tapps_agents/agents/reviewer/agent.py +43 -10
  5. tapps_agents/agents/reviewer/scoring.py +59 -68
  6. tapps_agents/agents/reviewer/tools/__init__.py +24 -0
  7. tapps_agents/agents/reviewer/tools/ruff_grouping.py +250 -0
  8. tapps_agents/agents/reviewer/tools/scoped_mypy.py +284 -0
  9. tapps_agents/beads/__init__.py +11 -0
  10. tapps_agents/beads/hydration.py +213 -0
  11. tapps_agents/beads/specs.py +206 -0
  12. tapps_agents/cli/commands/health.py +19 -3
  13. tapps_agents/cli/commands/simple_mode.py +842 -676
  14. tapps_agents/cli/commands/task.py +227 -0
  15. tapps_agents/cli/commands/top_level.py +13 -0
  16. tapps_agents/cli/main.py +658 -651
  17. tapps_agents/cli/parsers/top_level.py +1978 -1881
  18. tapps_agents/core/config.py +1622 -1622
  19. tapps_agents/core/init_project.py +3012 -2897
  20. tapps_agents/epic/markdown_sync.py +105 -0
  21. tapps_agents/epic/orchestrator.py +1 -2
  22. tapps_agents/epic/parser.py +427 -423
  23. tapps_agents/experts/adaptive_domain_detector.py +0 -2
  24. tapps_agents/experts/knowledge/api-design-integration/api-security-patterns.md +15 -15
  25. tapps_agents/experts/knowledge/api-design-integration/external-api-integration.md +19 -44
  26. tapps_agents/health/checks/outcomes.backup_20260204_064058.py +324 -0
  27. tapps_agents/health/checks/outcomes.backup_20260204_064256.py +324 -0
  28. tapps_agents/health/checks/outcomes.backup_20260204_064600.py +324 -0
  29. tapps_agents/health/checks/outcomes.py +134 -46
  30. tapps_agents/health/orchestrator.py +12 -4
  31. tapps_agents/hooks/__init__.py +33 -0
  32. tapps_agents/hooks/config.py +140 -0
  33. tapps_agents/hooks/events.py +135 -0
  34. tapps_agents/hooks/executor.py +128 -0
  35. tapps_agents/hooks/manager.py +143 -0
  36. tapps_agents/session/__init__.py +19 -0
  37. tapps_agents/session/manager.py +256 -0
  38. tapps_agents/simple_mode/code_snippet_handler.py +382 -0
  39. tapps_agents/simple_mode/intent_parser.py +29 -4
  40. tapps_agents/simple_mode/orchestrators/base.py +185 -59
  41. tapps_agents/simple_mode/orchestrators/build_orchestrator.py +2667 -2642
  42. tapps_agents/simple_mode/orchestrators/fix_orchestrator.py +2 -2
  43. tapps_agents/simple_mode/workflow_suggester.py +37 -3
  44. tapps_agents/workflow/agent_handlers/implementer_handler.py +18 -3
  45. tapps_agents/workflow/cursor_executor.py +2337 -2118
  46. tapps_agents/workflow/direct_execution_fallback.py +16 -3
  47. tapps_agents/workflow/message_formatter.py +2 -1
  48. tapps_agents/workflow/models.py +38 -1
  49. tapps_agents/workflow/parallel_executor.py +43 -4
  50. tapps_agents/workflow/parser.py +375 -357
  51. tapps_agents/workflow/rules_generator.py +337 -337
  52. tapps_agents/workflow/skill_invoker.py +9 -3
  53. {tapps_agents-3.5.39.dist-info → tapps_agents-3.5.41.dist-info}/METADATA +5 -1
  54. {tapps_agents-3.5.39.dist-info → tapps_agents-3.5.41.dist-info}/RECORD +58 -54
  55. tapps_agents/agents/analyst/SKILL.md +0 -85
  56. tapps_agents/agents/architect/SKILL.md +0 -80
  57. tapps_agents/agents/debugger/SKILL.md +0 -66
  58. tapps_agents/agents/designer/SKILL.md +0 -78
  59. tapps_agents/agents/documenter/SKILL.md +0 -95
  60. tapps_agents/agents/enhancer/SKILL.md +0 -189
  61. tapps_agents/agents/implementer/SKILL.md +0 -117
  62. tapps_agents/agents/improver/SKILL.md +0 -55
  63. tapps_agents/agents/ops/SKILL.md +0 -64
  64. tapps_agents/agents/orchestrator/SKILL.md +0 -238
  65. tapps_agents/agents/planner/story_template.md +0 -37
  66. tapps_agents/agents/reviewer/templates/quality-dashboard.html.j2 +0 -150
  67. tapps_agents/agents/tester/SKILL.md +0 -71
  68. {tapps_agents-3.5.39.dist-info → tapps_agents-3.5.41.dist-info}/WHEEL +0 -0
  69. {tapps_agents-3.5.39.dist-info → tapps_agents-3.5.41.dist-info}/entry_points.txt +0 -0
  70. {tapps_agents-3.5.39.dist-info → tapps_agents-3.5.41.dist-info}/licenses/LICENSE +0 -0
  71. {tapps_agents-3.5.39.dist-info → tapps_agents-3.5.41.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,227 @@
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
+ elif final_state.status == "blocked":
211
+ # BUG-003B fix: Set status to "blocked" when workflow fails
212
+ spec = spec.model_copy(update={"status": "blocked"})
213
+ save_task_spec(spec, root)
214
+ print(f"Workflow blocked: {final_state.error or 'Required step failed'}", file=sys.stderr)
215
+ sys.exit(1)
216
+ else:
217
+ # Other statuses (paused, etc.) - set to todo for retry
218
+ spec = spec.model_copy(update={"status": "todo"})
219
+ save_task_spec(spec, root)
220
+ print(f"Workflow ended with status: {final_state.status}", file=sys.stderr)
221
+ sys.exit(1)
222
+ except Exception as e:
223
+ # BUG-003B fix: Set status to "blocked" on exception
224
+ spec = spec.model_copy(update={"status": "blocked"})
225
+ save_task_spec(spec, root)
226
+ print(f"Error running workflow: {e}", file=sys.stderr)
227
+ 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