toolplane-python-client 0.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.
Files changed (81) hide show
  1. toolplane/__init__.py +106 -0
  2. toolplane/common/__init__.py +93 -0
  3. toolplane/common/base_config.py +129 -0
  4. toolplane/common/base_connection_manager.py +171 -0
  5. toolplane/common/base_session_manager.py +321 -0
  6. toolplane/common/base_tool_manager.py +347 -0
  7. toolplane/common/constants.py +47 -0
  8. toolplane/common/utils.py +310 -0
  9. toolplane/core/__init__.py +67 -0
  10. toolplane/core/config.py +107 -0
  11. toolplane/core/connection.py +285 -0
  12. toolplane/core/errors.py +298 -0
  13. toolplane/core/machine.py +480 -0
  14. toolplane/core/request.py +775 -0
  15. toolplane/core/session.py +332 -0
  16. toolplane/core/session_context.py +514 -0
  17. toolplane/core/task.py +130 -0
  18. toolplane/core/tool.py +329 -0
  19. toolplane/http_core/__init__.py +37 -0
  20. toolplane/http_core/http_config.py +97 -0
  21. toolplane/http_core/http_connection.py +409 -0
  22. toolplane/http_core/http_machine.py +298 -0
  23. toolplane/http_core/http_request.py +748 -0
  24. toolplane/http_core/http_session.py +348 -0
  25. toolplane/http_core/http_session_context.py +491 -0
  26. toolplane/http_core/http_task.py +101 -0
  27. toolplane/http_core/http_tool.py +400 -0
  28. toolplane/interfaces/__init__.py +27 -0
  29. toolplane/interfaces/client_interface.py +122 -0
  30. toolplane/interfaces/connection_interface.py +193 -0
  31. toolplane/interfaces/event_interface.py +290 -0
  32. toolplane/interfaces/request_interface.py +439 -0
  33. toolplane/interfaces/session_interface.py +288 -0
  34. toolplane/interfaces/tool_interface.py +441 -0
  35. toolplane/proto/__init__.py +0 -0
  36. toolplane/proto/service_pb2.py +315 -0
  37. toolplane/proto/service_pb2_grpc.py +2240 -0
  38. toolplane/provider_cli.py +268 -0
  39. toolplane/provider_registry.py +77 -0
  40. toolplane/provider_runtime.py +302 -0
  41. toolplane/toolkits/__init__.py +0 -0
  42. toolplane/toolkits/standalone_tools/__init__.py +0 -0
  43. toolplane/toolkits/standalone_tools/create_directory.py +94 -0
  44. toolplane/toolkits/standalone_tools/create_file.py +124 -0
  45. toolplane/toolkits/standalone_tools/file_search.py +229 -0
  46. toolplane/toolkits/standalone_tools/grep_search.py +372 -0
  47. toolplane/toolkits/standalone_tools/launcher.py +146 -0
  48. toolplane/toolkits/standalone_tools/list_dir.py +395 -0
  49. toolplane/toolkits/standalone_tools/read_file.py +346 -0
  50. toolplane/toolkits/standalone_tools/replace_string_in_file.py +407 -0
  51. toolplane/toolkits/standalone_tools/run_tests.py +66 -0
  52. toolplane/toolkits/standalone_tools/semantic_search.py +485 -0
  53. toolplane/toolkits/standalone_tools/standalone_toolkit.py +979 -0
  54. toolplane/toolkits/standalone_tools/test_failure_analysis.py +618 -0
  55. toolplane/toolkits/standalone_tools/test_standalone_toolkit.py +517 -0
  56. toolplane/toolkits/swe/__init__.py +35 -0
  57. toolplane/toolkits/swe/create_directory.py +15 -0
  58. toolplane/toolkits/swe/create_file.py +15 -0
  59. toolplane/toolkits/swe/descriptions.py +273 -0
  60. toolplane/toolkits/swe/execute_bash.py +93 -0
  61. toolplane/toolkits/swe/file_editor.py +775 -0
  62. toolplane/toolkits/swe/file_search.py +16 -0
  63. toolplane/toolkits/swe/finish.py +50 -0
  64. toolplane/toolkits/swe/grep_search.py +19 -0
  65. toolplane/toolkits/swe/list_dir.py +407 -0
  66. toolplane/toolkits/swe/read_file.py +18 -0
  67. toolplane/toolkits/swe/replace_string_in_file.py +17 -0
  68. toolplane/toolkits/swe/search.py +260 -0
  69. toolplane/toolkits/swe/semantic_search.py +20 -0
  70. toolplane/toolkits/swe/str_replace_editor.py +647 -0
  71. toolplane/toolkits/swe/submit.py +29 -0
  72. toolplane/toolkits/swe/swe_toolkit.py +1296 -0
  73. toolplane/toolplane_client.py +686 -0
  74. toolplane/toolplane_http_client.py +681 -0
  75. toolplane/utils/__init__.py +3 -0
  76. toolplane/utils/schema.py +146 -0
  77. toolplane_python_client-0.1.0.dist-info/METADATA +543 -0
  78. toolplane_python_client-0.1.0.dist-info/RECORD +81 -0
  79. toolplane_python_client-0.1.0.dist-info/WHEEL +5 -0
  80. toolplane_python_client-0.1.0.dist-info/entry_points.txt +2 -0
  81. toolplane_python_client-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,372 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Description: Fast text search in files using grep-like functionality with advanced features.
