doit-toolkit-cli 0.1.9__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 (134) hide show
  1. doit_cli/__init__.py +1356 -0
  2. doit_cli/cli/__init__.py +26 -0
  3. doit_cli/cli/analytics_command.py +616 -0
  4. doit_cli/cli/context_command.py +213 -0
  5. doit_cli/cli/diagram_command.py +304 -0
  6. doit_cli/cli/fixit_command.py +641 -0
  7. doit_cli/cli/hooks_command.py +211 -0
  8. doit_cli/cli/init_command.py +613 -0
  9. doit_cli/cli/memory_command.py +293 -0
  10. doit_cli/cli/status_command.py +117 -0
  11. doit_cli/cli/sync_prompts_command.py +248 -0
  12. doit_cli/cli/validate_command.py +196 -0
  13. doit_cli/cli/verify_command.py +204 -0
  14. doit_cli/cli/workflow_mixin.py +224 -0
  15. doit_cli/cli/xref_command.py +555 -0
  16. doit_cli/formatters/__init__.py +8 -0
  17. doit_cli/formatters/base.py +38 -0
  18. doit_cli/formatters/json_formatter.py +126 -0
  19. doit_cli/formatters/markdown_formatter.py +97 -0
  20. doit_cli/formatters/rich_formatter.py +257 -0
  21. doit_cli/main.py +49 -0
  22. doit_cli/models/__init__.py +139 -0
  23. doit_cli/models/agent.py +74 -0
  24. doit_cli/models/analytics_models.py +384 -0
  25. doit_cli/models/context_config.py +464 -0
  26. doit_cli/models/crossref_models.py +182 -0
  27. doit_cli/models/diagram_models.py +363 -0
  28. doit_cli/models/fixit_models.py +355 -0
  29. doit_cli/models/hook_config.py +125 -0
  30. doit_cli/models/project.py +91 -0
  31. doit_cli/models/results.py +121 -0
  32. doit_cli/models/search_models.py +228 -0
  33. doit_cli/models/status_models.py +195 -0
  34. doit_cli/models/sync_models.py +146 -0
  35. doit_cli/models/template.py +77 -0
  36. doit_cli/models/validation_models.py +175 -0
  37. doit_cli/models/workflow_models.py +319 -0
  38. doit_cli/prompts/__init__.py +5 -0
  39. doit_cli/prompts/fixit_prompts.py +344 -0
  40. doit_cli/prompts/interactive.py +390 -0
  41. doit_cli/rules/__init__.py +5 -0
  42. doit_cli/rules/builtin_rules.py +160 -0
  43. doit_cli/services/__init__.py +79 -0
  44. doit_cli/services/agent_detector.py +168 -0
  45. doit_cli/services/analytics_service.py +218 -0
  46. doit_cli/services/architecture_generator.py +290 -0
  47. doit_cli/services/backup_service.py +204 -0
  48. doit_cli/services/config_loader.py +113 -0
  49. doit_cli/services/context_loader.py +1121 -0
  50. doit_cli/services/coverage_calculator.py +142 -0
  51. doit_cli/services/crossref_service.py +237 -0
  52. doit_cli/services/cycle_time_calculator.py +134 -0
  53. doit_cli/services/date_inferrer.py +349 -0
  54. doit_cli/services/diagram_service.py +337 -0
  55. doit_cli/services/drift_detector.py +109 -0
  56. doit_cli/services/entity_parser.py +301 -0
  57. doit_cli/services/er_diagram_generator.py +197 -0
  58. doit_cli/services/fixit_service.py +699 -0
  59. doit_cli/services/github_service.py +192 -0
  60. doit_cli/services/hook_manager.py +258 -0
  61. doit_cli/services/hook_validator.py +528 -0
  62. doit_cli/services/input_validator.py +322 -0
  63. doit_cli/services/memory_search.py +527 -0
  64. doit_cli/services/mermaid_validator.py +334 -0
  65. doit_cli/services/prompt_transformer.py +91 -0
  66. doit_cli/services/prompt_writer.py +133 -0
  67. doit_cli/services/query_interpreter.py +428 -0
  68. doit_cli/services/report_exporter.py +219 -0
  69. doit_cli/services/report_generator.py +256 -0
  70. doit_cli/services/requirement_parser.py +112 -0
  71. doit_cli/services/roadmap_summarizer.py +209 -0
  72. doit_cli/services/rule_engine.py +443 -0
  73. doit_cli/services/scaffolder.py +215 -0
  74. doit_cli/services/score_calculator.py +172 -0
  75. doit_cli/services/section_parser.py +204 -0
  76. doit_cli/services/spec_scanner.py +327 -0
  77. doit_cli/services/state_manager.py +355 -0
  78. doit_cli/services/status_reporter.py +143 -0
  79. doit_cli/services/task_parser.py +347 -0
  80. doit_cli/services/template_manager.py +710 -0
  81. doit_cli/services/template_reader.py +158 -0
  82. doit_cli/services/user_journey_generator.py +214 -0
  83. doit_cli/services/user_story_parser.py +232 -0
  84. doit_cli/services/validation_service.py +188 -0
  85. doit_cli/services/validator.py +232 -0
  86. doit_cli/services/velocity_tracker.py +173 -0
  87. doit_cli/services/workflow_engine.py +405 -0
  88. doit_cli/templates/agent-file-template.md +28 -0
  89. doit_cli/templates/checklist-template.md +39 -0
  90. doit_cli/templates/commands/doit.checkin.md +363 -0
  91. doit_cli/templates/commands/doit.constitution.md +187 -0
  92. doit_cli/templates/commands/doit.documentit.md +485 -0
  93. doit_cli/templates/commands/doit.fixit.md +181 -0
  94. doit_cli/templates/commands/doit.implementit.md +265 -0
  95. doit_cli/templates/commands/doit.planit.md +262 -0
  96. doit_cli/templates/commands/doit.reviewit.md +355 -0
  97. doit_cli/templates/commands/doit.roadmapit.md +368 -0
  98. doit_cli/templates/commands/doit.scaffoldit.md +458 -0
  99. doit_cli/templates/commands/doit.specit.md +521 -0
  100. doit_cli/templates/commands/doit.taskit.md +304 -0
  101. doit_cli/templates/commands/doit.testit.md +277 -0
  102. doit_cli/templates/config/context.yaml +134 -0
  103. doit_cli/templates/config/hooks.yaml +93 -0
  104. doit_cli/templates/config/validation-rules.yaml +64 -0
  105. doit_cli/templates/github-issue-templates/epic.yml +78 -0
  106. doit_cli/templates/github-issue-templates/feature.yml +116 -0
  107. doit_cli/templates/github-issue-templates/task.yml +129 -0
  108. doit_cli/templates/hooks/.gitkeep +0 -0
  109. doit_cli/templates/hooks/post-commit.sh +25 -0
  110. doit_cli/templates/hooks/post-merge.sh +75 -0
  111. doit_cli/templates/hooks/pre-commit.sh +17 -0
  112. doit_cli/templates/hooks/pre-push.sh +18 -0
  113. doit_cli/templates/memory/completed_roadmap.md +50 -0
  114. doit_cli/templates/memory/constitution.md +125 -0
  115. doit_cli/templates/memory/roadmap.md +61 -0
  116. doit_cli/templates/plan-template.md +146 -0
  117. doit_cli/templates/scripts/bash/check-prerequisites.sh +166 -0
  118. doit_cli/templates/scripts/bash/common.sh +156 -0
  119. doit_cli/templates/scripts/bash/create-new-feature.sh +297 -0
  120. doit_cli/templates/scripts/bash/setup-plan.sh +61 -0
  121. doit_cli/templates/scripts/bash/update-agent-context.sh +675 -0
  122. doit_cli/templates/scripts/powershell/check-prerequisites.ps1 +148 -0
  123. doit_cli/templates/scripts/powershell/common.ps1 +137 -0
  124. doit_cli/templates/scripts/powershell/create-new-feature.ps1 +283 -0
  125. doit_cli/templates/scripts/powershell/setup-plan.ps1 +61 -0
  126. doit_cli/templates/scripts/powershell/update-agent-context.ps1 +406 -0
  127. doit_cli/templates/spec-template.md +159 -0
  128. doit_cli/templates/tasks-template.md +313 -0
  129. doit_cli/templates/vscode-settings.json +14 -0
  130. doit_toolkit_cli-0.1.9.dist-info/METADATA +324 -0
  131. doit_toolkit_cli-0.1.9.dist-info/RECORD +134 -0
  132. doit_toolkit_cli-0.1.9.dist-info/WHEEL +4 -0
  133. doit_toolkit_cli-0.1.9.dist-info/entry_points.txt +2 -0
  134. doit_toolkit_cli-0.1.9.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,344 @@
