fenix-mcp 0.7.0__py3-none-any.whl → 1.0.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.
@@ -39,90 +39,93 @@ class KnowledgeAction(str, Enum):
39
39
  # Work items
40
40
  WORK_CREATE = (
41
41
  "work_create",
42
- "Cria um work item com título, status e vínculos opcionais.",
42
+ "Creates a work item with title, status and optional links.",
43
43
  )
44
44
  WORK_LIST = (
45
45
  "work_list",
46
- "Lista work items com filtros de status, prioridade e contexto.",
46
+ "Lists work items with status, priority and context filters.",
47
47
  )
48
- WORK_GET = ("work_get", "Obtém detalhes completos de um work item pelo ID.")
48
+ WORK_GET = ("work_get", "Gets full details of a work item by ID.")
49
49
  WORK_UPDATE = (
50
50
  "work_update",
51
- "Atualiza campos específicos de um work item existente.",
51
+ "Updates specific fields of an existing work item.",
52
52
  )
53
- WORK_DELETE = ("work_delete", "Remove um work item definitivamente.")
54
- WORK_BACKLOG = ("work_backlog", "Lista itens do backlog de um time.")
55
- WORK_SEARCH = ("work_search", "Busca work items por texto com filtros adicionais.")
56
- WORK_ANALYTICS = ("work_analytics", "Retorna métricas consolidadas de work items.")
57
- WORK_BY_BOARD = ("work_by_board", "Lista work items associados a um board.")
58
- WORK_BY_SPRINT = ("work_by_sprint", "Lista work items associados a um sprint.")
59
- WORK_BY_EPIC = ("work_by_epic", "Lista work items associados a um épico.")
60
- WORK_CHILDREN = ("work_children", "Lista work items filhos de um item pai.")
53
+ WORK_DELETE = ("work_delete", "Permanently removes a work item.")
54
+ WORK_BACKLOG = ("work_backlog", "Lists backlog items for a team.")
55
+ WORK_SEARCH = (
56
+ "work_search",
57
+ "Searches work items by text with additional filters.",
58
+ )
59
+ WORK_ANALYTICS = ("work_analytics", "Returns consolidated work item metrics.")
60
+ WORK_BY_BOARD = ("work_by_board", "Lists work items associated with a board.")
61
+ WORK_BY_SPRINT = ("work_by_sprint", "Lists work items associated with a sprint.")
62
+ WORK_BY_EPIC = ("work_by_epic", "Lists work items associated with an epic.")
63
+ WORK_CHILDREN = ("work_children", "Lists child work items of a parent item.")
61
64
  WORK_STATUS_UPDATE = (
62
65
  "work_status_update",
63
- "Atualiza apenas o status de um work item.",
66
+ "Updates only the status of a work item.",
64
67
  )
65
68
  WORK_ASSIGN_SPRINT = (
66
69
  "work_assign_sprint",
67
- "Atribui work items a um sprint.",
70
+ "Assigns work items to a sprint.",
68
71
  )
69
72
 
70
73
  # Boards
71
- BOARD_LIST = ("board_list", "Lista boards disponíveis com filtros opcionais.")
72
- BOARD_BY_TEAM = ("board_by_team", "Lista boards de um time específico.")
73
- BOARD_FAVORITES = ("board_favorites", "Lista boards marcados como favoritos.")
74
- BOARD_GET = ("board_get", "Obtém detalhes de um board pelo ID.")
75
- BOARD_COLUMNS = ("board_columns", "Lista colunas configuradas para um board.")
74
+ BOARD_LIST = ("board_list", "Lists available boards with optional filters.")
75
+ BOARD_BY_TEAM = ("board_by_team", "Lists boards for a specific team.")
76
+ BOARD_FAVORITES = ("board_favorites", "Lists boards marked as favorites.")
77
+ BOARD_GET = ("board_get", "Gets board details by ID.")
78
+ BOARD_COLUMNS = ("board_columns", "Lists columns configured for a board.")
76
79
 
77
80
  # Sprints
78
- SPRINT_LIST = ("sprint_list", "Lista sprints disponíveis com filtros opcionais.")
79
- SPRINT_BY_TEAM = ("sprint_by_team", "Lista sprints associados a um time.")
80
- SPRINT_ACTIVE = ("sprint_active", "Obtém o sprint ativo de um time.")
81
- SPRINT_GET = ("sprint_get", "Obtém detalhes de um sprint pelo ID.")
81
+ SPRINT_LIST = ("sprint_list", "Lists available sprints with optional filters.")
82
+ SPRINT_BY_TEAM = ("sprint_by_team", "Lists sprints associated with a team.")
83
+ SPRINT_ACTIVE = ("sprint_active", "Gets the active sprint for a team.")
84
+ SPRINT_GET = ("sprint_get", "Gets sprint details by ID.")
82
85
  SPRINT_WORK_ITEMS = (
83
86
  "sprint_work_items",
84
- "Lista work items vinculados a um sprint.",
87
+ "Lists work items linked to a sprint.",
85
88
  )
86
89
 
87
90
  # Modes
88
- MODE_CREATE = ("mode_create", "Cria um modo com conteúdo e metadados opcionais.")
89
- MODE_LIST = ("mode_list", "Lista modes cadastrados.")
90
- MODE_GET = ("mode_get", "Obtém detalhes completos de um modo.")
91
- MODE_UPDATE = ("mode_update", "Atualiza propriedades de um modo existente.")
92
- MODE_DELETE = ("mode_delete", "Remove um modo.")
93
- MODE_RULE_ADD = ("mode_rule_add", "Associa uma regra a um modo.")
91
+ MODE_CREATE = ("mode_create", "Creates a mode with content and optional metadata.")
92
+ MODE_LIST = ("mode_list", "Lists registered modes.")
93
+ MODE_GET = ("mode_get", "Gets full details of a mode.")
94
+ MODE_UPDATE = ("mode_update", "Updates properties of an existing mode.")
95
+ MODE_DELETE = ("mode_delete", "Removes a mode.")
96
+ MODE_RULE_ADD = ("mode_rule_add", "Associates a rule with a mode.")
94
97
  MODE_RULE_REMOVE = (
95
98
  "mode_rule_remove",
96
- "Remove a associação de uma regra com um modo.",
99
+ "Removes the association of a rule with a mode.",
97
100
  )
98
- MODE_RULES = ("mode_rules", "Lista regras associadas a um modo.")
101
+ MODE_RULES = ("mode_rules", "Lists rules associated with a mode.")
99
102
 
100
103
  # Rules
101
- RULE_CREATE = ("rule_create", "Cria uma regra com conteúdo e metadados.")
102
- RULE_LIST = ("rule_list", "Lista regras cadastradas.")
103
- RULE_GET = ("rule_get", "Obtém detalhes de uma regra.")
104
- RULE_UPDATE = ("rule_update", "Atualiza uma regra existente.")
105
- RULE_DELETE = ("rule_delete", "Remove uma regra.")
104
+ RULE_CREATE = ("rule_create", "Creates a rule with content and metadata.")
105
+ RULE_LIST = ("rule_list", "Lists registered rules.")
106
+ RULE_GET = ("rule_get", "Gets rule details.")
107
+ RULE_UPDATE = ("rule_update", "Updates an existing rule.")
108
+ RULE_DELETE = ("rule_delete", "Removes a rule.")
106
109
 
107
110
  # Documentation