4
+
5
+ This tool performs fast text search in files using exact strings or regex patterns.
6
+ It provides context lines, file filtering, and other advanced search options.
7
+
8
+ Parameters:
9
+ query (string, required): The pattern to search for in files.
10
+ is_regexp (boolean, required): Whether the pattern is a regex.
11
+ include_pattern (string, optional): Search files matching this glob pattern.
12
+ max_results (integer, optional): Maximum number of results to return.
13
+ context_lines (integer, optional): Number of context lines to show around matches.
14
+ ignore_case (boolean, optional): Perform case-insensitive search.
15
+ whole_word (boolean, optional): Match whole words only.
16
+ invert_match (boolean, optional): Show lines that don't match the pattern.
17
+ """
18
+
19
+ import argparse
20
+ import glob
21
+ import os
22
+ import re
23
+ import sys
24
+ from pathlib import Path
25
+ from typing import Any, Dict, Iterator, List
26
+
27
+
28
+ def grep_search(
29
+ query: str,
30
+ is_regexp: bool,
31
+ include_pattern: str = None,
32
+ max_results: int = None,
33
+ context_lines: int = 0,
34
+ ignore_case: bool = False,
35
+ whole_word: bool = False,
36
+ invert_match: bool = False,
37
+ base_path: str = None,
38
+ ) -> List[Dict[str, Any]]:
39
+ """
40
+ Fast text search in files using grep-like functionality.
41
+
42
+ Args:
43
+ query: The pattern to search for
44
+ is_regexp: Whether the pattern is a regex
45
+ include_pattern: Search files matching this glob pattern
46
+ max_results: Maximum number of results to return
47
+ context_lines: Number of context lines to show around matches
48
+ ignore_case: Perform case-insensitive search
49
+ whole_word: Match whole words only
50
+ invert_match: Show lines that don't match the pattern
51
+ base_path: Base directory to search from
52
+
53
+ Returns:
54
+ List of dictionaries containing search results
55
+ """
56
+ if base_path is None:
57
+ base_path = os.getcwd()
58
+
59
+ # Prepare the search pattern
60
+ if is_regexp:
61
+ pattern = query
62
+ else:
63
+ pattern = re.escape(query)
64
+
65
+ if whole_word:
66
+ pattern = r"\b" + pattern + r"\b"
67
+
68
+ flags = re.IGNORECASE if ignore_case else 0
69
+ try:
70
+ compiled_pattern = re.compile(pattern, flags)
71
+ except re.error as e:
72
+ print(f"Invalid regex pattern: {e}", file=sys.stderr)
73
+ return []
74
+
75
+ # Get list of files to search
76
+ if include_pattern:
77
+ files_to_search = get_files_by_pattern(include_pattern, base_path)
78
+ else:
79
+ files_to_search = get_all_text_files(base_path)
80
+
81
+ results = []
82
+ total_matches = 0
83
+
84
+ for file_path in files_to_search:
85
+ if max_results and total_matches >= max_results:
86
+ break
87
+
88
+ try:
89
+ file_results = search_file(
90
+ file_path, compiled_pattern, context_lines, invert_match
91
+ )
92
+
93
+ if file_results["matches"]:
94
+ results.append(file_results)
95
+ total_matches += len(file_results["matches"])
96
+
97
+ except Exception as e:
98
+ # Skip files that can't be read
99
+ continue
100
+
101
+ return results
102
+
103
+
104
+ def get_files_by_pattern(pattern: str, base_path: str) -> List[str]:
105
+ """Get list of files matching the glob pattern.
106
+
107
+ Globs against base_path directly instead of os.chdir: changing the
108
+ process working directory is global state and races with every other
109
+ thread in the provider runtime.
110
+ """
111
+ matches = glob.glob(str(Path(base_path) / pattern), recursive=True)
112
+ files = []
113
+
114
+ for match in matches:
115
+ path = Path(match)
116
+ if path.is_file():
117
+ files.append(str(path.resolve()))
118
+
119
+ return files
120
+
121
+
122
+ def get_all_text_files(base_path: str) -> List[str]:
123
+ """Get all text files in the directory tree."""
124
+ text_extensions = {
125
+ ".txt",
126
+ ".py",
127
+ ".js",
128
+ ".ts",
129
+ ".jsx",
130
+ ".tsx",
131
+ ".java",
132
+ ".cpp",
133
+ ".c",
134
+ ".h",
135
+ ".cs",
136
+ ".php",
137
+ ".rb",
138
+ ".go",
139
+ ".rs",
140
+ ".swift",
141
+ ".kt",
142
+ ".scala",
143
+ ".r",
144
+ ".sql",
145
+ ".html",
146
+ ".htm",
147
+ ".css",
148
+ ".scss",
149
+ ".sass",
150
+ ".less",
151
+ ".xml",
152
+ ".json",
153
+ ".yaml",
154
+ ".yml",
155
+ ".toml",
156
+ ".ini",
157
+ ".cfg",
158
+ ".conf",
159
+ ".md",
160
+ ".rst",
161
+ ".tex",
162
+ ".sh",
163
+ ".bash",
164
+ ".zsh",
165
+ ".fish",
166
+ ".ps1",
167
+ ".bat",
168
+ ".dockerfile",
169
+ ".makefile",
170
+ ".cmake",
171
+ ".gradle",
172
+ ".properties",
173
+ }
174
+
175
+ files = []
176
+ for root, dirs, file_names in os.walk(base_path):
177
+ # Skip hidden directories
178
+ dirs[:] = [d for d in dirs if not d.startswith(".")]
179
+
180
+ for filename in file_names:
181
+ if filename.startswith("."):
182
+ continue
183
+
184
+ path = Path(root) / filename
185
+
186
+ # Check extension
187
+ if path.suffix.lower() in text_extensions:
188
+ files.append(str(path.resolve()))
189
+ # Check if it's a text file by reading first few bytes
190
+ elif not path.suffix and is_text_file(path):
191
+ files.append(str(path.resolve()))
192
+
193
+ return files
194
+
195
+
196
+ def is_text_file(file_path: Path) -> bool:
197
+ """Check if a file is a text file by examining its content."""
198
+ try:
199
+ with open(file_path, "rb") as f:
200
+ chunk = f.read(1024)
201
+
202
+ # Check for null bytes (binary files usually contain them)
203
+ if b"\x00" in chunk:
204
+ return False
205
+
206
+ # Try to decode as UTF-8
207
+ try:
208
+ chunk.decode("utf-8")
209
+ return True
210
+ except UnicodeDecodeError:
211
+ return False
212
+
213
+ except (IOError, OSError):
214
+ return False
215
+
216
+
217
+ def search_file(
218
+ file_path: str, pattern: re.Pattern, context_lines: int, invert_match: bool
219
+ ) -> Dict[str, Any]:
220
+ """Search for pattern in a single file."""
221
+ try:
222
+ with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
223
+ lines = f.readlines()
224
+ except Exception as e:
225
+ return {"file": file_path, "error": str(e), "matches": []}
226
+
227
+ matches = []
228
+
229
+ for line_num, line in enumerate(lines, 1):
230
+ line = line.rstrip("\n\r")
231
+
232
+ if invert_match:
233
+ match = not pattern.search(line)
234
+ else:
235
+ match = pattern.search(line)
236
+
237
+ if match:
238
+ # Get context lines
239
+ start_line = max(0, line_num - context_lines - 1)
240
+ end_line = min(len(lines), line_num + context_lines)
241
+
242
+ context = []
243
+ for i in range(start_line, end_line):
244
+ context_line = lines[i].rstrip("\n\r")
245
+ context.append(
246
+ {
247
+ "line_number": i + 1,
248
+ "content": context_line,
249
+ "is_match": i + 1 == line_num,
250
+ }
251
+ )
252
+
253
+ matches.append(
254
+ {
255
+ "line_number": line_num,
256
+ "content": line,
257
+ "context": context if context_lines > 0 else None,
258
+ }
259
+ )
260
+
261
+ return {"file": file_path, "matches": matches, "total_matches": len(matches)}
262
+
263
+
264
+ def main():
265
+ parser = argparse.ArgumentParser(
266
+ description="Fast text search in files using grep-like functionality with advanced features."
267
+ )
268
+ parser.add_argument("query", type=str, help="The pattern to search for in files")
269
+ parser.add_argument(
270
+ "--is_regexp",
271
+ action="store_true",
272
+ default=False,
273
+ help="Whether the pattern is a regex",
274
+ )
275
+ parser.add_argument(
276
+ "--include_pattern", type=str, help="Search files matching this glob pattern"
277
+ )
278
+ parser.add_argument(
279
+ "--max_results", type=int, help="Maximum number of results to return"
280
+ )
281
+ parser.add_argument(
282
+ "--context_lines",
283
+ type=int,
284
+ default=0,
285
+ help="Number of context lines to show around matches",
286
+ )
287
+ parser.add_argument(
288
+ "--ignore_case",
289
+ action="store_true",
290
+ default=False,
291
+ help="Perform case-insensitive search",
292
+ )
293
+ parser.add_argument(
294
+ "--whole_word",
295
+ action="store_true",
296
+ default=False,
297
+ help="Match whole words only",
298
+ )
299
+ parser.add_argument(
300
+ "--invert_match",
301
+ action="store_true",
302
+ default=False,
303
+ help="Show lines that don't match the pattern",
304
+ )
305
+ parser.add_argument(
306
+ "--base_path",
307
+ type=str,
308
+ help="Base directory to search from (default: current directory)",
309
+ )
310
+ parser.add_argument(
311
+ "--output_format",
312
+ choices=["default", "json", "count"],
313
+ default="default",
314
+ help="Output format (default: default)",
315
+ )
316
+
317
+ args = parser.parse_args()
318
+
319
+ results = grep_search(
320
+ args.query,
321
+ args.is_regexp,
322
+ include_pattern=args.include_pattern,
323
+ max_results=args.max_results,
324
+ context_lines=args.context_lines,
325
+ ignore_case=args.ignore_case,
326
+ whole_word=args.whole_word,
327
+ invert_match=args.invert_match,
328
+ base_path=args.base_path,
329
+ )
330
+
331
+ if not results:
332
+ print(f"No matches found for pattern: {args.query}")
333
+ sys.exit(0)
334
+
335
+ if args.output_format == "json":
336
+ import json
337
+
338
+ print(json.dumps(results, indent=2))
339
+
340
+ elif args.output_format == "count":
341
+ total_matches = sum(r["total_matches"] for r in results)
342
+ print(f"Total matches: {total_matches}")
343
+ print(f"Files with matches: {len(results)}")
344
+
345
+ for result in results:
346
+ print(f"{result['file']}: {result['total_matches']} matches")
347
+
348
+ else: # default format
349
+ total_matches = sum(r["total_matches"] for r in results)
350
+ print(f"Found {total_matches} matches in {len(results)} files")
351
+ print("=" * 60)
352
+
353
+ for result in results:
354
+ if "error" in result:
355
+ print(f"Error in {result['file']}: {result['error']}")
356
+ continue
357
+
358
+ print(f"\nFile: {result['file']}")
359
+ print(f"Matches: {result['total_matches']}")
360
+ print("-" * 40)
361
+
362
+ for match in result["matches"]:
363
+ if args.context_lines > 0 and match["context"]:
364
+ for ctx in match["context"]:
365
+ prefix = ">" if ctx["is_match"] else " "
366
+ print(f"{prefix}{ctx['line_number']:4d}: {ctx['content']}")
367
+ else:
368
+ print(f"{match['line_number']:4d}: {match['content']}")
369
+
370
+
371
+ if __name__ == "__main__":
372
+ main()
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Standalone Tools Launcher
4
+
5
+ This script helps you discover and run the available standalone tools.
6
+ """
7
+
8
+ import argparse
9
+ import os
10
+ import subprocess
11
+ import sys
12
+ from pathlib import Path
13
+
14
+
15
+ def get_available_tools():
16
+ """Get list of available tools in the current directory."""
17
+ tools = []
18
+ current_dir = Path(__file__).parent
19
+
20
+ for file in current_dir.glob("*.py"):
21
+ if file.name not in ["launcher.py", "__init__.py"]:
22
+ tools.append(file.name)
23
+
24
+ return sorted(tools)
25
+
26
+
27
+ def get_tool_description(tool_name):
28
+ """Extract description from tool's docstring."""
29
+ try:
30
+ tool_path = Path(__file__).parent / tool_name
31
+ with open(tool_path, "r", encoding="utf-8") as f:
32
+ content = f.read()
33
+
34
+ # Extract description from docstring
35
+ if '"""' in content:
36
+ docstring = content.split('"""')[1]
37
+ if "Description:" in docstring:
38
+ desc_line = docstring.split("Description:")[1].split("\n")[0]
39
+ return desc_line.strip()
40
+
41
+ return "No description available"
42
+ except:
43
+ return "No description available"
44
+
45
+
46
+ def list_tools():
47
+ """List all available tools with their descriptions."""
48
+ print("Available Standalone Tools:")
49
+ print("=" * 50)
50
+
51
+ tools = get_available_tools()
52
+ for tool in tools:
53
+ description = get_tool_description(tool)
54
+ print(f"{tool:<30} - {description}")
55
+
56
+ print(f"\nTotal: {len(tools)} tools available")
57
+ print(
58
+ "\nUse 'python launcher.py run <tool_name> --help' to see tool-specific options"
59
+ )
60
+
61
+
62
+ def run_tool(tool_name, args):
63
+ """Run a specific tool with the given arguments."""
64
+ tools = get_available_tools()
65
+
66
+ if tool_name not in tools:
67
+ print(f"Error: Tool '{tool_name}' not found.")
68
+ print("Available tools:")
69
+ for tool in tools:
70
+ print(f" - {tool}")
71
+ return 1
72
+
73
+ tool_path = Path(__file__).parent / tool_name
74
+
75
+ # Execute the tool
76
+ try:
77
+ cmd = [sys.executable, str(tool_path)] + args
78
+ result = subprocess.run(cmd, check=False)
79
+ return result.returncode
80
+ except Exception as e:
81
+ print(f"Error running tool '{tool_name}': {e}")
82
+ return 1
83
+
84
+
85
+ def search_tools(keyword):
86
+ """Search for tools by keyword in name or description."""
87
+ print(f"Searching for tools containing '{keyword}':")
88
+ print("=" * 50)
89
+
90
+ tools = get_available_tools()
91
+ found = []
92
+
93
+ for tool in tools:
94
+ description = get_tool_description(tool)
95
+ if keyword.lower() in tool.lower() or keyword.lower() in description.lower():
96
+ found.append((tool, description))
97
+
98
+ if found:
99
+ for tool, description in found:
100
+ print(f"{tool:<30} - {description}")
101
+ print(f"\nFound {len(found)} matching tools")
102
+ else:
103
+ print("No tools found matching the keyword.")
104
+
105
+
106
+ def main():
107
+ parser = argparse.ArgumentParser(
108
+ description="Launcher for standalone development tools",
109
+ formatter_class=argparse.RawDescriptionHelpFormatter,
110
+ epilog="""
111
+ Examples:
112
+ python launcher.py list # List all available tools
113
+ python launcher.py search grep # Search for tools containing 'grep'
114
+ python launcher.py run file_search.py "*.py" # Run file_search.py with arguments
115
+ python launcher.py run read_file.py --help # Show help for read_file.py
116
+ """,
117
+ )
118
+
119
+ subparsers = parser.add_subparsers(dest="command", help="Available commands")
120
+
121
+ # List command
122
+ list_parser = subparsers.add_parser("list", help="List all available tools")
123
+
124
+ # Search command
125
+ search_parser = subparsers.add_parser("search", help="Search for tools by keyword")
126
+ search_parser.add_argument("keyword", help="Keyword to search for")
127
+
128
+ # Run command
129
+ run_parser = subparsers.add_parser("run", help="Run a specific tool")
130
+ run_parser.add_argument("tool", help="Name of the tool to run")
131
+ run_parser.add_argument("args", nargs="*", help="Arguments to pass to the tool")
132
+
133
+ args = parser.parse_args()
134
+
135
+ if args.command == "list" or args.command is None:
136
+ list_tools()
137
+ elif args.command == "search":
138
+ search_tools(args.keyword)
139
+ elif args.command == "run":
140
+ return run_tool(args.tool, args.args)
141
+
142
+ return 0
143
+
144
+
145
+ if __name__ == "__main__":
146
+ sys.exit(main())