codegraphcontext-rust 0.5.5__cp311-cp311-win_amd64.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 (101) hide show
  1. codegraphcontext/__init__.py +2 -0
  2. codegraphcontext/__main__.py +5 -0
  3. codegraphcontext/_cgc_rust.cp311-win_amd64.pyd +0 -0
  4. codegraphcontext/cli/__init__.py +1 -0
  5. codegraphcontext/cli/cli_helpers.py +774 -0
  6. codegraphcontext/cli/config_manager.py +1051 -0
  7. codegraphcontext/cli/main.py +2386 -0
  8. codegraphcontext/cli/registry_commands.py +404 -0
  9. codegraphcontext/cli/setup_macos.py +93 -0
  10. codegraphcontext/cli/setup_wizard.py +991 -0
  11. codegraphcontext/cli/visualizer.py +50 -0
  12. codegraphcontext/core/__init__.py +165 -0
  13. codegraphcontext/core/bundle_registry.py +181 -0
  14. codegraphcontext/core/cgc_bundle.py +858 -0
  15. codegraphcontext/core/cgcignore.py +118 -0
  16. codegraphcontext/core/database.py +273 -0
  17. codegraphcontext/core/database_falkordb.py +480 -0
  18. codegraphcontext/core/database_falkordb_remote.py +199 -0
  19. codegraphcontext/core/database_kuzu.py +636 -0
  20. codegraphcontext/core/falkor_worker.py +132 -0
  21. codegraphcontext/core/jobs.py +132 -0
  22. codegraphcontext/core/watcher.py +260 -0
  23. codegraphcontext/prompts.py +125 -0
  24. codegraphcontext/server.py +471 -0
  25. codegraphcontext/tool_definitions.py +220 -0
  26. codegraphcontext/tools/__init__.py +0 -0
  27. codegraphcontext/tools/advanced_language_query_tool.py +103 -0
  28. codegraphcontext/tools/code_finder.py +1160 -0
  29. codegraphcontext/tools/graph_builder.py +337 -0
  30. codegraphcontext/tools/handlers/analysis_handlers.py +114 -0
  31. codegraphcontext/tools/handlers/indexing_handlers.py +116 -0
  32. codegraphcontext/tools/handlers/management_handlers.py +339 -0
  33. codegraphcontext/tools/handlers/query_handlers.py +83 -0
  34. codegraphcontext/tools/handlers/watcher_handlers.py +83 -0
  35. codegraphcontext/tools/indexing/__init__.py +1 -0
  36. codegraphcontext/tools/indexing/constants.py +25 -0
  37. codegraphcontext/tools/indexing/discovery.py +64 -0
  38. codegraphcontext/tools/indexing/engine.py +109 -0
  39. codegraphcontext/tools/indexing/persistence/__init__.py +3 -0
  40. codegraphcontext/tools/indexing/persistence/parquet_loader.py +643 -0
  41. codegraphcontext/tools/indexing/persistence/writer.py +1114 -0
  42. codegraphcontext/tools/indexing/pipeline.py +171 -0
  43. codegraphcontext/tools/indexing/pre_scan.py +105 -0
  44. codegraphcontext/tools/indexing/resolution/__init__.py +8 -0
  45. codegraphcontext/tools/indexing/resolution/calls.py +253 -0
  46. codegraphcontext/tools/indexing/resolution/inheritance.py +91 -0
  47. codegraphcontext/tools/indexing/sanitize.py +41 -0
  48. codegraphcontext/tools/indexing/schema.py +79 -0
  49. codegraphcontext/tools/indexing/schema_contract.py +44 -0
  50. codegraphcontext/tools/indexing/scip_pipeline.py +140 -0
  51. codegraphcontext/tools/languages/c.py +563 -0
  52. codegraphcontext/tools/languages/cpp.py +616 -0
  53. codegraphcontext/tools/languages/csharp.py +551 -0
  54. codegraphcontext/tools/languages/dart.py +378 -0
  55. codegraphcontext/tools/languages/elixir.py +460 -0
  56. codegraphcontext/tools/languages/go.py +499 -0
  57. codegraphcontext/tools/languages/haskell.py +426 -0
  58. codegraphcontext/tools/languages/java.py +500 -0
  59. codegraphcontext/tools/languages/javascript.py +589 -0
  60. codegraphcontext/tools/languages/kotlin.py +640 -0
  61. codegraphcontext/tools/languages/perl.py +260 -0
  62. codegraphcontext/tools/languages/php.py +519 -0
  63. codegraphcontext/tools/languages/python.py +576 -0
  64. codegraphcontext/tools/languages/ruby.py +537 -0
  65. codegraphcontext/tools/languages/rust.py +295 -0
  66. codegraphcontext/tools/languages/scala.py +519 -0
  67. codegraphcontext/tools/languages/swift.py +491 -0
  68. codegraphcontext/tools/languages/typescript.py +575 -0
  69. codegraphcontext/tools/languages/typescriptjsx.py +151 -0
  70. codegraphcontext/tools/package_resolver.py +472 -0
  71. codegraphcontext/tools/query_tool_languages/c_toolkit.py +5 -0
  72. codegraphcontext/tools/query_tool_languages/cpp_toolkit.py +87 -0
  73. codegraphcontext/tools/query_tool_languages/csharp_toolkit.py +5 -0
  74. codegraphcontext/tools/query_tool_languages/dart_toolkit.py +5 -0
  75. codegraphcontext/tools/query_tool_languages/go_toolkit.py +5 -0
  76. codegraphcontext/tools/query_tool_languages/haskell_toolkit.py +5 -0
  77. codegraphcontext/tools/query_tool_languages/java_toolkit.py +5 -0
  78. codegraphcontext/tools/query_tool_languages/javascript_toolkit.py +5 -0
  79. codegraphcontext/tools/query_tool_languages/perl_toolkit.py +5 -0
  80. codegraphcontext/tools/query_tool_languages/python_toolkit.py +5 -0
  81. codegraphcontext/tools/query_tool_languages/ruby_toolkit.py +5 -0
  82. codegraphcontext/tools/query_tool_languages/rust_toolkit.py +5 -0
  83. codegraphcontext/tools/query_tool_languages/scala_toolkit.py +5 -0
  84. codegraphcontext/tools/query_tool_languages/swift_toolkit.py +5 -0
  85. codegraphcontext/tools/query_tool_languages/typescript_toolkit.py +5 -0
  86. codegraphcontext/tools/scip_indexer.py +467 -0
  87. codegraphcontext/tools/scip_pb2.py +2455 -0
  88. codegraphcontext/tools/system.py +133 -0
  89. codegraphcontext/tools/tree_sitter_parser.py +103 -0
  90. codegraphcontext/utils/debug_log.py +90 -0
  91. codegraphcontext/utils/path_ignore.py +55 -0
  92. codegraphcontext/utils/repo_path.py +27 -0
  93. codegraphcontext/utils/tree_sitter_manager.py +285 -0
  94. codegraphcontext/utils/visualize_graph.py +0 -0
  95. codegraphcontext/viz/server.py +282 -0
  96. codegraphcontext_rust-0.5.5.dist-info/METADATA +537 -0
  97. codegraphcontext_rust-0.5.5.dist-info/RECORD +101 -0
  98. codegraphcontext_rust-0.5.5.dist-info/WHEEL +4 -0
  99. codegraphcontext_rust-0.5.5.dist-info/entry_points.txt +3 -0
  100. codegraphcontext_rust-0.5.5.dist-info/licenses/LICENSE +21 -0
  101. codegraphcontext_rust-0.5.5.dist-info/sboms/cgc-python.cyclonedx.json +2333 -0
