devsquad 3.6.0__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.
- devsquad-3.6.0.dist-info/METADATA +944 -0
- devsquad-3.6.0.dist-info/RECORD +95 -0
- devsquad-3.6.0.dist-info/WHEEL +5 -0
- devsquad-3.6.0.dist-info/entry_points.txt +2 -0
- devsquad-3.6.0.dist-info/licenses/LICENSE +21 -0
- devsquad-3.6.0.dist-info/top_level.txt +2 -0
- scripts/__init__.py +0 -0
- scripts/ai_semantic_matcher.py +512 -0
- scripts/alert_manager.py +505 -0
- scripts/api/__init__.py +43 -0
- scripts/api/models.py +386 -0
- scripts/api/routes/__init__.py +20 -0
- scripts/api/routes/dispatch.py +348 -0
- scripts/api/routes/lifecycle.py +330 -0
- scripts/api/routes/metrics_gates.py +347 -0
- scripts/api_server.py +318 -0
- scripts/auth.py +451 -0
- scripts/cli/__init__.py +1 -0
- scripts/cli/cli_visual.py +642 -0
- scripts/cli.py +1094 -0
- scripts/collaboration/__init__.py +212 -0
- scripts/collaboration/_version.py +1 -0
- scripts/collaboration/agent_briefing.py +656 -0
- scripts/collaboration/ai_semantic_matcher.py +260 -0
- scripts/collaboration/anchor_checker.py +281 -0
- scripts/collaboration/anti_rationalization.py +470 -0
- scripts/collaboration/async_integration_example.py +255 -0
- scripts/collaboration/batch_scheduler.py +149 -0
- scripts/collaboration/checkpoint_manager.py +561 -0
- scripts/collaboration/ci_feedback_adapter.py +351 -0
- scripts/collaboration/code_map_generator.py +247 -0
- scripts/collaboration/concern_pack_loader.py +352 -0
- scripts/collaboration/confidence_score.py +496 -0
- scripts/collaboration/config_loader.py +188 -0
- scripts/collaboration/consensus.py +244 -0
- scripts/collaboration/context_compressor.py +533 -0
- scripts/collaboration/coordinator.py +668 -0
- scripts/collaboration/dispatcher.py +1636 -0
- scripts/collaboration/dual_layer_context.py +128 -0
- scripts/collaboration/enhanced_worker.py +539 -0
- scripts/collaboration/feature_usage_tracker.py +206 -0
- scripts/collaboration/five_axis_consensus.py +334 -0
- scripts/collaboration/input_validator.py +401 -0
- scripts/collaboration/integration_example.py +287 -0
- scripts/collaboration/intent_workflow_mapper.py +350 -0
- scripts/collaboration/language_parsers.py +269 -0
- scripts/collaboration/lifecycle_protocol.py +1446 -0
- scripts/collaboration/llm_backend.py +453 -0
- scripts/collaboration/llm_cache.py +448 -0
- scripts/collaboration/llm_cache_async.py +347 -0
- scripts/collaboration/llm_retry.py +387 -0
- scripts/collaboration/llm_retry_async.py +389 -0
- scripts/collaboration/mce_adapter.py +597 -0
- scripts/collaboration/memory_bridge.py +1607 -0
- scripts/collaboration/models.py +537 -0
- scripts/collaboration/null_providers.py +297 -0
- scripts/collaboration/operation_classifier.py +289 -0
- scripts/collaboration/output_slicer.py +225 -0
- scripts/collaboration/performance_monitor.py +462 -0
- scripts/collaboration/permission_guard.py +865 -0
- scripts/collaboration/prompt_assembler.py +756 -0
- scripts/collaboration/prompt_variant_generator.py +483 -0
- scripts/collaboration/protocols.py +267 -0
- scripts/collaboration/report_formatter.py +352 -0
- scripts/collaboration/retrospective.py +279 -0
- scripts/collaboration/role_matcher.py +92 -0
- scripts/collaboration/role_template_market.py +352 -0
- scripts/collaboration/rule_collector.py +678 -0
- scripts/collaboration/scratchpad.py +346 -0
- scripts/collaboration/skill_registry.py +151 -0
- scripts/collaboration/skillifier.py +878 -0
- scripts/collaboration/standardized_role_template.py +317 -0
- scripts/collaboration/task_completion_checker.py +237 -0
- scripts/collaboration/test_quality_guard.py +695 -0
- scripts/collaboration/unified_gate_engine.py +598 -0
- scripts/collaboration/usage_tracker.py +309 -0
- scripts/collaboration/user_friendly_error.py +176 -0
- scripts/collaboration/verification_gate.py +312 -0
- scripts/collaboration/warmup_manager.py +635 -0
- scripts/collaboration/worker.py +513 -0
- scripts/collaboration/workflow_engine.py +684 -0
- scripts/dashboard.py +1088 -0
- scripts/generate_benchmark_report.py +786 -0
- scripts/history_manager.py +604 -0
- scripts/mcp_server.py +289 -0
- skills/__init__.py +32 -0
- skills/dispatch/handler.py +52 -0
- skills/intent/handler.py +59 -0
- skills/registry.py +67 -0
- skills/retrospective/__init__.py +0 -0
- skills/retrospective/handler.py +125 -0
- skills/review/handler.py +356 -0
- skills/security/handler.py +454 -0
- skills/test/__init__.py +0 -0
- skills/test/handler.py +78 -0
skills/review/handler.py
ADDED
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
"""Five-Axis Code Review Skill - V3.6.0
|
|
2
|
+
|
|
3
|
+
Encapsulates FiveAxisConsensusEngine for multi-dimensional code review:
|
|
4
|
+
1. Correctness: Logic correctness, bug-free, meets requirements
|
|
5
|
+
2. Readability: Code clarity, naming, comments, structure
|
|
6
|
+
3. Architecture: Design patterns, modularity, scalability
|
|
7
|
+
4. Security: Vulnerabilities, input validation, data protection
|
|
8
|
+
5. Performance: Efficiency, resource usage, bottlenecks
|
|
9
|
+
|
|
10
|
+
Supports both direct API and dispatcher integration (mode="consensus").
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, Dict, List, Optional
|
|
15
|
+
|
|
16
|
+
from skills.registry import BaseSkill
|
|
17
|
+
|
|
18
|
+
from scripts.collaboration.five_axis_consensus import (
|
|
19
|
+
FiveAxisConsensusEngine,
|
|
20
|
+
ReviewAxis,
|
|
21
|
+
ConsensusResult,
|
|
22
|
+
FiveAxisReview,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ReviewSkill(BaseSkill):
|
|
27
|
+
"""Five-axis code review skill for comprehensive code quality assessment."""
|
|
28
|
+
|
|
29
|
+
name = "review"
|
|
30
|
+
description = "Five-axis code review: correctness/readability/architecture/security/performance"
|
|
31
|
+
version = "3.6.0"
|
|
32
|
+
|
|
33
|
+
AXES_INFO = [
|
|
34
|
+
{
|
|
35
|
+
"axis": "correctness",
|
|
36
|
+
"label": "Correctness",
|
|
37
|
+
"description": "Logic correctness, bug-free, meets requirements",
|
|
38
|
+
"weight": 0.30,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"axis": "readability",
|
|
42
|
+
"label": "Readability",
|
|
43
|
+
"description": "Code clarity, naming conventions, comments, structure",
|
|
44
|
+
"weight": 0.10,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"axis": "architecture",
|
|
48
|
+
"label": "Architecture",
|
|
49
|
+
"description": "Design patterns, modularity, scalability",
|
|
50
|
+
"weight": 0.20,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"axis": "security",
|
|
54
|
+
"label": "Security",
|
|
55
|
+
"description": "Vulnerabilities, input validation, data protection",
|
|
56
|
+
"weight": 0.25,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"axis": "performance",
|
|
60
|
+
"label": "Performance",
|
|
61
|
+
"description": "Efficiency, resource usage, bottleneck detection",
|
|
62
|
+
"weight": 0.15,
|
|
63
|
+
},
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
def __init__(self):
|
|
67
|
+
self._engine: Optional[FiveAxisConsensusEngine] = None
|
|
68
|
+
|
|
69
|
+
def _get_engine(self, strict_mode: bool = False) -> FiveAxisConsensusEngine:
|
|
70
|
+
if self._engine is None or self._engine._strict_mode != strict_mode:
|
|
71
|
+
self._engine = FiveAxisConsensusEngine(strict_mode=strict_mode)
|
|
72
|
+
return self._engine
|
|
73
|
+
|
|
74
|
+
def review(
|
|
75
|
+
self,
|
|
76
|
+
code: str,
|
|
77
|
+
strict_mode: bool = False,
|
|
78
|
+
file_path: Optional[str] = None,
|
|
79
|
+
) -> Dict[str, Any]:
|
|
80
|
+
"""
|
|
81
|
+
Perform five-axis code review.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
code: Source code to review (required)
|
|
85
|
+
strict_mode: Enable strict mode (security veto on low scores)
|
|
86
|
+
file_path: Optional file path for context (reads file if provided)
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
Dict with review results including:
|
|
90
|
+
- axis_scores: Per-axis consensus scores
|
|
91
|
+
- overall_score: Weighted overall score
|
|
92
|
+
- verdict: APPROVE/CONDITIONAL/REJECT
|
|
93
|
+
- action_items: List of improvement suggestions
|
|
94
|
+
- metadata: Review metadata (file_path, mode, etc.)
|
|
95
|
+
"""
|
|
96
|
+
if file_path and not code:
|
|
97
|
+
path = Path(file_path)
|
|
98
|
+
if path.exists():
|
|
99
|
+
code = path.read_text(encoding="utf-8")
|
|
100
|
+
else:
|
|
101
|
+
return {
|
|
102
|
+
"error": f"File not found: {file_path}",
|
|
103
|
+
"verdict": "REJECT",
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if not code or not code.strip():
|
|
107
|
+
return {
|
|
108
|
+
"error": "No code provided for review",
|
|
109
|
+
"verdict": "REJECT",
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
engine = self._get_engine(strict_mode=strict_mode)
|
|
113
|
+
|
|
114
|
+
review = engine.create_review(reviewer_id="review-skill", role="code-reviewer")
|
|
115
|
+
|
|
116
|
+
axis_scores = self._analyze_code(code)
|
|
117
|
+
|
|
118
|
+
for axis_name, score_data in axis_scores.items():
|
|
119
|
+
try:
|
|
120
|
+
axis = ReviewAxis(axis_name)
|
|
121
|
+
engine.add_axis_vote(
|
|
122
|
+
review=review,
|
|
123
|
+
axis=axis,
|
|
124
|
+
score=score_data["score"],
|
|
125
|
+
confidence=score_data["confidence"],
|
|
126
|
+
comment=score_data["comment"],
|
|
127
|
+
)
|
|
128
|
+
except ValueError:
|
|
129
|
+
continue
|
|
130
|
+
|
|
131
|
+
result: ConsensusResult = engine.compute_consensus([review])
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
**result.to_dict(),
|
|
135
|
+
"metadata": {
|
|
136
|
+
"file_path": file_path,
|
|
137
|
+
"strict_mode": strict_mode,
|
|
138
|
+
"code_length": len(code),
|
|
139
|
+
"skill_version": self.version,
|
|
140
|
+
},
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
def quick_review(self, code_snippet: str) -> Dict[str, Any]:
|
|
144
|
+
"""
|
|
145
|
+
Simplified single-axis quick scan for rapid feedback.
|
|
146
|
+
|
|
147
|
+
Focuses on correctness axis only for fast iteration.
|
|
148
|
+
Suitable for inline code snippets during development.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
code_snippet: Short code snippet to quickly review
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
Dict with quick assessment:
|
|
155
|
+
- score: Correctness score (0.0-1.0)
|
|
156
|
+
- status: PASS/WARN/FAIL
|
|
157
|
+
- issues: List of detected issues
|
|
158
|
+
- suggestion: One-line improvement suggestion
|
|
159
|
+
"""
|
|
160
|
+
if not code_snippet or not code_snippet.strip():
|
|
161
|
+
return {
|
|
162
|
+
"score": 0.0,
|
|
163
|
+
"status": "FAIL",
|
|
164
|
+
"issues": ["Empty code snippet"],
|
|
165
|
+
"suggestion": "Provide valid code for review",
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
issues = []
|
|
169
|
+
score = 1.0
|
|
170
|
+
|
|
171
|
+
lines = code_snippet.strip().split("\n")
|
|
172
|
+
|
|
173
|
+
if len(lines) < 3:
|
|
174
|
+
issues.append("Very short snippet - limited analysis possible")
|
|
175
|
+
score -= 0.1
|
|
176
|
+
|
|
177
|
+
has_comments = any(line.strip().startswith("#") for line in lines)
|
|
178
|
+
if not has_comments and len(lines) > 5:
|
|
179
|
+
issues.append("No comments found")
|
|
180
|
+
score -= 0.15
|
|
181
|
+
|
|
182
|
+
if "TODO" in code_snippet or "FIXME" in code_snippet or "XXX" in code_snippet:
|
|
183
|
+
issues.append("Contains TODO/FIXME markers")
|
|
184
|
+
score -= 0.2
|
|
185
|
+
|
|
186
|
+
if "print(" in code_snippet and "logging" not in code_snippet:
|
|
187
|
+
issues.append("Uses print() instead of logging")
|
|
188
|
+
score -= 0.1
|
|
189
|
+
|
|
190
|
+
if "except:" in code_snippet or "except Exception" in code_snippet:
|
|
191
|
+
for line in lines:
|
|
192
|
+
if "except" in line and ("pass" in line or "continue" in line):
|
|
193
|
+
issues.append("Silent exception handling detected")
|
|
194
|
+
score -= 0.2
|
|
195
|
+
break
|
|
196
|
+
|
|
197
|
+
if len(lines[0]) > 120:
|
|
198
|
+
issues.append("Very long first line")
|
|
199
|
+
score -= 0.05
|
|
200
|
+
|
|
201
|
+
score = max(0.0, min(1.0, score))
|
|
202
|
+
|
|
203
|
+
if score >= 0.8:
|
|
204
|
+
status = "PASS"
|
|
205
|
+
elif score >= 0.5:
|
|
206
|
+
status = "WARN"
|
|
207
|
+
else:
|
|
208
|
+
status = "FAIL"
|
|
209
|
+
|
|
210
|
+
suggestion = "Looks good" if status == "PASS" else \
|
|
211
|
+
"Consider addressing warnings" if status == "WARN" else \
|
|
212
|
+
"Needs significant improvement"
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
"score": round(score, 2),
|
|
216
|
+
"status": status,
|
|
217
|
+
"issues": issues,
|
|
218
|
+
"suggestion": suggestion,
|
|
219
|
+
"snippet_length": len(code_snippet),
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
def list_axes(self) -> List[Dict[str, Any]]:
|
|
223
|
+
"""
|
|
224
|
+
Return information about all five review axes.
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
List of dicts with axis details:
|
|
228
|
+
- axis: Axis identifier
|
|
229
|
+
- label: Human-readable name
|
|
230
|
+
- description: What this axis evaluates
|
|
231
|
+
- weight: Default weight in consensus calculation
|
|
232
|
+
"""
|
|
233
|
+
return self.AXES_INFO
|
|
234
|
+
|
|
235
|
+
def run(self, *args, **kwargs):
|
|
236
|
+
"""
|
|
237
|
+
Main entry point for the skill.
|
|
238
|
+
|
|
239
|
+
Supports multiple calling patterns:
|
|
240
|
+
|
|
241
|
+
1. Direct call: run(code="...", strict_mode=False)
|
|
242
|
+
2. Quick mode: run(mode="quick", code_snippet="...")
|
|
243
|
+
3. Dispatcher integration: run(task="...", mode="consensus")
|
|
244
|
+
"""
|
|
245
|
+
mode = kwargs.get("mode", "full")
|
|
246
|
+
|
|
247
|
+
if mode == "quick":
|
|
248
|
+
code_snippet = kwargs.get("code_snippet", "") or kwargs.get("code", "")
|
|
249
|
+
return self.quick_review(code_snippet)
|
|
250
|
+
|
|
251
|
+
elif mode == "consensus":
|
|
252
|
+
task = kwargs.get("task", "")
|
|
253
|
+
code = kwargs.get("code", task)
|
|
254
|
+
strict_mode = kwargs.get("strict_mode", False)
|
|
255
|
+
file_path = kwargs.get("file_path")
|
|
256
|
+
return self.review(code=code, strict_mode=strict_mode, file_path=file_path)
|
|
257
|
+
|
|
258
|
+
else:
|
|
259
|
+
code = kwargs.get("code", "")
|
|
260
|
+
if not code and args:
|
|
261
|
+
code = str(args[0])
|
|
262
|
+
strict_mode = kwargs.get("strict_mode", False)
|
|
263
|
+
file_path = kwargs.get("file_path")
|
|
264
|
+
return self.review(code=code, strict_mode=strict_mode, file_path=file_path)
|
|
265
|
+
|
|
266
|
+
@staticmethod
|
|
267
|
+
def _analyze_code(code: str) -> Dict[str, Dict[str, Any]]:
|
|
268
|
+
"""
|
|
269
|
+
Static analysis of code across five axes.
|
|
270
|
+
Returns simulated scores based on heuristics.
|
|
271
|
+
In production, this would integrate LLM-based analysis.
|
|
272
|
+
"""
|
|
273
|
+
lines = code.split("\n")
|
|
274
|
+
total_lines = len(lines)
|
|
275
|
+
non_empty = [l for l in lines if l.strip()]
|
|
276
|
+
|
|
277
|
+
scores = {
|
|
278
|
+
"correctness": {"score": 0.85, "confidence": 0.8, "comment": "Basic structure looks valid"},
|
|
279
|
+
"readability": {"score": 0.75, "confidence": 0.7, "comment": "Moderate readability"},
|
|
280
|
+
"architecture": {"score": 0.80, "confidence": 0.6, "comment": "Reasonable structure"},
|
|
281
|
+
"security": {"score": 0.90, "confidence": 0.7, "comment": "No obvious security issues"},
|
|
282
|
+
"performance": {"score": 0.80, "confidence": 0.6, "comment": "Acceptable performance characteristics"},
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
has_imports = any(line.strip().startswith("import ") or line.strip().startswith("from ") for line in lines)
|
|
286
|
+
has_functions = any("def " in line for line in lines)
|
|
287
|
+
has_classes = any("class " in line for line in lines)
|
|
288
|
+
has_docstring = '"""' in code or "'''" in code
|
|
289
|
+
has_comments = any(line.strip().startswith("#") for line in lines)
|
|
290
|
+
|
|
291
|
+
comment_ratio = sum(1 for l in lines if l.strip().startswith("#")) / max(len(non_empty), 1)
|
|
292
|
+
|
|
293
|
+
avg_line_length = sum(len(l) for l in non_empty) / max(len(non_empty), 1)
|
|
294
|
+
|
|
295
|
+
if total_lines < 10:
|
|
296
|
+
scores["correctness"]["score"] -= 0.1
|
|
297
|
+
scores["correctness"]["comment"] = "Short code snippet - limited analysis"
|
|
298
|
+
else:
|
|
299
|
+
if has_functions or has_classes:
|
|
300
|
+
scores["correctness"]["score"] = min(1.0, scores["correctness"]["score"] + 0.05)
|
|
301
|
+
scores["correctness"]["comment"] = "Contains functions/classes - good structure"
|
|
302
|
+
|
|
303
|
+
if has_docstring:
|
|
304
|
+
scores["readability"]["score"] = min(1.0, scores["readability"]["score"] + 0.1)
|
|
305
|
+
scores["readability"]["comment"] = "Has docstrings"
|
|
306
|
+
else:
|
|
307
|
+
scores["readability"]["score"] -= 0.1
|
|
308
|
+
scores["readability"]["comment"] = "Missing docstrings"
|
|
309
|
+
|
|
310
|
+
if 0.1 <= comment_ratio <= 0.3:
|
|
311
|
+
scores["readability"]["score"] = min(1.0, scores["readability"]["score"] + 0.05)
|
|
312
|
+
elif comment_ratio > 0.5:
|
|
313
|
+
scores["readability"]["score"] -= 0.05
|
|
314
|
+
scores["readability"]["comment"] += " (over-commented?)"
|
|
315
|
+
|
|
316
|
+
if avg_line_length > 100:
|
|
317
|
+
scores["readability"]["score"] -= 0.1
|
|
318
|
+
scores["readability"]["comment"] += "; Long lines detected"
|
|
319
|
+
|
|
320
|
+
if has_classes and has_functions:
|
|
321
|
+
scores["architecture"]["score"] = min(1.0, scores["architecture"]["score"] + 0.1)
|
|
322
|
+
scores["architecture"]["comment"] = "OOP structure detected"
|
|
323
|
+
elif has_imports:
|
|
324
|
+
scores["architecture"]["score"] = min(1.0, scores["architecture"]["score"] + 0.05)
|
|
325
|
+
scores["architecture"]["comment"] = "Modular imports present"
|
|
326
|
+
|
|
327
|
+
dangerous_patterns = ["eval(", "exec(", "os.system(", "subprocess.call(", "__import__"]
|
|
328
|
+
for pattern in dangerous_patterns:
|
|
329
|
+
if pattern in code:
|
|
330
|
+
scores["security"]["score"] -= 0.2
|
|
331
|
+
scores["security"]["comment"] = f"Dangerous pattern found: {pattern}"
|
|
332
|
+
break
|
|
333
|
+
|
|
334
|
+
if "password" in code.lower() or "secret" in code.lower() or "api_key" in code.lower():
|
|
335
|
+
if "=" in code and ("\"" in code or "'" in code):
|
|
336
|
+
scores["security"]["score"] -= 0.3
|
|
337
|
+
scores["security"]["comment"] = "Possible hardcoded credentials detected"
|
|
338
|
+
|
|
339
|
+
if "sql" in code.lower() and ("SELECT" in code or "INSERT" in code):
|
|
340
|
+
if "f\"" in code or "f'" in code or "%" in code or ".format(" in code:
|
|
341
|
+
scores["security"]["score"] -= 0.15
|
|
342
|
+
scores["security"]["comment"] += "; Possible SQL injection risk"
|
|
343
|
+
|
|
344
|
+
if "for " in code and " range(" in code:
|
|
345
|
+
if total_lines > 50:
|
|
346
|
+
scores["performance"]["score"] -= 0.1
|
|
347
|
+
scores["performance"]["comment"] = "Nested loops may impact performance at scale"
|
|
348
|
+
elif "while True" in code:
|
|
349
|
+
scores["performance"]["score"] -= 0.15
|
|
350
|
+
scores["performance"]["comment"] = "Infinite loop detected - ensure proper exit condition"
|
|
351
|
+
|
|
352
|
+
for axis in scores:
|
|
353
|
+
scores[axis]["score"] = max(0.0, min(1.0, scores[axis]["score"]))
|
|
354
|
+
scores[axis]["score"] = round(scores[axis]["score"], 2)
|
|
355
|
+
|
|
356
|
+
return scores
|