108
- DOC_CREATE = ("doc_create", "Cria um item de documentação.")
109
- DOC_LIST = ("doc_list", "Lista itens de documentação com filtros.")
110
- DOC_GET = ("doc_get", "Obtém detalhes de um item de documentação.")
111
- DOC_UPDATE = ("doc_update", "Atualiza um item de documentação.")
112
- DOC_DELETE = ("doc_delete", "Remove um item de documentação.")
113
- DOC_SEARCH = ("doc_search", "Busca itens de documentação por texto.")
114
- DOC_ROOTS = ("doc_roots", "Lista documentos raiz disponíveis.")
115
- DOC_RECENT = ("doc_recent", "Lista documentos acessados recentemente.")
116
- DOC_ANALYTICS = ("doc_analytics", "Retorna analytics dos documentos.")
117
- DOC_CHILDREN = ("doc_children", "Lista documentos filhos de um item.")
118
- DOC_TREE = ("doc_tree", "Recupera a árvore direta de um documento.")
119
- DOC_FULL_TREE = ("doc_full_tree", "Recupera a árvore completa de documentação.")
120
- DOC_MOVE = ("doc_move", "Move um documento para outro pai.")
121
- DOC_PUBLISH = ("doc_publish", "Altera status de publicação de um documento.")
122
- DOC_VERSION = ("doc_version", "Gera ou recupera versão de um documento.")
123
- DOC_DUPLICATE = ("doc_duplicate", "Duplica um documento existente.")
124
-
125
- HELP = ("knowledge_help", "Mostra as ações disponíveis e seus usos.")
111
+ DOC_CREATE = ("doc_create", "Creates a documentation item.")
112
+ DOC_LIST = ("doc_list", "Lists documentation items with filters.")
113
+ DOC_GET = ("doc_get", "Gets documentation item details.")
114
+ DOC_UPDATE = ("doc_update", "Updates a documentation item.")
115
+ DOC_DELETE = ("doc_delete", "Removes a documentation item.")
116
+ DOC_SEARCH = ("doc_search", "Searches documentation items by text.")
117
+ DOC_ROOTS = ("doc_roots", "Lists available root documents.")
118
+ DOC_RECENT = ("doc_recent", "Lists recently accessed documents.")
119
+ DOC_ANALYTICS = ("doc_analytics", "Returns document analytics.")
120
+ DOC_CHILDREN = ("doc_children", "Lists child documents of an item.")
121
+ DOC_TREE = ("doc_tree", "Retrieves the direct tree of a document.")
122
+ DOC_FULL_TREE = ("doc_full_tree", "Retrieves the full documentation tree.")
123
+ DOC_MOVE = ("doc_move", "Moves a document to another parent.")
124
+ DOC_PUBLISH = ("doc_publish", "Changes publication status of a document.")
125
+ DOC_VERSION = ("doc_version", "Generates or retrieves a document version.")
126
+ DOC_DUPLICATE = ("doc_duplicate", "Duplicates an existing document.")
127
+
128
+ HELP = ("knowledge_help", "Shows available actions and their uses.")
126
129
 
127
130
  @classmethod
128
131
  def choices(cls) -> List[str]:
@@ -131,7 +134,7 @@ class KnowledgeAction(str, Enum):
131
134
  @classmethod
132
135
  def formatted_help(cls) -> str:
133
136
  lines = [
134
- "| **Ação** | **Descrição** |",
137
+ "| **Action** | **Description** |",
135
138
  "| --- | --- |",
136
139
  ]
137
140
  for member in cls:
@@ -139,7 +142,7 @@ class KnowledgeAction(str, Enum):
139
142
  return "\n".join(lines)
140
143
 
141
144
 