@@ -0,0 +1,151 @@
1
+ from pathlib import Path
2
+
3
+ def pre_scan_typescript(files: list[Path], parser_wrapper) -> dict:
4
+ """
5
+ Scans TypeScript JSX (.tsx) files to create a map of class/function names to their file paths.
6
+ Reuses the logic from TypeScript parser, but can be extended for JSX-specific extraction.
7
+ """
8
+ imports_map = {}
9
+ # Use the same queries as TypeScript
10
+ query_strings = [
11
+ "(class_declaration) @class",
12
+ "(function_declaration) @function",
13
+ "(variable_declarator) @var_decl",
14
+ "(method_definition) @method",
15
+ "(interface_declaration) @interface",
16
+ "(type_alias_declaration) @type_alias",
17
+ ]
18
+ for path in files:
19
+ try:
20
+ with open(path, "r", encoding="utf-8") as f:
21
+ source_code = f.read()
22
+ tree = parser_wrapper.parser.parse(bytes(source_code, "utf8"))
23
+ for query_str in query_strings:
24
+ try:
25
+ for node, capture_name in execute_query(parser_wrapper.language, query_str, tree.root_node):
26
+ name = None
27
+ if capture_name == 'class':
28
+ name_node = node.child_by_field_name('name')
29
+ if name_node:
30
+ name = name_node.text.decode('utf-8')
31
+ elif capture_name == 'function':
32
+ name_node = node.child_by_field_name('name')
33
+ if name_node:
34
+ name = name_node.text.decode('utf-8')
35
+ elif capture_name == 'var_decl':
36
+ name_node = node.child_by_field_name('name')
37
+ value_node = node.child_by_field_name('value')
38
+ if name_node and value_node:
39
+ if value_node.type in ('function', 'arrow_function'):
40
+ name = name_node.text.decode('utf-8')
41
+ elif capture_name == 'method':
42
+ name_node = node.child_by_field_name('name')
43
+ if name_node:
44
+ name = name_node.text.decode('utf-8')
45
+ elif capture_name == 'interface':
46
+ name_node = node.child_by_field_name('name')
47
+ if name_node:
48
+ name = name_node.text.decode('utf-8')
49
+ elif capture_name == 'type_alias':
50
+ name_node = node.child_by_field_name('name')
51
+ if name_node:
52
+ name = name_node.text.decode('utf-8')
53
+ if name:
54
+ if name not in imports_map:
55
+ imports_map[name] = []
56
+ file_path_str = str(path.resolve())
57
+ if file_path_str not in imports_map[name]:
58
+ imports_map[name].append(file_path_str)
59
+ except Exception as query_error:
60
+ warning_logger(f"Query failed for pattern '{query_str}': {query_error}")
61
+ except Exception as e:
62
+ warning_logger(f"Tree-sitter pre-scan failed for {path}: {e}")
63
+ return imports_map
64
+ from typing import Dict, Any
65
+ from codegraphcontext.utils.debug_log import warning_logger
66
+ from codegraphcontext.utils.tree_sitter_manager import execute_query
67
+ from .typescript import TypescriptTreeSitterParser
68
+
69
+ class TypescriptJSXTreeSitterParser(TypescriptTreeSitterParser):
70
+ """
71
+ A parser for TypeScript JSX (.tsx) files.
72
+ """
73
+ def __init__(self, generic_parser_wrapper):
74
+ super().__init__(generic_parser_wrapper)
75
+ self.language_name = 'typescript'
76
+ self.jsx_enabled = True
77
+ def parse(self, path: Path, is_dependency: bool = False, index_source: bool = False) -> Dict[str, Any]:
78
+ """
79
+ Parse a .tsx file, reusing TypeScript logic and ensuring JSX nodes are handled.
80
+ Indexes components, functions, imports, and exports.
81
+ """
82
+ self.index_source = index_source
83
+ with open(path, "r", encoding="utf-8") as f:
84
+ source_code = f.read()
85
+ tree = self.parser.parse(bytes(source_code, "utf8"))
86
+ root_node = tree.root_node
87
+
88
+ # Reuse TypeScript logic for functions, classes, interfaces, type aliases, imports, calls, variables
89
+ functions = self._find_functions(root_node)
90
+ classes = self._find_classes(root_node)
91
+ interfaces = self._find_interfaces(root_node)
92
+ type_aliases = self._find_type_aliases(root_node)
93
+ imports = self._find_imports(root_node)
94
+ function_calls = self._find_calls(root_node)
95
+ variables = self._find_variables(root_node)
96
+
97
+ # Index React components (function and class components)
98
+ components = self._find_react_components(root_node)
99
+
100
+ return {
101
+ "path": str(path),
102
+ "functions": functions,
103
+ "classes": classes,
104
+ "interfaces": interfaces,
105
+ "type_aliases": type_aliases,
106
+ "variables": variables,
107
+ "imports": imports,
108
+ "function_calls": function_calls,
109
+ "components": components,
110
+ "is_dependency": is_dependency,
111
+ "lang": self.language_name,
112
+ }
113
+
114
+ def _find_react_components(self, root_node):
115
+ """
116
+ Find React components in .tsx files (function and class components).
117
+ """
118
+ components = []
119
+ # Function components: exported arrow/function assigned to const, returning JSX
120
+ # Class components: class extending React.Component or React.PureComponent
121
+ # This is a simplified query, can be extended for more cases
122
+ query_strings = [
123
+ '(class_declaration name: (type_identifier) @name)',
124
+ '(variable_declarator name: (identifier) @name value: (arrow_function) @fn)',
125
+ '(variable_declarator name: (identifier) @name value: (function_expression) @fn)',
126
+ '(function_declaration name: (identifier) @name)',
127
+ ]
128
+ for query_str in query_strings:
129
+ for node, capture_name in execute_query(self.language, query_str, root_node):
130
+ if capture_name == 'name':
131
+ name = node.text.decode('utf-8')
132
+ line_number = node.start_point[0] + 1
133
+ component_data = {
134
+ "name": name,
135
+ "line_number": line_number,
136
+ "type": "component",
137
+ "lang": self.language_name,
138
+ }
139
+
140
+ if self.index_source:
141
+ # Assuming node is the name node, we might want the parent declaration node for source
142
+ # The query captures 'name', so node is the identifier.
143
+ # We need the parent node.
144
+ # (class_declaration ... name: (identifier) @name) -> parent is class_declaration
145
+ # (variable_declarator name: (identifier) @name ...) -> parent is variable_declarator
146
+ # (function_declaration name: (identifier) @name) -> parent is function_declaration
147
+ parent = node.parent
148
+ component_data["source"] = parent.text.decode('utf-8')
149
+
150
+ components.append(component_data)
151
+ return components
@@ -0,0 +1,472 @@
1
+ # src/codegraphcontext/tools/package_resolver.py
2
+ import importlib.util
3
+ import stdlibs
4
+ from pathlib import Path
5
+ import subprocess
6
+ from typing import Optional
7
+
8
+ from ..utils.debug_log import debug_log
9
+
10
+ def _get_python_package_path(package_name: str) -> Optional[str]:
11
+ """
12
+ Finds the local installation path of a Python package.
13
+ Uses importlib.util.find_spec() to locate the module without executing its code.
14
+ """
15
+ try:
16
+ debug_log(f"Getting local path for Python package: {package_name}")
17
+ spec = importlib.util.find_spec(package_name)
18
+ if spec is None:
19
+ return None
20
+ if spec.origin and spec.origin != "frozen":
21
+ module_file = Path(spec.origin)
22
+ if module_file.name == '__init__.py':
23
+ return str(module_file.parent)
24
+ elif package_name in stdlibs.module_names:
25
+ return str(module_file)
26
+ else:
27
+ return str(module_file.parent)
28
+ elif spec.submodule_search_locations:
29
+ locations = list(spec.submodule_search_locations)
30
+ if locations:
31
+ return str(Path(locations[0]))
32
+ return None
33
+ except (ModuleNotFoundError, ValueError):
34
+ return None
35
+ except Exception as e:
36
+ debug_log(f"Error getting local path for {package_name}: {e}")
37
+ return None
38
+
39
+ def _get_npm_package_path(package_name: str) -> Optional[str]:
40
+ """
41
+ Finds the local installation path of a Node.js package using `npm root`.
42
+ """
43
+ try:
44
+ debug_log(f"Getting local path for npm package: {package_name}")
45
+ local_path = Path(f"./node_modules/{package_name}")
46
+ if local_path.exists():
47
+ return str(local_path.resolve())
48
+
49
+ result = subprocess.run(["npm", "root", "-g"], capture_output=True, text=True)
50
+ if result.returncode == 0:
51
+ global_root = result.stdout.strip()
52
+ package_path = Path(global_root) / package_name
53
+ if package_path.exists():
54
+ return str(package_path.resolve())
55
+ return None
56
+ except Exception as e:
57
+ debug_log(f"Error getting npm package path for {package_name}: {e}")
58
+ return None
59
+
60
+ def _get_typescript_package_path(package_name: str) -> Optional[str]:
61
+ """
62
+ Finds the local installation path of a TypeScript package.
63
+ TypeScript packages are typically npm packages, so this uses the same logic as npm.
64
+ """
65
+ try:
66
+ debug_log(f"Getting local path for TypeScript package: {package_name}")
67
+
68
+ # Check local node_modules first
69
+ local_path = Path(f"./node_modules/{package_name}")
70
+ if local_path.exists():
71
+ return str(local_path.resolve())
72
+
73
+ # Check global npm packages
74
+ result = subprocess.run(["npm", "root", "-g"], capture_output=True, text=True, timeout=5)
75
+ if result.returncode == 0:
76
+ global_root = result.stdout.strip()
77
+ package_path = Path(global_root) / package_name
78
+ if package_path.exists():
79
+ return str(package_path.resolve())
80
+
81
+ return None
82
+ except subprocess.TimeoutExpired:
83
+ debug_log(f"npm command timed out for {package_name}")
84
+ return None
85
+ except Exception as e:
86
+ debug_log(f"Error getting TypeScript package path for {package_name}: {e}")
87
+ return None
88
+
89
+ def _get_java_package_path(package_name: str) -> Optional[str]:
90
+ """
91
+ Finds the local installation path of a Java package (JAR).
92
+ Searches in Maven and Gradle cache directories.
93
+
94
+ Args:
95
+ package_name: Package name in format "groupId:artifactId" (e.g., "com.google.code.gson:gson")
96
+ or just "artifactId" for simple search.
97
+ """
98
+ try:
99
+ debug_log(f"Getting local path for Java package: {package_name}")
100
+
101
+ # Parse package name - expect format "groupId:artifactId" or just "artifactId"
102
+ if ':' in package_name:
103
+ group_id, artifact_id = package_name.split(':', 1)
104
+ # Convert group_id dots to path separators (e.g., com.google.gson -> com/google/gson)
105
+ group_path = group_id.replace('.', '/')
106
+ else:
107
+ # If only artifact_id provided, search for it
108
+ artifact_id = package_name
109
+ group_path = None
110
+
111
+ search_paths = []
112
+
113
+ # Maven repository (~/.m2/repository)
114
+ maven_repo = Path.home() / ".m2" / "repository"
115
+ if maven_repo.exists():
116
+ if group_path:
117
+ # Search for specific group/artifact
118
+ package_path = maven_repo / group_path / artifact_id
119
+ if package_path.exists():
120
+ # Find the latest version directory
121
+ version_dirs = [d for d in package_path.iterdir() if d.is_dir()]
122
+ if version_dirs:
123
+ # Sort by name (assumes semantic versioning) and get the latest
124
+ latest_version = sorted(version_dirs, key=lambda x: x.name)[-1]
125
+ return str(latest_version.resolve())
126
+ else:
127
+ # Search for artifact_id in the entire Maven repo
128
+ search_paths.append(maven_repo)
129
+
130
+ # Gradle cache (~/.gradle/caches/modules-2/files-2.1)
131
+ gradle_cache = Path.home() / ".gradle" / "caches" / "modules-2" / "files-2.1"
132
+ if gradle_cache.exists():
133
+ if group_path:
134
+ group_id_full = group_id if ':' in package_name else None
135
+ if group_id_full:
136
+ package_path = gradle_cache / group_id_full / artifact_id
137
+ if package_path.exists():
138
+ # Find the latest version directory
139
+ version_dirs = [d for d in package_path.iterdir() if d.is_dir()]
140
+ if version_dirs:
141
+ latest_version = sorted(version_dirs, key=lambda x: x.name)[-1]
142
+ # Gradle stores files in hash subdirectories
143
+ hash_dirs = [d for d in latest_version.iterdir() if d.is_dir()]
144
+ if hash_dirs:
145
+ return str(hash_dirs[0].resolve())
146
+ else:
147
+ search_paths.append(gradle_cache)
148
+
149
+ # If group_path wasn't provided or not found, search in the cache directories
150
+ if not group_path or search_paths:
151
+ for base_path in search_paths:
152
+ for jar_file in base_path.rglob(f"*{artifact_id}*.jar"):
153
+ return str(jar_file.parent.resolve())
154
+
155
+ # Check local lib directories
156
+ local_lib_paths = [
157
+ Path("./lib"),
158
+ Path("./libs"),
159
+ Path("/usr/local/lib/java"),
160
+ Path("/opt/java/lib"),
161
+ ]
162
+
163
+ for lib_path in local_lib_paths:
164
+ if not lib_path.exists():
165
+ continue
166
+
167
+ # Look for JAR files matching the artifact name
168
+ for jar_file in lib_path.glob(f"*{artifact_id}*.jar"):
169
+ return str(jar_file.resolve())
170
+
171
+ return None
172
+ except Exception as e:
173
+ debug_log(f"Error getting Java package path for {package_name}: {e}")
174
+ def _get_c_package_path(package_name: str) -> Optional[str]:
175
+ """
176
+ Finds the local installation path of a C package.
177
+ """
178
+ try:
179
+ debug_log(f"Getting local path for C package: {package_name}")
180
+
181
+ # Try using pkg-config to find the package
182
+ try:
183
+ result = subprocess.run(
184
+ ["pkg-config", "--variable=includedir", package_name],
185
+ capture_output=True,
186
+ text=True,
187
+ timeout=5
188
+ )
189
+ if result.returncode == 0 and result.stdout.strip():
190
+ include_dir = Path(result.stdout.strip())
191
+ package_path = include_dir / package_name
192
+ if package_path.exists():
193
+ return str(package_path.resolve())
194
+ if include_dir.exists():
195
+ return str(include_dir.resolve())
196
+ except (subprocess.TimeoutExpired, FileNotFoundError):
197
+ debug_log(f"pkg-config not available or timed out for {package_name}")
198
+
199
+ # Search in standard system include directories
200
+ common_include_paths = [
201
+ "/usr/include",
202
+ "/usr/local/include",
203
+ "/opt/homebrew/include",
204
+ "/opt/local/include",
205
+ Path.home() / ".local" / "include",
206
+ ]
207
+
208
+ for base_path in common_include_paths:
209
+ base_path = Path(base_path)
210
+ if not base_path.exists():
211
+ continue
212
+
213
+ # Check if package exists as a directory
214
+ package_dir = base_path / package_name
215
+ if package_dir.exists() and package_dir.is_dir():
216
+ return str(package_dir.resolve())
217
+
218
+ # Check for header files with package name
219
+ header_file = base_path / f"{package_name}.h"
220
+ if header_file.exists():
221
+ return str(header_file.resolve())
222
+
223
+ # Check current directory for local installations
224
+ local_package = Path(f"./{package_name}")
225
+ if local_package.exists():
226
+ return str(local_package.resolve())
227
+
228
+ return None
229
+ except Exception as e:
230
+ debug_log(f"Error getting C package path for {package_name}: {e}")
231
+ return None
232
+
233
+ def _get_ruby_package_path(package_name: str) -> Optional[str]:
234
+ """
235
+ Finds the local installation path of a Ruby gem.
236
+ """
237
+ try:
238
+ debug_log(f"Getting local path for Ruby gem: {package_name}")
239
+ result = subprocess.run(
240
+ ["gem", "which", package_name],
241
+ capture_output=True,
242
+ text=True,
243
+ timeout=5
244
+ )
245
+ if result.returncode == 0 and result.stdout.strip():
246
+ gem_path = Path(result.stdout.strip())
247
+ if gem_path.exists():
248
+ lib_dir = gem_path.parent if gem_path.is_file() else gem_path
249
+ # If we are inside a gem (…/gems/foo-x.y.z/lib/foo.rb), prefer the lib/ dir:
250
+ if (lib_dir.name == "lib") and lib_dir.is_dir():
251
+ return str(lib_dir.resolve())
252
+ # Try parent/lib in case `gem which` returned .../lib/foo.rb
253
+ if (lib_dir / "lib").is_dir():
254
+ return str((lib_dir / "lib").resolve())
255
+ # Fallback: just return the directory containing the file (stdlib case like 'json')
256
+ return str(lib_dir.resolve())
257
+ return None
258
+ except (subprocess.TimeoutExpired, FileNotFoundError):
259
+ debug_log(f"gem command not available or timed out for {package_name}")
260
+ return None
261
+ except Exception as e:
262
+ debug_log(f"Error getting Ruby gem path for {package_name}: {e}")
263
+ return None
264
+
265
+ def _get_go_package_path(package_name: str) -> Optional[str]:
266
+ """
267
+ Finds the local installation path of a Go package using `go list`.
268
+ Tries multiple approaches in sequence to handle different package scenarios:
269
+ 1) package dir: go list -f '{{.Dir}}' <pkg> (works for stdlib, GOPATH, or module subpackages)
270
+ 2) module root: go list -m -f '{{.Dir}}' <module> (works for full module paths)
271
+ 3) force mod: go list -mod=mod -f '{{.Dir}}' <pkg> (works when outside a module context)
272
+ 4) GOROOT check: for standard library packages
273
+ 5) GOPATH check: for packages in GOPATH
274
+ """
275
+
276
+ def _first_existing_dir(output: str) -> Optional[str]:
277
+ for line in (l.strip().strip("'\"") for l in output.splitlines() if l.strip()):
278
+ p = Path(line)
279
+ if p.exists() and p.is_dir():
280
+ return str(p.resolve())
281
+ return None
282
+
283
+ try:
284
+ debug_log(f"Getting local path for Go package: {package_name}")
285
+
286
+ # 1. Package directory (works for stdlib, GOPATH, or subpackages)
287
+ cp = subprocess.run(
288
+ ["go", "list", "-f", "{{.Dir}}", package_name],
289
+ capture_output=True, text=True, timeout=15
290
+ )
291
+ if cp.returncode == 0:
292
+ d = _first_existing_dir(cp.stdout)
293
+ if d:
294
+ return d
295
+
296
+ # 2. Module root directory (where go.mod lives)
297
+ cp2 = subprocess.run(
298
+ ["go", "list", "-m", "-f", "{{.Dir}}", package_name],
299
+ capture_output=True, text=True, timeout=15
300
+ )
301
+ if cp2.returncode == 0:
302
+ d = _first_existing_dir(cp2.stdout)
303
+ if d:
304
+ debug_log(f"Found Go module {package_name} at {d}")
305
+ return d
306
+
307
+ # 3. Retry forcing module mode
308
+ cp3 = subprocess.run(
309
+ ["go", "list", "-mod=mod", "-f", "{{.Dir}}", package_name],
310
+ capture_output=True, text=True, timeout=15
311
+ )
312
+ if cp3.returncode == 0:
313
+ d = _first_existing_dir(cp3.stdout)
314
+ if d:
315
+ return d
316
+
317
+ # 4. Check in GOROOT for standard library packages
318
+ try:
319
+ cp4 = subprocess.run(
320
+ ["go", "env", "GOROOT"],
321
+ capture_output=True, text=True, timeout=5
322
+ )
323
+ if cp4.returncode == 0:
324
+ goroot = cp4.stdout.strip()
325
+ if goroot:
326
+ std_lib_path = Path(goroot) / "src" / package_name
327
+ if std_lib_path.exists() and std_lib_path.is_dir():
328
+ return str(std_lib_path.resolve())
329
+ except Exception as e:
330
+ debug_log(f"Error checking GOROOT for {package_name}: {e}")
331
+
332
+ # 5. Check in GOPATH as fallback
333
+ try:
334
+ cp5 = subprocess.run(
335
+ ["go", "env", "GOPATH"],
336
+ capture_output=True, text=True, timeout=5
337
+ )
338
+ if cp5.returncode == 0:
339
+ gopath = cp5.stdout.strip()
340
+ if gopath:
341
+ gopath_lib_path = Path(gopath) / "src" / package_name
342
+ if gopath_lib_path.exists() and gopath_lib_path.is_dir():
343
+ debug_log(f"Found Go package in GOPATH {package_name} at {gopath_lib_path}")
344
+ return str(gopath_lib_path.resolve())
345
+ except Exception as e:
346
+ debug_log(f"Error checking GOPATH for {package_name}: {e}")
347
+
348
+ debug_log(f"Could not find Go package: {package_name}")
349
+ return None
350
+
351
+ except (subprocess.TimeoutExpired, FileNotFoundError):
352
+ debug_log(f"go command not available or timed out for {package_name}")
353
+ return None
354
+ except Exception as e:
355
+ debug_log(f"Error getting Go package path for {package_name}: {e}")
356
+ return None
357
+
358
+ def _get_php_package_path(package_name: str) -> Optional[str]:
359
+ try:
360
+ debug_log(f"Getting local path for PHP package: {package_name}")
361
+
362
+ local_vendor = Path("./vendor") / package_name
363
+ if local_vendor.exists() and local_vendor.is_dir():
364
+ return str(local_vendor.resolve())
365
+
366
+ current_dir = Path.cwd()
367
+ for parent in [current_dir] + list(current_dir.parents):
368
+ vendor_path = parent / "vendor" / package_name
369
+ if vendor_path.exists() and vendor_path.is_dir():
370
+ return str(vendor_path.resolve())
371
+
372
+ if (parent / "composer.json").exists():
373
+ break
374
+
375
+ composer_home = Path.home() / ".composer" / "vendor" / package_name
376
+ if composer_home.exists() and composer_home.is_dir():
377
+ return str(composer_home.resolve())
378
+
379
+ composer_global = Path.home() / ".config" / "composer" / "vendor" / package_name
380
+ if composer_global.exists() and composer_global.is_dir():
381
+ return str(composer_global.resolve())
382
+
383
+ return None
384
+ except Exception as e:
385
+ debug_log(f"Error getting PHP package path for {package_name}: {e}")
386
+ return None
387
+
388
+
389
+
390
+ def _get_dart_package_path(package_name: str) -> Optional[str]:
391
+ """
392
+ Finds the local installation path of a Dart package.
393
+ Uses 'dart pub cache list' or looks in PUB_CACHE.
394
+ """
395
+ try:
396
+ import os
397
+ debug_log(f"Getting local path for Dart package: {package_name}")
398
+
399
+ # Check environment variable
400
+ pub_cache = os.environ.get("PUB_CACHE")
401
+ if not pub_cache:
402
+ pub_cache = str(Path.home() / ".pub-cache")
403
+
404
+ hosted_path = Path(pub_cache) / "hosted" / "pub.dev" / package_name
405
+ if hosted_path.exists():
406
+ # Find the latest version if multiple exist
407
+ versions = [d for d in hosted_path.parent.glob(f"{package_name}-*") if d.is_dir()]
408
+ if versions:
409
+ return str(sorted(versions)[-1].resolve())
410
+ return str(hosted_path.resolve())
411
+
412
+ return None
413
+ except Exception as e:
414
+ debug_log(f"Error getting Dart package path for {package_name}: {e}")
415
+ return None
416
+
417
+ def get_local_package_path(package_name: str, language: str) -> Optional[str]:
418
+ """
419
+ Dispatches to the correct package path finder based on the language.
420
+ """
421
+ finders = {
422
+ "python": _get_python_package_path,
423
+ "javascript": _get_npm_package_path,
424
+ "typescript": _get_typescript_package_path,
425
+ "java": _get_java_package_path,
426
+ "c": _get_c_package_path,
427
+ "go": _get_go_package_path,
428
+ "ruby": _get_ruby_package_path,
429
+ "php": _get_php_package_path,
430
+ "cpp": _get_cpp_package_path,
431
+ "dart": _get_dart_package_path,
432
+ }
433
+ finder = finders.get(language)
434
+ if finder:
435
+ return finder(package_name)
436
+ return None
437
+
438
+ def _get_cpp_package_path(package_name: str) -> Optional[str]:
439
+ """
440
+ C++ package ka local path find karta hai.
441
+ Pehle pkg-config try karta hai, fir common system paths check karta hai.
442
+ """
443
+ import subprocess
444
+ import os
445
+
446
+ # Try pkg-config
447
+ try:
448
+ result = subprocess.run(
449
+ ["pkg-config", "--variable=includedir", package_name],
450
+ capture_output=True,
451
+ text=True,
452
+ check=False
453
+ )
454
+ path = result.stdout.strip()
455
+ if path and os.path.exists(path):
456
+ return path
457
+ except FileNotFoundError:
458
+ pass
459
+
460
+ # Common system include/lib folders
461
+ common_paths = [
462
+ f"/usr/include/{package_name}",
463
+ f"/usr/local/include/{package_name}",
464
+ f"/usr/lib/{package_name}",
465
+ f"/usr/local/lib/{package_name}",
466
+ ]
467
+ for path in common_paths:
468
+ if os.path.exists(path):
469
+ return path
470
+
471
+ return None
472
+
@@ -0,0 +1,5 @@
1
+ class CToolkit:
2
+ """Template placeholder for future implementation."""
3
+
4
+ def get_cypher_query(query: str) -> str:
5
+ raise NotImplementedError("AdvancedLanguageQuery is not implemented yet.")