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.
@@ -4,7 +4,7 @@
4
4
  from __future__ import annotations
5
5
 
6
6
  from enum import Enum
7
- from typing import Any, Dict, Iterable, List, Optional
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(f"`{member.value}` ({member.description.rstrip('.')})." for member in TodoAction)
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(default=None, description="Título do TODO (obrigatório em create).")
62
- content: Optional[str] = Field(default=None, description="Conteúdo em Markdown (obrigatório em create).")
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(default=None, description="Data de vencimento do TODO (ISO).")
68
- limit: int = Field(default=20, ge=1, le=100, description="Limite de resultados em list/search.")
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(default=None, ge=1, le=30, description="Janela de dias para upcoming.")
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(payload.query, limit=payload.limit, offset=payload.offset)
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("📚 **Ações disponíveis para productivity**\n\n" + TodoAction.formatted_help())
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
- "Ação a executar. Escolha um dos valores: "
48
- + ", ".join(f"`{member.value}` ({member.description.rstrip('.')})." for member in UserConfigAction)
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(default=None, description="Conteúdo em Markdown/JSON.")
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(default=None, description="Marca o documento como padrão.")
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(default=None, description="Retorna conteúdo completo.")
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("📚 **Ações disponíveis para user_config**\n\n" + UserConfigAction.formatted_help())
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(self, *, include_user_docs: bool, limit: int) -> InitializationData:
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 = await self._safe_call(
39
- self._api.list_user_core_documents,
40
- return_content=True,
41
- ) or []
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(data: InitializationData, include_user_docs: bool) -> str:
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")) for doc in data.core_documents[:5]
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(doc.get("name", "sem título") for doc in data.user_documents[:5])
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(mem.get("title", "sem título") for mem in data.recent_memories[:3])
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("")
@@ -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 await self._call(
48
- self.api.list_memories,
49
- include_content=include_content,
50
- include_metadata=include_metadata,
51
- **params,
52
- ) or []
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 = await self._call(self.api.find_similar_memories, _strip_none(payload)) or []
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 await self._call(
82
- self.api.list_memories,
83
- include_content=False,
84
- include_metadata=False,
85
- **params,
86
- ) or []
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(limit=200, timeRange=time_range, groupBy=group_by)
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(payload.pop("importance"))
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",
@@ -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(self, work_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
76
- return await self._call(self.api.update_work_item, work_id, _strip_none(payload))
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(self, *, query: str, team_id: str, limit: int) -> List[Dict[str, Any]]:
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 await self._call(self.api.get_work_items_analytics, team_id=team_id) or {}
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(self, *, team_id: str, sprints_count: int) -> Dict[str, Any]:
96
- return await self._call(
97
- self.api.get_work_items_velocity,
98
- team_id=team_id,
99
- sprints_count=sprints_count,
100
- ) or {}
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(self.api.list_work_items_by_sprint, sprint_id=sprint_id)
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 await self._call(self.api.get_work_items_burndown, sprint_id=sprint_id) or {}
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 await self._call(self.api.get_work_items_epic_progress, epic_id=epic_id) or {}
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(self.api.list_work_items_by_board, board_id=board_id)
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(self, work_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
124
- return await self._call(self.api.update_work_item_status, work_id, _strip_none(payload))
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(self, work_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
127
- return await self._call(self.api.move_work_item_to_board, work_id, _strip_none(payload))
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(self.api.assign_work_items_to_sprint, _strip_none(payload))
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(self, *, query: str, team_id: str, limit: int) -> List[Dict[str, Any]]:
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(self, board_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
174
- return await self._call(self.api.update_work_board, board_id, _strip_none(payload))
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(self, board_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
187
- return await self._call(self.api.toggle_work_board_favorite, board_id, _strip_none(payload))
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(self, board_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
190
- return await self._call(self.api.clone_work_board, board_id, _strip_none(payload))
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(self.api.reorder_work_board_columns, _strip_none(payload))
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(self, column_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
205
- return await self._call(self.api.update_work_board_column, column_id, _strip_none(payload))
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(self, sprint_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
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 await self._call(self.api.list_recent_sprints, team_id=team_id, limit=limit) or []
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(self, *, query: str, team_id: str, limit: int) -> List[Dict[str, Any]]:
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(self, sprint_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
255
- return await self._call(self.api.add_work_items_to_sprint, sprint_id, _strip_none(payload))
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(self.api.remove_work_items_from_sprint, _strip_none(payload))
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(self, sprint_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
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(self, sprint_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
270
- return await self._call(self.api.complete_sprint, sprint_id, _strip_none(payload))
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 await self._call(
289
- self.api.list_modes,
290
- include_rules=include_rules,
291
- return_description=return_description,
292
- return_metadata=return_metadata,
293
- ) or []
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(self, mode_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
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 await self._call(
338
- self.api.list_rules,
339
- return_description=return_description,
340
- return_metadata=return_metadata,
341
- return_modes=return_modes,
342
- ) or []
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(self, rule_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
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(self.api.create_documentation_item, _strip_none(payload))
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(self.api.list_documentation_items, **_strip_none(filters))
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(self.api.get_documentation_item, doc_id, **_strip_none(filters))
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(self.api.update_documentation_item, doc_id, _strip_none(payload))
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(self, *, query: str, team_id: str, limit: int) -> List[Dict[str, Any]]:
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(self.api.move_documentation_item, doc_id, _strip_none(payload))
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(self.api.create_documentation_version, doc_id, _strip_none(payload))
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(self, doc_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
430
- return await self._call_dict(self.api.duplicate_documentation_item, doc_id, _strip_none(payload))
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__ = [