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