142
- ACTION_FIELD_DESCRIPTION = "Ação de conhecimento. Escolha um dos valores: " + ", ".join(
145
+ ACTION_FIELD_DESCRIPTION = "Knowledge action. Choose one of the values: " + ", ".join(
143
146
  f"`{member.value}` ({member.description.rstrip('.')})."
144
147
  for member in KnowledgeAction
145
148
  )
@@ -156,165 +159,158 @@ _ALLOWED_DOC_TYPES = {
156
159
  class KnowledgeRequest(ToolRequest):
157
160
  action: KnowledgeAction = Field(description=ACTION_FIELD_DESCRIPTION)
158
161
  id: Optional[UUIDStr] = Field(
159
- default=None, description="ID principal do recurso (UUID)."
162
+ default=None, description="Primary resource ID (UUID)."
160
163
  )
161
- limit: int = Field(default=20, ge=1, le=100, description="Limite de resultados.")
164
+ limit: int = Field(default=20, ge=1, le=100, description="Result limit.")
162
165
  offset: int = Field(
163
- default=0, ge=0, description="Offset de paginação (quando suportado)."
164
- )
165
- team_id: Optional[UUIDStr] = Field(
166
- default=None, description="ID do time para filtros (UUID)."
166
+ default=0, ge=0, description="Pagination offset (when supported)."
167
167
  )
168
168
  board_id: Optional[UUIDStr] = Field(
169
- default=None, description="ID do board associado (UUID)."
169
+ default=None, description="Associated board ID (UUID)."
170
170
  )
171
171
  sprint_id: Optional[UUIDStr] = Field(
172
- default=None, description="ID do sprint associado (UUID)."
172
+ default=None, description="Associated sprint ID (UUID)."
173
173
  )
174
174
  epic_id: Optional[UUIDStr] = Field(
175
- default=None, description="ID do épico associado (UUID)."
175
+ default=None, description="Associated epic ID (UUID)."
176
176
  )
177
- query: Optional[str] = Field(default=None, description="Filtro/busca.")
177
+ query: Optional[str] = Field(default=None, description="Filter/search term.")
178
178
  return_content: Optional[bool] = Field(
179
- default=None, description="Retorna conteúdo completo."
179
+ default=None, description="Return full content."
180
180
  )
181
181
  return_description: Optional[bool] = Field(
182
- default=None, description="Retorna descrição completa."
182
+ default=None, description="Return full description."
183
183
  )
184
184
  return_metadata: Optional[bool] = Field(
185
- default=None, description="Retorna metadados completos."
185
+ default=None, description="Return full metadata."
186
186
  )
187
187
 
188
188
  # Work item fields
189
- work_title: Optional[TitleStr] = Field(
190
- default=None, description="Título do work item."
191
- )
189
+ work_title: Optional[TitleStr] = Field(default=None, description="Work item title.")
192
190
  work_description: Optional[MarkdownStr] = Field(
193
- default=None, description="Descrição do work item (Markdown)."
191
+ default=None, description="Work item description (Markdown)."
194
192
  )
195
193
  work_type: Optional[str] = Field(
196
194
  default="task",
197
- description="Tipo do work item (epic, feature, story, task, subtask, bug).",
195
+ description="Work item type (epic, feature, story, task, subtask, bug).",
198
196
  )
199
197
  work_status: Optional[str] = Field(
200
198
  default=None,
201
- description="Status do work item (backlog, todo, in_progress, review, testing, done, cancelled).",
199
+ description="Work item status (backlog, todo, in_progress, review, testing, done, cancelled).",
202
200
  )
203
201
  work_priority: Optional[str] = Field(
204
202
  default=None,
205
- description="Prioridade do work item (critical, high, medium, low).",
203
+ description="Work item priority (critical, high, medium, low).",
206
204
  )
207
205
  story_points: Optional[int] = Field(
208
206
  default=None, ge=0, le=100, description="Story points (0-100)."
209
207
  )
210
208
  assignee_id: Optional[UUIDStr] = Field(
211
- default=None, description="ID do responsável (UUID)."
209
+ default=None, description="Assignee ID (UUID)."
212
210
  )
213
211
  parent_id: Optional[UUIDStr] = Field(
214
- default=None, description="ID do item pai (UUID)."
212
+ default=None, description="Parent item ID (UUID)."
215
213
  )
216
214
  work_due_date: Optional[DateTimeStr] = Field(
217
- default=None, description="Data de vencimento do work item (ISO 8601)."
215
+ default=None, description="Work item due date (ISO 8601)."
218
216
  )
219
217
  work_tags: Optional[List[TagStr]] = Field(
220
- default=None, description="Tags do work item."
218
+ default=None, description="Work item tags."
221
219
  )
222
220
  work_item_ids: Optional[List[UUIDStr]] = Field(
223
221
  default=None,
224
- description="Lista de IDs de work items para operações em lote (UUIDs).",
222
+ description="List of work item IDs for batch operations (UUIDs).",
225
223
  )
226
224
 
227
225
  # Mode fields
228
226
  mode_id: Optional[UUIDStr] = Field(
229
- default=None, description="ID do modo relacionado (UUID)."
227
+ default=None, description="Related mode ID (UUID)."
230
228
  )
231
- mode_name: Optional[TitleStr] = Field(default=None, description="Nome do modo.")
229
+ mode_name: Optional[TitleStr] = Field(default=None, description="Mode name.")
232
230
  mode_description: Optional[DescriptionStr] = Field(
233
- default=None, description="Descrição do modo."
231
+ default=None, description="Mode description."
234
232
  )
235
233
  mode_content: Optional[MarkdownStr] = Field(
236
- default=None, description="Conteúdo do modo (Markdown)."
234
+ default=None, description="Mode content (Markdown)."
237
235
  )
238
236
  mode_is_default: Optional[bool] = Field(
239
- default=None, description="Indica se o modo é padrão."
237
+ default=None, description="Indicates if the mode is default."
240
238
  )
241
239
  mode_metadata: Optional[MarkdownStr] = Field(
242
- default=None, description="Metadata do modo para processamento de IA."
240
+ default=None, description="Mode metadata for AI processing."
243
241
  )
244
242
 
245
243
  # Rule fields
246
244
  rule_id: Optional[UUIDStr] = Field(
247
- default=None, description="ID da regra relacionada (UUID)."
245
+ default=None, description="Related rule ID (UUID)."
248
246
  )
249
- rule_name: Optional[TitleStr] = Field(default=None, description="Nome da regra.")
247
+ rule_name: Optional[TitleStr] = Field(default=None, description="Rule name.")
250
248
  rule_description: Optional[DescriptionStr] = Field(
251
- default=None, description="Descrição da regra."
249
+ default=None, description="Rule description."
252
250
  )
253
251
  rule_content: Optional[MarkdownStr] = Field(
254
- default=None, description="Conteúdo da regra (Markdown)."
252
+ default=None, description="Rule content (Markdown)."
255
253
  )
256
- rule_is_default: Optional[bool] = Field(default=None, description="Regra padrão.")
254
+ rule_is_default: Optional[bool] = Field(default=None, description="Default rule.")
257
255
  rule_metadata: Optional[MarkdownStr] = Field(
258
- default=None, description="Metadata da regra para processamento de IA."
256
+ default=None, description="Rule metadata for AI processing."
259
257
  )
260
258
 
261
259
  # Documentation fields
262
260
  doc_title: Optional[TitleStr] = Field(
263
- default=None, description="Título da documentação."
261
+ default=None, description="Documentation title."
264
262
  )
265
263
  doc_description: Optional[DescriptionStr] = Field(
266
- default=None, description="Descrição da documentação."
264
+ default=None, description="Documentation description."
267
265
  )
268
266
  doc_content: Optional[MarkdownStr] = Field(
269
- default=None, description="Conteúdo da documentação (Markdown)."
267
+ default=None, description="Documentation content (Markdown)."
270
268
  )
271
269
  doc_status: Optional[str] = Field(
272
270
  default=None,
273
- description="Status da documentação (draft, review, published, archived).",
271
+ description="Documentation status (draft, review, published, archived).",
274
272
  )
275
273
  doc_type: Optional[str] = Field(
276
- default=None, description="Tipo da documentação (folder, page, api_doc, guide)."
274
+ default=None,
275
+ description="Documentation type. Values: folder, page, api_doc, guide.",
277
276
  )
278
277
  doc_language: Optional[LanguageStr] = Field(
279
- default=None, description="Idioma da documentação (ex: pt, en, pt-BR)."
278
+ default=None, description="Documentation language (e.g.: pt, en, pt-BR)."
280
279
  )
281
280
  doc_parent_id: Optional[UUIDStr] = Field(
282
- default=None, description="ID do documento pai (UUID)."
283
- )
284
- doc_team_id: Optional[UUIDStr] = Field(
285
- default=None, description="ID do time responsável pela documentação (UUID)."
281
+ default=None, description="Parent document ID (UUID)."
286
282
  )
287
283
  doc_owner_id: Optional[UUIDStr] = Field(
288
- default=None, description="ID do dono (UUID)."
284
+ default=None, description="Owner ID (UUID)."
289
285
  )
290
286
  doc_reviewer_id: Optional[UUIDStr] = Field(
291
- default=None, description="ID do revisor (UUID)."
287
+ default=None, description="Reviewer ID (UUID)."
292
288
  )
293
289
  doc_version: Optional[VersionStr] = Field(
294
- default=None, description="Versão do documento (ex: 1.0, 2.1.3)."
290
+ default=None, description="Document version (e.g.: 1.0, 2.1.3)."
295
291
  )
296
- doc_category: Optional[CategoryStr] = Field(default=None, description="Categoria.")
292
+ doc_category: Optional[CategoryStr] = Field(default=None, description="Category.")
297
293
  doc_tags: Optional[List[TagStr]] = Field(default=None, description="Tags.")
298
294
  doc_position: Optional[int] = Field(
299
- default=None, ge=0, description="Posição desejada ao mover documentos."
295
+ default=None, ge=0, description="Desired position when moving documents."
300
296
  )
301
297
  doc_emoji: Optional[EmojiStr] = Field(
302
- default=None, description="Emoji exibido junto ao documento."
298
+ default=None, description="Emoji displayed with the document."
303
299
  )
304
300
  doc_emote: Optional[EmojiStr] = Field(
305
- default=None, description="Alias para emoji, mantido por compatibilidade."
301
+ default=None, description="Alias for emoji, kept for compatibility."
306
302
  )
307
303
  doc_keywords: Optional[List[TagStr]] = Field(
308
- default=None, description="Palavras-chave para busca."
304
+ default=None, description="Keywords for search."
309
305
  )
310
306
  doc_is_public: Optional[bool] = Field(
311
- default=None, description="Se o documento é público."
307
+ default=None, description="Whether the document is public."
312
308
  )
313
309
 
314
310
 
315
311
  class KnowledgeTool(Tool):
316
312
  name = "knowledge"
317
- description = "Operações de conhecimento do Fênix Cloud (Work Items, Boards, Sprints, Modes, Rules, Docs)."
313
+ description = "Fenix Cloud knowledge operations (Work Items, Boards, Sprints, Modes, Rules, Docs)."
318
314
  request_model = KnowledgeRequest
319
315
 
320
316
  def __init__(self, context: AppContext):
@@ -338,7 +334,7 @@ class KnowledgeTool(Tool):
338
334
  if action.value.startswith("doc_"):
339
335
  return await self._run_doc(payload)
340
336
  return text(
341
- "❌ Ação inválida para knowledge.\n\nEscolha um dos valores:\n"
337
+ "❌ Invalid action for knowledge.\n\nChoose one of the values:\n"
342
338
  + "\n".join(f"- `{value}`" for value in KnowledgeAction.choices())
343
339
  )
344
340
 
@@ -349,9 +345,7 @@ class KnowledgeTool(Tool):
349
345
  action = payload.action
350
346
  if action is KnowledgeAction.WORK_CREATE:
351
347
  if not payload.work_title:
352
- return text("❌ Informe work_title para criar o item.")
353
- if not payload.team_id:
354
- return text("❌ Informe team_id para criar o item.")
348
+ return text("❌ Provide work_title to create the item.")
355
349
  work = await self._service.work_create(
356
350
  {
357
351
  "title": payload.work_title,
@@ -364,12 +358,11 @@ class KnowledgeTool(Tool):
364
358
  "sprint_id": payload.sprint_id,
365
359
  "board_id": payload.board_id,
366
360
  "parent_id": payload.parent_id,
367
- "team_id": payload.team_id,
368
361
  "due_date": payload.work_due_date,
369
362
  "tags": payload.work_tags,
370
363
  }
371
364
  )
372
- return text(_format_work(work, header="✅ Work item criado"))
365
+ return text(_format_work(work, header="✅ Work item created"))
373
366
 
374
367
  if action is KnowledgeAction.WORK_LIST:
375
368
  items = await self._service.work_list(
@@ -382,19 +375,19 @@ class KnowledgeTool(Tool):
382
375
  board=payload.board_id,
383
376
  )
384
377
  if not items:
385
- return text("🎯 Nenhum work item encontrado.")
378
+ return text("🎯 No work items found.")
386
379
  body = "\n\n".join(_format_work(item) for item in items)
387
380
  return text(f"🎯 **Work items ({len(items)}):**\n\n{body}")
388
381
 
389
382
  if action is KnowledgeAction.WORK_GET:
390
383
  if not payload.id:
391
- return text("❌ Informe o ID do work item.")
384
+ return text("❌ Provide the work item ID.")
392
385
  work = await self._service.work_get(payload.id)
393
- return text(_format_work(work, header="🎯 Detalhes do work item"))
386
+ return text(_format_work(work, header="🎯 Work item details"))
394
387
 
395
388
  if action is KnowledgeAction.WORK_UPDATE:
396
389
  if not payload.id:
397
- return text("❌ Informe o ID do work item.")
390
+ return text("❌ Provide the work item ID.")
398
391
  work = await self._service.work_update(
399
392
  payload.id,
400
393
  {
@@ -408,106 +401,97 @@ class KnowledgeTool(Tool):
408
401
  "sprint_id": payload.sprint_id,
409
402
  "board_id": payload.board_id,
410
403
  "parent_id": payload.parent_id,
411
- "team_id": payload.team_id,
412
404
  "due_date": payload.work_due_date,
413
405
  "tags": payload.work_tags,
414
406
  },
415
407
  )
416
- return text(_format_work(work, header="✅ Work item atualizado"))
408
+ return text(_format_work(work, header="✅ Work item updated"))
417
409
 
418
410
  if action is KnowledgeAction.WORK_DELETE:
419
411
  if not payload.id:
420
- return text("❌ Informe o ID do work item.")
412
+ return text("❌ Provide the work item ID.")
421
413
  await self._service.work_delete(payload.id)
422
- return text(f"🗑️ Work item {payload.id} removido.")
414
+ return text(f"🗑️ Work item {payload.id} removed.")
423
415
 
424
416
  if action is KnowledgeAction.WORK_BACKLOG:
425
- team_id = sanitize_null(payload.team_id)
426
- if not team_id:
427
- return text("❌ Informe team_id para consultar o backlog.")
428
- items = await self._service.work_backlog(team_id=team_id)
417
+ items = await self._service.work_backlog()
429
418
  if not items:
430
- return text("📋 Backlog vazio para o time informado.")
419
+ return text("📋 Backlog empty.")
431
420
  body = "\n\n".join(_format_work(item) for item in items)
432
421
  return text(f"📋 **Backlog ({len(items)}):**\n\n{body}")
433
422
 
434
423
  if action is KnowledgeAction.WORK_SEARCH:
435
424
  query = sanitize_null(payload.query)
436
- team_id = sanitize_null(payload.team_id)
437
- if not query or not team_id:
438
- return text("❌ Informe query e team_id para buscar work items.")
425
+ if not query:
426
+ return text("❌ Provide query to search work items.")
439
427
  items = await self._service.work_search(
440
428
  query=query,
441
- team_id=team_id,
442
429
  limit=payload.limit,
443
430
  )
444
431
  if not items:
445
- return text("🔍 Nenhum work item encontrado.")
432
+ return text("🔍 No work items found.")
446
433
  body = "\n\n".join(_format_work(item) for item in items)
447
- return text(f"🔍 **Resultados ({len(items)}):**\n\n{body}")
434
+ return text(f"🔍 **Results ({len(items)}):**\n\n{body}")
448
435
 
449
436
  if action is KnowledgeAction.WORK_ANALYTICS:
450
- team_id = sanitize_null(payload.team_id)
451
- if not team_id:
452
- return text("❌ Informe team_id para obter analytics.")
453
- analytics = await self._service.work_analytics(team_id=team_id)
454
- lines = ["📊 **Analytics de Work Items**"]
437
+ analytics = await self._service.work_analytics()
438
+ lines = ["📊 **Work Items Analytics**"]
455
439
  for key, value in analytics.items():
456
440
  lines.append(f"- {key}: {value}")
457
441
  return text("\n".join(lines))
458
442
 
459
443
  if action is KnowledgeAction.WORK_BY_BOARD:
460
444
  if not payload.board_id:
461
- return text("❌ Informe board_id para listar os itens.")
445
+ return text("❌ Provide board_id to list items.")
462
446
  items = await self._service.work_by_board(board_id=payload.board_id)
463
447
  if not items:
464
- return text("🗂️ Nenhum work item para o board informado.")
448
+ return text("🗂️ No work items for the specified board.")
465
449
  body = "\n\n".join(_format_work(item) for item in items)
466
- return text(f"🗂️ **Itens do board ({len(items)}):**\n\n{body}")
450
+ return text(f"🗂️ **Board items ({len(items)}):**\n\n{body}")
467
451
 
468
452
  if action is KnowledgeAction.WORK_BY_SPRINT:
469
453
  if not payload.sprint_id:
470
- return text("❌ Informe sprint_id para listar os itens.")
454
+ return text("❌ Provide sprint_id to list items.")
471
455
  items = await self._service.work_by_sprint(sprint_id=payload.sprint_id)
472
456
  if not items:
473
- return text("🏃 Nenhum item vinculado ao sprint informado.")
457
+ return text("🏃 No items linked to the specified sprint.")
474
458
  body = "\n\n".join(_format_work(item) for item in items)
475
- return text(f"🏃 **Work items do sprint ({len(items)}):**\n\n{body}")
459
+ return text(f"🏃 **Sprint work items ({len(items)}):**\n\n{body}")
476
460
 
477
461
  if action is KnowledgeAction.WORK_BY_EPIC:
478
462
  if not payload.epic_id:
479
- return text("❌ Informe epic_id para listar os itens.")
463
+ return text("❌ Provide epic_id to list items.")
480
464
  items = await self._service.work_by_epic(epic_id=payload.epic_id)
481
465
  if not items:
482
- return text("📦 Nenhum item vinculado ao épico informado.")
466
+ return text("📦 No items linked to the specified epic.")
483
467
  body = "\n\n".join(_format_work(item) for item in items)
484
- return text(f"📦 **Work items do épico ({len(items)}):**\n\n{body}")
468
+ return text(f"📦 **Epic work items ({len(items)}):**\n\n{body}")
485
469
 
486
470
  if action is KnowledgeAction.WORK_CHILDREN:
487
471
  if not payload.id:
488
- return text("❌ Informe o ID do work item pai.")
472
+ return text("❌ Provide the parent work item ID.")
489
473
  items = await self._service.work_children(payload.id)
490
474
  if not items:
491
- return text("👶 Nenhum item filho encontrado.")
475
+ return text("👶 No child items found.")
492
476
  body = "\n\n".join(_format_work(item) for item in items)
493
- return text(f"👶 **Work items filhos ({len(items)}):**\n\n{body}")
477
+ return text(f"👶 **Child work items ({len(items)}):**\n\n{body}")
494
478
 
495
479
  if action is KnowledgeAction.WORK_STATUS_UPDATE:
496
480
  if not payload.id:
497
- return text("❌ Informe o ID do work item.")
481
+ return text("❌ Provide the work item ID.")
498
482
  if not payload.work_status:
499
- return text("❌ Informe work_status para atualizar.")
483
+ return text("❌ Provide work_status to update.")
500
484
  work = await self._service.work_update_status(
501
485
  payload.id,
502
486
  {"status": payload.work_status},
503
487
  )
504
- return text(_format_work(work, header="✅ Status atualizado"))
488
+ return text(_format_work(work, header="✅ Status updated"))
505
489
 
506
490
  if action is KnowledgeAction.WORK_ASSIGN_SPRINT:
507
491
  if not payload.sprint_id:
508
- return text("❌ Informe sprint_id para atribuir os itens.")
492
+ return text("❌ Provide sprint_id to assign items.")
509
493
  if not payload.work_item_ids:
510
- return text("❌ Informe work_item_ids com a lista de IDs.")
494
+ return text("❌ Provide work_item_ids with the list of IDs.")
511
495
  await self._service.work_assign_to_sprint(
512
496
  {
513
497
  "sprint_id": payload.sprint_id,
@@ -515,10 +499,10 @@ class KnowledgeTool(Tool):
515
499
  }
516
500
  )
517
501
  count = len(payload.work_item_ids)
518
- return text(f"✅ {count} work item(s) atribuído(s) ao sprint.")
502
+ return text(f"✅ {count} work item(s) assigned to sprint.")
519
503
 
520
504
  return text(
521
- "❌ Ação de work item não suportada.\n\nEscolha um dos valores:\n"
505
+ "❌ Unsupported work item action.\n\nChoose one of the values:\n"
522
506
  + "\n".join(
523
507
  f"- `{value}`"
524
508
  for value in KnowledgeAction.choices()
@@ -536,46 +520,44 @@ class KnowledgeTool(Tool):
536
520
  limit=payload.limit, offset=payload.offset
537
521
  )
538
522
  if not boards:
539
- return text("🗂️ Nenhum board encontrado.")
523
+ return text("🗂️ No boards found.")
540
524
  body = "\n\n".join(_format_board(board) for board in boards)
541
525
  return text(f"🗂️ **Boards ({len(boards)}):**\n\n{body}")
542
526
 
543
527
  if action is KnowledgeAction.BOARD_BY_TEAM:
544
- if not payload.team_id:
545
- return text("❌ Informe team_id para listar boards do time.")
546
- boards = await self._service.board_list_by_team(payload.team_id)
528
+ boards = await self._service.board_list_by_team()
547
529
  if not boards:
548
- return text("🗂️ Nenhum board cadastrado para o time.")
530
+ return text("🗂️ No boards registered for the team.")
549
531
  body = "\n\n".join(_format_board(board) for board in boards)
550
- return text(f"🗂️ **Boards do time ({len(boards)}):**\n\n{body}")
532
+ return text(f"🗂️ **Team boards ({len(boards)}):**\n\n{body}")
551
533
 
552
534
  if action is KnowledgeAction.BOARD_FAVORITES:
553
535
  boards = await self._service.board_favorites()
554
536
  if not boards:
555
- return text("⭐ Nenhum board favorito cadastrado.")
537
+ return text("⭐ No favorite boards registered.")
556
538
  body = "\n\n".join(_format_board(board) for board in boards)
557
- return text(f"⭐ **Boards favoritos ({len(boards)}):**\n\n{body}")
539
+ return text(f"⭐ **Favorite boards ({len(boards)}):**\n\n{body}")
558
540
 
559
541
  if action is KnowledgeAction.BOARD_GET:
560
542
  if not payload.board_id:
561
- return text("❌ Informe board_id para consultar detalhes.")
543
+ return text("❌ Provide board_id to get details.")
562
544
  board = await self._service.board_get(payload.board_id)
563
- return text(_format_board(board, header="🗂️ Detalhes do board"))
545
+ return text(_format_board(board, header="🗂️ Board details"))
564
546
 
565
547
  if action is KnowledgeAction.BOARD_COLUMNS:
566
548
  if not payload.board_id:
567
- return text("❌ Informe board_id para listar colunas.")
549
+ return text("❌ Provide board_id to list columns.")
568
550
  columns = await self._service.board_columns(payload.board_id)
569
551
  if not columns:
570
- return text("📊 Board sem colunas cadastradas.")
552
+ return text("📊 Board has no columns registered.")
571
553
  body = "\n".join(
572
- f"- {col.get('name', 'Sem nome')} (ID: {col.get('id')})"
554
+ f"- {col.get('name', 'Unnamed')} (ID: {col.get('id')})"
573
555
  for col in columns
574
556
  )
575
- return text(f"📊 **Colunas do board:**\n{body}")
557
+ return text(f"📊 **Board columns:**\n{body}")
576
558
 
577
559
  return text(
578
- "❌ Ação de board não suportada.\n\nEscolha um dos valores:\n"
560
+ "❌ Unsupported board action.\n\nChoose one of the values:\n"
579
561
  + "\n".join(
580
562
  f"- `{value}`"
581
563
  for value in KnowledgeAction.choices()
@@ -593,44 +575,40 @@ class KnowledgeTool(Tool):
593
575
  limit=payload.limit, offset=payload.offset
594
576
  )
595
577
  if not sprints:
596
- return text("🏃 Nenhum sprint encontrado.")
578
+ return text("🏃 No sprints found.")
597
579
  body = "\n\n".join(_format_sprint(sprint) for sprint in sprints)
598
580
  return text(f"🏃 **Sprints ({len(sprints)}):**\n\n{body}")
599
581
 
600
582
  if action is KnowledgeAction.SPRINT_BY_TEAM:
601
- if not payload.team_id:
602
- return text("❌ Informe team_id para listar sprints do time.")
603
- sprints = await self._service.sprint_list_by_team(payload.team_id)
583
+ sprints = await self._service.sprint_list_by_team()
604
584
  if not sprints:
605
- return text("🏃 Nenhum sprint cadastrado para o time.")
585
+ return text("🏃 No sprints registered for the team.")
606
586
  body = "\n\n".join(_format_sprint(sprint) for sprint in sprints)
607
- return text(f"🏃 **Sprints do time ({len(sprints)}):**\n\n{body}")
587
+ return text(f"🏃 **Team sprints ({len(sprints)}):**\n\n{body}")
608
588
 
609
589
  if action is KnowledgeAction.SPRINT_ACTIVE:
610
- if not payload.team_id:
611
- return text("❌ Informe team_id para consultar o sprint ativo.")
612
- sprint = await self._service.sprint_active(payload.team_id)
590
+ sprint = await self._service.sprint_active()
613
591
  if not sprint:
614
- return text("⏳ Nenhum sprint ativo no momento.")
615
- return text(_format_sprint(sprint, header="⏳ Sprint ativo"))
592
+ return text("⏳ No active sprint at the moment.")
593
+ return text(_format_sprint(sprint, header="⏳ Active sprint"))
616
594
 
617
595
  if action is KnowledgeAction.SPRINT_GET:
618
596
  if not payload.sprint_id:
619
- return text("❌ Informe sprint_id para consultar detalhes.")
597
+ return text("❌ Provide sprint_id to get details.")
620
598
  sprint = await self._service.sprint_get(payload.sprint_id)
621
- return text(_format_sprint(sprint, header="🏃 Detalhes do sprint"))
599
+ return text(_format_sprint(sprint, header="🏃 Sprint details"))
622
600
 
623
601
  if action is KnowledgeAction.SPRINT_WORK_ITEMS:
624
602
  if not payload.sprint_id:
625
- return text("❌ Informe sprint_id para listar os itens.")
603
+ return text("❌ Provide sprint_id to list items.")
626
604
  items = await self._service.sprint_work_items(payload.sprint_id)
627
605
  if not items:
628
- return text("🏃 Nenhum item vinculado ao sprint informado.")
606
+ return text("🏃 No items linked to the specified sprint.")
629
607
  body = "\n\n".join(_format_work(item) for item in items)
630
- return text(f"🏃 **Itens do sprint ({len(items)}):**\n\n{body}")
608
+ return text(f"🏃 **Sprint items ({len(items)}):**\n\n{body}")
631
609
 
632
610
  return text(
633
- "❌ Ação de sprint não suportada.\n\nEscolha um dos valores:\n"
611
+ "❌ Unsupported sprint action.\n\nChoose one of the values:\n"
634
612
  + "\n".join(
635
613
  f"- `{value}`"
636
614
  for value in KnowledgeAction.choices()
@@ -645,7 +623,7 @@ class KnowledgeTool(Tool):
645
623
  action = payload.action
646
624
  if action is KnowledgeAction.MODE_CREATE:
647
625
  if not payload.mode_name:
648
- return text("❌ Informe mode_name para criar o modo.")
626
+ return text("❌ Provide mode_name to create the mode.")
649
627
  mode = await self._service.mode_create(
650
628
  {
651
629
  "name": payload.mode_name,
@@ -655,7 +633,7 @@ class KnowledgeTool(Tool):
655
633
  "metadata": payload.mode_metadata,
656
634
  }
657
635
  )
658
- return text(_format_mode(mode, header="✅ Modo criado"))
636
+ return text(_format_mode(mode, header="✅ Mode created"))
659
637
 
660
638
  if action is KnowledgeAction.MODE_LIST:
661
639
  modes = await self._service.mode_list(
@@ -664,23 +642,23 @@ class KnowledgeTool(Tool):
664
642
  return_metadata=payload.return_metadata,
665
643
  )
666
644
  if not modes:
667
- return text("🎭 Nenhum modo encontrado.")
645
+ return text("🎭 No modes found.")
668
646
  body = "\n\n".join(_format_mode(mode) for mode in modes)
669
647
  return text(f"🎭 **Modes ({len(modes)}):**\n\n{body}")
670
648
 
671
649
  if action is KnowledgeAction.MODE_GET:
672
650
  if not payload.mode_id:
673
- return text("❌ Informe mode_id para consultar detalhes.")
651
+ return text("❌ Provide mode_id to get details.")
674
652
  mode = await self._service.mode_get(
675
653
  payload.mode_id,
676
654
  return_description=payload.return_description,
677
655
  return_metadata=payload.return_metadata,
678
656
  )
679
- return text(_format_mode(mode, header="🎭 Detalhes do modo"))
657
+ return text(_format_mode(mode, header="🎭 Mode details"))
680
658
 
681
659
  if action is KnowledgeAction.MODE_UPDATE:
682
660
  if not payload.mode_id:
683
- return text("❌ Informe mode_id para atualizar.")
661
+ return text("❌ Provide mode_id to update.")
684
662
  mode = await self._service.mode_update(
685
663
  payload.mode_id,
686
664
  {
@@ -691,53 +669,53 @@ class KnowledgeTool(Tool):
691
669
  "metadata": payload.mode_metadata,
692
670
  },
693
671
  )
694
- return text(_format_mode(mode, header="✅ Modo atualizado"))
672
+ return text(_format_mode(mode, header="✅ Mode updated"))
695
673
 
696
674
  if action is KnowledgeAction.MODE_DELETE:
697
675
  if not payload.mode_id:
698
- return text("❌ Informe mode_id para remover.")
676
+ return text("❌ Provide mode_id to remove.")
699
677
  await self._service.mode_delete(payload.mode_id)
700
- return text(f"🗑️ Modo {payload.mode_id} removido.")
678
+ return text(f"🗑️ Mode {payload.mode_id} removed.")
701
679
 
702
680
  if action is KnowledgeAction.MODE_RULE_ADD:
703
681
  if not payload.mode_id or not payload.rule_id:
704
- return text("❌ Informe mode_id e rule_id para associar.")
682
+ return text("❌ Provide mode_id and rule_id to associate.")
705
683
  link = await self._service.mode_rule_add(payload.mode_id, payload.rule_id)
706
684
  return text(
707
685
  "\n".join(
708
686
  [
709
- "🔗 **Regra associada ao modo!**",
710
- f"Modo: {link.get('modeId', payload.mode_id)}",
711
- f"Regra: {link.get('ruleId', payload.rule_id)}",
687
+ "🔗 **Rule associated with mode!**",
688
+ f"Mode: {link.get('modeId', payload.mode_id)}",
689
+ f"Rule: {link.get('ruleId', payload.rule_id)}",
712
690
  ]
713
691
  )
714
692
  )
715
693
 
716
694
  if action is KnowledgeAction.MODE_RULE_REMOVE:
717
695
  if not payload.mode_id or not payload.rule_id:
718
- return text("❌ Informe mode_id e rule_id para remover a associação.")
696
+ return text("❌ Provide mode_id and rule_id to remove the association.")
719
697
  await self._service.mode_rule_remove(payload.mode_id, payload.rule_id)
720
- return text("🔗 Associação removida.")
698
+ return text("🔗 Association removed.")
721
699
 
722
700
  if action is KnowledgeAction.MODE_RULES:
723
701
  if payload.mode_id:
724
702
  rules = await self._service.mode_rules(payload.mode_id)
725
- context_label = f"modo {payload.mode_id}"
703
+ context_label = f"mode {payload.mode_id}"
726
704
  elif payload.rule_id:
727
705
  rules = await self._service.mode_rules_for_rule(payload.rule_id)
728
- context_label = f"regra {payload.rule_id}"
706
+ context_label = f"rule {payload.rule_id}"
729
707
  else:
730
- return text("❌ Informe mode_id ou rule_id para listar associações.")
708
+ return text("❌ Provide mode_id or rule_id to list associations.")
731
709
  if not rules:
732
- return text("🔗 Nenhuma associação encontrada.")
710
+ return text("🔗 No associations found.")
733
711
  body = "\n".join(
734
- f"- {item.get('name', 'Sem nome')} (ID: {item.get('id')})"
712
+ f"- {item.get('name', 'Unnamed')} (ID: {item.get('id')})"
735
713
  for item in rules
736
714
  )
737
- return text(f"🔗 **Associações para {context_label}:**\n{body}")
715
+ return text(f"🔗 **Associations for {context_label}:**\n{body}")
738
716
 
739
717
  return text(
740
- "❌ Ação de modo não suportada.\n\nEscolha um dos valores:\n"
718
+ "❌ Unsupported mode action.\n\nChoose one of the values:\n"
741
719
  + "\n".join(
742
720
  f"- `{value}`"
743
721
  for value in KnowledgeAction.choices()
@@ -752,7 +730,7 @@ class KnowledgeTool(Tool):
752
730
  action = payload.action
753
731
  if action is KnowledgeAction.RULE_CREATE:
754
732
  if not payload.rule_name or not payload.rule_content:
755
- return text("❌ Informe rule_name e rule_content.")
733
+ return text("❌ Provide rule_name and rule_content.")
756
734
  rule = await self._service.rule_create(
757
735
  {
758
736
  "name": payload.rule_name,
@@ -762,7 +740,7 @@ class KnowledgeTool(Tool):
762
740
  "metadata": payload.rule_metadata,
763
741
  }
764
742
  )
765
- return text(_format_rule(rule, header="✅ Regra criada"))
743
+ return text(_format_rule(rule, header="✅ Rule created"))
766
744
 
767
745
  if action is KnowledgeAction.RULE_LIST:
768
746
  rules = await self._service.rule_list(
@@ -771,24 +749,24 @@ class KnowledgeTool(Tool):
771
749
  return_modes=payload.return_metadata,
772
750
  )
773
751
  if not rules:
774
- return text("📋 Nenhuma regra encontrada.")
752
+ return text("📋 No rules found.")
775
753
  body = "\n\n".join(_format_rule(rule) for rule in rules)
776
- return text(f"📋 **Regras ({len(rules)}):**\n\n{body}")
754
+ return text(f"📋 **Rules ({len(rules)}):**\n\n{body}")
777
755
 
778
756
  if action is KnowledgeAction.RULE_GET:
779
757
  if not payload.rule_id:
780
- return text("❌ Informe rule_id para consultar detalhes.")
758
+ return text("❌ Provide rule_id to get details.")
781
759
  rule = await self._service.rule_get(
782
760
  payload.rule_id,
783
761
  return_description=payload.return_description,
784
762
  return_metadata=payload.return_metadata,
785
763
  return_modes=payload.return_metadata,
786
764
  )
787
- return text(_format_rule(rule, header="📋 Detalhes da regra"))
765
+ return text(_format_rule(rule, header="📋 Rule details"))
788
766
 
789
767
  if action is KnowledgeAction.RULE_UPDATE:
790
768
  if not payload.rule_id:
791
- return text("❌ Informe rule_id para atualizar.")
769
+ return text("❌ Provide rule_id to update.")
792
770
  rule = await self._service.rule_update(
793
771
  payload.rule_id,
794
772
  {
@@ -799,16 +777,16 @@ class KnowledgeTool(Tool):
799
777
  "metadata": payload.rule_metadata,
800
778
  },
801
779
  )
802
- return text(_format_rule(rule, header="✅ Regra atualizada"))
780
+ return text(_format_rule(rule, header="✅ Rule updated"))
803
781
 
804
782
  if action is KnowledgeAction.RULE_DELETE:
805
783
  if not payload.rule_id:
806
- return text("❌ Informe rule_id para remover.")
784
+ return text("❌ Provide rule_id to remove.")
807
785
  await self._service.rule_delete(payload.rule_id)
808
- return text(f"🗑️ Regra {payload.rule_id} removida.")
786
+ return text(f"🗑️ Rule {payload.rule_id} removed.")
809
787
 
810
788
  return text(
811
- "❌ Ação de regra não suportada.\n\nEscolha um dos valores:\n"
789
+ "❌ Unsupported rule action.\n\nChoose one of the values:\n"
812
790
  + "\n".join(
813
791
  f"- `{value}`"
814
792
  for value in KnowledgeAction.choices()
@@ -823,11 +801,11 @@ class KnowledgeTool(Tool):
823
801
  action = payload.action
824
802
  if action is KnowledgeAction.DOC_CREATE:
825
803
  if not payload.doc_title:
826
- return text("❌ Informe doc_title para criar a documentação.")
804
+ return text("❌ Provide doc_title to create the documentation.")
827
805
  if payload.doc_type and payload.doc_type not in _ALLOWED_DOC_TYPES:
828
806
  allowed = ", ".join(sorted(_ALLOWED_DOC_TYPES))
829
807
  return text(
830
- "❌ doc_type inválido. Use um dos valores suportados: " + allowed
808
+ "❌ Invalid doc_type. Use one of the supported values: " + allowed
831
809
  )
832
810
  doc = await self._service.doc_create(
833
811
  {
@@ -838,7 +816,6 @@ class KnowledgeTool(Tool):
838
816
  "doc_type": sanitize_null(payload.doc_type),
839
817
  "language": sanitize_null(payload.doc_language),
840
818
  "parent_id": sanitize_null(payload.doc_parent_id),
841
- "team_id": sanitize_null(payload.doc_team_id or payload.team_id),
842
819
  "owner_user_id": sanitize_null(payload.doc_owner_id),
843
820
  "reviewer_user_id": sanitize_null(payload.doc_reviewer_id),
844
821
  "version": sanitize_null(payload.doc_version),
@@ -849,7 +826,7 @@ class KnowledgeTool(Tool):
849
826
  "is_public": payload.doc_is_public,
850
827
  }
851
828
  )
852
- return text(_format_doc(doc, header="✅ Documentação criada"))
829
+ return text(_format_doc(doc, header="✅ Documentation created"))
853
830
 
854
831
  if action is KnowledgeAction.DOC_LIST:
855
832
  docs = await self._service.doc_list(
@@ -858,26 +835,26 @@ class KnowledgeTool(Tool):
858
835
  returnContent=payload.return_content,
859
836
  )
860
837
  if not docs:
861
- return text("📄 Nenhuma documentação encontrada.")
838
+ return text("📄 No documentation found.")
862
839
  body = "\n\n".join(_format_doc(doc) for doc in docs)
863
- return text(f"📄 **Documentos ({len(docs)}):**\n\n{body}")
840
+ return text(f"📄 **Documents ({len(docs)}):**\n\n{body}")
864
841
 
865
842
  if action is KnowledgeAction.DOC_GET:
866
843
  if not payload.id:
867
- return text("❌ Informe o ID da documentação.")
844
+ return text("❌ Provide the documentation ID.")
868
845
  doc = await self._service.doc_get(
869
846
  payload.id,
870
847
  returnContent=payload.return_content,
871
848
  )
872
- return text(_format_doc(doc, header="📄 Detalhes da documentação"))
849
+ return text(_format_doc(doc, header="📄 Documentation details"))
873
850
 
874
851
  if action is KnowledgeAction.DOC_UPDATE:
875
852
  if not payload.id:
876
- return text("❌ Informe o ID da documentação.")
853
+ return text("❌ Provide the documentation ID.")
877
854
  if payload.doc_type and payload.doc_type not in _ALLOWED_DOC_TYPES:
878
855
  allowed = ", ".join(sorted(_ALLOWED_DOC_TYPES))
879
856
  return text(
880
- "❌ doc_type inválido. Use um dos valores suportados: " + allowed
857
+ "❌ Invalid doc_type. Use one of the supported values: " + allowed
881
858
  )
882
859
  doc = await self._service.doc_update(
883
860
  payload.id,
@@ -889,7 +866,6 @@ class KnowledgeTool(Tool):
889
866
  "doc_type": sanitize_null(payload.doc_type),
890
867
  "language": sanitize_null(payload.doc_language),
891
868
  "parent_id": sanitize_null(payload.doc_parent_id),
892
- "team_id": sanitize_null(payload.doc_team_id or payload.team_id),
893
869
  "owner_user_id": sanitize_null(payload.doc_owner_id),
894
870
  "reviewer_user_id": sanitize_null(payload.doc_reviewer_id),
895
871
  "version": sanitize_null(payload.doc_version),
@@ -900,115 +876,99 @@ class KnowledgeTool(Tool):
900
876
  "is_public": payload.doc_is_public,
901
877
  },
902
878
  )
903
- return text(_format_doc(doc, header="✅ Documentação atualizada"))
879
+ return text(_format_doc(doc, header="✅ Documentation updated"))
904
880
 
905
881
  if action is KnowledgeAction.DOC_DELETE:
906
882
  if not payload.id:
907
- return text("❌ Informe o ID da documentação.")
883
+ return text("❌ Provide the documentation ID.")
908
884
  await self._service.doc_delete(payload.id)
909
- return text(f"🗑️ Documentação {payload.id} removida.")
885
+ return text(f"🗑️ Documentation {payload.id} removed.")
910
886
 
911
887
  if action is KnowledgeAction.DOC_SEARCH:
912
888
  query = sanitize_null(payload.query)
913
- team_id = sanitize_null(payload.doc_team_id or payload.team_id)
914
- if not query or not team_id:
915
- return text("❌ Informe query e team_id para buscar documentação.")
889
+ if not query:
890
+ return text("❌ Provide query to search documentation.")
916
891
  docs = await self._service.doc_search(
917
892
  query=query,
918
- team_id=team_id,
919
893
  limit=payload.limit,
920
894
  )
921
895
  if not docs:
922
- return text(
923
- "🔍 Nenhum documento encontrado para os filtros informados."
924
- )
896
+ return text("🔍 No documents found for the specified filters.")
925
897
  body = "\n\n".join(_format_doc(doc) for doc in docs)
926
- return text(f"🔍 **Resultados ({len(docs)}):**\n\n{body}")
898
+ return text(f"🔍 **Results ({len(docs)}):**\n\n{body}")
927
899
 
928
900
  if action is KnowledgeAction.DOC_ROOTS:
929
- team_id = sanitize_null(payload.doc_team_id or payload.team_id)
930
- if not team_id:
931
- return text("❌ Informe team_id para listar raízes.")
932
- docs = await self._service.doc_roots(team_id=team_id)
901
+ docs = await self._service.doc_roots()
933
902
  if not docs:
934
- return text("📚 Nenhuma raiz encontrada.")
903
+ return text("📚 No roots found.")
935
904
  body = "\n".join(
936
- f"- {doc.get('title', 'Sem título')} (ID: {doc.get('id')})"
905
+ f"- {doc.get('title', 'Untitled')} (ID: {doc.get('id')})"
937
906
  for doc in docs
938
907
  )
939
- return text(f"📚 **Raízes de documentação:**\n{body}")
908
+ return text(f"📚 **Documentation roots:**\n{body}")
940
909
 
941
910
  if action is KnowledgeAction.DOC_RECENT:
942
- team_id = sanitize_null(payload.doc_team_id or payload.team_id)
943
- if not team_id:
944
- return text("❌ Informe team_id para listar documentos recentes.")
945
911
  docs = await self._service.doc_recent(
946
- team_id=team_id,
947
912
  limit=payload.limit,
948
913
  )
949
914
  if not docs:
950
- return text("🕒 Nenhuma documentação recente encontrada.")
915
+ return text("🕒 No recent documentation found.")
951
916
  body = "\n\n".join(_format_doc(doc) for doc in docs)
952
- return text(f"🕒 **Documentos recentes ({len(docs)}):**\n\n{body}")
917
+ return text(f"🕒 **Recent documents ({len(docs)}):**\n\n{body}")
953
918
 
954
919
  if action is KnowledgeAction.DOC_ANALYTICS:
955
- team_id = sanitize_null(payload.doc_team_id or payload.team_id)
956
- if not team_id:
957
- return text("❌ Informe team_id para obter analytics.")
958
- analytics = await self._service.doc_analytics(team_id=team_id)
959
- lines = ["📊 **Analytics de Documentação**"]
920
+ analytics = await self._service.doc_analytics()
921
+ lines = ["📊 **Documentation Analytics**"]
960
922
  for key, value in analytics.items():
961
923
  lines.append(f"- {key}: {value}")
962
924
  return text("\n".join(lines))
963
925
 
964
926
  if action is KnowledgeAction.DOC_CHILDREN:
965
927
  if not payload.id:
966
- return text("❌ Informe o ID da documentação.")
928
+ return text("❌ Provide the documentation ID.")
967
929
  docs = await self._service.doc_children(payload.id)
968
930
  if not docs:
969
- return text("📄 Nenhum filho cadastrado para o documento informado.")
931
+ return text("📄 No children registered for the specified document.")
970
932
  body = "\n".join(
971
- f"- {doc.get('title', 'Sem título')} (ID: {doc.get('id')})"
933
+ f"- {doc.get('title', 'Untitled')} (ID: {doc.get('id')})"
972
934
  for doc in docs
973
935
  )
974
- return text(f"📄 **Filhos:**\n{body}")
936
+ return text(f"📄 **Children:**\n{body}")
975
937
 
976
938
  if action is KnowledgeAction.DOC_TREE:
977
939
  if not payload.id:
978
- return text("❌ Informe o ID da documentação.")
940
+ return text("❌ Provide the documentation ID.")
979
941
  tree = await self._service.doc_tree(payload.id)
980
- return text(f"🌳 **Árvore de documentação para {payload.id}:**\n{tree}")
942
+ return text(f"🌳 **Documentation tree for {payload.id}:**\n{tree}")
981
943
 
982
944
  if action is KnowledgeAction.DOC_FULL_TREE:
983
945
  tree = await self._service.doc_full_tree()
984
- return text(f"🌳 **Árvore completa de documentação:**\n{tree}")
946
+ return text(f"🌳 **Full documentation tree:**\n{tree}")
985
947
 
986
948
  if action is KnowledgeAction.DOC_MOVE:
987
949
  if not payload.id:
988
- return text("❌ Informe o ID da documentação.")
950
+ return text("❌ Provide the documentation ID.")
989
951
  if payload.doc_parent_id is None and payload.doc_position is None:
990
- return text(
991
- "❌ Informe doc_parent_id, doc_position ou ambos para mover."
992
- )
952
+ return text("❌ Provide doc_parent_id, doc_position or both to move.")
993
953
  move_payload = {
994
954
  "new_parent_id": payload.doc_parent_id,
995
955
  "new_position": payload.doc_position,
996
956
  }
997
957
  doc = await self._service.doc_move(payload.id, move_payload)
998
- return text(_format_doc(doc, header="📦 Documentação movida"))
958
+ return text(_format_doc(doc, header="📦 Documentation moved"))
999
959
 
1000
960
  if action is KnowledgeAction.DOC_PUBLISH:
1001
961
  if not payload.id:
1002
- return text("❌ Informe o ID da documentação.")
962
+ return text("❌ Provide the documentation ID.")
1003
963
  result = await self._service.doc_publish(payload.id)
1004
- return text(f"🗞️ Documento publicado: {result}")
964
+ return text(f"🗞️ Document published: {result}")
1005
965
 
1006
966
  if action is KnowledgeAction.DOC_VERSION:
1007
967
  if not payload.id:
1008
- return text("❌ Informe o ID da documentação.")
968
+ return text("❌ Provide the documentation ID.")
1009
969
  if not payload.doc_version:
1010
970
  return text(
1011
- "❌ Informe doc_version com o número/identificador da versão."
971
+ "❌ Provide doc_version with the version number/identifier."
1012
972
  )
1013
973
  version_payload = {
1014
974
  "title": payload.doc_title or f"Version {payload.doc_version}",
@@ -1016,24 +976,23 @@ class KnowledgeTool(Tool):
1016
976
  "content": payload.doc_content,
1017
977
  }
1018
978
  doc = await self._service.doc_version(payload.id, version_payload)
1019
- return text(_format_doc(doc, header="🗞️ Nova versão criada"))
979
+ return text(_format_doc(doc, header="🗞️ New version created"))
1020
980
 
1021
981
  if action is KnowledgeAction.DOC_DUPLICATE:
1022
982
  if not payload.id:
1023
- return text("❌ Informe o ID da documentação.")
983
+ return text("❌ Provide the documentation ID.")
1024
984
  if not payload.doc_title:
1025
- return text("❌ Informe doc_title para nomear a cópia.")
985
+ return text("❌ Provide doc_title to name the copy.")
1026
986
  doc = await self._service.doc_duplicate(
1027
987
  payload.id,
1028
988
  {
1029
989
  "title": payload.doc_title,
1030
- "team_id": payload.doc_team_id or payload.team_id,
1031
990
  },
1032
991
  )
1033
- return text(_format_doc(doc, header="🗂️ Documento duplicado"))
992
+ return text(_format_doc(doc, header="🗂️ Document duplicated"))
1034
993
 
1035
994
  return text(
1036
- "❌ Ação de documentação não suportada.\n\nEscolha um dos valores:\n"
995
+ "❌ Unsupported documentation action.\n\nChoose one of the values:\n"
1037
996
  + "\n".join(
1038
997
  f"- `{value}`"
1039
998
  for value in KnowledgeAction.choices()
@@ -1043,7 +1002,7 @@ class KnowledgeTool(Tool):
1043
1002
 
1044
1003
  async def _handle_help(self):
1045
1004
  return text(
1046
- "📚 **Ações disponíveis para knowledge**\n\n"
1005
+ "📚 **Available actions for knowledge**\n\n"
1047
1006
  + KnowledgeAction.formatted_help()
1048
1007
  )
1049
1008
 
@@ -1055,13 +1014,13 @@ def _format_work(item: Dict[str, Any], *, header: Optional[str] = None) -> str:
1055
1014
  lines.append("")
1056
1015
 
1057
1016
  # Extract title
1058
- title = item.get("title") or item.get("name") or "Sem título"
1017
+ title = item.get("title") or item.get("name") or "Untitled"
1059
1018
 
1060
1019
  # Extract status
1061
- status = item.get("status") or item.get("state") or "desconhecido"
1020
+ status = item.get("status") or item.get("state") or "unknown"
1062
1021
 
1063
1022
  # Extract priority
1064
- priority = item.get("priority") or item.get("priority_level") or "indefinido"
1023
+ priority = item.get("priority") or item.get("priority_level") or "undefined"
1065
1024
 
1066
1025
  # Extract ID
1067
1026
  item_id = item.get("id", "N/A")
@@ -1080,13 +1039,13 @@ def _format_work(item: Dict[str, Any], *, header: Optional[str] = None) -> str:
1080
1039
  f"🎯 **{title}**",
1081
1040
  f"ID: {item_id}",
1082
1041
  f"Status: {status}",
1083
- f"Prioridade: {priority}",
1084
- f"Responsável: {assignee}",
1042
+ f"Priority: {priority}",
1043
+ f"Assignee: {assignee}",
1085
1044
  ]
1086
1045
  )
1087
1046
  if item.get("due_date") or item.get("dueDate"):
1088
1047
  lines.append(
1089
- f"Vencimento: {_format_date(item.get('due_date') or item.get('dueDate'))}"
1048
+ f"Due date: {_format_date(item.get('due_date') or item.get('dueDate'))}"
1090
1049
  )
1091
1050
  if item.get("tags"):
1092
1051
  tags = item.get("tags", [])
@@ -1102,10 +1061,10 @@ def _format_board(board: Dict[str, Any], header: Optional[str] = None) -> str:
1102
1061
  lines.append("")
1103
1062
  lines.extend(
1104
1063
  [
1105
- f"🗂️ **{board.get('name', 'Sem nome')}**",
1064
+ f"🗂️ **{board.get('name', 'Unnamed')}**",
1106
1065
  f"ID: {board.get('id', 'N/A')}",
1107
- f"Time: {board.get('team_id', 'N/A')}",
1108
- f"Colunas: {len(board.get('columns', []))}",
1066
+ f"Team: {board.get('team_id', 'N/A')}",
1067
+ f"Columns: {len(board.get('columns', []))}",
1109
1068
  ]
1110
1069
  )
1111
1070
  return "\n".join(lines)
@@ -1118,19 +1077,19 @@ def _format_sprint(sprint: Dict[str, Any], header: Optional[str] = None) -> str:
1118
1077
  lines.append("")
1119
1078
  lines.extend(
1120
1079
  [
1121
- f"🏃 **{sprint.get('name', 'Sem nome')}**",
1080
+ f"🏃 **{sprint.get('name', 'Unnamed')}**",
1122
1081
  f"ID: {sprint.get('id', 'N/A')}",
1123
1082
  f"Status: {sprint.get('status', 'N/A')}",
1124
- f"Time: {sprint.get('team_id', 'N/A')}",
1083
+ f"Team: {sprint.get('team_id', 'N/A')}",
1125
1084
  ]
1126
1085
  )
1127
1086
  if sprint.get("start_date") or sprint.get("startDate"):
1128
1087
  lines.append(
1129
- f"Início: {_format_date(sprint.get('start_date') or sprint.get('startDate'))}"
1088
+ f"Start: {_format_date(sprint.get('start_date') or sprint.get('startDate'))}"
1130
1089
  )
1131
1090
  if sprint.get("end_date") or sprint.get("endDate"):
1132
1091
  lines.append(
1133
- f"Fim: {_format_date(sprint.get('end_date') or sprint.get('endDate'))}"
1092
+ f"End: {_format_date(sprint.get('end_date') or sprint.get('endDate'))}"
1134
1093
  )
1135
1094
  return "\n".join(lines)
1136
1095
 
@@ -1142,13 +1101,13 @@ def _format_mode(mode: Dict[str, Any], header: Optional[str] = None) -> str:
1142
1101
  lines.append("")
1143
1102
  lines.extend(
1144
1103
  [
1145
- f"🎭 **{mode.get('name', 'Sem nome')}**",
1104
+ f"🎭 **{mode.get('name', 'Unnamed')}**",
1146
1105
  f"ID: {mode.get('id', 'N/A')}",
1147
- f"Padrão: {mode.get('is_default', False)}",
1106
+ f"Default: {mode.get('is_default', False)}",
1148
1107
  ]
1149
1108
  )
1150
1109
  if mode.get("description"):
1151
- lines.append(f"Descrição: {mode['description']}")
1110
+ lines.append(f"Description: {mode['description']}")
1152
1111
  return "\n".join(lines)
1153
1112
 
1154
1113
 
@@ -1159,13 +1118,13 @@ def _format_rule(rule: Dict[str, Any], header: Optional[str] = None) -> str:
1159
1118
  lines.append("")
1160
1119
  lines.extend(
1161
1120
  [
1162
- f"📋 **{rule.get('name', 'Sem nome')}**",
1121
+ f"📋 **{rule.get('name', 'Unnamed')}**",
1163
1122
  f"ID: {rule.get('id', 'N/A')}",
1164
- f"Padrão: {rule.get('is_default', False)}",
1123
+ f"Default: {rule.get('is_default', False)}",
1165
1124
  ]
1166
1125
  )
1167
1126
  if rule.get("description"):
1168
- lines.append(f"Descrição: {rule['description']}")
1127
+ lines.append(f"Description: {rule['description']}")
1169
1128
  return "\n".join(lines)
1170
1129
 
1171
1130
 
@@ -1176,15 +1135,15 @@ def _format_doc(doc: Dict[str, Any], header: Optional[str] = None) -> str:
1176
1135
  lines.append("")
1177
1136
  lines.extend(
1178
1137
  [
1179
- f"📄 **{doc.get('title') or doc.get('name', 'Sem título')}**",
1138
+ f"📄 **{doc.get('title') or doc.get('name', 'Untitled')}**",
1180
1139
  f"ID: {doc.get('id', 'N/A')}",
1181
1140
  f"Status: {doc.get('status', 'N/A')}",
1182
- f"Time: {doc.get('team_id', 'N/A')}",
1141
+ f"Team: {doc.get('team_id', 'N/A')}",
1183
1142
  ]
1184
1143
  )
1185
1144
  if doc.get("updated_at") or doc.get("updatedAt"):
1186
1145
  lines.append(
1187
- f"Atualizado em: {_format_date(doc.get('updated_at') or doc.get('updatedAt'))}"
1146
+ f"Updated at: {_format_date(doc.get('updated_at') or doc.get('updatedAt'))}"
1188
1147
  )
1189
1148
  return "\n".join(lines)
1190
1149