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.
Files changed (95) hide show
  1. devsquad-3.6.0.dist-info/METADATA +944 -0
  2. devsquad-3.6.0.dist-info/RECORD +95 -0
  3. devsquad-3.6.0.dist-info/WHEEL +5 -0
  4. devsquad-3.6.0.dist-info/entry_points.txt +2 -0
  5. devsquad-3.6.0.dist-info/licenses/LICENSE +21 -0
  6. devsquad-3.6.0.dist-info/top_level.txt +2 -0
  7. scripts/__init__.py +0 -0
  8. scripts/ai_semantic_matcher.py +512 -0
  9. scripts/alert_manager.py +505 -0
  10. scripts/api/__init__.py +43 -0
  11. scripts/api/models.py +386 -0
  12. scripts/api/routes/__init__.py +20 -0
  13. scripts/api/routes/dispatch.py +348 -0
  14. scripts/api/routes/lifecycle.py +330 -0
  15. scripts/api/routes/metrics_gates.py +347 -0
  16. scripts/api_server.py +318 -0
  17. scripts/auth.py +451 -0
  18. scripts/cli/__init__.py +1 -0
  19. scripts/cli/cli_visual.py +642 -0
  20. scripts/cli.py +1094 -0
  21. scripts/collaboration/__init__.py +212 -0
  22. scripts/collaboration/_version.py +1 -0
  23. scripts/collaboration/agent_briefing.py +656 -0
  24. scripts/collaboration/ai_semantic_matcher.py +260 -0
  25. scripts/collaboration/anchor_checker.py +281 -0
  26. scripts/collaboration/anti_rationalization.py +470 -0
  27. scripts/collaboration/async_integration_example.py +255 -0
  28. scripts/collaboration/batch_scheduler.py +149 -0
  29. scripts/collaboration/checkpoint_manager.py +561 -0
  30. scripts/collaboration/ci_feedback_adapter.py +351 -0
  31. scripts/collaboration/code_map_generator.py +247 -0
  32. scripts/collaboration/concern_pack_loader.py +352 -0
  33. scripts/collaboration/confidence_score.py +496 -0
  34. scripts/collaboration/config_loader.py +188 -0
  35. scripts/collaboration/consensus.py +244 -0
  36. scripts/collaboration/context_compressor.py +533 -0
  37. scripts/collaboration/coordinator.py +668 -0
  38. scripts/collaboration/dispatcher.py +1636 -0
  39. scripts/collaboration/dual_layer_context.py +128 -0
  40. scripts/collaboration/enhanced_worker.py +539 -0
  41. scripts/collaboration/feature_usage_tracker.py +206 -0
  42. scripts/collaboration/five_axis_consensus.py +334 -0
  43. scripts/collaboration/input_validator.py +401 -0
  44. scripts/collaboration/integration_example.py +287 -0
  45. scripts/collaboration/intent_workflow_mapper.py +350 -0
  46. scripts/collaboration/language_parsers.py +269 -0
  47. scripts/collaboration/lifecycle_protocol.py +1446 -0
  48. scripts/collaboration/llm_backend.py +453 -0
  49. scripts/collaboration/llm_cache.py +448 -0
  50. scripts/collaboration/llm_cache_async.py +347 -0
  51. scripts/collaboration/llm_retry.py +387 -0
  52. scripts/collaboration/llm_retry_async.py +389 -0
  53. scripts/collaboration/mce_adapter.py +597 -0
  54. scripts/collaboration/memory_bridge.py +1607 -0
  55. scripts/collaboration/models.py +537 -0
  56. scripts/collaboration/null_providers.py +297 -0
  57. scripts/collaboration/operation_classifier.py +289 -0
  58. scripts/collaboration/output_slicer.py +225 -0
  59. scripts/collaboration/performance_monitor.py +462 -0
  60. scripts/collaboration/permission_guard.py +865 -0
  61. scripts/collaboration/prompt_assembler.py +756 -0
  62. scripts/collaboration/prompt_variant_generator.py +483 -0
  63. scripts/collaboration/protocols.py +267 -0
  64. scripts/collaboration/report_formatter.py +352 -0
  65. scripts/collaboration/retrospective.py +279 -0
  66. scripts/collaboration/role_matcher.py +92 -0
  67. scripts/collaboration/role_template_market.py +352 -0
  68. scripts/collaboration/rule_collector.py +678 -0
  69. scripts/collaboration/scratchpad.py +346 -0
  70. scripts/collaboration/skill_registry.py +151 -0
  71. scripts/collaboration/skillifier.py +878 -0
  72. scripts/collaboration/standardized_role_template.py +317 -0
  73. scripts/collaboration/task_completion_checker.py +237 -0
  74. scripts/collaboration/test_quality_guard.py +695 -0
  75. scripts/collaboration/unified_gate_engine.py +598 -0
  76. scripts/collaboration/usage_tracker.py +309 -0
  77. scripts/collaboration/user_friendly_error.py +176 -0
  78. scripts/collaboration/verification_gate.py +312 -0
  79. scripts/collaboration/warmup_manager.py +635 -0
  80. scripts/collaboration/worker.py +513 -0
  81. scripts/collaboration/workflow_engine.py +684 -0
  82. scripts/dashboard.py +1088 -0
  83. scripts/generate_benchmark_report.py +786 -0
  84. scripts/history_manager.py +604 -0
  85. scripts/mcp_server.py +289 -0
  86. skills/__init__.py +32 -0
  87. skills/dispatch/handler.py +52 -0
  88. skills/intent/handler.py +59 -0
  89. skills/registry.py +67 -0
  90. skills/retrospective/__init__.py +0 -0
  91. skills/retrospective/handler.py +125 -0
  92. skills/review/handler.py +356 -0
  93. skills/security/handler.py +454 -0
  94. skills/test/__init__.py +0 -0
  95. skills/test/handler.py +78 -0
