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,363 @@
1
+ """Models for automatic Mermaid diagram generation."""
2
+
3
+ from dataclasses import dataclass, field
4
+ from enum import Enum
5
+ from pathlib import Path
6
+ from typing import Optional
7
+
8
+
9
+ class DiagramType(str, Enum):
10
+ """Type of Mermaid diagram to generate.
11
+
12
+ Values:
13
+ USER_JOURNEY: Flowchart showing user story flows
14
+ ER_DIAGRAM: Entity relationship diagram from Key Entities
15
+ ARCHITECTURE: Architecture diagram from plan.md
16
+ """
17
+
18
+ USER_JOURNEY = "user-journey"
19
+ ER_DIAGRAM = "er-diagram"
20
+ ARCHITECTURE = "architecture"
21
+
22
+ @classmethod
23
+ def from_string(cls, value: str) -> "DiagramType":
24
+ """Parse a diagram type string.
25
+
26
+ Args:
27
+ value: Type string (e.g., "user-journey", "er-diagram")
28
+
29
+ Returns:
30
+ Corresponding DiagramType enum value.
31
+
32
+ Raises:
33
+ ValueError: If value doesn't match any type.
34
+ """
35
+ normalized = value.lower().strip().replace("_", "-")
36
+ mapping = {
37
+ "user-journey": cls.USER_JOURNEY,
38
+ "userjourney": cls.USER_JOURNEY,
39
+ "flowchart": cls.USER_JOURNEY,
40
+ "er-diagram": cls.ER_DIAGRAM,
41
+ "erdiagram": cls.ER_DIAGRAM,
42
+ "er": cls.ER_DIAGRAM,
43
+ "architecture": cls.ARCHITECTURE,
44
+ "arch": cls.ARCHITECTURE,
45
+ }
46
+ if normalized not in mapping:
47
+ raise ValueError(f"Unknown diagram type: {value}")
48
+ return mapping[normalized]
49
+
50
+
51
+ class Cardinality(str, Enum):
52
+ """ER diagram relationship cardinality.
53
+
54
+ Values map to Mermaid ER diagram notation.
55
+ """
56
+
57
+ ONE_TO_ONE = "||--||"
58
+ ONE_TO_MANY = "||--o{"
59
+ MANY_TO_ONE = "}o--||"
60
+ MANY_TO_MANY = "}o--o{"
61
+ ZERO_OR_ONE_TO_ONE = "|o--||"
62
+ ONE_TO_ZERO_OR_ONE = "||--o|"
63
+ ZERO_OR_ONE_TO_MANY = "|o--o{"
64
+ ZERO_OR_MANY_TO_ONE = "}o--o|"
65
+
66
+ @classmethod
67
+ def from_keywords(cls, text: str) -> "Cardinality":
68
+ """Infer cardinality from natural language keywords.
69
+
70
+ Args:
71
+ text: Description text containing relationship keywords
72
+
73
+ Returns:
74
+ Inferred Cardinality (defaults to ONE_TO_MANY if unclear)
75
+ """
76
+ text_lower = text.lower()
77
+
78
+ # Check for many-to-many first
79
+ if "many-to-many" in text_lower or "many to many" in text_lower:
80
+ return cls.MANY_TO_MANY
81
+
82
+ # Check for one-to-one
83
+ if "has one" in text_lower or "one-to-one" in text_lower:
84
+ return cls.ONE_TO_ONE
85
+
86
+ # Check for belongs to (reverse relationship)
87
+ if "belongs to" in text_lower:
88
+ return cls.MANY_TO_ONE
89
+
90
+ # Default for "has many", "contains", etc.
91
+ if "has many" in text_lower or "contains" in text_lower or "owns" in text_lower:
92
+ return cls.ONE_TO_MANY
93
+
94
+ # Default to one-to-many for unrecognized patterns
95
+ return cls.ONE_TO_MANY
96
+
97
+ @property
98
+ def mermaid_notation(self) -> str:
99
+ """Return the Mermaid ER diagram notation."""
100
+ return self.value
101
+
102
+
103
+ @dataclass
104
+ class AcceptanceScenario:
105
+ """Represents a Given/When/Then acceptance scenario.
106
+
107
+ Attributes:
108
+ id: Unique ID (e.g., "US1_S1")
109
+ scenario_number: Scenario number within story (1, 2, 3...)
110
+ given_clause: Initial state condition
111
+ when_clause: Action or trigger
112
+ then_clause: Expected outcome
113
+ raw_text: Original text from spec
114
+ """
115
+
116
+ id: str
117
+ scenario_number: int
118
+ given_clause: str
119
+ when_clause: str
120
+ then_clause: str
121
+ raw_text: str = ""
122
+
123
+ @property
124
+ def node_label(self) -> str:
125
+ """Generate a label suitable for flowchart node."""
126
+ # Truncate to reasonable length for display
127
+ max_len = 40
128
+ given_short = (
129
+ self.given_clause[:max_len] + "..."
130
+ if len(self.given_clause) > max_len
131
+ else self.given_clause
132
+ )
133
+ return given_short
134
+
135
+
136
+ @dataclass
137
+ class ParsedUserStory:
138
+ """Structured representation of a user story extracted from spec.
139
+
140
+ Attributes:
141
+ id: Unique ID (e.g., "US1")
142
+ story_number: Story number (1, 2, 3...)
143
+ title: Brief title from header
144
+ priority: Priority level (P1, P2, P3, P4)
145
+ description: Full user story description
146
+ scenarios: List of acceptance scenarios
147
+ raw_text: Original markdown text
148
+ """
149
+
150
+ id: str
151
+ story_number: int
152
+ title: str
153
+ priority: str
154
+ description: str = ""
155
+ scenarios: list[AcceptanceScenario] = field(default_factory=list)
156
+ raw_text: str = ""
157
+
158
+ @property
159
+ def subgraph_id(self) -> str:
160
+ """Generate unique subgraph ID for Mermaid flowchart."""
161
+ return f"US{self.story_number}"
162
+
163
+ @property
164
+ def subgraph_label(self) -> str:
165
+ """Generate subgraph label for Mermaid flowchart."""
166
+ return f"US{self.story_number} - {self.title}"
167
+
168
+
169
+ @dataclass
170
+ class EntityAttribute:
171
+ """Attribute within an entity definition.
172
+
173
+ Attributes:
174
+ name: Attribute name
175
+ attr_type: Data type (string, int, uuid, etc.)
176
+ is_pk: Primary key flag
177
+ is_fk: Foreign key flag
178
+ """
179
+
180
+ name: str
181
+ attr_type: str = "string"
182
+ is_pk: bool = False
183
+ is_fk: bool = False
184
+
185
+ @property
186
+ def mermaid_line(self) -> str:
187
+ """Generate Mermaid ER attribute line."""
188
+ pk_marker = " PK" if self.is_pk else ""
189
+ fk_marker = " FK" if self.is_fk else ""
190
+ return f" {self.attr_type} {self.name}{pk_marker}{fk_marker}"
191
+
192
+
193
+ @dataclass
194
+ class EntityRelationship:
195
+ """Relationship between two entities.
196
+
197
+ Attributes:
198
+ source_entity: Source entity name
199
+ target_entity: Target entity name
200
+ cardinality: Relationship cardinality
201
+ label: Relationship label (verb phrase)
202
+ """
203
+
204
+ source_entity: str
205
+ target_entity: str
206
+ cardinality: Cardinality
207
+ label: str = ""
208
+
209
+ @property
210
+ def mermaid_line(self) -> str:
211
+ """Generate Mermaid ER relationship line."""
212
+ label_part = f' : "{self.label}"' if self.label else ""
213
+ return f" {self.source_entity} {self.cardinality.mermaid_notation} {self.target_entity}{label_part}"
214
+
215
+
216
+ @dataclass
217
+ class ParsedEntity:
218
+ """Structured representation of an entity from Key Entities section.
219
+
220
+ Attributes:
221
+ name: Entity name (e.g., "User")
222
+ description: What the entity represents
223
+ raw_text: Original markdown text
224
+ attributes: Parsed attributes
225
+ relationships: Relationships to other entities
226
+ """
227
+
228
+ name: str
229
+ description: str = ""
230
+ raw_text: str = ""
231
+ attributes: list[EntityAttribute] = field(default_factory=list)
232
+ relationships: list[EntityRelationship] = field(default_factory=list)
233
+
234
+ @property
235
+ def mermaid_entity_block(self) -> str:
236
+ """Generate Mermaid ER entity block."""
237
+ if not self.attributes:
238
+ return f" {self.name}"
239
+
240
+ lines = [f" {self.name} {{"]
241
+ for attr in self.attributes:
242
+ lines.append(attr.mermaid_line)
243
+ lines.append(" }")
244
+ return "\n".join(lines)
245
+
246
+
247
+ @dataclass
248
+ class DiagramSection:
249
+ """Represents an AUTO-GENERATED section in a file.
250
+
251
+ Attributes:
252
+ section_name: Section identifier (e.g., "user-journey")
253
+ start_line: Start line number (BEGIN marker)
254
+ end_line: End line number (END marker)
255
+ content: Content between markers
256
+ """
257
+
258
+ section_name: str
259
+ start_line: int
260
+ end_line: int
261
+ content: str = ""
262
+
263
+ @property
264
+ def begin_marker(self) -> str:
265
+ """Generate the BEGIN marker comment."""
266
+ return f'<!-- BEGIN:AUTO-GENERATED section="{self.section_name}" -->'
267
+
268
+ @property
269
+ def end_marker(self) -> str:
270
+ """Generate the END marker comment."""
271
+ return "<!-- END:AUTO-GENERATED -->"
272
+
273
+
274
+ @dataclass
275
+ class ValidationResult:
276
+ """Result of Mermaid syntax validation.
277
+
278
+ Attributes:
279
+ passed: Overall pass/fail
280
+ errors: Syntax errors found
281
+ warnings: Non-blocking warnings
282
+ """
283
+
284
+ passed: bool
285
+ errors: list[str] = field(default_factory=list)
286
+ warnings: list[str] = field(default_factory=list)
287
+
288
+ @property
289
+ def error_count(self) -> int:
290
+ """Number of errors."""
291
+ return len(self.errors)
292
+
293
+ @property
294
+ def warning_count(self) -> int:
295
+ """Number of warnings."""
296
+ return len(self.warnings)
297
+
298
+ @property
299
+ def is_valid(self) -> bool:
300
+ """Alias for passed."""
301
+ return self.passed
302
+
303
+
304
+ @dataclass
305
+ class GeneratedDiagram:
306
+ """Result of diagram generation.
307
+
308
+ Attributes:
309
+ id: Unique diagram ID
310
+ diagram_type: Type of diagram generated
311
+ mermaid_content: Generated Mermaid syntax
312
+ is_valid: Whether syntax validation passed
313
+ validation: Detailed validation result
314
+ node_count: Number of nodes/entities in diagram
315
+ """
316
+
317
+ id: str
318
+ diagram_type: DiagramType
319
+ mermaid_content: str
320
+ is_valid: bool = True
321
+ validation: Optional[ValidationResult] = None
322
+ node_count: int = 0
323
+
324
+ @property
325
+ def wrapped_content(self) -> str:
326
+ """Return content wrapped in Mermaid code fence."""
327
+ return f"```mermaid\n{self.mermaid_content}\n```"
328
+
329
+
330
+ @dataclass
331
+ class DiagramResult:
332
+ """Result of diagram generation operation.
333
+
334
+ Attributes:
335
+ file_path: Path to the file that was processed
336
+ diagrams: List of generated diagrams
337
+ sections_found: AUTO-GENERATED sections found in file
338
+ sections_updated: Sections that were updated
339
+ success: Overall success status
340
+ error: Error message if failed
341
+ """
342
+
343
+ file_path: Path
344
+ diagrams: list[GeneratedDiagram] = field(default_factory=list)
345
+ sections_found: list[DiagramSection] = field(default_factory=list)
346
+ sections_updated: list[str] = field(default_factory=list)
347
+ success: bool = True
348
+ error: Optional[str] = None
349
+
350
+ @property
351
+ def total_diagrams(self) -> int:
352
+ """Total diagrams generated."""
353
+ return len(self.diagrams)
354
+
355
+ @property
356
+ def valid_diagrams(self) -> int:
357
+ """Count of valid diagrams."""
358
+ return sum(1 for d in self.diagrams if d.is_valid)
359
+
360
+ @property
361
+ def total_nodes(self) -> int:
362
+ """Total nodes across all diagrams."""
363
+ return sum(d.node_count for d in self.diagrams)