fenix-mcp 0.1.0__py3-none-any.whl → 0.2.1__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.
- fenix_mcp/__init__.py +4 -1
- fenix_mcp/application/tool_base.py +3 -2
- fenix_mcp/application/tool_registry.py +3 -1
- fenix_mcp/application/tools/health.py +1 -3
- fenix_mcp/application/tools/initialize.py +18 -6
- fenix_mcp/application/tools/intelligence.py +47 -15
- fenix_mcp/application/tools/knowledge.py +162 -50
- fenix_mcp/application/tools/productivity.py +26 -9
- fenix_mcp/application/tools/user_config.py +18 -9
- fenix_mcp/domain/initialization.py +21 -9
- fenix_mcp/domain/intelligence.py +27 -15
- fenix_mcp/domain/knowledge.py +161 -61
- fenix_mcp/domain/productivity.py +3 -2
- fenix_mcp/domain/user_config.py +16 -7
- fenix_mcp/infrastructure/config.py +6 -2
- fenix_mcp/infrastructure/context.py +0 -1
- fenix_mcp/infrastructure/fenix_api/client.py +118 -38
- fenix_mcp/infrastructure/http_client.py +1 -1
- fenix_mcp/interface/mcp_server.py +0 -3
- fenix_mcp/interface/transports.py +19 -10
- fenix_mcp/main.py +4 -1
- {fenix_mcp-0.1.0.dist-info → fenix_mcp-0.2.1.dist-info}/METADATA +56 -6
- fenix_mcp-0.2.1.dist-info/RECORD +29 -0
- fenix_mcp-0.1.0.dist-info/RECORD +0 -29
- {fenix_mcp-0.1.0.dist-info → fenix_mcp-0.2.1.dist-info}/WHEEL +0 -0
- {fenix_mcp-0.1.0.dist-info → fenix_mcp-0.2.1.dist-info}/entry_points.txt +0 -0
- {fenix_mcp-0.1.0.dist-info → fenix_mcp-0.2.1.dist-info}/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
6
|
from enum import Enum
|
|
7
|
-
from typing import Any, Dict,
|
|
7
|
+
from typing import Any, Dict, List, Optional
|
|
8
8
|
|
|
9
9
|
from pydantic import Field
|
|
10
10
|
|
|
@@ -51,24 +51,36 @@ class TodoAction(str, Enum):
|
|
|
51
51
|
|
|
52
52
|
ACTION_FIELD_DESCRIPTION = (
|
|
53
53
|
"Ação de produtividade (TODO). Escolha um dos valores: "
|
|
54
|
-
+ ", ".join(
|
|
54
|
+
+ ", ".join(
|
|
55
|
+
f"`{member.value}` ({member.description.rstrip('.')})." for member in TodoAction
|
|
56
|
+
)
|
|
55
57
|
)
|
|
56
58
|
|
|
57
59
|
|
|
58
60
|
class ProductivityRequest(ToolRequest):
|
|
59
61
|
action: TodoAction = Field(description=ACTION_FIELD_DESCRIPTION)
|
|
60
62
|
id: Optional[str] = Field(default=None, description="Identificador do item TODO.")
|
|
61
|
-
title: Optional[str] = Field(
|
|
62
|
-
|
|
63
|
+
title: Optional[str] = Field(
|
|
64
|
+
default=None, description="Título do TODO (obrigatório em create)."
|
|
65
|
+
)
|
|
66
|
+
content: Optional[str] = Field(
|
|
67
|
+
default=None, description="Conteúdo em Markdown (obrigatório em create)."
|
|
68
|
+
)
|
|
63
69
|
status: Optional[str] = Field(default="pending", description="Status do TODO.")
|
|
64
70
|
priority: Optional[str] = Field(default="medium", description="Prioridade do TODO.")
|
|
65
71
|
category: Optional[str] = Field(default=None, description="Categoria opcional.")
|
|
66
72
|
tags: Optional[List[str]] = Field(default=None, description="Lista de tags.")
|
|
67
|
-
due_date: Optional[str] = Field(
|
|
68
|
-
|
|
73
|
+
due_date: Optional[str] = Field(
|
|
74
|
+
default=None, description="Data de vencimento do TODO (ISO)."
|
|
75
|
+
)
|
|
76
|
+
limit: int = Field(
|
|
77
|
+
default=20, ge=1, le=100, description="Limite de resultados em list/search."
|
|
78
|
+
)
|
|
69
79
|
offset: int = Field(default=0, ge=0, description="Offset de paginação.")
|
|
70
80
|
query: Optional[str] = Field(default=None, description="Termo de busca.")
|
|
71
|
-
days: Optional[int] = Field(
|
|
81
|
+
days: Optional[int] = Field(
|
|
82
|
+
default=None, ge=1, le=30, description="Janela de dias para upcoming."
|
|
83
|
+
)
|
|
72
84
|
|
|
73
85
|
|
|
74
86
|
class ProductivityTool(Tool):
|
|
@@ -175,7 +187,9 @@ class ProductivityTool(Tool):
|
|
|
175
187
|
async def _handle_search(self, payload: ProductivityRequest):
|
|
176
188
|
if not payload.query:
|
|
177
189
|
return text("❌ Informe um termo de busca (query).")
|
|
178
|
-
todos = await self._service.search(
|
|
190
|
+
todos = await self._service.search(
|
|
191
|
+
payload.query, limit=payload.limit, offset=payload.offset
|
|
192
|
+
)
|
|
179
193
|
if not todos:
|
|
180
194
|
return text("🔍 Nenhum TODO encontrado para a busca.")
|
|
181
195
|
body = "\n\n".join(ProductivityService.format_todo(todo) for todo in todos)
|
|
@@ -213,7 +227,10 @@ class ProductivityTool(Tool):
|
|
|
213
227
|
return text(f"🔖 **Tags utilizadas:**\n{body}")
|
|
214
228
|
|
|
215
229
|
async def _handle_help(self):
|
|
216
|
-
return text(
|
|
230
|
+
return text(
|
|
231
|
+
"📚 **Ações disponíveis para productivity**\n\n"
|
|
232
|
+
+ TodoAction.formatted_help()
|
|
233
|
+
)
|
|
217
234
|
|
|
218
235
|
@staticmethod
|
|
219
236
|
def _format_single(todo: Dict[str, Any], *, header: str) -> str:
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
6
|
from enum import Enum
|
|
7
|
-
from typing import Dict, List, Optional
|
|
7
|
+
from typing import Any, Dict, List, Optional
|
|
8
8
|
|
|
9
9
|
from pydantic import Field
|
|
10
10
|
|
|
@@ -43,9 +43,9 @@ class UserConfigAction(str, Enum):
|
|
|
43
43
|
return "\n".join(lines)
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
ACTION_FIELD_DESCRIPTION = (
|
|
47
|
-
"
|
|
48
|
-
|
|
46
|
+
ACTION_FIELD_DESCRIPTION = "Ação a executar. Escolha um dos valores: " + ", ".join(
|
|
47
|
+
f"`{member.value}` ({member.description.rstrip('.')})."
|
|
48
|
+
for member in UserConfigAction
|
|
49
49
|
)
|
|
50
50
|
|
|
51
51
|
|
|
@@ -53,12 +53,18 @@ class UserConfigRequest(ToolRequest):
|
|
|
53
53
|
action: UserConfigAction = Field(description=ACTION_FIELD_DESCRIPTION)
|
|
54
54
|
id: Optional[str] = Field(default=None, description="ID do documento.")
|
|
55
55
|
name: Optional[str] = Field(default=None, description="Nome do documento.")
|
|
56
|
-
content: Optional[str] = Field(
|
|
56
|
+
content: Optional[str] = Field(
|
|
57
|
+
default=None, description="Conteúdo em Markdown/JSON."
|
|
58
|
+
)
|
|
57
59
|
mode_id: Optional[str] = Field(default=None, description="ID do modo associado.")
|
|
58
|
-
is_default: Optional[bool] = Field(
|
|
60
|
+
is_default: Optional[bool] = Field(
|
|
61
|
+
default=None, description="Marca o documento como padrão."
|
|
62
|
+
)
|
|
59
63
|
limit: int = Field(default=20, ge=1, le=100, description="Limite para listagem.")
|
|
60
64
|
offset: int = Field(default=0, ge=0, description="Offset para listagem.")
|
|
61
|
-
return_content: Optional[bool] = Field(
|
|
65
|
+
return_content: Optional[bool] = Field(
|
|
66
|
+
default=None, description="Retorna conteúdo completo."
|
|
67
|
+
)
|
|
62
68
|
|
|
63
69
|
|
|
64
70
|
class UserConfigTool(Tool):
|
|
@@ -125,7 +131,7 @@ class UserConfigTool(Tool):
|
|
|
125
131
|
|
|
126
132
|
if action is UserConfigAction.DELETE:
|
|
127
133
|
if not payload.id:
|
|
128
|
-
return text("❌ Informe o ID do documento."
|
|
134
|
+
return text("❌ Informe o ID do documento.")
|
|
129
135
|
await self._service.delete(payload.id)
|
|
130
136
|
return text(f"🗑️ Documento {payload.id} removido.")
|
|
131
137
|
|
|
@@ -135,7 +141,10 @@ class UserConfigTool(Tool):
|
|
|
135
141
|
)
|
|
136
142
|
|
|
137
143
|
async def _handle_help(self):
|
|
138
|
-
return text(
|
|
144
|
+
return text(
|
|
145
|
+
"📚 **Ações disponíveis para user_config**\n\n"
|
|
146
|
+
+ UserConfigAction.formatted_help()
|
|
147
|
+
)
|
|
139
148
|
|
|
140
149
|
|
|
141
150
|
def _format_doc(doc: Dict[str, Any], header: Optional[str] = None) -> str:
|
|
@@ -25,7 +25,9 @@ class InitializationService:
|
|
|
25
25
|
self._api = api_client
|
|
26
26
|
self._logger = logger
|
|
27
27
|
|
|
28
|
-
async def gather_data(
|
|
28
|
+
async def gather_data(
|
|
29
|
+
self, *, include_user_docs: bool, limit: int
|
|
30
|
+
) -> InitializationData:
|
|
29
31
|
profile = await self._safe_call(self._api.get_profile)
|
|
30
32
|
core_docs = await self._safe_call(
|
|
31
33
|
self._api.list_core_documents,
|
|
@@ -35,10 +37,13 @@ class InitializationService:
|
|
|
35
37
|
self._logger.debug("Core docs response", extra={"core_docs": core_docs})
|
|
36
38
|
user_docs: List[Dict[str, Any]] = []
|
|
37
39
|
if include_user_docs:
|
|
38
|
-
user_docs =
|
|
39
|
-
self.
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
user_docs = (
|
|
41
|
+
await self._safe_call(
|
|
42
|
+
self._api.list_user_core_documents,
|
|
43
|
+
return_content=True,
|
|
44
|
+
)
|
|
45
|
+
or []
|
|
46
|
+
)
|
|
42
47
|
if self._logger:
|
|
43
48
|
self._logger.debug("User docs response", extra={"user_docs": user_docs})
|
|
44
49
|
memories = await self._safe_call(
|
|
@@ -80,7 +85,9 @@ class InitializationService:
|
|
|
80
85
|
return []
|
|
81
86
|
|
|
82
87
|
@staticmethod
|
|
83
|
-
def build_existing_user_summary(
|
|
88
|
+
def build_existing_user_summary(
|
|
89
|
+
data: InitializationData, include_user_docs: bool
|
|
90
|
+
) -> str:
|
|
84
91
|
profile = data.profile or {}
|
|
85
92
|
user_info = profile.get("user") or {}
|
|
86
93
|
tenant_info = profile.get("tenant") or {}
|
|
@@ -109,16 +116,21 @@ class InitializationService:
|
|
|
109
116
|
|
|
110
117
|
if core_count:
|
|
111
118
|
preview = ", ".join(
|
|
112
|
-
doc.get("name", doc.get("title", "sem título"))
|
|
119
|
+
doc.get("name", doc.get("title", "sem título"))
|
|
120
|
+
for doc in data.core_documents[:5]
|
|
113
121
|
)
|
|
114
122
|
lines.append(f"- Exemplos de documentos principais: {preview}")
|
|
115
123
|
|
|
116
124
|
if include_user_docs and user_count:
|
|
117
|
-
preview = ", ".join(
|
|
125
|
+
preview = ", ".join(
|
|
126
|
+
doc.get("name", "sem título") for doc in data.user_documents[:5]
|
|
127
|
+
)
|
|
118
128
|
lines.append(f"- Exemplos de documentos pessoais: {preview}")
|
|
119
129
|
|
|
120
130
|
if memories_count:
|
|
121
|
-
preview = ", ".join(
|
|
131
|
+
preview = ", ".join(
|
|
132
|
+
mem.get("title", "sem título") for mem in data.recent_memories[:3]
|
|
133
|
+
)
|
|
122
134
|
lines.append(f"- Memórias recentes: {preview}")
|
|
123
135
|
|
|
124
136
|
lines.append("")
|
fenix_mcp/domain/intelligence.py
CHANGED
|
@@ -44,12 +44,15 @@ class IntelligenceService:
|
|
|
44
44
|
params = _strip_none(filters)
|
|
45
45
|
include_content = bool(params.pop("content", True))
|
|
46
46
|
include_metadata = bool(params.pop("metadata", False))
|
|
47
|
-
return
|
|
48
|
-
self.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
return (
|
|
48
|
+
await self._call(
|
|
49
|
+
self.api.list_memories,
|
|
50
|
+
include_content=include_content,
|
|
51
|
+
include_metadata=include_metadata,
|
|
52
|
+
**params,
|
|
53
|
+
)
|
|
54
|
+
or []
|
|
55
|
+
)
|
|
53
56
|
|
|
54
57
|
async def similar_memories(
|
|
55
58
|
self, *, content: str, threshold: float, max_results: int
|
|
@@ -58,7 +61,9 @@ class IntelligenceService:
|
|
|
58
61
|
"content": content,
|
|
59
62
|
"threshold": threshold,
|
|
60
63
|
}
|
|
61
|
-
result =
|
|
64
|
+
result = (
|
|
65
|
+
await self._call(self.api.find_similar_memories, _strip_none(payload)) or []
|
|
66
|
+
)
|
|
62
67
|
if isinstance(result, list) and max_results:
|
|
63
68
|
return result[:max_results]
|
|
64
69
|
return result
|
|
@@ -78,15 +83,20 @@ class IntelligenceService:
|
|
|
78
83
|
"sortBy": "priority_score",
|
|
79
84
|
"sortOrder": "desc",
|
|
80
85
|
}
|
|
81
|
-
return
|
|
82
|
-
self.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
return (
|
|
87
|
+
await self._call(
|
|
88
|
+
self.api.list_memories,
|
|
89
|
+
include_content=False,
|
|
90
|
+
include_metadata=False,
|
|
91
|
+
**params,
|
|
92
|
+
)
|
|
93
|
+
or []
|
|
94
|
+
)
|
|
87
95
|
|
|
88
96
|
async def analytics(self, *, time_range: str, group_by: str) -> Dict[str, Any]:
|
|
89
|
-
memories = await self.query_memories(
|
|
97
|
+
memories = await self.query_memories(
|
|
98
|
+
limit=200, timeRange=time_range, groupBy=group_by
|
|
99
|
+
)
|
|
90
100
|
summary: Dict[str, Any] = {
|
|
91
101
|
"total_memories": len(memories),
|
|
92
102
|
"by_group": {},
|
|
@@ -100,7 +110,9 @@ class IntelligenceService:
|
|
|
100
110
|
async def update_memory(self, memory_id: str, **fields: Any) -> Dict[str, Any]:
|
|
101
111
|
payload = _strip_none(fields)
|
|
102
112
|
if "importance" in payload:
|
|
103
|
-
payload["priority_score"] = _importance_to_priority(
|
|
113
|
+
payload["priority_score"] = _importance_to_priority(
|
|
114
|
+
payload.pop("importance")
|
|
115
|
+
)
|
|
104
116
|
mapping = {
|
|
105
117
|
"documentation_item_id": "documentationItemId",
|
|
106
118
|
"mode_id": "modeId",
|
fenix_mcp/domain/knowledge.py
CHANGED
|
@@ -72,8 +72,12 @@ class KnowledgeService:
|
|
|
72
72
|
async def work_get(self, work_id: str) -> Dict[str, Any]:
|
|
73
73
|
return await self._call_dict(self.api.get_work_item, work_id)
|
|
74
74
|
|
|
75
|
-
async def work_update(
|
|
76
|
-
|
|
75
|
+
async def work_update(
|
|
76
|
+
self, work_id: str, payload: Dict[str, Any]
|
|
77
|
+
) -> Dict[str, Any]:
|
|
78
|
+
return await self._call(
|
|
79
|
+
self.api.update_work_item, work_id, _strip_none(payload)
|
|
80
|
+
)
|
|
77
81
|
|
|
78
82
|
async def work_delete(self, work_id: str) -> None:
|
|
79
83
|
await self._call(self.api.delete_work_item, work_id)
|
|
@@ -81,7 +85,9 @@ class KnowledgeService:
|
|
|
81
85
|
async def work_backlog(self, *, team_id: str) -> List[Dict[str, Any]]:
|
|
82
86
|
return await self._call_list(self.api.list_work_items_backlog, team_id=team_id)
|
|
83
87
|
|
|
84
|
-
async def work_search(
|
|
88
|
+
async def work_search(
|
|
89
|
+
self, *, query: str, team_id: str, limit: int
|
|
90
|
+
) -> List[Dict[str, Any]]:
|
|
85
91
|
return await self._call_list(
|
|
86
92
|
self.api.search_work_items,
|
|
87
93
|
query=query,
|
|
@@ -90,29 +96,46 @@ class KnowledgeService:
|
|
|
90
96
|
)
|
|
91
97
|
|
|
92
98
|
async def work_analytics(self, *, team_id: str) -> Dict[str, Any]:
|
|
93
|
-
return
|
|
99
|
+
return (
|
|
100
|
+
await self._call(self.api.get_work_items_analytics, team_id=team_id) or {}
|
|
101
|
+
)
|
|
94
102
|
|
|
95
|
-
async def work_velocity(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
103
|
+
async def work_velocity(
|
|
104
|
+
self, *, team_id: str, sprints_count: int
|
|
105
|
+
) -> Dict[str, Any]:
|
|
106
|
+
return (
|
|
107
|
+
await self._call(
|
|
108
|
+
self.api.get_work_items_velocity,
|
|
109
|
+
team_id=team_id,
|
|
110
|
+
sprints_count=sprints_count,
|
|
111
|
+
)
|
|
112
|
+
or {}
|
|
113
|
+
)
|
|
101
114
|
|
|
102
115
|
async def work_by_sprint(self, *, sprint_id: str) -> List[Dict[str, Any]]:
|
|
103
|
-
return await self._call_list(
|
|
116
|
+
return await self._call_list(
|
|
117
|
+
self.api.list_work_items_by_sprint, sprint_id=sprint_id
|
|
118
|
+
)
|
|
104
119
|
|
|
105
120
|
async def work_burndown(self, *, sprint_id: str) -> Dict[str, Any]:
|
|
106
|
-
return
|
|
121
|
+
return (
|
|
122
|
+
await self._call(self.api.get_work_items_burndown, sprint_id=sprint_id)
|
|
123
|
+
or {}
|
|
124
|
+
)
|
|
107
125
|
|
|
108
126
|
async def work_by_epic(self, *, epic_id: str) -> List[Dict[str, Any]]:
|
|
109
127
|
return await self._call(self.api.list_work_items_by_epic, epic_id=epic_id) or []
|
|
110
128
|
|
|
111
129
|
async def work_epic_progress(self, *, epic_id: str) -> Dict[str, Any]:
|
|
112
|
-
return
|
|
130
|
+
return (
|
|
131
|
+
await self._call(self.api.get_work_items_epic_progress, epic_id=epic_id)
|
|
132
|
+
or {}
|
|
133
|
+
)
|
|
113
134
|
|
|
114
135
|
async def work_by_board(self, *, board_id: str) -> List[Dict[str, Any]]:
|
|
115
|
-
return await self._call_list(
|
|
136
|
+
return await self._call_list(
|
|
137
|
+
self.api.list_work_items_by_board, board_id=board_id
|
|
138
|
+
)
|
|
116
139
|
|
|
117
140
|
async def work_children(self, work_id: str) -> List[Dict[str, Any]]:
|
|
118
141
|
return await self._call_list(self.api.get_work_item_children, work_id)
|
|
@@ -120,17 +143,27 @@ class KnowledgeService:
|
|
|
120
143
|
async def work_move(self, work_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
121
144
|
return await self._call(self.api.move_work_item, work_id, _strip_none(payload))
|
|
122
145
|
|
|
123
|
-
async def work_update_status(
|
|
124
|
-
|
|
146
|
+
async def work_update_status(
|
|
147
|
+
self, work_id: str, payload: Dict[str, Any]
|
|
148
|
+
) -> Dict[str, Any]:
|
|
149
|
+
return await self._call(
|
|
150
|
+
self.api.update_work_item_status, work_id, _strip_none(payload)
|
|
151
|
+
)
|
|
125
152
|
|
|
126
|
-
async def work_move_to_board(
|
|
127
|
-
|
|
153
|
+
async def work_move_to_board(
|
|
154
|
+
self, work_id: str, payload: Dict[str, Any]
|
|
155
|
+
) -> Dict[str, Any]:
|
|
156
|
+
return await self._call(
|
|
157
|
+
self.api.move_work_item_to_board, work_id, _strip_none(payload)
|
|
158
|
+
)
|
|
128
159
|
|
|
129
160
|
async def work_link(self, work_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
130
161
|
return await self._call(self.api.link_work_item, work_id, _strip_none(payload))
|
|
131
162
|
|
|
132
163
|
async def work_assign_to_sprint(self, payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
133
|
-
return await self._call(
|
|
164
|
+
return await self._call(
|
|
165
|
+
self.api.assign_work_items_to_sprint, _strip_none(payload)
|
|
166
|
+
)
|
|
134
167
|
|
|
135
168
|
async def work_bulk_update(self, payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
136
169
|
return await self._call(self.api.bulk_update_work_items, _strip_none(payload))
|
|
@@ -153,7 +186,9 @@ class KnowledgeService:
|
|
|
153
186
|
result = await self._call(self.api.list_favorite_work_boards)
|
|
154
187
|
return _ensure_list(result)
|
|
155
188
|
|
|
156
|
-
async def board_search(
|
|
189
|
+
async def board_search(
|
|
190
|
+
self, *, query: str, team_id: str, limit: int
|
|
191
|
+
) -> List[Dict[str, Any]]:
|
|
157
192
|
result = await self._call(
|
|
158
193
|
self.api.search_work_boards,
|
|
159
194
|
query=query,
|
|
@@ -170,8 +205,12 @@ class KnowledgeService:
|
|
|
170
205
|
result = await self._call(self.api.get_work_board, board_id)
|
|
171
206
|
return _ensure_dict(result)
|
|
172
207
|
|
|
173
|
-
async def board_update(
|
|
174
|
-
|
|
208
|
+
async def board_update(
|
|
209
|
+
self, board_id: str, payload: Dict[str, Any]
|
|
210
|
+
) -> Dict[str, Any]:
|
|
211
|
+
return await self._call(
|
|
212
|
+
self.api.update_work_board, board_id, _strip_none(payload)
|
|
213
|
+
)
|
|
175
214
|
|
|
176
215
|
async def board_delete(self, board_id: str) -> None:
|
|
177
216
|
await self._call(self.api.delete_work_board, board_id)
|
|
@@ -183,11 +222,19 @@ class KnowledgeService:
|
|
|
183
222
|
result = await self._call(self.api.list_work_board_columns, board_id)
|
|
184
223
|
return _ensure_list(result)
|
|
185
224
|
|
|
186
|
-
async def board_toggle_favorite(
|
|
187
|
-
|
|
225
|
+
async def board_toggle_favorite(
|
|
226
|
+
self, board_id: str, payload: Dict[str, Any]
|
|
227
|
+
) -> Dict[str, Any]:
|
|
228
|
+
return await self._call(
|
|
229
|
+
self.api.toggle_work_board_favorite, board_id, _strip_none(payload)
|
|
230
|
+
)
|
|
188
231
|
|
|
189
|
-
async def board_clone(
|
|
190
|
-
|
|
232
|
+
async def board_clone(
|
|
233
|
+
self, board_id: str, payload: Dict[str, Any]
|
|
234
|
+
) -> Dict[str, Any]:
|
|
235
|
+
return await self._call(
|
|
236
|
+
self.api.clone_work_board, board_id, _strip_none(payload)
|
|
237
|
+
)
|
|
191
238
|
|
|
192
239
|
async def board_reorder(self, payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
193
240
|
return await self._call(self.api.reorder_work_boards, _strip_none(payload))
|
|
@@ -196,13 +243,19 @@ class KnowledgeService:
|
|
|
196
243
|
return await self._call(self.api.create_work_board_column, _strip_none(payload))
|
|
197
244
|
|
|
198
245
|
async def board_column_reorder(self, payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
199
|
-
return await self._call(
|
|
246
|
+
return await self._call(
|
|
247
|
+
self.api.reorder_work_board_columns, _strip_none(payload)
|
|
248
|
+
)
|
|
200
249
|
|
|
201
250
|
async def board_column_get(self, column_id: str) -> Dict[str, Any]:
|
|
202
251
|
return await self._call(self.api.get_work_board_column, column_id)
|
|
203
252
|
|
|
204
|
-
async def board_column_update(
|
|
205
|
-
|
|
253
|
+
async def board_column_update(
|
|
254
|
+
self, column_id: str, payload: Dict[str, Any]
|
|
255
|
+
) -> Dict[str, Any]:
|
|
256
|
+
return await self._call(
|
|
257
|
+
self.api.update_work_board_column, column_id, _strip_none(payload)
|
|
258
|
+
)
|
|
206
259
|
|
|
207
260
|
async def board_column_delete(self, column_id: str) -> None:
|
|
208
261
|
await self._call(self.api.delete_work_board_column, column_id)
|
|
@@ -219,7 +272,9 @@ class KnowledgeService:
|
|
|
219
272
|
async def sprint_get(self, sprint_id: str) -> Dict[str, Any]:
|
|
220
273
|
return await self._call_dict(self.api.get_sprint, sprint_id)
|
|
221
274
|
|
|
222
|
-
async def sprint_update(
|
|
275
|
+
async def sprint_update(
|
|
276
|
+
self, sprint_id: str, payload: Dict[str, Any]
|
|
277
|
+
) -> Dict[str, Any]:
|
|
223
278
|
return await self._call(self.api.update_sprint, sprint_id, _strip_none(payload))
|
|
224
279
|
|
|
225
280
|
async def sprint_delete(self, sprint_id: str) -> None:
|
|
@@ -229,9 +284,14 @@ class KnowledgeService:
|
|
|
229
284
|
return await self._call_list(self.api.list_sprints_by_team, team_id=team_id)
|
|
230
285
|
|
|
231
286
|
async def sprint_recent(self, *, team_id: str, limit: int) -> List[Dict[str, Any]]:
|
|
232
|
-
return
|
|
287
|
+
return (
|
|
288
|
+
await self._call(self.api.list_recent_sprints, team_id=team_id, limit=limit)
|
|
289
|
+
or []
|
|
290
|
+
)
|
|
233
291
|
|
|
234
|
-
async def sprint_search(
|
|
292
|
+
async def sprint_search(
|
|
293
|
+
self, *, query: str, team_id: str, limit: int
|
|
294
|
+
) -> List[Dict[str, Any]]:
|
|
235
295
|
return await self._call_list(
|
|
236
296
|
self.api.search_sprints,
|
|
237
297
|
query=query,
|
|
@@ -251,11 +311,17 @@ class KnowledgeService:
|
|
|
251
311
|
async def sprint_work_items(self, sprint_id: str) -> List[Dict[str, Any]]:
|
|
252
312
|
return await self._call_list(self.api.get_sprint_work_items, sprint_id)
|
|
253
313
|
|
|
254
|
-
async def sprint_add_work_items(
|
|
255
|
-
|
|
314
|
+
async def sprint_add_work_items(
|
|
315
|
+
self, sprint_id: str, payload: Dict[str, Any]
|
|
316
|
+
) -> Dict[str, Any]:
|
|
317
|
+
return await self._call(
|
|
318
|
+
self.api.add_work_items_to_sprint, sprint_id, _strip_none(payload)
|
|
319
|
+
)
|
|
256
320
|
|
|
257
321
|
async def sprint_remove_work_items(self, payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
258
|
-
return await self._call(
|
|
322
|
+
return await self._call(
|
|
323
|
+
self.api.remove_work_items_from_sprint, _strip_none(payload)
|
|
324
|
+
)
|
|
259
325
|
|
|
260
326
|
async def sprint_analytics(self, sprint_id: str) -> Dict[str, Any]:
|
|
261
327
|
return await self._call(self.api.get_sprint_analytics, sprint_id) or {}
|
|
@@ -263,11 +329,17 @@ class KnowledgeService:
|
|
|
263
329
|
async def sprint_capacity(self, sprint_id: str) -> Dict[str, Any]:
|
|
264
330
|
return await self._call(self.api.get_sprint_capacity, sprint_id) or {}
|
|
265
331
|
|
|
266
|
-
async def sprint_start(
|
|
332
|
+
async def sprint_start(
|
|
333
|
+
self, sprint_id: str, payload: Dict[str, Any]
|
|
334
|
+
) -> Dict[str, Any]:
|
|
267
335
|
return await self._call(self.api.start_sprint, sprint_id, _strip_none(payload))
|
|
268
336
|
|
|
269
|
-
async def sprint_complete(
|
|
270
|
-
|
|
337
|
+
async def sprint_complete(
|
|
338
|
+
self, sprint_id: str, payload: Dict[str, Any]
|
|
339
|
+
) -> Dict[str, Any]:
|
|
340
|
+
return await self._call(
|
|
341
|
+
self.api.complete_sprint, sprint_id, _strip_none(payload)
|
|
342
|
+
)
|
|
271
343
|
|
|
272
344
|
async def sprint_cancel(self, sprint_id: str) -> Dict[str, Any]:
|
|
273
345
|
return await self._call(self.api.cancel_sprint, sprint_id)
|
|
@@ -285,12 +357,15 @@ class KnowledgeService:
|
|
|
285
357
|
return_description: Optional[bool] = None,
|
|
286
358
|
return_metadata: Optional[bool] = None,
|
|
287
359
|
) -> List[Dict[str, Any]]:
|
|
288
|
-
return
|
|
289
|
-
self.
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
360
|
+
return (
|
|
361
|
+
await self._call(
|
|
362
|
+
self.api.list_modes,
|
|
363
|
+
include_rules=include_rules,
|
|
364
|
+
return_description=return_description,
|
|
365
|
+
return_metadata=return_metadata,
|
|
366
|
+
)
|
|
367
|
+
or []
|
|
368
|
+
)
|
|
294
369
|
|
|
295
370
|
async def mode_get(
|
|
296
371
|
self,
|
|
@@ -306,7 +381,9 @@ class KnowledgeService:
|
|
|
306
381
|
return_metadata=return_metadata,
|
|
307
382
|
)
|
|
308
383
|
|
|
309
|
-
async def mode_update(
|
|
384
|
+
async def mode_update(
|
|
385
|
+
self, mode_id: str, payload: Dict[str, Any]
|
|
386
|
+
) -> Dict[str, Any]:
|
|
310
387
|
return await self._call(self.api.update_mode, mode_id, _strip_none(payload))
|
|
311
388
|
|
|
312
389
|
async def mode_delete(self, mode_id: str) -> None:
|
|
@@ -334,12 +411,15 @@ class KnowledgeService:
|
|
|
334
411
|
return_metadata: Optional[bool] = None,
|
|
335
412
|
return_modes: Optional[bool] = None,
|
|
336
413
|
) -> List[Dict[str, Any]]:
|
|
337
|
-
return
|
|
338
|
-
self.
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
414
|
+
return (
|
|
415
|
+
await self._call(
|
|
416
|
+
self.api.list_rules,
|
|
417
|
+
return_description=return_description,
|
|
418
|
+
return_metadata=return_metadata,
|
|
419
|
+
return_modes=return_modes,
|
|
420
|
+
)
|
|
421
|
+
or []
|
|
422
|
+
)
|
|
343
423
|
|
|
344
424
|
async def rule_get(
|
|
345
425
|
self,
|
|
@@ -357,7 +437,9 @@ class KnowledgeService:
|
|
|
357
437
|
return_modes=return_modes,
|
|
358
438
|
)
|
|
359
439
|
|
|
360
|
-
async def rule_update(
|
|
440
|
+
async def rule_update(
|
|
441
|
+
self, rule_id: str, payload: Dict[str, Any]
|
|
442
|
+
) -> Dict[str, Any]:
|
|
361
443
|
return await self._call(self.api.update_rule, rule_id, _strip_none(payload))
|
|
362
444
|
|
|
363
445
|
async def rule_delete(self, rule_id: str) -> None:
|
|
@@ -367,23 +449,33 @@ class KnowledgeService:
|
|
|
367
449
|
# Documentation
|
|
368
450
|
# ------------------------------------------------------------------
|
|
369
451
|
async def doc_create(self, payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
370
|
-
return await self._call_dict(
|
|
452
|
+
return await self._call_dict(
|
|
453
|
+
self.api.create_documentation_item, _strip_none(payload)
|
|
454
|
+
)
|
|
371
455
|
|
|
372
456
|
async def doc_list(self, **filters: Any) -> List[Dict[str, Any]]:
|
|
373
|
-
result = await self._call(
|
|
457
|
+
result = await self._call(
|
|
458
|
+
self.api.list_documentation_items, **_strip_none(filters)
|
|
459
|
+
)
|
|
374
460
|
return _ensure_list(result)
|
|
375
461
|
|
|
376
462
|
async def doc_get(self, doc_id: str, **filters: Any) -> Dict[str, Any]:
|
|
377
|
-
result = await self._call(
|
|
463
|
+
result = await self._call(
|
|
464
|
+
self.api.get_documentation_item, doc_id, **_strip_none(filters)
|
|
465
|
+
)
|
|
378
466
|
return _ensure_dict(result)
|
|
379
467
|
|
|
380
468
|
async def doc_update(self, doc_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
381
|
-
return await self._call_dict(
|
|
469
|
+
return await self._call_dict(
|
|
470
|
+
self.api.update_documentation_item, doc_id, _strip_none(payload)
|
|
471
|
+
)
|
|
382
472
|
|
|
383
473
|
async def doc_delete(self, doc_id: str) -> None:
|
|
384
474
|
await self._call(self.api.delete_documentation_item, doc_id)
|
|
385
475
|
|
|
386
|
-
async def doc_search(
|
|
476
|
+
async def doc_search(
|
|
477
|
+
self, *, query: str, team_id: str, limit: int
|
|
478
|
+
) -> List[Dict[str, Any]]:
|
|
387
479
|
result = await self._call(
|
|
388
480
|
self.api.search_documentation_items,
|
|
389
481
|
query=query,
|
|
@@ -418,16 +510,24 @@ class KnowledgeService:
|
|
|
418
510
|
return await self._call(self.api.get_documentation_full_tree) or {}
|
|
419
511
|
|
|
420
512
|
async def doc_move(self, doc_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
421
|
-
return await self._call_dict(
|
|
513
|
+
return await self._call_dict(
|
|
514
|
+
self.api.move_documentation_item, doc_id, _strip_none(payload)
|
|
515
|
+
)
|
|
422
516
|
|
|
423
517
|
async def doc_publish(self, doc_id: str) -> Dict[str, Any]:
|
|
424
518
|
return await self._call_dict(self.api.publish_documentation_item, doc_id)
|
|
425
519
|
|
|
426
520
|
async def doc_version(self, doc_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
|
|
427
|
-
return await self._call_dict(
|
|
521
|
+
return await self._call_dict(
|
|
522
|
+
self.api.create_documentation_version, doc_id, _strip_none(payload)
|
|
523
|
+
)
|
|
428
524
|
|
|
429
|
-
async def doc_duplicate(
|
|
430
|
-
|
|
525
|
+
async def doc_duplicate(
|
|
526
|
+
self, doc_id: str, payload: Dict[str, Any]
|
|
527
|
+
) -> Dict[str, Any]:
|
|
528
|
+
return await self._call_dict(
|
|
529
|
+
self.api.duplicate_documentation_item, doc_id, _strip_none(payload)
|
|
530
|
+
)
|
|
431
531
|
|
|
432
532
|
|
|
433
533
|
__all__ = [
|