@@ -0,0 +1,279 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ RetrospectiveEngine - V3.6.0 Independent Retrospective Engine
5
+
6
+ Automatically runs a retrospective after task completion:
7
+ 1. Analyzes deviations from the original goal
8
+ 2. Identifies redundant steps
9
+ 3. Generates improvement suggestions
10
+ 4. Stores conclusions in MemoryBridge for future task loading
11
+
12
+ Design Principles:
13
+ - No LLM calls: Pure algorithmic analysis
14
+ - Triggered automatically on task completion
15
+ - Conclusions stored as RETROSPECTIVE memory type
16
+ - Next similar task auto-loads historical retrospectives
17
+ """
18
+
19
+ import logging
20
+ from datetime import datetime
21
+ from typing import Dict, List, Optional, Any
22
+
23
+ from .models import (
24
+ StructuredGoal, AnchorResult, AnchorTrigger,
25
+ DeviationRecord, RetrospectiveReport, DriftSeverity,
26
+ )
27
+ from .anchor_checker import AnchorChecker
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+
32
+ class RetrospectiveEngine:
33
+ """
34
+ Independent retrospective engine that runs after task completion.
35
+
36
+ Usage:
37
+ engine = RetrospectiveEngine(memory_bridge=bridge)
38
+ report = engine.run(goal=structured_goal, anchor_history=checker.check_history)
39
+ print(report.to_markdown())
40
+ """
41
+
42
+ MEMORY_TYPE_STR = "retrospective"
43
+
44
+ def __init__(self, memory_bridge=None):
45
+ self._memory_bridge = memory_bridge
46
+
47
+ def run(
48
+ self,
49
+ goal: StructuredGoal,
50
+ anchor_history: List[AnchorResult],
51
+ worker_outputs: Optional[Dict[str, str]] = None,
52
+ task_duration_seconds: float = 0.0,
53
+ ) -> RetrospectiveReport:
54
+ """
55
+ Run a retrospective analysis on a completed task.
56
+
57
+ Args:
58
+ goal: The original structured goal.
59
+ anchor_history: History of anchor check results during execution.
60
+ worker_outputs: Optional dict of role_id -> output text.
61
+ task_duration_seconds: Total task execution time.
62
+
63
+ Returns:
64
+ RetrospectiveReport with deviations, improvements, and summary.
65
+ """
66
+ deviations = self._analyze_deviations(goal, anchor_history)
67
+ redundant = self._find_redundant_steps(anchor_history)
68
+ improvements = self._generate_improvements(deviations, anchor_history, goal)
69
+ summary = self._build_summary(goal, deviations, improvements, anchor_history)
70
+
71
+ drift_count = sum(1 for a in anchor_history if not a.aligned)
72
+
73
+ report = RetrospectiveReport(
74
+ task_goal=goal.original_description,
75
+ goal_id=goal.goal_id,
76
+ deviations=deviations,
77
+ redundant_steps=redundant,
78
+ improvements=improvements,
79
+ anchor_check_count=len(anchor_history),
80
+ anchor_drift_count=drift_count,
81
+ final_coverage=goal.overall_coverage,
82
+ summary=summary,
83
+ created_at=datetime.now().isoformat(),
84
+ )
85
+
86
+ self._store_report(report, goal)
87
+
88
+ logger.info(
89
+ "Retrospective complete: %d deviations, %d improvements, coverage=%.0f%%",
90
+ len(deviations), len(improvements), goal.overall_coverage * 100,
91
+ )
92
+
93
+ return report
94
+
95
+ def _analyze_deviations(
96
+ self,
97
+ goal: StructuredGoal,
98
+ anchor_history: List[AnchorResult],
99
+ ) -> List[DeviationRecord]:
100
+ deviations = []
101
+ for item in goal.items:
102
+ if item.status.value in ("pending", "partially_covered"):
103
+ deviations.append(DeviationRecord(
104
+ step_description=item.description,
105
+ deviation_type="goal_uncovered",
106
+ reason=f"Goal item '{item.description}' was only {item.coverage_score:.0%} covered",
107
+ impact="Partial delivery - user requirement not fully met",
108
+ suggestion=f"Ensure next task explicitly addresses: {item.description}",
109
+ ))
110
+
111
+ drift_events = [a for a in anchor_history if not a.aligned]
112
+ if drift_events:
113
+ worst = max(drift_events, key=lambda a: a.drift_score)
114
+ deviations.append(DeviationRecord(
115
+ step_description=f"Anchor check at {worst.checked_at}",
116
+ deviation_type="goal_drift",
117
+ reason=f"Maximum drift score: {worst.drift_score:.0%} (trigger: {worst.trigger.value})",
118
+ impact="Work may have been done on items outside the original scope",
119
+ suggestion="Add intermediate anchor checks to catch drift earlier",
120
+ ))
121
+
122
+ consecutive_drifts = 0
123
+ max_consecutive = 0
124
+ for a in anchor_history:
125
+ if not a.aligned:
126
+ consecutive_drifts += 1
127
+ max_consecutive = max(max_consecutive, consecutive_drifts)
128
+ else:
129
+ consecutive_drifts = 0
130
+ if max_consecutive >= 3:
131
+ deviations.append(DeviationRecord(
132
+ step_description=f"{max_consecutive} consecutive drift checks",
133
+ deviation_type="sustained_drift",
134
+ reason=f"Task drifted for {max_consecutive} consecutive anchor checks",
135
+ impact="Significant effort spent on off-goal work",
136
+ suggestion="Break task into smaller sub-tasks with more frequent anchor checks",
137
+ ))
138
+
139
+ return deviations
140
+
141
+ def _find_redundant_steps(self, anchor_history: List[AnchorResult]) -> List[str]:
142
+ redundant = []
143
+ seen_triggers = {}
144
+ for a in anchor_history:
145
+ key = a.trigger.value
146
+ if key in seen_triggers:
147
+ prev = seen_triggers[key]
148
+ if a.coverage <= prev.coverage and a.aligned and prev.aligned:
149
+ redundant.append(
150
+ f"Anchor at {a.checked_at} ({a.trigger.value}): "
151
+ f"coverage {a.coverage:.0%} did not improve from previous {prev.coverage:.0%}"
152
+ )
153
+ seen_triggers[key] = a
154
+ return redundant
155
+
156
+ def _generate_improvements(
157
+ self,
158
+ deviations: List[DeviationRecord],
159
+ anchor_history: List[AnchorResult],
160
+ goal: StructuredGoal,
161
+ ) -> List[str]:
162
+ improvements = []
163
+
164
+ deviation_types = set(d.deviation_type for d in deviations)
165
+ if "goal_uncovered" in deviation_types:
166
+ improvements.append(
167
+ "Decompose task into smaller sub-tasks, each mapping to specific goal items"
168
+ )
169
+ if "goal_drift" in deviation_types:
170
+ improvements.append(
171
+ "Add anchor checks at direction-change points to catch drift earlier"
172
+ )
173
+ if "sustained_drift" in deviation_types:
174
+ improvements.append(
175
+ "Implement auto-correction: when drift exceeds threshold, pause and re-align"
176
+ )
177
+
178
+ if anchor_history:
179
+ first_drift = next((a for a in anchor_history if not a.aligned), None)
180
+ if first_drift:
181
+ improvements.append(
182
+ f"First drift detected at {first_drift.trigger.value} - "
183
+ f"consider adding a pre-check before this trigger point"
184
+ )
185
+
186
+ uncovered = goal.uncovered_items
187
+ if uncovered:
188
+ improvements.append(
189
+ f"Prioritize these uncovered goals in next iteration: "
190
+ f"{', '.join(i.description[:40] for i in uncovered[:3])}"
191
+ )
192
+
193
+ if not improvements:
194
+ improvements.append("Task well-executed. Maintain current process for similar tasks.")
195
+
196
+ return improvements
197
+
198
+ def _build_summary(
199
+ self,
200
+ goal: StructuredGoal,
201
+ deviations: List[DeviationRecord],
202
+ improvements: List[str],
203
+ anchor_history: List[AnchorResult],
204
+ ) -> str:
205
+ total = len(anchor_history)
206
+ drifts = sum(1 for a in anchor_history if not a.aligned)
207
+ coverage = goal.overall_coverage
208
+
209
+ if not deviations:
210
+ return (
211
+ f"Task completed with full goal alignment. "
212
+ f"Coverage: {coverage:.0%}, Anchor checks: {total}, Drifts: {drifts}. "
213
+ f"No deviations detected."
214
+ )
215
+
216
+ severity_counts = {}
217
+ for d in deviations:
218
+ severity_counts[d.deviation_type] = severity_counts.get(d.deviation_type, 0) + 1
219
+
220
+ parts = [f"Coverage: {coverage:.0%}, Anchor checks: {total}, Drifts: {drifts}."]
221
+ parts.append(f"Deviations: {len(deviations)} ({', '.join(f'{v}x{k}' for k, v in severity_counts.items())}).")
222
+ parts.append(f"Improvements: {len(improvements)} suggestions generated.")
223
+
224
+ return " ".join(parts)
225
+
226
+ def _store_report(self, report: RetrospectiveReport, goal: StructuredGoal):
227
+ if self._memory_bridge is None:
228
+ logger.debug("No MemoryBridge configured, retrospective not persisted")
229
+ return
230
+
231
+ try:
232
+ from .memory_bridge import MemoryType, AnalysisCase
233
+ analysis = AnalysisCase(
234
+ id=f"retro_{goal.goal_id}",
235
+ problem=f"Retrospective: {goal.original_description[:60]}",
236
+ context=report.summary,
237
+ root_cause="; ".join(d.reason for d in report.deviations[:3]) if report.deviations else "No deviations",
238
+ solutions=report.improvements,
239
+ status="completed",
240
+ )
241
+ writer = getattr(self._memory_bridge, 'writer', None)
242
+ if writer and hasattr(writer, 'write_analysis'):
243
+ writer.write_analysis(analysis)
244
+ else:
245
+ self._memory_bridge.store.save(MemoryType.ANALYSIS, report.to_dict())
246
+ logger.info("Retrospective report stored in MemoryBridge (goal_id=%s)", goal.goal_id)
247
+ except Exception as e:
248
+ logger.warning("Failed to store retrospective report: %s", e)
249
+
250
+ def load_historical(
251
+ self,
252
+ task_description: str,
253
+ limit: int = 3,
254
+ ) -> List[Dict[str, Any]]:
255
+ if self._memory_bridge is None:
256
+ return []
257
+
258
+ try:
259
+ from .memory_bridge import MemoryQuery
260
+ query = MemoryQuery(
261
+ query_text=task_description,
262
+ limit=limit,
263
+ )
264
+ result = self._memory_bridge.recall(query)
265
+ if result and hasattr(result, 'memories') and result.memories:
266
+ return [
267
+ m.content if isinstance(m.content, dict) else {"summary": str(m.content)[:200]}
268
+ for m in result.memories[:limit]
269
+ ]
270
+ return []
271
+ except Exception as e:
272
+ logger.warning("Failed to load historical retrospectives: %s", e)
273
+ return []
274
+
275
+
276
+ def _tokenize_simple(text: str) -> List[str]:
277
+ import re
278
+ tokens = re.findall(r'[a-zA-Z_]{2,}|[\u4e00-\u9fff]{2,}', text.lower())
279
+ return tokens[:10]
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env python3
2
+ import re
3
+ from typing import Dict, List
4
+
5
+ from .models import ROLE_REGISTRY, ROLE_ALIASES, resolve_role_id
6
+
7
+ ROLE_TEMPLATES = {rid: {"name": rdef.name, "prompt": rdef.prompt, "keywords": rdef.keywords} for rid, rdef in ROLE_REGISTRY.items()}
8
+
9
+
10
+ class RoleMatcher:
11
+ """Role matching engine based on keyword analysis."""
12
+
13
+ def analyze_task(self, task_description: str) -> List[Dict[str, str]]:
14
+ """
15
+ Analyze a task description and match appropriate roles.
16
+
17
+ Args:
18
+ task_description: Task description text
19
+
20
+ Returns:
21
+ List of matched roles: [{"role_id": "...", "name": "...", "reason": "..."}]
22
+ """
23
+ task_lower = task_description.lower()
24
+ matched = []
25
+
26
+ for role_id, role_info in ROLE_TEMPLATES.items():
27
+ score = 0
28
+ matched_keywords = []
29
+ for kw in role_info["keywords"]:
30
+ if kw in task_lower:
31
+ score += 1
32
+ matched_keywords.append(kw)
33
+
34
+ if score > 0:
35
+ confidence = min(score / len(role_info["keywords"]), 1.0)
36
+ matched.append({
37
+ "role_id": role_id,
38
+ "name": role_info["name"],
39
+ "confidence": confidence,
40
+ "matched_keywords": matched_keywords,
41
+ "reason": f"匹配关键词: {', '.join(matched_keywords)}",
42
+ })
43
+
44
+ matched.sort(key=lambda x: x["confidence"], reverse=True)
45
+
46
+ if not matched:
47
+ matched.append({
48
+ "role_id": "solo-coder",
49
+ "name": "独立开发者",
50
+ "confidence": 0.5,
51
+ "matched_keywords": [],
52
+ "reason": "默认角色:无明确关键词匹配",
53
+ })
54
+
55
+ return matched
56
+
57
+ @staticmethod
58
+ def resolve_roles(roles: List[str], matched_roles: List[Dict]) -> List[Dict]:
59
+ """
60
+ Resolve user-specified roles, merging with auto-matched results.
61
+
62
+ Args:
63
+ roles: User-specified role ID list (may include aliases)
64
+ matched_roles: Auto-matched roles from analyze_task()
65
+
66
+ Returns:
67
+ Final matched roles list with user overrides applied
68
+ """
69
+ from .models import ROLE_REGISTRY as _RR
70
+ PLANNED_ROLES = {}
71
+
72
+ resolved_roles = [resolve_role_id(r) for r in roles]
73
+ role_ids_set = set(resolved_roles)
74
+ final = [r for r in matched_roles if r["role_id"] in role_ids_set]
75
+
76
+ for rid, original_rid in zip(resolved_roles, roles):
77
+ if not any(r["role_id"] == rid for r in final):
78
+ template = ROLE_TEMPLATES.get(rid, {"name": rid, "prompt": ""})
79
+ rdef = _RR.get(rid)
80
+ if rdef and rdef.status == "planned":
81
+ reason = f"用户指定({rdef.name} - 规划中角色,暂无完整模板)"
82
+ else:
83
+ reason = "用户指定"
84
+ final.append({
85
+ "role_id": rid,
86
+ "name": template.get("name", rid),
87
+ "confidence": 1.0,
88
+ "matched_keywords": [],
89
+ "reason": reason,
90
+ })
91
+
92
+ return final