1
+ """Interactive prompts for fixit workflow.
2
+
3
+ This module provides Rich-based interactive prompts
4
+ for the bug-fix workflow user interactions.
5
+ """
6
+
7
+ from typing import Optional
8
+
9
+ from rich.console import Console
10
+ from rich.panel import Panel
11
+ from rich.prompt import Confirm, IntPrompt, Prompt
12
+ from rich.table import Table
13
+
14
+ from ..models.fixit_models import (
15
+ FixPhase,
16
+ FixPlan,
17
+ FixWorkflow,
18
+ GitHubIssue,
19
+ InvestigationFinding,
20
+ )
21
+
22
+ console = Console()
23
+
24
+
25
+ # =============================================================================
26
+ # Issue Selection Prompts
27
+ # =============================================================================
28
+
29
+
30
+ def prompt_select_issue(bugs: list[GitHubIssue]) -> Optional[GitHubIssue]:
31
+ """Display bugs and prompt user to select one.
32
+
33
+ Args:
34
+ bugs: List of GitHubIssue objects to choose from.
35
+
36
+ Returns:
37
+ Selected GitHubIssue or None if cancelled.
38
+ """
39
+ if not bugs:
40
+ return None
41
+
42
+ # Display table of bugs
43
+ table = Table(title="Open Bugs", show_header=True)
44
+ table.add_column("#", style="cyan", width=4)
45
+ table.add_column("Issue", style="cyan", width=6)
46
+ table.add_column("Title", style="white")
47
+ table.add_column("Labels", style="dim")
48
+
49
+ for idx, bug in enumerate(bugs, 1):
50
+ labels_str = ", ".join(bug.labels[:3]) if bug.labels else ""
51
+ if len(bug.labels) > 3:
52
+ labels_str += "..."
53
+ table.add_row(str(idx), f"#{bug.number}", bug.title[:60], labels_str)
54
+
55
+ console.print(table)
56
+ console.print()
57
+
58
+ # Prompt for selection
59
+ while True:
60
+ try:
61
+ choice = IntPrompt.ask(
62
+ "Select bug number to fix (or 0 to cancel)",
63
+ default=0,
64
+ )
65
+ if choice == 0:
66
+ return None
67
+ if 1 <= choice <= len(bugs):
68
+ return bugs[choice - 1]
69
+ console.print(f"[red]Please select a number between 1 and {len(bugs)}[/red]")
70
+ except KeyboardInterrupt:
71
+ return None
72
+
73
+
74
+ # =============================================================================
75
+ # Workflow Display Functions
76
+ # =============================================================================
77
+
78
+
79
+ def display_workflow_started(workflow: FixWorkflow, issue_id: int) -> None:
80
+ """Display confirmation that workflow has started.
81
+
82
+ Args:
83
+ workflow: The started FixWorkflow.
84
+ issue_id: GitHub issue number.
85
+ """
86
+ console.print()
87
+ console.print(
88
+ Panel(
89
+ f"[green]Workflow started for issue [cyan]#{issue_id}[/cyan][/green]\n\n"
90
+ f"[dim]Branch:[/dim] [cyan]{workflow.branch_name}[/cyan]\n"
91
+ f"[dim]Phase:[/dim] [yellow]{workflow.phase.value}[/yellow]",
92
+ title="Bug Fix Workflow",
93
+ border_style="green",
94
+ )
95
+ )
96
+
97
+
98
+ def display_workflow_status(workflow: FixWorkflow) -> None:
99
+ """Display detailed workflow status.
100
+
101
+ Args:
102
+ workflow: The FixWorkflow to display.
103
+ """
104
+ phase_style = _get_phase_style(workflow.phase)
105
+
106
+ # Build phase progress indicator
107
+ phases = [
108
+ FixPhase.INITIALIZED,
109
+ FixPhase.INVESTIGATING,
110
+ FixPhase.PLANNING,
111
+ FixPhase.REVIEWING,
112
+ FixPhase.APPROVED,
113
+ FixPhase.IMPLEMENTING,
114
+ FixPhase.COMPLETED,
115
+ ]
116
+
117
+ progress_parts = []
118
+ current_found = False
119
+ for phase in phases:
120
+ if phase == workflow.phase:
121
+ progress_parts.append(f"[{phase_style}]{phase.value}[/{phase_style}]")
122
+ current_found = True
123
+ elif not current_found:
124
+ progress_parts.append(f"[green]{phase.value}[/green]")
125
+ else:
126
+ progress_parts.append(f"[dim]{phase.value}[/dim]")
127
+
128
+ progress_line = " → ".join(progress_parts)
129
+
130
+ console.print()
131
+ console.print(
132
+ Panel(
133
+ f"[dim]Issue:[/dim] [cyan]#{workflow.issue_id}[/cyan]\n"
134
+ f"[dim]Branch:[/dim] [white]{workflow.branch_name}[/white]\n"
135
+ f"[dim]Started:[/dim] {workflow.started_at.strftime('%Y-%m-%d %H:%M')}\n"
136
+ f"[dim]Updated:[/dim] {workflow.updated_at.strftime('%Y-%m-%d %H:%M')}\n\n"
137
+ f"[dim]Progress:[/dim]\n{progress_line}",
138
+ title=f"Fixit Workflow: {workflow.id}",
139
+ border_style=phase_style,
140
+ )
141
+ )
142
+
143
+
144
+ def display_investigation_findings(findings: list[InvestigationFinding]) -> None:
145
+ """Display investigation findings.
146
+
147
+ Args:
148
+ findings: List of findings to display.
149
+ """
150
+ if not findings:
151
+ console.print("[yellow]No findings recorded yet.[/yellow]")
152
+ return
153
+
154
+ table = Table(title="Investigation Findings")
155
+ table.add_column("Type", style="cyan", width=15)
156
+ table.add_column("Description", style="white")
157
+ table.add_column("Location", style="dim")
158
+
159
+ for finding in findings:
160
+ location = ""
161
+ if finding.file_path:
162
+ location = finding.file_path
163
+ if finding.line_number:
164
+ location += f":{finding.line_number}"
165
+
166
+ table.add_row(
167
+ finding.finding_type.value,
168
+ finding.description[:50] + "..." if len(finding.description) > 50 else finding.description,
169
+ location,
170
+ )
171
+
172
+ console.print(table)
173
+
174
+
175
+ def display_fix_plan(plan: FixPlan) -> None:
176
+ """Display fix plan details.
177
+
178
+ Args:
179
+ plan: The FixPlan to display.
180
+ """
181
+ # Status style
182
+ status_styles = {
183
+ "draft": "dim",
184
+ "pending_review": "yellow",
185
+ "revision_needed": "red",
186
+ "approved": "green",
187
+ }
188
+ status_style = status_styles.get(plan.status.value, "white")
189
+
190
+ # Risk level style
191
+ risk_styles = {
192
+ "low": "green",
193
+ "medium": "yellow",
194
+ "high": "red",
195
+ }
196
+ risk_style = risk_styles.get(plan.risk_level.value, "white")
197
+
198
+ # Build plan content
199
+ content = (
200
+ f"[dim]Plan ID:[/dim] {plan.id}\n"
201
+ f"[dim]Status:[/dim] [{status_style}]{plan.status.value}[/{status_style}]\n"
202
+ f"[dim]Risk Level:[/dim] [{risk_style}]{plan.risk_level.value}[/{risk_style}]\n\n"
203
+ f"[cyan]Root Cause:[/cyan]\n{plan.root_cause}\n\n"
204
+ f"[cyan]Proposed Solution:[/cyan]\n{plan.proposed_solution}"
205
+ )
206
+
207
+ console.print(
208
+ Panel(
209
+ content,
210
+ title="Fix Plan",
211
+ border_style=status_style,
212
+ )
213
+ )
214
+
215
+ # Display affected files
216
+ if plan.affected_files:
217
+ table = Table(title="Affected Files")
218
+ table.add_column("File", style="cyan")
219
+ table.add_column("Change", style="dim", width=10)
220
+ table.add_column("Description", style="white")
221
+
222
+ for fc in plan.affected_files:
223
+ table.add_row(
224
+ fc.file_path,
225
+ fc.change_type.value,
226
+ fc.description[:50] + "..." if len(fc.description) > 50 else fc.description,
227
+ )
228
+
229
+ console.print(table)
230
+
231
+
232
+ # =============================================================================
233
+ # Confirmation Prompts
234
+ # =============================================================================
235
+
236
+
237
+ def confirm_start_workflow(issue: GitHubIssue) -> bool:
238
+ """Confirm starting a workflow for an issue.
239
+
240
+ Args:
241
+ issue: The GitHub issue.
242
+
243
+ Returns:
244
+ True if confirmed, False otherwise.
245
+ """
246
+ console.print()
247
+ console.print(
248
+ Panel(
249
+ f"[cyan]#{issue.number}[/cyan] {issue.title}\n\n"
250
+ f"[dim]{issue.body[:200]}{'...' if len(issue.body) > 200 else ''}[/dim]",
251
+ title="Issue Details",
252
+ border_style="cyan",
253
+ )
254
+ )
255
+ console.print()
256
+
257
+ return Confirm.ask("Start fix workflow for this issue?", default=True)
258
+
259
+
260
+ def confirm_cancel_workflow(issue_id: int) -> bool:
261
+ """Confirm cancelling a workflow.
262
+
263
+ Args:
264
+ issue_id: GitHub issue number.
265
+
266
+ Returns:
267
+ True if confirmed, False otherwise.
268
+ """
269
+ return Confirm.ask(
270
+ f"[yellow]Cancel workflow for issue #{issue_id}?[/yellow]",
271
+ default=False,
272
+ )
273
+
274
+
275
+ def confirm_complete_workflow(issue_id: int, close_issue: bool = True) -> bool:
276
+ """Confirm completing a workflow.
277
+
278
+ Args:
279
+ issue_id: GitHub issue number.
280
+ close_issue: Whether the issue will be closed.
281
+
282
+ Returns:
283
+ True if confirmed, False otherwise.
284
+ """
285
+ msg = f"Complete workflow for issue #{issue_id}?"
286
+ if close_issue:
287
+ msg += " (Issue will be closed)"
288
+
289
+ return Confirm.ask(msg, default=True)
290
+
291
+
292
+ # =============================================================================
293
+ # Input Prompts
294
+ # =============================================================================
295
+
296
+
297
+ def prompt_branch_name(default: str) -> str:
298
+ """Prompt for custom branch name.
299
+
300
+ Args:
301
+ default: Default branch name.
302
+
303
+ Returns:
304
+ Branch name (custom or default).
305
+ """
306
+ return Prompt.ask("Branch name", default=default)
307
+
308
+
309
+ def prompt_finding_description() -> str:
310
+ """Prompt for a finding description.
311
+
312
+ Returns:
313
+ Finding description.
314
+ """
315
+ return Prompt.ask("Describe the finding")
316
+
317
+
318
+ def prompt_root_cause() -> str:
319
+ """Prompt for root cause description.
320
+
321
+ Returns:
322
+ Root cause description.
323
+ """
324
+ return Prompt.ask("Describe the root cause")
325
+
326
+
327
+ # =============================================================================
328
+ # Helper Functions
329
+ # =============================================================================
330
+
331
+
332
+ def _get_phase_style(phase: FixPhase) -> str:
333
+ """Get Rich style for a phase."""
334
+ styles = {
335
+ FixPhase.INITIALIZED: "dim",
336
+ FixPhase.INVESTIGATING: "yellow",
337
+ FixPhase.PLANNING: "yellow",
338
+ FixPhase.REVIEWING: "cyan",
339
+ FixPhase.APPROVED: "green",
340
+ FixPhase.IMPLEMENTING: "blue",
341
+ FixPhase.COMPLETED: "green bold",
342
+ FixPhase.CANCELLED: "red dim",
343
+ }
344
+ return styles.get(phase, "white")