cicada-mcp 0.2.0__py3-none-any.whl → 0.3.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.
- cicada/_version_hash.py +4 -0
- cicada/cli.py +6 -748
- cicada/commands.py +1255 -0
- cicada/dead_code/__init__.py +1 -0
- cicada/{find_dead_code.py → dead_code/finder.py} +2 -1
- cicada/dependency_analyzer.py +147 -0
- cicada/entry_utils.py +92 -0
- cicada/extractors/base.py +9 -9
- cicada/extractors/call.py +17 -20
- cicada/extractors/common.py +64 -0
- cicada/extractors/dependency.py +117 -235
- cicada/extractors/doc.py +2 -49
- cicada/extractors/function.py +10 -14
- cicada/extractors/keybert.py +228 -0
- cicada/extractors/keyword.py +191 -0
- cicada/extractors/module.py +6 -10
- cicada/extractors/spec.py +8 -56
- cicada/format/__init__.py +20 -0
- cicada/{ascii_art.py → format/ascii_art.py} +1 -1
- cicada/format/formatter.py +1145 -0
- cicada/git_helper.py +134 -7
- cicada/indexer.py +322 -89
- cicada/interactive_setup.py +251 -323
- cicada/interactive_setup_helpers.py +302 -0
- cicada/keyword_expander.py +437 -0
- cicada/keyword_search.py +208 -422
- cicada/keyword_test.py +383 -16
- cicada/mcp/__init__.py +10 -0
- cicada/mcp/entry.py +17 -0
- cicada/mcp/filter_utils.py +107 -0
- cicada/mcp/pattern_utils.py +118 -0
- cicada/{mcp_server.py → mcp/server.py} +819 -73
- cicada/mcp/tools.py +473 -0
- cicada/pr_finder.py +2 -3
- cicada/pr_indexer/indexer.py +3 -2
- cicada/setup.py +167 -35
- cicada/tier.py +225 -0
- cicada/utils/__init__.py +9 -2
- cicada/utils/fuzzy_match.py +54 -0
- cicada/utils/index_utils.py +9 -0
- cicada/utils/path_utils.py +18 -0
- cicada/utils/text_utils.py +52 -1
- cicada/utils/tree_utils.py +47 -0
- cicada/version_check.py +99 -0
- cicada/watch_manager.py +320 -0
- cicada/watcher.py +431 -0
- cicada_mcp-0.3.0.dist-info/METADATA +541 -0
- cicada_mcp-0.3.0.dist-info/RECORD +70 -0
- cicada_mcp-0.3.0.dist-info/entry_points.txt +4 -0
- cicada/formatter.py +0 -864
- cicada/keybert_extractor.py +0 -286
- cicada/lightweight_keyword_extractor.py +0 -290
- cicada/mcp_entry.py +0 -683
- cicada/mcp_tools.py +0 -291
- cicada_mcp-0.2.0.dist-info/METADATA +0 -735
- cicada_mcp-0.2.0.dist-info/RECORD +0 -53
- cicada_mcp-0.2.0.dist-info/entry_points.txt +0 -4
- /cicada/{dead_code_analyzer.py → dead_code/analyzer.py} +0 -0
- /cicada/{colors.py → format/colors.py} +0 -0
- {cicada_mcp-0.2.0.dist-info → cicada_mcp-0.3.0.dist-info}/WHEEL +0 -0
- {cicada_mcp-0.2.0.dist-info → cicada_mcp-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {cicada_mcp-0.2.0.dist-info → cicada_mcp-0.3.0.dist-info}/top_level.txt +0 -0
cicada/mcp/tools.py
ADDED
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tool definitions for Cicada MCP Server.
|
|
3
|
+
|
|
4
|
+
This module contains all tool schemas that define the interface
|
|
5
|
+
for the Cicada MCP server without any implementation logic.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from mcp.types import Tool
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_tool_definitions() -> list[Tool]:
|
|
12
|
+
"""Return all tool definitions for the Cicada MCP server."""
|
|
13
|
+
return [
|
|
14
|
+
Tool(
|
|
15
|
+
name="search_module",
|
|
16
|
+
description=(
|
|
17
|
+
"PREFERRED for Elixir: View a module's complete API - functions with arity, signatures, docs, typespecs, and line numbers.\n\n"
|
|
18
|
+
"Supports wildcards (*) and OR patterns (|) for both module names and file paths. Examples: 'MyApp.*', '*User*', 'lib/my_app/*.ex', 'MyApp.User|MyApp.Admin'.\n\n"
|
|
19
|
+
"Search by module_name='MyApp.User' or file_path='lib/my_app/user.ex'. "
|
|
20
|
+
"Control visibility with private_functions: 'exclude' (default), 'include', or 'only'.\n\n"
|
|
21
|
+
"Returns public functions in markdown format by default. Start here when exploring modules.\n\n"
|
|
22
|
+
"🤖 AI USAGE TIPS:\n"
|
|
23
|
+
"• Use this when you know the exact module name (e.g., from search_by_features)\n"
|
|
24
|
+
"• Don't ask user for module names - use search_by_features first to find modules\n"
|
|
25
|
+
"• Returns: full API surface, function signatures, line numbers for navigation\n"
|
|
26
|
+
"• If module not found, error will suggest alternatives - try those suggestions!"
|
|
27
|
+
),
|
|
28
|
+
inputSchema={
|
|
29
|
+
"type": "object",
|
|
30
|
+
"properties": {
|
|
31
|
+
"module_name": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"description": "Module name or pattern (supports * and |, e.g., 'MyApp.*' or 'MyApp.User|MyApp.Admin'). Provide either this or file_path.",
|
|
34
|
+
},
|
|
35
|
+
"file_path": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"description": "Path (relative or absolute) to the file containing the module (e.g., 'lib/my_app/user.ex'). Provide either this or module_name.",
|
|
38
|
+
},
|
|
39
|
+
"format": {
|
|
40
|
+
"type": "string",
|
|
41
|
+
"enum": ["markdown", "json"],
|
|
42
|
+
"description": "Output format. Defaults to 'markdown'.",
|
|
43
|
+
},
|
|
44
|
+
"private_functions": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"enum": ["exclude", "include", "only"],
|
|
47
|
+
"description": "Control private function visibility. Defaults to 'exclude'.",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
),
|
|
52
|
+
Tool(
|
|
53
|
+
name="search_function",
|
|
54
|
+
description=(
|
|
55
|
+
"PREFERRED for Elixir: Find function definitions and call sites across the codebase.\n\n"
|
|
56
|
+
"Search by function name, optionally with module, file path, and arity: 'function_name', 'Module.function_name', 'function_name/2', or 'lib/my_app/user.ex:function_name'.\n\n"
|
|
57
|
+
"Supports wildcards (*) and OR patterns (|) across function names, modules, and file paths (e.g., 'create*|update*', 'MyApp.*.create', 'lib/*/user.ex:create*').\n\n"
|
|
58
|
+
"Returns definition location, signature, documentation, and all call sites. "
|
|
59
|
+
"Use include_usage_examples to see actual code snippets where the function is called.\n\n"
|
|
60
|
+
"🤖 AI USAGE TIPS:\n"
|
|
61
|
+
"• Use this for impact analysis - see where functions are called before modifying\n"
|
|
62
|
+
"• Set include_usage_examples=true to see real code examples (helps understand usage patterns)\n"
|
|
63
|
+
"• Use test_files_only=true to see how functions are tested\n"
|
|
64
|
+
"• Returns: definition + ALL call sites with file:line references\n"
|
|
65
|
+
"• If you see function references in code, search them to understand what they do"
|
|
66
|
+
),
|
|
67
|
+
inputSchema={
|
|
68
|
+
"type": "object",
|
|
69
|
+
"properties": {
|
|
70
|
+
"function_name": {
|
|
71
|
+
"type": "string",
|
|
72
|
+
"description": (
|
|
73
|
+
"Function pattern to search. Supports module qualifiers, file scoping via 'file.ex:function', wildcards (*), OR (|), "
|
|
74
|
+
"and arity filters (e.g., 'MyApp.create_user/2', 'create*|update*', 'lib/*/user.ex:create*')."
|
|
75
|
+
),
|
|
76
|
+
},
|
|
77
|
+
"format": {
|
|
78
|
+
"type": "string",
|
|
79
|
+
"enum": ["markdown", "json"],
|
|
80
|
+
"description": "Output format. Defaults to 'markdown'.",
|
|
81
|
+
},
|
|
82
|
+
"include_usage_examples": {
|
|
83
|
+
"type": "boolean",
|
|
84
|
+
"description": "Include actual code snippets showing how the function is called. Defaults to false.",
|
|
85
|
+
},
|
|
86
|
+
"max_examples": {
|
|
87
|
+
"type": "integer",
|
|
88
|
+
"description": "Maximum number of code examples to include. Defaults to 5.",
|
|
89
|
+
},
|
|
90
|
+
"test_files_only": {
|
|
91
|
+
"type": "boolean",
|
|
92
|
+
"description": "Only show call sites from test files. Defaults to false.",
|
|
93
|
+
},
|
|
94
|
+
"changed_since": {
|
|
95
|
+
"type": "string",
|
|
96
|
+
"description": (
|
|
97
|
+
"Filter functions changed after this date/time. "
|
|
98
|
+
"Formats: ISO date ('2024-01-15'), relative ('7d', '2w', '3m', '1y'), "
|
|
99
|
+
"or git ref ('HEAD~10', 'v1.0.0'). "
|
|
100
|
+
"Examples: '2024-01-01', '7d' (last 7 days), '2w' (last 2 weeks). "
|
|
101
|
+
"Requires index to be built with timestamp support."
|
|
102
|
+
),
|
|
103
|
+
},
|
|
104
|
+
"show_relationships": {
|
|
105
|
+
"type": "boolean",
|
|
106
|
+
"description": "Show inline relationship information: what functions this calls and what calls this function. Defaults to true.",
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
"required": ["function_name"],
|
|
110
|
+
},
|
|
111
|
+
),
|
|
112
|
+
Tool(
|
|
113
|
+
name="search_module_usage",
|
|
114
|
+
description=(
|
|
115
|
+
"PREFERRED for Elixir: Find all module usage and dependencies for impact analysis.\n\n"
|
|
116
|
+
"Shows where a module is imported, aliased, required, and all locations where its functions are called.\n\n"
|
|
117
|
+
"Returns aliases, imports, function calls, and dependency relationships.\n\n"
|
|
118
|
+
"🤖 AI USAGE TIPS:\n"
|
|
119
|
+
"• Use BEFORE modifying a module - see what depends on it to avoid breaking changes\n"
|
|
120
|
+
"• Shows: aliases, imports, requires, uses, and ALL function call sites\n"
|
|
121
|
+
"• Critical for refactoring - identify all affected modules before making changes\n"
|
|
122
|
+
"• If a module has many dependents, changes may have wide impact"
|
|
123
|
+
),
|
|
124
|
+
inputSchema={
|
|
125
|
+
"type": "object",
|
|
126
|
+
"properties": {
|
|
127
|
+
"module_name": {
|
|
128
|
+
"type": "string",
|
|
129
|
+
"description": "Module name to search (e.g., 'MyApp.User').",
|
|
130
|
+
},
|
|
131
|
+
"format": {
|
|
132
|
+
"type": "string",
|
|
133
|
+
"enum": ["markdown", "json"],
|
|
134
|
+
"description": "Output format. Defaults to 'markdown'.",
|
|
135
|
+
},
|
|
136
|
+
"usage_type": {
|
|
137
|
+
"type": "string",
|
|
138
|
+
"enum": ["all", "test_only", "production_only"],
|
|
139
|
+
"description": "Filter usage sites by file type. 'all' shows everything, 'test_only' shows only test files, 'production_only' shows only non-test files. Defaults to 'all'.",
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
"required": ["module_name"],
|
|
143
|
+
},
|
|
144
|
+
),
|
|
145
|
+
Tool(
|
|
146
|
+
name="find_pr_for_line",
|
|
147
|
+
description=(
|
|
148
|
+
"PREFERRED for git history: Discover why code exists and who wrote it.\n\n"
|
|
149
|
+
"Find the pull request that introduced a specific line of code. "
|
|
150
|
+
"Requires PR index (run 'cicada index-pr' first).\n\n"
|
|
151
|
+
"Returns PR number, title, description, and author.\n\n"
|
|
152
|
+
"🤖 AI USAGE TIPS:\n"
|
|
153
|
+
'• Use when you need context: "Why does this code exist? What problem did it solve?"\n'
|
|
154
|
+
"• Perfect for understanding complex/confusing code - read the PR discussion\n"
|
|
155
|
+
"• Provides: PR title, description, author, and link to full discussion\n"
|
|
156
|
+
"• If this interests you, also try: get_file_pr_history (all PRs for a file)"
|
|
157
|
+
),
|
|
158
|
+
inputSchema={
|
|
159
|
+
"type": "object",
|
|
160
|
+
"properties": {
|
|
161
|
+
"file_path": {
|
|
162
|
+
"type": "string",
|
|
163
|
+
"description": "Path to the file (relative to repo root).",
|
|
164
|
+
},
|
|
165
|
+
"line_number": {
|
|
166
|
+
"type": "integer",
|
|
167
|
+
"description": "Line number in the file (1-indexed).",
|
|
168
|
+
},
|
|
169
|
+
"format": {
|
|
170
|
+
"type": "string",
|
|
171
|
+
"enum": ["text", "json", "markdown"],
|
|
172
|
+
"description": "Output format. Defaults to 'text'.",
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
"required": ["file_path", "line_number"],
|
|
176
|
+
},
|
|
177
|
+
),
|
|
178
|
+
Tool(
|
|
179
|
+
name="get_commit_history",
|
|
180
|
+
description=(
|
|
181
|
+
"PREFERRED for git history: Get commit log for files or functions.\n\n"
|
|
182
|
+
"Get the git commit history for a file or function. When function_name is provided, uses git's "
|
|
183
|
+
"function tracking which works even as the function moves around in the file.\n\n"
|
|
184
|
+
"Returns commits with dates, authors, and messages. Optionally shows function evolution metadata.\n\n"
|
|
185
|
+
"🤖 AI USAGE TIPS:\n"
|
|
186
|
+
'• Use for understanding evolution: "How has this function changed over time?"\n'
|
|
187
|
+
"• Set show_evolution=true to see: creation date, total modifications, frequency\n"
|
|
188
|
+
"• Provide function_name for precise tracking (even as function moves in file)\n"
|
|
189
|
+
"• Helps identify frequently changing code (may indicate complexity/bugs)\n"
|
|
190
|
+
"• Use max_commits to limit results (default: 10)"
|
|
191
|
+
),
|
|
192
|
+
inputSchema={
|
|
193
|
+
"type": "object",
|
|
194
|
+
"properties": {
|
|
195
|
+
"file_path": {
|
|
196
|
+
"type": "string",
|
|
197
|
+
"description": "Path to the file (relative to repo root).",
|
|
198
|
+
},
|
|
199
|
+
"function_name": {
|
|
200
|
+
"type": "string",
|
|
201
|
+
"description": "Optional: Function name for function-level tracking. Uses git log -L :funcname:file for precise tracking.",
|
|
202
|
+
},
|
|
203
|
+
"start_line": {
|
|
204
|
+
"type": "integer",
|
|
205
|
+
"description": "Optional: Starting line for line-range tracking. Required with end_line for line-based history.",
|
|
206
|
+
},
|
|
207
|
+
"end_line": {
|
|
208
|
+
"type": "integer",
|
|
209
|
+
"description": "Optional: Ending line for line-range tracking. Required with start_line for line-based history.",
|
|
210
|
+
},
|
|
211
|
+
"precise_tracking": {
|
|
212
|
+
"type": "boolean",
|
|
213
|
+
"description": "Deprecated - function tracking is automatic when function_name provided.",
|
|
214
|
+
},
|
|
215
|
+
"show_evolution": {
|
|
216
|
+
"type": "boolean",
|
|
217
|
+
"description": "Show function evolution metadata (creation date, last modification, modification frequency). Defaults to false.",
|
|
218
|
+
},
|
|
219
|
+
"max_commits": {
|
|
220
|
+
"type": "integer",
|
|
221
|
+
"description": "Maximum number of commits to return. Defaults to 10.",
|
|
222
|
+
},
|
|
223
|
+
"since_date": {
|
|
224
|
+
"type": "string",
|
|
225
|
+
"description": "Only include commits after this date. Format: ISO date (YYYY-MM-DD) or relative (7d, 2w, 3m, 1y). Examples: '2024-01-01', '30d'.",
|
|
226
|
+
},
|
|
227
|
+
"until_date": {
|
|
228
|
+
"type": "string",
|
|
229
|
+
"description": "Only include commits before this date. Format: ISO date (YYYY-MM-DD) or relative (7d, 2w, 3m, 1y).",
|
|
230
|
+
},
|
|
231
|
+
"author": {
|
|
232
|
+
"type": "string",
|
|
233
|
+
"description": "Filter by author name (substring match, case-insensitive). Example: 'john' matches 'John Doe'.",
|
|
234
|
+
},
|
|
235
|
+
"min_changes": {
|
|
236
|
+
"type": "integer",
|
|
237
|
+
"description": "Minimum number of lines changed (insertions + deletions) in the file. Useful for finding substantial changes.",
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
"required": ["file_path"],
|
|
241
|
+
},
|
|
242
|
+
),
|
|
243
|
+
Tool(
|
|
244
|
+
name="get_blame",
|
|
245
|
+
description=(
|
|
246
|
+
"PREFERRED for authorship: Git blame showing who wrote each line.\n\n"
|
|
247
|
+
"Get line-by-line authorship information for a code section using git blame. "
|
|
248
|
+
"Groups consecutive lines with the same authorship together.\n\n"
|
|
249
|
+
"Returns author name, email, commit hash, and date for each authorship group.\n\n"
|
|
250
|
+
"🤖 AI USAGE TIPS:\n"
|
|
251
|
+
'• Use when you need to know: "Who wrote this code? When?"\n'
|
|
252
|
+
"• Shows line-by-line authorship with commit hashes for each change\n"
|
|
253
|
+
"• Requires start_line and end_line (from search_function results)\n"
|
|
254
|
+
"• Groups consecutive lines by same author for readability"
|
|
255
|
+
),
|
|
256
|
+
inputSchema={
|
|
257
|
+
"type": "object",
|
|
258
|
+
"properties": {
|
|
259
|
+
"file_path": {
|
|
260
|
+
"type": "string",
|
|
261
|
+
"description": "Path to the file (relative to repo root).",
|
|
262
|
+
},
|
|
263
|
+
"start_line": {
|
|
264
|
+
"type": "integer",
|
|
265
|
+
"description": "Starting line number (1-indexed).",
|
|
266
|
+
},
|
|
267
|
+
"end_line": {
|
|
268
|
+
"type": "integer",
|
|
269
|
+
"description": "Ending line number (1-indexed, inclusive).",
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
"required": ["file_path", "start_line", "end_line"],
|
|
273
|
+
},
|
|
274
|
+
),
|
|
275
|
+
Tool(
|
|
276
|
+
name="get_file_pr_history",
|
|
277
|
+
description=(
|
|
278
|
+
"Get all PRs that modified a file with descriptions and review comments.\n\n"
|
|
279
|
+
"Returns a chronological list of pull requests that modified the specified file, "
|
|
280
|
+
"including descriptions and code review comments specific to that file.\n\n"
|
|
281
|
+
"Requires PR index (run 'cicada index-pr' first).\n\n"
|
|
282
|
+
"🤖 AI USAGE TIPS:\n"
|
|
283
|
+
'• Use for deep context: "What\'s the full history of changes to this file?"\n'
|
|
284
|
+
"• Shows ALL PRs that touched the file + review comments (discussions, decisions)\n"
|
|
285
|
+
"• Review comments reveal: design decisions, concerns, tradeoffs, bugs found\n"
|
|
286
|
+
"• Perfect for understanding controversial/complex code - read the debates!\n"
|
|
287
|
+
"• Complements find_pr_for_line (which finds PR for a single line)"
|
|
288
|
+
),
|
|
289
|
+
inputSchema={
|
|
290
|
+
"type": "object",
|
|
291
|
+
"properties": {
|
|
292
|
+
"file_path": {
|
|
293
|
+
"type": "string",
|
|
294
|
+
"description": "Path to the file (relative to repo root or absolute).",
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
"required": ["file_path"],
|
|
298
|
+
},
|
|
299
|
+
),
|
|
300
|
+
Tool(
|
|
301
|
+
name="search_by_features",
|
|
302
|
+
description=(
|
|
303
|
+
"🎯 USE THIS FIRST when exploring code or when you don't know exact module/function names.\n\n"
|
|
304
|
+
"Search for code by concepts and features - find code by describing what it does, not what it's called. "
|
|
305
|
+
"Perfect for discovering relevant code when exploring unfamiliar codebases.\n\n"
|
|
306
|
+
"Examples: ['authentication', 'login'], ['api', 'key', 'storage'], ['email', 'validation']\n\n"
|
|
307
|
+
"Uses AI-powered keyword extraction and semantic similarity. Supports wildcards like 'create*', '*_user', 'validate_*'.\n\n"
|
|
308
|
+
"🤖 AI USAGE TIPS:\n"
|
|
309
|
+
"• **USE THIS FIRST** - don't ask user for module names when you can search for concepts\n"
|
|
310
|
+
"• Try broad queries first: ['authentication'], then narrow: ['oauth', 'token']\n"
|
|
311
|
+
"• Multiple searches are NORMAL - try 3-5 different keyword combinations\n"
|
|
312
|
+
"• Empty results? Try broader terms, check spelling, or use wildcards: ['*auth*']\n"
|
|
313
|
+
"• Results show modules AND functions with relevance scores\n"
|
|
314
|
+
"• Use filter_type to narrow: 'modules', 'functions', or 'all' (default)\n\n"
|
|
315
|
+
"Requires keywords in index (run 'cicada index' first - uses semantic extraction by default)."
|
|
316
|
+
),
|
|
317
|
+
inputSchema={
|
|
318
|
+
"type": "object",
|
|
319
|
+
"properties": {
|
|
320
|
+
"keywords": {
|
|
321
|
+
"type": "array",
|
|
322
|
+
"items": {"type": "string"},
|
|
323
|
+
"description": "List of keywords to search for (e.g., ['authentication', 'login']).",
|
|
324
|
+
},
|
|
325
|
+
"filter_type": {
|
|
326
|
+
"type": "string",
|
|
327
|
+
"enum": ["all", "modules", "functions"],
|
|
328
|
+
"description": "Filter results to include only modules, only functions, or all results (default: 'all').",
|
|
329
|
+
},
|
|
330
|
+
"min_score": {
|
|
331
|
+
"type": "number",
|
|
332
|
+
"description": "Minimum relevance score threshold (0.0 to 1.0). Only results with scores >= this value will be shown. Default: 0.0 (no filtering).",
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
"required": ["keywords"],
|
|
336
|
+
},
|
|
337
|
+
),
|
|
338
|
+
Tool(
|
|
339
|
+
name="search_by_keywords",
|
|
340
|
+
description=(
|
|
341
|
+
"⚠️ DEPRECATED: Use 'search_by_features' instead. This tool will be removed in a future version.\n\n"
|
|
342
|
+
"Search for code by concepts and features when exact names are unknown.\n\n"
|
|
343
|
+
"Uses AI-powered keyword extraction and semantic similarity. Supports wildcards like 'create*', '*_user', 'validate_*'.\n\n"
|
|
344
|
+
"Requires keywords in index (run 'cicada index' first - uses semantic extraction by default)."
|
|
345
|
+
),
|
|
346
|
+
inputSchema={
|
|
347
|
+
"type": "object",
|
|
348
|
+
"properties": {
|
|
349
|
+
"keywords": {
|
|
350
|
+
"type": "array",
|
|
351
|
+
"items": {"type": "string"},
|
|
352
|
+
"description": "List of keywords to search for (e.g., ['authentication', 'login']).",
|
|
353
|
+
},
|
|
354
|
+
"filter_type": {
|
|
355
|
+
"type": "string",
|
|
356
|
+
"enum": ["all", "modules", "functions"],
|
|
357
|
+
"description": "Filter results to include only modules, only functions, or all results (default: 'all').",
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
"required": ["keywords"],
|
|
361
|
+
},
|
|
362
|
+
),
|
|
363
|
+
Tool(
|
|
364
|
+
name="find_dead_code",
|
|
365
|
+
description=(
|
|
366
|
+
"Find potentially unused public functions with confidence levels.\n\n"
|
|
367
|
+
"Analyzes the codebase to identify public functions that may not be used. "
|
|
368
|
+
"Returns results categorized by confidence level (high, medium, low).\n\n"
|
|
369
|
+
"Note: Results are best-effort - some unused functions may be part of the public API, "
|
|
370
|
+
"used dynamically via atom introspection, or used in external packages.\n\n"
|
|
371
|
+
"🤖 AI USAGE TIPS:\n"
|
|
372
|
+
'• Use for cleanup: "What code can potentially be removed?"\n'
|
|
373
|
+
"• Start with min_confidence='high' to find most likely unused code\n"
|
|
374
|
+
"• VERIFY before deleting - may be public API, dynamic calls, or external usage\n"
|
|
375
|
+
"• Results show: function signature, location, confidence level, reasons"
|
|
376
|
+
),
|
|
377
|
+
inputSchema={
|
|
378
|
+
"type": "object",
|
|
379
|
+
"properties": {
|
|
380
|
+
"min_confidence": {
|
|
381
|
+
"type": "string",
|
|
382
|
+
"enum": ["high", "medium", "low"],
|
|
383
|
+
"description": "Minimum confidence level for dead code detection. Defaults to 'high'.",
|
|
384
|
+
},
|
|
385
|
+
"format": {
|
|
386
|
+
"type": "string",
|
|
387
|
+
"enum": ["markdown", "json"],
|
|
388
|
+
"description": "Output format. Defaults to 'markdown'.",
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
},
|
|
392
|
+
),
|
|
393
|
+
Tool(
|
|
394
|
+
name="get_module_dependencies",
|
|
395
|
+
description=(
|
|
396
|
+
"Get all modules that a given module depends on.\n\n"
|
|
397
|
+
"Shows which modules the target module imports, aliases, uses, requires, and calls. "
|
|
398
|
+
"Complements search_module_usage (which shows who depends on this module).\n\n"
|
|
399
|
+
"Returns list of dependent modules with dependency types (alias, import, use, require, call).\n\n"
|
|
400
|
+
"🤖 AI USAGE TIPS:\n"
|
|
401
|
+
'• Use for understanding: "What does this module need to work?"\n'
|
|
402
|
+
"• Pair with search_module_usage for full dependency graph (in + out)\n"
|
|
403
|
+
"• Helps identify coupling - modules with many dependencies may need refactoring\n"
|
|
404
|
+
"• Set depth=2 to see transitive dependencies (dependencies of dependencies)\n"
|
|
405
|
+
"• Useful for: refactoring planning, dependency analysis, circular dependency detection"
|
|
406
|
+
),
|
|
407
|
+
inputSchema={
|
|
408
|
+
"type": "object",
|
|
409
|
+
"properties": {
|
|
410
|
+
"module_name": {
|
|
411
|
+
"type": "string",
|
|
412
|
+
"description": "Module name to analyze (e.g., 'MyApp.User').",
|
|
413
|
+
},
|
|
414
|
+
"format": {
|
|
415
|
+
"type": "string",
|
|
416
|
+
"enum": ["markdown", "json"],
|
|
417
|
+
"description": "Output format. Defaults to 'markdown'.",
|
|
418
|
+
},
|
|
419
|
+
"depth": {
|
|
420
|
+
"type": "integer",
|
|
421
|
+
"description": "Depth for transitive dependencies. 1 = direct only, 2 = include dependencies of dependencies. Defaults to 1.",
|
|
422
|
+
},
|
|
423
|
+
"granular": {
|
|
424
|
+
"type": "boolean",
|
|
425
|
+
"description": "Show which specific functions use which dependencies. When true, displays function-level dependency details. Defaults to false.",
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
"required": ["module_name"],
|
|
429
|
+
},
|
|
430
|
+
),
|
|
431
|
+
Tool(
|
|
432
|
+
name="get_function_dependencies",
|
|
433
|
+
description=(
|
|
434
|
+
"Get all functions that a given function calls.\n\n"
|
|
435
|
+
"Shows which functions are called within the target function, including both "
|
|
436
|
+
"internal (same module) and external (other modules) calls.\n\n"
|
|
437
|
+
"Returns list of called functions with module, name, arity, and line numbers.\n\n"
|
|
438
|
+
"🤖 AI USAGE TIPS:\n"
|
|
439
|
+
'• Use for understanding: "What does this function do? What does it call?"\n'
|
|
440
|
+
"• Helps identify function complexity - many dependencies = complex function\n"
|
|
441
|
+
"• Shows exact line numbers where each dependency is called\n"
|
|
442
|
+
"• Useful for: refactoring, understanding control flow, identifying coupling\n"
|
|
443
|
+
"• Pair with search_function to see both what it calls and who calls it"
|
|
444
|
+
),
|
|
445
|
+
inputSchema={
|
|
446
|
+
"type": "object",
|
|
447
|
+
"properties": {
|
|
448
|
+
"module_name": {
|
|
449
|
+
"type": "string",
|
|
450
|
+
"description": "Module name containing the function (e.g., 'MyApp.User').",
|
|
451
|
+
},
|
|
452
|
+
"function_name": {
|
|
453
|
+
"type": "string",
|
|
454
|
+
"description": "Function name to analyze (e.g., 'create_user').",
|
|
455
|
+
},
|
|
456
|
+
"arity": {
|
|
457
|
+
"type": "integer",
|
|
458
|
+
"description": "Function arity (number of arguments). Required to uniquely identify the function.",
|
|
459
|
+
},
|
|
460
|
+
"format": {
|
|
461
|
+
"type": "string",
|
|
462
|
+
"enum": ["markdown", "json"],
|
|
463
|
+
"description": "Output format. Defaults to 'markdown'.",
|
|
464
|
+
},
|
|
465
|
+
"include_context": {
|
|
466
|
+
"type": "boolean",
|
|
467
|
+
"description": "Include code context showing where dependencies are called. Defaults to false.",
|
|
468
|
+
},
|
|
469
|
+
},
|
|
470
|
+
"required": ["module_name", "function_name", "arity"],
|
|
471
|
+
},
|
|
472
|
+
),
|
|
473
|
+
]
|
cicada/pr_finder.py
CHANGED
|
@@ -10,7 +10,7 @@ import sys
|
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from typing import Any
|
|
12
12
|
|
|
13
|
-
from cicada.utils import load_index
|
|
13
|
+
from cicada.utils import is_git_repository, load_index
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class PRFinder:
|
|
@@ -58,8 +58,7 @@ class PRFinder:
|
|
|
58
58
|
|
|
59
59
|
def _validate_git_repo(self):
|
|
60
60
|
"""Validate that the path is a git repository."""
|
|
61
|
-
|
|
62
|
-
if not git_dir.exists():
|
|
61
|
+
if not is_git_repository(self.repo_path):
|
|
63
62
|
raise ValueError(f"Not a git repository: {self.repo_path}")
|
|
64
63
|
|
|
65
64
|
def _validate_gh_cli(self):
|
cicada/pr_indexer/indexer.py
CHANGED
|
@@ -7,6 +7,8 @@ Fetches all PRs from a GitHub repository and builds an index mapping commits to
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from typing import Any
|
|
9
9
|
|
|
10
|
+
from cicada.utils import is_git_repository
|
|
11
|
+
|
|
10
12
|
from .github_api_client import GitHubAPIClient
|
|
11
13
|
from .line_mapper import LineMapper
|
|
12
14
|
from .pr_index_builder import PRIndexBuilder
|
|
@@ -42,8 +44,7 @@ class PRIndexer:
|
|
|
42
44
|
|
|
43
45
|
def _validate_git_repo(self):
|
|
44
46
|
"""Validate that the path is a git repository."""
|
|
45
|
-
|
|
46
|
-
if not git_dir.exists():
|
|
47
|
+
if not is_git_repository(self.repo_path):
|
|
47
48
|
raise ValueError(f"Not a git repository: {self.repo_path}")
|
|
48
49
|
|
|
49
50
|
def fetch_all_prs(self, state: str = "all") -> list[dict[str, Any]]:
|