jarvis-ai-assistant 0.1.222__py3-none-any.whl → 0.7.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.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +1143 -245
- jarvis/jarvis_agent/agent_manager.py +97 -0
- jarvis/jarvis_agent/builtin_input_handler.py +12 -10
- jarvis/jarvis_agent/config_editor.py +57 -0
- jarvis/jarvis_agent/edit_file_handler.py +392 -99
- jarvis/jarvis_agent/event_bus.py +48 -0
- jarvis/jarvis_agent/events.py +157 -0
- jarvis/jarvis_agent/file_context_handler.py +79 -0
- jarvis/jarvis_agent/file_methodology_manager.py +117 -0
- jarvis/jarvis_agent/jarvis.py +1117 -147
- jarvis/jarvis_agent/main.py +78 -34
- jarvis/jarvis_agent/memory_manager.py +195 -0
- jarvis/jarvis_agent/methodology_share_manager.py +174 -0
- jarvis/jarvis_agent/prompt_manager.py +82 -0
- jarvis/jarvis_agent/prompts.py +46 -9
- jarvis/jarvis_agent/protocols.py +4 -1
- jarvis/jarvis_agent/rewrite_file_handler.py +141 -0
- jarvis/jarvis_agent/run_loop.py +146 -0
- jarvis/jarvis_agent/session_manager.py +9 -9
- jarvis/jarvis_agent/share_manager.py +228 -0
- jarvis/jarvis_agent/shell_input_handler.py +23 -3
- jarvis/jarvis_agent/stdio_redirect.py +295 -0
- jarvis/jarvis_agent/task_analyzer.py +212 -0
- jarvis/jarvis_agent/task_manager.py +154 -0
- jarvis/jarvis_agent/task_planner.py +496 -0
- jarvis/jarvis_agent/tool_executor.py +8 -4
- jarvis/jarvis_agent/tool_share_manager.py +139 -0
- jarvis/jarvis_agent/user_interaction.py +42 -0
- jarvis/jarvis_agent/utils.py +54 -0
- jarvis/jarvis_agent/web_bridge.py +189 -0
- jarvis/jarvis_agent/web_output_sink.py +53 -0
- jarvis/jarvis_agent/web_server.py +751 -0
- jarvis/jarvis_c2rust/__init__.py +26 -0
- jarvis/jarvis_c2rust/cli.py +613 -0
- jarvis/jarvis_c2rust/collector.py +258 -0
- jarvis/jarvis_c2rust/library_replacer.py +1122 -0
- jarvis/jarvis_c2rust/llm_module_agent.py +1300 -0
- jarvis/jarvis_c2rust/optimizer.py +960 -0
- jarvis/jarvis_c2rust/scanner.py +1681 -0
- jarvis/jarvis_c2rust/transpiler.py +2325 -0
- jarvis/jarvis_code_agent/build_validation_config.py +133 -0
- jarvis/jarvis_code_agent/code_agent.py +1605 -178
- jarvis/jarvis_code_agent/code_analyzer/__init__.py +62 -0
- jarvis/jarvis_code_agent/code_analyzer/base_language.py +74 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +44 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +102 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +59 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +125 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +69 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +38 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +44 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +38 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +50 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +93 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +129 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +54 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +154 -0
- jarvis/jarvis_code_agent/code_analyzer/build_validator.py +43 -0
- jarvis/jarvis_code_agent/code_analyzer/context_manager.py +363 -0
- jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +18 -0
- jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +132 -0
- jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +330 -0
- jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +781 -0
- jarvis/jarvis_code_agent/code_analyzer/language_registry.py +185 -0
- jarvis/jarvis_code_agent/code_analyzer/language_support.py +89 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +31 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +231 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +183 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +219 -0
- jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +209 -0
- jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +451 -0
- jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +77 -0
- jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +48 -0
- jarvis/jarvis_code_agent/lint.py +275 -13
- jarvis/jarvis_code_agent/utils.py +142 -0
- jarvis/jarvis_code_analysis/checklists/loader.py +20 -6
- jarvis/jarvis_code_analysis/code_review.py +583 -548
- jarvis/jarvis_data/config_schema.json +339 -28
- jarvis/jarvis_git_squash/main.py +22 -13
- jarvis/jarvis_git_utils/git_commiter.py +171 -55
- jarvis/jarvis_mcp/sse_mcp_client.py +22 -15
- jarvis/jarvis_mcp/stdio_mcp_client.py +4 -4
- jarvis/jarvis_mcp/streamable_mcp_client.py +36 -16
- jarvis/jarvis_memory_organizer/memory_organizer.py +753 -0
- jarvis/jarvis_methodology/main.py +48 -63
- jarvis/jarvis_multi_agent/__init__.py +302 -43
- jarvis/jarvis_multi_agent/main.py +70 -24
- jarvis/jarvis_platform/ai8.py +40 -23
- jarvis/jarvis_platform/base.py +210 -49
- jarvis/jarvis_platform/human.py +11 -1
- jarvis/jarvis_platform/kimi.py +82 -76
- jarvis/jarvis_platform/openai.py +73 -1
- jarvis/jarvis_platform/registry.py +8 -15
- jarvis/jarvis_platform/tongyi.py +115 -101
- jarvis/jarvis_platform/yuanbao.py +89 -63
- jarvis/jarvis_platform_manager/main.py +194 -132
- jarvis/jarvis_platform_manager/service.py +122 -86
- jarvis/jarvis_rag/cli.py +156 -53
- jarvis/jarvis_rag/embedding_manager.py +155 -12
- jarvis/jarvis_rag/llm_interface.py +10 -13
- jarvis/jarvis_rag/query_rewriter.py +63 -12
- jarvis/jarvis_rag/rag_pipeline.py +222 -40
- jarvis/jarvis_rag/reranker.py +26 -3
- jarvis/jarvis_rag/retriever.py +270 -14
- jarvis/jarvis_sec/__init__.py +3605 -0
- jarvis/jarvis_sec/checkers/__init__.py +32 -0
- jarvis/jarvis_sec/checkers/c_checker.py +2680 -0
- jarvis/jarvis_sec/checkers/rust_checker.py +1108 -0
- jarvis/jarvis_sec/cli.py +116 -0
- jarvis/jarvis_sec/report.py +257 -0
- jarvis/jarvis_sec/status.py +264 -0
- jarvis/jarvis_sec/types.py +20 -0
- jarvis/jarvis_sec/workflow.py +219 -0
- jarvis/jarvis_smart_shell/main.py +405 -137
- jarvis/jarvis_stats/__init__.py +13 -0
- jarvis/jarvis_stats/cli.py +387 -0
- jarvis/jarvis_stats/stats.py +711 -0
- jarvis/jarvis_stats/storage.py +612 -0
- jarvis/jarvis_stats/visualizer.py +282 -0
- jarvis/jarvis_tools/ask_user.py +1 -0
- jarvis/jarvis_tools/base.py +18 -2
- jarvis/jarvis_tools/clear_memory.py +239 -0
- jarvis/jarvis_tools/cli/main.py +220 -144
- jarvis/jarvis_tools/execute_script.py +52 -12
- jarvis/jarvis_tools/file_analyzer.py +17 -12
- jarvis/jarvis_tools/generate_new_tool.py +46 -24
- jarvis/jarvis_tools/read_code.py +277 -18
- jarvis/jarvis_tools/read_symbols.py +141 -0
- jarvis/jarvis_tools/read_webpage.py +86 -13
- jarvis/jarvis_tools/registry.py +294 -90
- jarvis/jarvis_tools/retrieve_memory.py +227 -0
- jarvis/jarvis_tools/save_memory.py +194 -0
- jarvis/jarvis_tools/search_web.py +62 -28
- jarvis/jarvis_tools/sub_agent.py +205 -0
- jarvis/jarvis_tools/sub_code_agent.py +217 -0
- jarvis/jarvis_tools/virtual_tty.py +330 -62
- jarvis/jarvis_utils/builtin_replace_map.py +4 -5
- jarvis/jarvis_utils/clipboard.py +90 -0
- jarvis/jarvis_utils/config.py +607 -50
- jarvis/jarvis_utils/embedding.py +3 -0
- jarvis/jarvis_utils/fzf.py +57 -0
- jarvis/jarvis_utils/git_utils.py +251 -29
- jarvis/jarvis_utils/globals.py +174 -17
- jarvis/jarvis_utils/http.py +58 -79
- jarvis/jarvis_utils/input.py +899 -153
- jarvis/jarvis_utils/methodology.py +210 -83
- jarvis/jarvis_utils/output.py +220 -137
- jarvis/jarvis_utils/utils.py +1906 -135
- jarvis_ai_assistant-0.7.0.dist-info/METADATA +465 -0
- jarvis_ai_assistant-0.7.0.dist-info/RECORD +192 -0
- {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/entry_points.txt +8 -2
- jarvis/jarvis_git_details/main.py +0 -265
- jarvis/jarvis_platform/oyi.py +0 -357
- jarvis/jarvis_tools/edit_file.py +0 -255
- jarvis/jarvis_tools/rewrite_file.py +0 -195
- jarvis_ai_assistant-0.1.222.dist-info/METADATA +0 -767
- jarvis_ai_assistant-0.1.222.dist-info/RECORD +0 -110
- /jarvis/{jarvis_git_details → jarvis_memory_organizer}/__init__.py +0 -0
- {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.222.dist-info → jarvis_ai_assistant-0.7.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Lightweight function-name collector for header files using libclang.
|
|
4
|
+
|
|
5
|
+
Purpose:
|
|
6
|
+
- Given one or more C/C++ header files (.h/.hh/.hpp/.hxx), parse each file with libclang
|
|
7
|
+
and collect function names.
|
|
8
|
+
- Prefer qualified names when available; fall back to unqualified names.
|
|
9
|
+
- Write unique names (de-duplicated, preserving first-seen order) to the specified output file (one per line).
|
|
10
|
+
|
|
11
|
+
Design:
|
|
12
|
+
- Reuse scanner utilities:
|
|
13
|
+
- _try_import_libclang()
|
|
14
|
+
- find_compile_commands()
|
|
15
|
+
- load_compile_commands()
|
|
16
|
+
- scan_file() (note: scan_file collects only definitions; inline headers are often definitions)
|
|
17
|
+
- If compile_commands.json exists, use its args; otherwise, fall back to minimal include of file.parent.
|
|
18
|
+
- For header parsing, ensure a language flag (-x c-header / -x c++-header) is present if args do not specify one.
|
|
19
|
+
|
|
20
|
+
Notes:
|
|
21
|
+
- This module focuses on correctness/robustness over performance.
|
|
22
|
+
- It does not attempt to discover transitive includes; it only assists the parser by adding -I <file.parent>.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
from typing import List, Optional, Dict
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
from jarvis.jarvis_c2rust.scanner import (
|
|
32
|
+
_try_import_libclang,
|
|
33
|
+
find_compile_commands,
|
|
34
|
+
load_compile_commands,
|
|
35
|
+
scan_file,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
HEADER_EXTS = {".h", ".hh", ".hpp", ".hxx"}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _guess_lang_header_flag(file: Path) -> List[str]:
|
|
43
|
+
"""
|
|
44
|
+
Guess appropriate -x language flag for header if not specified in compile args.
|
|
45
|
+
"""
|
|
46
|
+
ext = file.suffix.lower()
|
|
47
|
+
if ext in {".hh", ".hpp", ".hxx"}:
|
|
48
|
+
return ["-x", "c++-header"]
|
|
49
|
+
# Default to C header for .h (conservative)
|
|
50
|
+
return ["-x", "c-header"]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _ensure_parse_args_for_header(file: Path, base_args: Optional[List[str]]) -> List[str]:
|
|
54
|
+
"""
|
|
55
|
+
Ensure minimal args for header parsing:
|
|
56
|
+
- include file.parent via -I
|
|
57
|
+
- add a language flag -x c-header/c++-header if none exists
|
|
58
|
+
"""
|
|
59
|
+
args = list(base_args or [])
|
|
60
|
+
# Detect if a language flag already exists (-x <lang>)
|
|
61
|
+
has_lang = False
|
|
62
|
+
for i, a in enumerate(args):
|
|
63
|
+
if a == "-x":
|
|
64
|
+
# If '-x' present and followed by a value, treat as language specified
|
|
65
|
+
if i + 1 < len(args):
|
|
66
|
+
has_lang = True
|
|
67
|
+
break
|
|
68
|
+
elif a.startswith("-x"):
|
|
69
|
+
has_lang = True
|
|
70
|
+
break
|
|
71
|
+
|
|
72
|
+
if not has_lang:
|
|
73
|
+
args.extend(_guess_lang_header_flag(file))
|
|
74
|
+
|
|
75
|
+
# Ensure -I <file.parent> is present
|
|
76
|
+
inc_dir = str(file.parent)
|
|
77
|
+
has_inc = False
|
|
78
|
+
i = 0
|
|
79
|
+
while i < len(args):
|
|
80
|
+
a = args[i]
|
|
81
|
+
if a == "-I":
|
|
82
|
+
if i + 1 < len(args) and args[i + 1] == inc_dir:
|
|
83
|
+
has_inc = True
|
|
84
|
+
break
|
|
85
|
+
i += 2
|
|
86
|
+
continue
|
|
87
|
+
elif a.startswith("-I"):
|
|
88
|
+
# Could be like -I/path
|
|
89
|
+
if a[2:] == inc_dir:
|
|
90
|
+
has_inc = True
|
|
91
|
+
break
|
|
92
|
+
i += 1
|
|
93
|
+
if not has_inc:
|
|
94
|
+
args.extend(["-I", inc_dir])
|
|
95
|
+
|
|
96
|
+
return args
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _collect_decl_function_names(cindex, file: Path, args: List[str]) -> List[str]:
|
|
100
|
+
"""
|
|
101
|
+
Fallback for headers without inline definitions:
|
|
102
|
+
collect function declarations (prototypes/methods) defined in this header file.
|
|
103
|
+
"""
|
|
104
|
+
try:
|
|
105
|
+
index = cindex.Index.create()
|
|
106
|
+
tu = index.parse(str(file), args=args, options=0)
|
|
107
|
+
except Exception:
|
|
108
|
+
return []
|
|
109
|
+
names: List[str] = []
|
|
110
|
+
seen = set()
|
|
111
|
+
|
|
112
|
+
def visit(node):
|
|
113
|
+
try:
|
|
114
|
+
kind = node.kind.name
|
|
115
|
+
except Exception:
|
|
116
|
+
kind = ""
|
|
117
|
+
if kind in {"FUNCTION_DECL", "CXX_METHOD", "FUNCTION_TEMPLATE", "CONSTRUCTOR", "DESTRUCTOR"}:
|
|
118
|
+
loc_file = getattr(getattr(node, "location", None), "file", None)
|
|
119
|
+
try:
|
|
120
|
+
same_file = loc_file is not None and Path(loc_file.name).resolve() == file.resolve()
|
|
121
|
+
except Exception:
|
|
122
|
+
same_file = False
|
|
123
|
+
if same_file:
|
|
124
|
+
try:
|
|
125
|
+
nm = str(node.spelling or "").strip()
|
|
126
|
+
except Exception:
|
|
127
|
+
nm = ""
|
|
128
|
+
if nm and nm not in seen:
|
|
129
|
+
seen.add(nm)
|
|
130
|
+
names.append(nm)
|
|
131
|
+
for ch in node.get_children():
|
|
132
|
+
visit(ch)
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
visit(tu.cursor)
|
|
136
|
+
except Exception:
|
|
137
|
+
pass
|
|
138
|
+
return names
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def collect_function_names(
|
|
142
|
+
files: List[Path],
|
|
143
|
+
out_path: Path,
|
|
144
|
+
compile_commands_root: Optional[Path] = None,
|
|
145
|
+
) -> Path:
|
|
146
|
+
"""
|
|
147
|
+
Collect function names from given header files and write unique names to out_path.
|
|
148
|
+
|
|
149
|
+
Parameters:
|
|
150
|
+
- files: list of header file paths (.h/.hh/.hpp/.hxx). Non-header files will be skipped.
|
|
151
|
+
- out_path: output file path. Will be created (parents too) and overwritten.
|
|
152
|
+
- compile_commands_root: optional root directory to search for compile_commands.json.
|
|
153
|
+
If not provided, we search upward from each file's directory.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
- Path to the written out_path.
|
|
157
|
+
"""
|
|
158
|
+
# Normalize and filter header files
|
|
159
|
+
hdrs: List[Path] = []
|
|
160
|
+
for p in files or []:
|
|
161
|
+
try:
|
|
162
|
+
fp = Path(p).resolve()
|
|
163
|
+
except Exception:
|
|
164
|
+
continue
|
|
165
|
+
if fp.is_file() and fp.suffix.lower() in HEADER_EXTS:
|
|
166
|
+
hdrs.append(fp)
|
|
167
|
+
|
|
168
|
+
if not hdrs:
|
|
169
|
+
raise ValueError("No valid header files (.h/.hh/.hpp/.hxx) were provided.")
|
|
170
|
+
|
|
171
|
+
# Prepare libclang
|
|
172
|
+
cindex = _try_import_libclang()
|
|
173
|
+
if cindex is None:
|
|
174
|
+
from clang import cindex as _ci # type: ignore
|
|
175
|
+
cindex = _ci
|
|
176
|
+
|
|
177
|
+
# Prepare compile_commands args map (either once for provided root, or per-file if None)
|
|
178
|
+
cc_args_map_global: Optional[Dict[str, List[str]]] = None
|
|
179
|
+
if compile_commands_root is not None:
|
|
180
|
+
cc_file = find_compile_commands(Path(compile_commands_root))
|
|
181
|
+
if cc_file:
|
|
182
|
+
cc_args_map_global = load_compile_commands(cc_file)
|
|
183
|
+
|
|
184
|
+
# Collect names (preserving order)
|
|
185
|
+
seen = set()
|
|
186
|
+
ordered_names: List[str] = []
|
|
187
|
+
|
|
188
|
+
for hf in hdrs:
|
|
189
|
+
# Determine args for this file
|
|
190
|
+
cc_args_map = cc_args_map_global
|
|
191
|
+
if cc_args_map is None:
|
|
192
|
+
# Try to find compile_commands.json near this file
|
|
193
|
+
cc_file_local = find_compile_commands(hf.parent)
|
|
194
|
+
if cc_file_local:
|
|
195
|
+
try:
|
|
196
|
+
cc_args_map = load_compile_commands(cc_file_local)
|
|
197
|
+
except Exception:
|
|
198
|
+
cc_args_map = None
|
|
199
|
+
|
|
200
|
+
base_args = None
|
|
201
|
+
if cc_args_map:
|
|
202
|
+
base_args = cc_args_map.get(str(hf))
|
|
203
|
+
if base_args is None:
|
|
204
|
+
base_args = ["-I", str(hf.parent)]
|
|
205
|
+
|
|
206
|
+
args = _ensure_parse_args_for_header(hf, base_args)
|
|
207
|
+
|
|
208
|
+
# Attempt to scan. If error, try a fallback with minimal args.
|
|
209
|
+
try:
|
|
210
|
+
funcs = scan_file(cindex, hf, args)
|
|
211
|
+
except Exception:
|
|
212
|
+
try:
|
|
213
|
+
funcs = scan_file(cindex, hf, _ensure_parse_args_for_header(hf, ["-I", str(hf.parent)]))
|
|
214
|
+
except Exception:
|
|
215
|
+
funcs = []
|
|
216
|
+
|
|
217
|
+
# Extract preferred name (qualified_name or name) from definitions
|
|
218
|
+
added_count = 0
|
|
219
|
+
for fn in funcs:
|
|
220
|
+
name = ""
|
|
221
|
+
try:
|
|
222
|
+
qn = getattr(fn, "qualified_name", "") or ""
|
|
223
|
+
nm = getattr(fn, "name", "") or ""
|
|
224
|
+
name = qn or nm
|
|
225
|
+
name = str(name).strip()
|
|
226
|
+
except Exception:
|
|
227
|
+
name = ""
|
|
228
|
+
if not name or name in seen:
|
|
229
|
+
continue
|
|
230
|
+
seen.add(name)
|
|
231
|
+
ordered_names.append(name)
|
|
232
|
+
added_count += 1
|
|
233
|
+
|
|
234
|
+
# Fallback: if no definitions found in this header, collect declarations
|
|
235
|
+
if not funcs or added_count == 0:
|
|
236
|
+
try:
|
|
237
|
+
decl_names = _collect_decl_function_names(cindex, hf, args)
|
|
238
|
+
except Exception:
|
|
239
|
+
decl_names = []
|
|
240
|
+
for nm in decl_names:
|
|
241
|
+
name = str(nm).strip()
|
|
242
|
+
if not name or name in seen:
|
|
243
|
+
continue
|
|
244
|
+
seen.add(name)
|
|
245
|
+
ordered_names.append(name)
|
|
246
|
+
|
|
247
|
+
# Write out file (one per line)
|
|
248
|
+
out_path = Path(out_path)
|
|
249
|
+
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
250
|
+
try:
|
|
251
|
+
out_path.write_text("\n".join(ordered_names) + ("\n" if ordered_names else ""), encoding="utf-8")
|
|
252
|
+
except Exception as e:
|
|
253
|
+
raise RuntimeError(f"Failed to write output file: {out_path}: {e}")
|
|
254
|
+
|
|
255
|
+
return out_path
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
__all__ = ["collect_function_names"]
|