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
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
协作系统数据模型
|
|
5
|
+
|
|
6
|
+
定义 Coordinator + Scratchpad + Worker 协作模式的所有核心数据结构。
|
|
7
|
+
|
|
8
|
+
设计决策(门禁条件解决):
|
|
9
|
+
- 门禁1: Scratchpad 并发写入 → 采用"时间戳排序+版本号"方案,简单可靠
|
|
10
|
+
- 门禁2: Consensus 升级 → 采用"权重投票+否决权+升级到人工"机制
|
|
11
|
+
- 门禁3: 存储选型 → Phase 1 采用内存+JSON文件持久化,无外部依赖
|
|
12
|
+
- 异常场景: 每个组件都有 timeout/retry/cancel 支持
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from enum import Enum
|
|
16
|
+
from dataclasses import dataclass, field
|
|
17
|
+
from typing import Dict, List, Optional, Any, Set
|
|
18
|
+
from datetime import datetime
|
|
19
|
+
import uuid
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class EntryType(Enum):
|
|
23
|
+
FINDING = "finding"
|
|
24
|
+
DECISION = "decision"
|
|
25
|
+
CONFLICT = "conflict"
|
|
26
|
+
QUESTION = "question"
|
|
27
|
+
SUGGESTION = "suggestion"
|
|
28
|
+
WARNING = "warning"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class EntryStatus(Enum):
|
|
32
|
+
ACTIVE = "active"
|
|
33
|
+
RESOLVED = "resolved"
|
|
34
|
+
SUPERSEDED = "superseded"
|
|
35
|
+
REJECTED = "rejected"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ReferenceType(Enum):
|
|
39
|
+
SUPPORTS = "supports"
|
|
40
|
+
CONTRADICTS = "contradicts"
|
|
41
|
+
EXTENDS = "extends"
|
|
42
|
+
CLARIFIES = "clarifies"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class Reference:
|
|
47
|
+
reference_type: ReferenceType
|
|
48
|
+
target_entry_id: str
|
|
49
|
+
summary: str = ""
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass
|
|
53
|
+
class ScratchpadEntry:
|
|
54
|
+
entry_id: str = field(default_factory=lambda: f"entry-{uuid.uuid4().hex[:12]}")
|
|
55
|
+
worker_id: str = ""
|
|
56
|
+
role_id: str = ""
|
|
57
|
+
timestamp: datetime = field(default_factory=datetime.now)
|
|
58
|
+
entry_type: EntryType = EntryType.FINDING
|
|
59
|
+
content: str = ""
|
|
60
|
+
confidence: float = 0.5
|
|
61
|
+
tags: List[str] = field(default_factory=list)
|
|
62
|
+
references: List[Reference] = field(default_factory=list)
|
|
63
|
+
status: EntryStatus = EntryStatus.ACTIVE
|
|
64
|
+
version: int = 1
|
|
65
|
+
|
|
66
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
67
|
+
return {
|
|
68
|
+
"entry_id": self.entry_id,
|
|
69
|
+
"worker_id": self.worker_id,
|
|
70
|
+
"role_id": self.role_id,
|
|
71
|
+
"timestamp": self.timestamp.isoformat(),
|
|
72
|
+
"entry_type": self.entry_type.value,
|
|
73
|
+
"content": self.content,
|
|
74
|
+
"confidence": self.confidence,
|
|
75
|
+
"tags": self.tags,
|
|
76
|
+
"references": [
|
|
77
|
+
{"type": r.reference_type.value, "target": r.target_entry_id, "summary": r.summary}
|
|
78
|
+
for r in self.references
|
|
79
|
+
],
|
|
80
|
+
"status": self.status.value,
|
|
81
|
+
"version": self.version,
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def from_dict(cls, data: Dict[str, Any]) -> "ScratchpadEntry":
|
|
86
|
+
refs = [
|
|
87
|
+
Reference(
|
|
88
|
+
reference_type=ReferenceType(r["type"]),
|
|
89
|
+
target_entry_id=r["target"],
|
|
90
|
+
summary=r.get("summary", ""),
|
|
91
|
+
)
|
|
92
|
+
for r in data.get("references", [])
|
|
93
|
+
]
|
|
94
|
+
return cls(
|
|
95
|
+
entry_id=data.get("entry_id", f"entry-{uuid.uuid4().hex[:12]}"),
|
|
96
|
+
worker_id=data.get("worker_id", ""),
|
|
97
|
+
role_id=data.get("role_id", ""),
|
|
98
|
+
timestamp=datetime.fromisoformat(data["timestamp"]) if "timestamp" in data else datetime.now(),
|
|
99
|
+
entry_type=EntryType(data.get("entry_type", "finding")),
|
|
100
|
+
content=data.get("content", ""),
|
|
101
|
+
confidence=data.get("confidence", 0.5),
|
|
102
|
+
tags=data.get("tags", []),
|
|
103
|
+
references=refs,
|
|
104
|
+
status=EntryStatus(data.get("status", "active")),
|
|
105
|
+
version=data.get("version", 1),
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@dataclass
|
|
110
|
+
class TaskNotification:
|
|
111
|
+
from_worker: str
|
|
112
|
+
to_workers: List[str]
|
|
113
|
+
notification_type: str
|
|
114
|
+
priority: str = "medium"
|
|
115
|
+
timestamp: datetime = field(default_factory=datetime.now)
|
|
116
|
+
summary: str = ""
|
|
117
|
+
details: str = ""
|
|
118
|
+
references: List[str] = field(default_factory=list)
|
|
119
|
+
action_required: str = ""
|
|
120
|
+
|
|
121
|
+
def to_xml(self) -> str:
|
|
122
|
+
refs_xml = "".join(f"<ref>{r}</ref>" for r in self.references)
|
|
123
|
+
to_xml = ",".join(self.to_workers)
|
|
124
|
+
return (
|
|
125
|
+
f'<task-notification\n'
|
|
126
|
+
f' from-worker="{self.from_worker}"\n'
|
|
127
|
+
f' to-workers="{to_xml}"\n'
|
|
128
|
+
f' type="{self.notification_type}"\n'
|
|
129
|
+
f' priority="{self.priority}"\n'
|
|
130
|
+
f' timestamp="{self.timestamp.isoformat()}">\n'
|
|
131
|
+
f' <summary>{self.summary}</summary>\n'
|
|
132
|
+
f' <details>{self.details}</details>\n'
|
|
133
|
+
f' <references>{refs_xml}</references>\n'
|
|
134
|
+
f' <action-required>{self.action_required}</action-required>\n'
|
|
135
|
+
f'</task-notification>'
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@dataclass
|
|
140
|
+
class TaskDefinition:
|
|
141
|
+
task_id: str = field(default_factory=lambda: f"task-{uuid.uuid4().hex[:8]}")
|
|
142
|
+
description: str = ""
|
|
143
|
+
role_id: str = ""
|
|
144
|
+
role_prompt: str = ""
|
|
145
|
+
stage_id: Optional[str] = None
|
|
146
|
+
input_data: Dict[str, Any] = field(default_factory=dict)
|
|
147
|
+
dependencies: List[str] = field(default_factory=list)
|
|
148
|
+
is_read_only: bool = True
|
|
149
|
+
timeout_seconds: int = 300
|
|
150
|
+
retry_count: int = 3
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@dataclass
|
|
154
|
+
class WorkerResult:
|
|
155
|
+
worker_id: str
|
|
156
|
+
task_id: str
|
|
157
|
+
success: bool
|
|
158
|
+
output: Any = None
|
|
159
|
+
error: Optional[str] = None
|
|
160
|
+
scratchpad_entries_written: int = 0
|
|
161
|
+
notifications_sent: int = 0
|
|
162
|
+
duration_seconds: float = 0.0
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@dataclass
|
|
166
|
+
class Vote:
|
|
167
|
+
voter_id: str
|
|
168
|
+
voter_role: str
|
|
169
|
+
decision: bool
|
|
170
|
+
reason: str = ""
|
|
171
|
+
weight: float = 1.0
|
|
172
|
+
confidence: float = 0.7
|
|
173
|
+
timestamp: datetime = field(default_factory=datetime.now)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@dataclass
|
|
177
|
+
class DecisionProposal:
|
|
178
|
+
proposal_id: str = field(default_factory=lambda: f"prop-{uuid.uuid4().hex[:8]}")
|
|
179
|
+
topic: str = ""
|
|
180
|
+
proposer_id: str = ""
|
|
181
|
+
proposal_content: str = ""
|
|
182
|
+
options: List[str] = field(default_factory=list)
|
|
183
|
+
deadline: Optional[datetime] = None
|
|
184
|
+
votes: List[Vote] = field(default_factory=list)
|
|
185
|
+
status: str = "open"
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class DecisionOutcome(Enum):
|
|
189
|
+
APPROVED = "approved"
|
|
190
|
+
REJECTED = "rejected"
|
|
191
|
+
SPLIT = "split"
|
|
192
|
+
ESCALATED = "escalated"
|
|
193
|
+
TIMEOUT = "timeout"
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@dataclass
|
|
197
|
+
class ConsensusRecord:
|
|
198
|
+
record_id: str = field(default_factory=lambda: f"consensus-{uuid.uuid4().hex[:8]}")
|
|
199
|
+
topic: str = ""
|
|
200
|
+
outcome: DecisionOutcome = DecisionOutcome.APPROVED
|
|
201
|
+
final_decision: str = ""
|
|
202
|
+
votes_for: int = 0
|
|
203
|
+
votes_against: int = 0
|
|
204
|
+
votes_abstain: int = 0
|
|
205
|
+
total_weight_for: float = 0.0
|
|
206
|
+
total_weight_against: float = 0.0
|
|
207
|
+
participants: List[str] = field(default_factory=list)
|
|
208
|
+
escalation_reason: Optional[str] = None
|
|
209
|
+
timestamp: datetime = field(default_factory=datetime.now)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
@dataclass
|
|
213
|
+
class ExecutionPlan:
|
|
214
|
+
plan_id: str = field(default_factory=lambda: f"plan-{uuid.uuid4().hex[:8]}")
|
|
215
|
+
batches: List[Any] = field(default_factory=list)
|
|
216
|
+
total_tasks: int = 0
|
|
217
|
+
estimated_parallelism: float = 0.0
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class BatchMode(Enum):
|
|
221
|
+
PARALLEL = "parallel"
|
|
222
|
+
SERIAL = "serial"
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
@dataclass
|
|
226
|
+
class TaskBatch:
|
|
227
|
+
batch_id: str = field(default_factory=lambda: f"batch-{uuid.uuid4().hex[:8]}")
|
|
228
|
+
mode: BatchMode = BatchMode.PARALLEL
|
|
229
|
+
tasks: List[TaskDefinition] = field(default_factory=list)
|
|
230
|
+
max_concurrency: int = 5
|
|
231
|
+
dependencies: List[str] = field(default_factory=list)
|
|
232
|
+
timeout_seconds: int = 600
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
@dataclass
|
|
236
|
+
class ScheduleResult:
|
|
237
|
+
success: bool = False
|
|
238
|
+
total_tasks: int = 0
|
|
239
|
+
completed_tasks: int = 0
|
|
240
|
+
failed_tasks: int = 0
|
|
241
|
+
results: List[WorkerResult] = field(default_factory=list)
|
|
242
|
+
duration_seconds: float = 0.0
|
|
243
|
+
errors: List[str] = field(default_factory=list)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
ROLE_WEIGHTS = {
|
|
247
|
+
"architect": 1.5,
|
|
248
|
+
"product-manager": 1.2,
|
|
249
|
+
"security": 1.1,
|
|
250
|
+
"tester": 1.0,
|
|
251
|
+
"solo-coder": 1.0,
|
|
252
|
+
"devops": 1.0,
|
|
253
|
+
"ui-designer": 0.9,
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
@dataclass
|
|
258
|
+
class RoleDefinition:
|
|
259
|
+
role_id: str
|
|
260
|
+
name: str
|
|
261
|
+
aliases: List[str]
|
|
262
|
+
prompt: str
|
|
263
|
+
keywords: List[str]
|
|
264
|
+
weight: float
|
|
265
|
+
description: str
|
|
266
|
+
status: str = "core"
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
ROLE_REGISTRY: Dict[str, RoleDefinition] = {
|
|
270
|
+
"architect": RoleDefinition(
|
|
271
|
+
role_id="architect",
|
|
272
|
+
name="架构师",
|
|
273
|
+
aliases=["arch"],
|
|
274
|
+
prompt="你是系统架构师。负责:\n1. 系统架构设计(分层、模块化、接口定义)\n2. 技术选型和评估\n3. 性能架构设计(缓存架构、CDN策略、分库分表方案)\n4. 安全架构设计(认证授权方案、加密策略、安全边界)\n5. 数据架构设计(数据模型、数据仓库架构、ETL架构)\n6. 输出:架构文档、技术方案、模块设计",
|
|
275
|
+
keywords=["架构", "设计", "选型", "性能", "模块", "接口", "微服务", "数据架构",
|
|
276
|
+
"architecture", "design", "microservice", "module", "interface", "performance", "scalability", "system"],
|
|
277
|
+
weight=1.5,
|
|
278
|
+
description="System design, tech stack, API design, performance/security/data architecture",
|
|
279
|
+
status="core",
|
|
280
|
+
),
|
|
281
|
+
"product-manager": RoleDefinition(
|
|
282
|
+
role_id="product-manager",
|
|
283
|
+
name="产品经理",
|
|
284
|
+
aliases=["pm"],
|
|
285
|
+
prompt="你是产品经理。负责:\n1. 需求分析和PRD编写\n2. 用户故事和验收标准\n3. 竞品分析\n4. 输出:需求文档、用户故事、功能规格",
|
|
286
|
+
keywords=["需求", "PRD", "用户故事", "竞品", "验收", "体验", "功能",
|
|
287
|
+
"requirement", "prd", "user story", "acceptance", "feature", "product", "specification"],
|
|
288
|
+
weight=1.2,
|
|
289
|
+
description="Requirements analysis, user stories, acceptance criteria",
|
|
290
|
+
status="core",
|
|
291
|
+
),
|
|
292
|
+
"tester": RoleDefinition(
|
|
293
|
+
role_id="tester",
|
|
294
|
+
name="测试专家",
|
|
295
|
+
aliases=["test", "qa"],
|
|
296
|
+
prompt="你是测试专家。负责:\n1. 测试策略和用例设计\n2. 自动化测试方案\n3. 质量评估和缺陷追踪\n4. 输出:测试计划、测试用例、质量报告",
|
|
297
|
+
keywords=["测试", "质量", "验收", "自动化", "性能测试", "缺陷", "门禁",
|
|
298
|
+
"test", "quality", "qa", "automated", "coverage", "bug", "validation"],
|
|
299
|
+
weight=1.0,
|
|
300
|
+
description="Test strategy, quality assurance, edge cases",
|
|
301
|
+
status="core",
|
|
302
|
+
),
|
|
303
|
+
"solo-coder": RoleDefinition(
|
|
304
|
+
role_id="solo-coder",
|
|
305
|
+
name="独立开发者",
|
|
306
|
+
aliases=["coder", "dev"],
|
|
307
|
+
prompt="你是全栈开发者。负责:\n1. 功能实现和代码编写\n2. 代码审查与质量把关(风格一致性、最佳实践、设计模式合规)\n3. 性能优化实现(算法优化、内存优化、并发优化、SQL调优)\n4. 代码重构和优化\n5. Bug修复\n6. 数据迁移实现\n7. 输出:源代码、测试、技术文档",
|
|
308
|
+
keywords=["实现", "开发", "代码", "修复", "优化", "重构", "审查", "最佳实践",
|
|
309
|
+
"implement", "develop", "code", "fix", "optimize", "refactor", "review", "debug"],
|
|
310
|
+
weight=1.0,
|
|
311
|
+
description="Implementation, code review, performance optimization, refactoring",
|
|
312
|
+
status="core",
|
|
313
|
+
),
|
|
314
|
+
"ui-designer": RoleDefinition(
|
|
315
|
+
role_id="ui-designer",
|
|
316
|
+
name="UI设计师",
|
|
317
|
+
aliases=["ui"],
|
|
318
|
+
prompt="你是UI/UX设计师。负责:\n1. 界面设计和交互原型\n2. 设计系统和组件规范\n3. 视觉稿和设计交付\n4. 输出:设计稿、原型、设计规范",
|
|
319
|
+
keywords=["UI", "界面", "前端", "视觉", "交互", "原型", "设计",
|
|
320
|
+
"ui", "interface", "frontend", "visual", "interaction", "prototype", "ux", "accessibility"],
|
|
321
|
+
weight=0.9,
|
|
322
|
+
description="UX design, interaction logic, accessibility",
|
|
323
|
+
status="core",
|
|
324
|
+
),
|
|
325
|
+
"devops": RoleDefinition(
|
|
326
|
+
role_id="devops",
|
|
327
|
+
name="DevOps工程师",
|
|
328
|
+
aliases=["infra"],
|
|
329
|
+
prompt="你是DevOps工程师。负责:\n1. CI/CD流水线设计与实现(GitHub Actions、GitLab CI、Jenkins)\n2. 容器化与编排(Docker、Kubernetes、Docker Compose)\n3. 基础设施即代码(Terraform、Pulumi、CloudFormation)\n4. 监控告警体系搭建(Prometheus、Grafana、ELK、Sentry)\n5. 部署策略设计(蓝绿部署、金丝雀发布、滚动更新)\n6. 环境管理(开发/测试/预生产/生产环境配置与隔离)\n7. 输出:CI/CD配置、Dockerfile、K8s Manifests、监控配置、部署文档",
|
|
330
|
+
keywords=["CI/CD", "部署", "监控", "运维", "Docker", "Kubernetes", "基础设施", "容器",
|
|
331
|
+
"deploy", "monitor", "infrastructure", "container", "pipeline", "devops", "ci/cd", "cloud"],
|
|
332
|
+
weight=1.0,
|
|
333
|
+
description="CI/CD pipeline, containerization, monitoring, infrastructure",
|
|
334
|
+
status="core",
|
|
335
|
+
),
|
|
336
|
+
"security": RoleDefinition(
|
|
337
|
+
role_id="security",
|
|
338
|
+
name="安全专家",
|
|
339
|
+
aliases=["sec"],
|
|
340
|
+
prompt="你是安全专家。负责:\n1. 威胁建模(STRIDE、DREAD攻击树分析)\n2. 漏洞审计(OWASP Top 10、CWE常见弱点枚举)\n3. 认证与授权安全审查(OAuth2、JWT、RBAC/ABAC)\n4. 数据安全评估(加密方案、密钥管理、数据脱敏)\n5. 依赖安全扫描与供应链安全(Snyk、Dependabot、SBOM)\n6. 合规性检查(GDPR、SOC2、HIPAA、PCI-DSS)\n7. 安全编码规范与最佳实践\n8. 输出:威胁模型、漏洞报告、安全建议、合规评估",
|
|
341
|
+
keywords=["安全", "漏洞", "审计", "威胁", "加密", "认证", "授权", "OWASP",
|
|
342
|
+
"security", "vulnerability", "audit", "threat", "encrypt", "auth", "compliance", "owasp"],
|
|
343
|
+
weight=1.1,
|
|
344
|
+
description="Threat modeling, vulnerability audit, compliance, security review",
|
|
345
|
+
status="core",
|
|
346
|
+
),
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def _build_role_aliases() -> Dict[str, str]:
|
|
351
|
+
aliases = {}
|
|
352
|
+
for rid, rdef in ROLE_REGISTRY.items():
|
|
353
|
+
for alias in rdef.aliases:
|
|
354
|
+
aliases[alias] = rid
|
|
355
|
+
return aliases
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
ROLE_ALIASES: Dict[str, str] = _build_role_aliases()
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def resolve_role_id(role_id: str) -> str:
|
|
362
|
+
if role_id in ROLE_REGISTRY:
|
|
363
|
+
return role_id
|
|
364
|
+
return ROLE_ALIASES.get(role_id, role_id)
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def get_core_roles() -> Dict[str, RoleDefinition]:
|
|
368
|
+
return {rid: rdef for rid, rdef in ROLE_REGISTRY.items() if rdef.status == "core"}
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def get_planned_roles() -> Dict[str, RoleDefinition]:
|
|
372
|
+
return {rid: rdef for rid, rdef in ROLE_REGISTRY.items() if rdef.status == "planned"}
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def get_all_role_ids() -> List[str]:
|
|
376
|
+
return list(ROLE_REGISTRY.keys())
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
def get_cli_role_list() -> List[str]:
|
|
380
|
+
result = []
|
|
381
|
+
for rid, rdef in ROLE_REGISTRY.items():
|
|
382
|
+
result.append(rdef.aliases[0] if rdef.aliases else rid)
|
|
383
|
+
return result
|
|
384
|
+
|
|
385
|
+
CONSENSUS_THRESHOLDS = {
|
|
386
|
+
"simple_majority": 0.51,
|
|
387
|
+
"super_majority": 0.67,
|
|
388
|
+
"unanimous": 1.0,
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
# ============================================================
|
|
393
|
+
# V3.6.0 "Anchor & Retrospect" Data Models
|
|
394
|
+
# ============================================================
|
|
395
|
+
|
|
396
|
+
class GoalItemStatus(Enum):
|
|
397
|
+
PENDING = "pending"
|
|
398
|
+
PARTIALLY_COVERED = "partially_covered"
|
|
399
|
+
FULLY_COVERED = "fully_covered"
|
|
400
|
+
EXCEEDED = "exceeded"
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
class AnchorTrigger(Enum):
|
|
404
|
+
STEP_COMPLETE = "step_complete"
|
|
405
|
+
PHASE_GATE = "phase_gate"
|
|
406
|
+
DIRECTION_CHANGE = "direction_change"
|
|
407
|
+
CONFLICT = "conflict"
|
|
408
|
+
MILESTONE = "milestone"
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
class DriftSeverity(Enum):
|
|
412
|
+
NONE = "none"
|
|
413
|
+
LOW = "low"
|
|
414
|
+
MEDIUM = "medium"
|
|
415
|
+
HIGH = "high"
|
|
416
|
+
CRITICAL = "critical"
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
@dataclass
|
|
420
|
+
class GoalItem:
|
|
421
|
+
item_id: str
|
|
422
|
+
description: str
|
|
423
|
+
keywords: List[str] = field(default_factory=list)
|
|
424
|
+
status: GoalItemStatus = GoalItemStatus.PENDING
|
|
425
|
+
coverage_score: float = 0.0
|
|
426
|
+
evidence: List[str] = field(default_factory=list)
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
@dataclass
|
|
430
|
+
class StructuredGoal:
|
|
431
|
+
goal_id: str = ""
|
|
432
|
+
original_description: str = ""
|
|
433
|
+
items: List[GoalItem] = field(default_factory=list)
|
|
434
|
+
created_at: str = ""
|
|
435
|
+
|
|
436
|
+
@property
|
|
437
|
+
def overall_coverage(self) -> float:
|
|
438
|
+
if not self.items:
|
|
439
|
+
return 0.0
|
|
440
|
+
return sum(i.coverage_score for i in self.items) / len(self.items)
|
|
441
|
+
|
|
442
|
+
@property
|
|
443
|
+
def uncovered_items(self) -> List[GoalItem]:
|
|
444
|
+
return [i for i in self.items if i.status in (GoalItemStatus.PENDING, GoalItemStatus.PARTIALLY_COVERED)]
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
@dataclass
|
|
448
|
+
class DriftItem:
|
|
449
|
+
content: str
|
|
450
|
+
severity: DriftSeverity = DriftSeverity.LOW
|
|
451
|
+
reason: str = ""
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
@dataclass
|
|
455
|
+
class AnchorResult:
|
|
456
|
+
aligned: bool = True
|
|
457
|
+
trigger: AnchorTrigger = AnchorTrigger.STEP_COMPLETE
|
|
458
|
+
coverage: float = 1.0
|
|
459
|
+
drift_score: float = 0.0
|
|
460
|
+
drifts: List[DriftItem] = field(default_factory=list)
|
|
461
|
+
uncovered_goals: List[str] = field(default_factory=list)
|
|
462
|
+
recommendation: str = ""
|
|
463
|
+
checked_at: str = ""
|
|
464
|
+
|
|
465
|
+
@property
|
|
466
|
+
def severity(self) -> DriftSeverity:
|
|
467
|
+
if self.drift_score < 0.1:
|
|
468
|
+
return DriftSeverity.NONE
|
|
469
|
+
elif self.drift_score < 0.2:
|
|
470
|
+
return DriftSeverity.LOW
|
|
471
|
+
elif self.drift_score < 0.3:
|
|
472
|
+
return DriftSeverity.MEDIUM
|
|
473
|
+
elif self.drift_score < 0.5:
|
|
474
|
+
return DriftSeverity.HIGH
|
|
475
|
+
return DriftSeverity.CRITICAL
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
@dataclass
|
|
479
|
+
class DeviationRecord:
|
|
480
|
+
step_description: str
|
|
481
|
+
deviation_type: str
|
|
482
|
+
reason: str
|
|
483
|
+
impact: str = ""
|
|
484
|
+
suggestion: str = ""
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
@dataclass
|
|
488
|
+
class RetrospectiveReport:
|
|
489
|
+
task_goal: str = ""
|
|
490
|
+
goal_id: str = ""
|
|
491
|
+
deviations: List[DeviationRecord] = field(default_factory=list)
|
|
492
|
+
redundant_steps: List[str] = field(default_factory=list)
|
|
493
|
+
improvements: List[str] = field(default_factory=list)
|
|
494
|
+
anchor_check_count: int = 0
|
|
495
|
+
anchor_drift_count: int = 0
|
|
496
|
+
final_coverage: float = 1.0
|
|
497
|
+
summary: str = ""
|
|
498
|
+
created_at: str = ""
|
|
499
|
+
|
|
500
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
501
|
+
return {
|
|
502
|
+
"task_goal": self.task_goal,
|
|
503
|
+
"goal_id": self.goal_id,
|
|
504
|
+
"deviation_count": len(self.deviations),
|
|
505
|
+
"redundant_step_count": len(self.redundant_steps),
|
|
506
|
+
"improvement_count": len(self.improvements),
|
|
507
|
+
"anchor_check_count": self.anchor_check_count,
|
|
508
|
+
"anchor_drift_count": self.anchor_drift_count,
|
|
509
|
+
"final_coverage": self.final_coverage,
|
|
510
|
+
"summary": self.summary,
|
|
511
|
+
"created_at": self.created_at,
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
def to_markdown(self) -> str:
|
|
515
|
+
lines = [
|
|
516
|
+
"# Retrospective Report",
|
|
517
|
+
"",
|
|
518
|
+
f"**Task**: {self.task_goal}",
|
|
519
|
+
f"**Goal ID**: {self.goal_id}",
|
|
520
|
+
f"**Final Coverage**: {self.final_coverage:.0%}",
|
|
521
|
+
f"**Anchor Checks**: {self.anchor_check_count} (drifts: {self.anchor_drift_count})",
|
|
522
|
+
"",
|
|
523
|
+
]
|
|
524
|
+
if self.deviations:
|
|
525
|
+
lines.append("## Deviations")
|
|
526
|
+
for d in self.deviations:
|
|
527
|
+
lines.append(f"- **{d.deviation_type}**: {d.reason}")
|
|
528
|
+
if d.suggestion:
|
|
529
|
+
lines.append(f" → {d.suggestion}")
|
|
530
|
+
lines.append("")
|
|
531
|
+
if self.improvements:
|
|
532
|
+
lines.append("## Improvements for Next Time")
|
|
533
|
+
for imp in self.improvements:
|
|
534
|
+
lines.append(f"- {imp}")
|
|
535
|
+
lines.append("")
|
|
536
|
+
lines.append(f"---\n*Generated by RetrospectiveEngine V3.6.0*")
|
|
537
|
+
return "\n".join(lines)
|