lagora-cli 1.1.0

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 (52) hide show
  1. package/README.md +138 -0
  2. package/dist/help.txt +70 -0
  3. package/dist/lagora.js +342 -0
  4. package/dist/report-help.txt +5 -0
  5. package/dist/scripts/agora_playground_harness.py +263 -0
  6. package/dist/scripts/announce.js +41 -0
  7. package/dist/scripts/check-kernel-submission.py +90 -0
  8. package/dist/scripts/chunk-2EAJVB5D.js +100 -0
  9. package/dist/scripts/chunk-2KTLCUFI.js +29 -0
  10. package/dist/scripts/chunk-AZ3EEBVD.js +137 -0
  11. package/dist/scripts/chunk-NBJMYAOA.js +2128 -0
  12. package/dist/scripts/chunk-NCJMUBTG.js +125 -0
  13. package/dist/scripts/chunk-QJPQHKIO.js +23 -0
  14. package/dist/scripts/chunk-RIR5KGHC.js +33 -0
  15. package/dist/scripts/chunk-TJZVQYBL.js +8 -0
  16. package/dist/scripts/chunk-UHJXD4TG.js +18 -0
  17. package/dist/scripts/chunk-UQ6I6VTY.js +117 -0
  18. package/dist/scripts/cli-auth.js +348 -0
  19. package/dist/scripts/cli-config-IA7EOSYD.js +7 -0
  20. package/dist/scripts/install-skill.js +199 -0
  21. package/dist/scripts/issue-local-client-DZUXZOKY.js +22 -0
  22. package/dist/scripts/issue-search.js +1823 -0
  23. package/dist/scripts/issue.js +386 -0
  24. package/dist/scripts/keycloak-provision.js +986 -0
  25. package/dist/scripts/legato-fsim-runner.py +126 -0
  26. package/dist/scripts/legato-lowering-runner.py +156 -0
  27. package/dist/scripts/legato_runner_annotations.py +235 -0
  28. package/dist/scripts/legato_runner_env.py +91 -0
  29. package/dist/scripts/legato_runner_launchers.py +287 -0
  30. package/dist/scripts/legato_runner_script_wrapper.py +193 -0
  31. package/dist/scripts/notifications-EU43SIEV.js +624 -0
  32. package/dist/scripts/playground.js +408 -0
  33. package/dist/scripts/report-bundle-sync-3U7QTP4Z.js +215 -0
  34. package/dist/scripts/report.js +104 -0
  35. package/dist/scripts/resolve-sdk-package-version.py +151 -0
  36. package/dist/scripts/sdk-runtime-JE6H2PB2.js +992 -0
  37. package/dist/scripts/sdk-runtime-kubernetes-job-KOWL4ITV.js +479 -0
  38. package/dist/scripts/sdk-runtime-smoke.py +168 -0
  39. package/dist/scripts/sdk.js +256 -0
  40. package/dist/scripts/site-feedback-CAPE5MPX.js +136 -0
  41. package/dist/scripts/site-feedback-rate-limit-5BU2WSFE.js +86 -0
  42. package/dist/scripts/site-feedback.js +117 -0
  43. package/dist/scripts/storage-234FBH54.js +67 -0
  44. package/dist/scripts/submit-issue.sh +489 -0
  45. package/dist/scripts/verification-3QCY66QW.js +772 -0
  46. package/dist/scripts/verify-issue.js +144 -0
  47. package/dist/skills/legato-agora-cli/SKILL.md +556 -0
  48. package/dist/skills/legato-agora-cli/agents/openai.yaml +7 -0
  49. package/dist/skills/legato-agora-cli/reference/kernel-with-golden.py +84 -0
  50. package/dist/skills/legato-site-feedback/SKILL.md +49 -0
  51. package/dist/skills/legato-site-feedback/agents/openai.yaml +7 -0
  52. package/package.json +16 -0
@@ -0,0 +1,287 @@
1
+ from __future__ import annotations
2
+
3
+ import ast
4
+ import importlib.util
5
+ import inspect
6
+ import os
7
+ import signal
8
+ import subprocess
9
+ import sys
10
+ from pathlib import Path
11
+ from typing import Any
12
+
13
+ from legato_runner_env import launcher_env, launcher_import_paths, launcher_working_directory, script_command
14
+
15
+ CALLABLE_ENTRY_NAMES = ("main", "run", "launch", "lower")
16
+ CALLABLE_ENTRY_PARAMETERS = {"output_type_name", "output_type", "stage", "output_root", "repo_root"}
17
+ LOWERING_ARTIFACT_SUFFIXES = {".mlir", ".ll", ".s", ".asm", ".bin", ".json", ".bc", ".elf", ".o"}
18
+ LEGATO_KERNEL_DECORATORS = {"compile", "primitive"}
19
+
20
+
21
+ class LauncherError(RuntimeError):
22
+ pass
23
+
24
+
25
+ class LauncherScriptError(LauncherError):
26
+ """The submitted kernel ran but failed on its own terms.
27
+
28
+ Distinct from LauncherError so callers can report a kernel failure instead
29
+ of blaming the SDK environment.
30
+ """
31
+
32
+
33
+ ACTIVE_PROCESS: subprocess.Popen[str] | None = None
34
+
35
+
36
+ def statically_decorated_kernel_names(kernel_path: Path) -> set[str]:
37
+ tree = parse_kernel(kernel_path)
38
+ return {
39
+ node.name
40
+ for node in tree.body
41
+ if isinstance(node, ast.FunctionDef)
42
+ and any(is_legato_kernel_decorator(decorator) for decorator in node.decorator_list)
43
+ }
44
+
45
+
46
+ def kernel_has_launcher(kernel_path: Path) -> bool:
47
+ return script_has_main_guard(kernel_path) or bool(callable_entry_names(kernel_path)) or bool(argparse_options(kernel_path))
48
+
49
+
50
+ def launcher_runs_in_subprocess(kernel_path: Path) -> bool:
51
+ """Whether run_launcher will execute this kernel in a child process.
52
+
53
+ In-process device state (hart's fsim environment) does not cross that
54
+ boundary, so callers that configure a device must know which side runs
55
+ the kernel. Mirrors the dispatch in run_launcher.
56
+ """
57
+ return script_has_main_guard(kernel_path) or not callable_entry_names(kernel_path)
58
+
59
+
60
+ def run_launcher(kernel_path: Path, stages: list[str], output_root: Path) -> None:
61
+ options = argparse_options(kernel_path)
62
+ if script_has_main_guard(kernel_path):
63
+ run_cli_launcher(kernel_path, stages, output_root, options)
64
+ return
65
+ if callable_entry_names(kernel_path):
66
+ run_callable_launcher(kernel_path, stages, output_root)
67
+ return
68
+ run_cli_launcher(kernel_path, stages, output_root, options)
69
+
70
+
71
+ def parse_kernel(kernel_path: Path) -> ast.Module:
72
+ with kernel_path.open("r", encoding="utf-8") as source:
73
+ return ast.parse(source.read(), filename=str(kernel_path))
74
+
75
+
76
+ def is_legato_kernel_decorator(decorator: ast.expr) -> bool:
77
+ target = decorator.func if isinstance(decorator, ast.Call) else decorator
78
+ return (
79
+ isinstance(target, ast.Attribute)
80
+ and target.attr in LEGATO_KERNEL_DECORATORS
81
+ ) or (
82
+ isinstance(target, ast.Name)
83
+ and target.id in LEGATO_KERNEL_DECORATORS
84
+ )
85
+
86
+
87
+ def script_has_main_guard(kernel_path: Path) -> bool:
88
+ for node in parse_kernel(kernel_path).body:
89
+ if isinstance(node, ast.If) and is_main_guard(node.test):
90
+ return True
91
+ return False
92
+
93
+
94
+ def is_main_guard(test: ast.expr) -> bool:
95
+ if not isinstance(test, ast.Compare) or len(test.ops) != 1 or len(test.comparators) != 1:
96
+ return False
97
+ left = test.left
98
+ right = test.comparators[0]
99
+ return (
100
+ isinstance(test.ops[0], ast.Eq)
101
+ and isinstance(left, ast.Name)
102
+ and left.id == "__name__"
103
+ and isinstance(right, ast.Constant)
104
+ and right.value == "__main__"
105
+ )
106
+
107
+
108
+ def argparse_options(kernel_path: Path) -> set[str]:
109
+ options: set[str] = set()
110
+ for node in ast.walk(parse_kernel(kernel_path)):
111
+ if not isinstance(node, ast.Call):
112
+ continue
113
+ if not isinstance(node.func, ast.Attribute) or node.func.attr != "add_argument":
114
+ continue
115
+ for arg in node.args:
116
+ if isinstance(arg, ast.Constant) and isinstance(arg.value, str) and arg.value.startswith("--"):
117
+ options.add(arg.value)
118
+ return options
119
+
120
+
121
+ def callable_entry_names(kernel_path: Path) -> set[str]:
122
+ return {
123
+ node.name
124
+ for node in parse_kernel(kernel_path).body
125
+ if isinstance(node, ast.FunctionDef)
126
+ and node.name in CALLABLE_ENTRY_NAMES
127
+ and has_supported_launcher_parameters(node)
128
+ }
129
+
130
+
131
+ def has_supported_launcher_parameters(node: ast.FunctionDef) -> bool:
132
+ positional = list(node.args.posonlyargs) + list(node.args.args)
133
+ all_parameters = [arg.arg for arg in positional]
134
+ all_parameters.extend(arg.arg for arg in node.args.kwonlyargs)
135
+ if not any(name in CALLABLE_ENTRY_PARAMETERS for name in all_parameters):
136
+ return False
137
+ required_count = len(positional) - len(node.args.defaults)
138
+ required = [arg.arg for arg in positional[:required_count]]
139
+ required.extend(arg.arg for arg, default in zip(node.args.kwonlyargs, node.args.kw_defaults) if default is None)
140
+ return all(name in CALLABLE_ENTRY_PARAMETERS for name in required)
141
+
142
+
143
+ def run_cli_launcher(kernel_path: Path, stages: list[str], output_root: Path, options: set[str]) -> None:
144
+ if "--output-type" in options:
145
+ for stage in stages:
146
+ run_cli_stage(kernel_path, stage, output_root / stage.lower(), options)
147
+ return
148
+ # One process per stage. legato compiles a kernel once per process and keys
149
+ # what it cached without the output type, so a launcher asked for MLIR,
150
+ # CORE_IR and BACKEND_IR in one run wrote the first and returned the cached
151
+ # result for the other two -- three listings collapsed into one, silently.
152
+ for stage in stages:
153
+ stage_root = output_root / stage.lower()
154
+ stage_root.mkdir(parents=True, exist_ok=True)
155
+ command = script_command(kernel_path)
156
+ if "--repo-root" in options:
157
+ command.extend(["--repo-root", str(Path.cwd())])
158
+ if "--output-root" in options:
159
+ command.extend(["--output-root", str(stage_root)])
160
+ if "--stages" in options:
161
+ command.extend(["--stages", stage])
162
+ run_command(command, launcher_working_directory(), launcher_env(kernel_path, stage_root, [stage]), stage_root, stage)
163
+
164
+
165
+ def run_cli_stage(kernel_path: Path, stage: str, stage_root: Path, options: set[str]) -> None:
166
+ command = [*script_command(kernel_path), "--output-type", stage]
167
+ if "--repo-root" in options:
168
+ command.extend(["--repo-root", str(Path.cwd())])
169
+ if "--output-root" in options:
170
+ command.extend(["--output-root", str(stage_root)])
171
+ run_command(command, launcher_working_directory(), launcher_env(kernel_path, stage_root, [stage]), stage_root, stage)
172
+
173
+
174
+ def run_command(command: list[str], cwd: Path, env: dict[str, str], output_root: Path, stage: str) -> None:
175
+ global ACTIVE_PROCESS
176
+ output_root.mkdir(parents=True, exist_ok=True)
177
+ print("[LEGATO_WORKER] launcher_mode=script", flush=True)
178
+ print(f"[LEGATO_WORKER] stage={stage} status=running", flush=True)
179
+ print(f"[LEGATO_WORKER] cwd={cwd}", flush=True)
180
+ print(f"[LEGATO_WORKER] output_path={output_root}", flush=True)
181
+ print(f"[LEGATO_WORKER] import_paths={env.get('AGORA_LEGATO_IMPORT_PATHS', '')}", flush=True)
182
+ print(f"[LEGATO_WORKER] command={' '.join(command)}", flush=True)
183
+ process = subprocess.Popen(command, cwd=cwd, env=env, start_new_session=True)
184
+ ACTIVE_PROCESS = process
185
+ try:
186
+ return_code = process.wait()
187
+ finally:
188
+ ACTIVE_PROCESS = None
189
+ if return_code != 0:
190
+ raise LauncherScriptError(f"launcher script exited with code {return_code}")
191
+ require_artifacts(output_root, "launcher script completed with no lowering artifacts")
192
+ print(f"[LEGATO_WORKER] stage={stage} status=success", flush=True)
193
+
194
+
195
+ def run_callable_launcher(kernel_path: Path, stages: list[str], output_root: Path) -> None:
196
+ module = load_module(kernel_path)
197
+ entry = first_callable_entry(module)
198
+ for stage in stages:
199
+ stage_root = output_root / stage.lower()
200
+ stage_root.mkdir(parents=True, exist_ok=True)
201
+ print("[LEGATO_WORKER] launcher_mode=callable", flush=True)
202
+ print(f"[LEGATO_WORKER] stage={stage} status=running", flush=True)
203
+ print(f"[LEGATO_WORKER] output_path={stage_root}", flush=True)
204
+ call_entry(entry, stage, stage_root)
205
+ require_artifacts(stage_root, "launcher callable completed without generated artifacts")
206
+ print(f"[LEGATO_WORKER] stage={stage} status=success", flush=True)
207
+
208
+
209
+ def load_module(kernel_path: Path) -> Any:
210
+ spec = importlib.util.spec_from_file_location("agora_launcher_kernel", kernel_path)
211
+ if spec is None or spec.loader is None:
212
+ raise LauncherError(f"cannot import launcher module: {kernel_path}")
213
+ module = importlib.util.module_from_spec(spec)
214
+ import_paths = launcher_import_paths(kernel_path)
215
+ for path in reversed(import_paths):
216
+ sys.path.insert(0, str(path))
217
+ try:
218
+ spec.loader.exec_module(module)
219
+ finally:
220
+ for path in import_paths:
221
+ if sys.path and sys.path[0] == str(path):
222
+ sys.path.pop(0)
223
+ return module
224
+
225
+
226
+ def require_artifacts(output_root: Path, message: str) -> None:
227
+ artifacts = [
228
+ path for path in output_root.rglob("*")
229
+ if path.is_file()
230
+ ]
231
+ lowering_artifacts = [
232
+ path for path in artifacts
233
+ if path.suffix.lower() in LOWERING_ARTIFACT_SUFFIXES
234
+ ]
235
+ if not lowering_artifacts:
236
+ if artifacts:
237
+ names = ", ".join(str(path.relative_to(output_root)) for path in artifacts[:5])
238
+ raise LauncherScriptError(f"{message}; found non-lowering files: {names}")
239
+ raise LauncherScriptError(message)
240
+ print(f"[LEGATO_WORKER] generated_artifacts={len(lowering_artifacts)}", flush=True)
241
+
242
+
243
+ def first_callable_entry(module: Any) -> Any:
244
+ for name in CALLABLE_ENTRY_NAMES:
245
+ value = getattr(module, name, None)
246
+ if callable(value) and has_supported_signature(value):
247
+ return value
248
+ raise LauncherError("no launcher entrypoint found; expected main(), run(), launch(), or lower()")
249
+
250
+
251
+ def has_supported_signature(value: Any) -> bool:
252
+ signature = inspect.signature(value)
253
+ if not any(name in CALLABLE_ENTRY_PARAMETERS for name in signature.parameters):
254
+ return False
255
+ for name, parameter in signature.parameters.items():
256
+ if name in CALLABLE_ENTRY_PARAMETERS:
257
+ continue
258
+ if parameter.default is inspect.Signature.empty:
259
+ return False
260
+ return True
261
+
262
+
263
+ def call_entry(entry: Any, stage: str, output_root: Path) -> None:
264
+ signature = inspect.signature(entry)
265
+ kwargs: dict[str, Any] = {}
266
+ for name, parameter in signature.parameters.items():
267
+ if name in {"output_type_name", "output_type", "stage"}:
268
+ kwargs[name] = stage
269
+ elif name == "output_root":
270
+ kwargs[name] = output_root
271
+ elif name == "repo_root":
272
+ kwargs[name] = launcher_working_directory()
273
+ elif parameter.default is inspect.Signature.empty:
274
+ raise LauncherError(f"launcher entrypoint has unsupported required parameter: {name}")
275
+ result = entry(**kwargs)
276
+ if isinstance(result, int) and result != 0:
277
+ raise LauncherError(f"launcher entrypoint returned {result}")
278
+
279
+
280
+ def terminate_active_process(signum: int, _frame: Any) -> None:
281
+ if ACTIVE_PROCESS is not None and ACTIVE_PROCESS.poll() is None:
282
+ os.killpg(ACTIVE_PROCESS.pid, signum)
283
+ raise SystemExit(128 + signum)
284
+
285
+
286
+ signal.signal(signal.SIGTERM, terminate_active_process)
287
+ signal.signal(signal.SIGINT, terminate_active_process)
@@ -0,0 +1,193 @@
1
+ from __future__ import annotations
2
+
3
+ import inspect
4
+ import os
5
+ import runpy
6
+ import sys
7
+ import types
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+
12
+ def prepare_bertha(ctx: Any) -> Any:
13
+ import legato.model.bertha as bertha_model
14
+
15
+ return bertha_model.Bertha(ctx, "default", 32, False, 8, 128 * pow(1024, 3))
16
+
17
+
18
+ def setup_ha_home(anchor: Path) -> Path:
19
+ return anchor
20
+
21
+
22
+ def install_compat_modules() -> None:
23
+ install_module("kernels", None)
24
+ install_module("kernels._common", {"prepare_bertha": prepare_bertha})
25
+ install_module("utils", None)
26
+ install_module("utils.legato_cache", {"setup_ha_home": setup_ha_home})
27
+
28
+
29
+ def install_module(name: str, members: dict[str, Any] | None) -> None:
30
+ if name in sys.modules:
31
+ return
32
+ module = types.ModuleType(name)
33
+ if members is None:
34
+ module.__path__ = [] # type: ignore[attr-defined]
35
+ else:
36
+ for key, value in members.items():
37
+ setattr(module, key, value)
38
+ sys.modules[name] = module
39
+
40
+
41
+ def install_legato_session_redirect() -> None:
42
+ output_root = os.environ.get("AGORA_LEGATO_OUTPUT_ROOT", "").strip()
43
+ stages = [stage.strip() for stage in os.environ.get("AGORA_LEGATO_STAGES", "").split(",") if stage.strip()]
44
+ launch_value = os.environ.get("AGORA_LEGATO_SESSION_LAUNCH", "").strip().lower()
45
+ launch_override = session_launch_override(launch_value)
46
+ if not output_root and not stages and launch_override is None:
47
+ return
48
+ import legato
49
+
50
+ original_session = legato.session
51
+ effective_output_path = str(Path(output_root).resolve()) if output_root else None
52
+ effective_output_type = getattr(legato.OutputType, stages[0]) if len(stages) == 1 else None
53
+ accepts_launch = session_accepts_launch(original_session)
54
+ output_type_position = session_parameter_position(original_session, "output_type")
55
+ output_path_position = session_parameter_position(original_session, "output_path")
56
+ launch_position = session_parameter_position(original_session, "launch")
57
+
58
+ def redirected_session(*args: Any, **kwargs: Any) -> Any:
59
+ next_args = list(args)
60
+ next_kwargs = dict(kwargs)
61
+ if effective_output_type is not None:
62
+ original_output_type = session_argument(next_args, next_kwargs, "output_type", output_type_position)
63
+ if original_output_type != effective_output_type:
64
+ print(f"[LEGATO_WORKER] session_output_type_effective={stages[0]}", flush=True)
65
+ replace_session_argument(
66
+ next_args,
67
+ next_kwargs,
68
+ "output_type",
69
+ output_type_position,
70
+ effective_output_type,
71
+ )
72
+ if effective_output_path is not None:
73
+ original_output_path = session_argument(next_args, next_kwargs, "output_path", output_path_position)
74
+ if original_output_path is not None:
75
+ original_text = str(original_output_path)
76
+ if original_text != effective_output_path:
77
+ print(f"[LEGATO_WORKER] session_output_path_original={original_text}", flush=True)
78
+ print(f"[LEGATO_WORKER] session_output_path_effective={effective_output_path}", flush=True)
79
+ else:
80
+ print(f"[LEGATO_WORKER] session_output_path_injected={effective_output_path}", flush=True)
81
+ replace_session_argument(
82
+ next_args,
83
+ next_kwargs,
84
+ "output_path",
85
+ output_path_position,
86
+ effective_output_path,
87
+ )
88
+ if launch_override is not None and accepts_launch:
89
+ original_launch = session_argument(next_args, next_kwargs, "launch", launch_position)
90
+ if original_launch != launch_override:
91
+ print(f"[LEGATO_WORKER] session_launch_effective={str(launch_override).lower()}", flush=True)
92
+ replace_session_argument(next_args, next_kwargs, "launch", launch_position, launch_override)
93
+ return original_session(*next_args, **next_kwargs)
94
+
95
+ legato.session = redirected_session
96
+
97
+
98
+ def session_launch_override(value: str) -> bool | None:
99
+ if value in {"0", "false", "no", "off"}:
100
+ return False
101
+ if value in {"1", "true", "yes", "on"}:
102
+ return True
103
+ return None
104
+
105
+
106
+ def session_accepts_launch(session_factory: Any) -> bool:
107
+ try:
108
+ signature = inspect.signature(session_factory)
109
+ except (TypeError, ValueError):
110
+ return False
111
+ return "launch" in signature.parameters or any(
112
+ parameter.kind is inspect.Parameter.VAR_KEYWORD
113
+ for parameter in signature.parameters.values()
114
+ )
115
+
116
+
117
+ def session_parameter_position(session_factory: Any, name: str) -> int | None:
118
+ try:
119
+ signature = inspect.signature(session_factory)
120
+ except (TypeError, ValueError):
121
+ return None
122
+ positional = [
123
+ parameter_name
124
+ for parameter_name, parameter in signature.parameters.items()
125
+ if parameter.kind in {inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD}
126
+ ]
127
+ return positional.index(name) if name in positional else None
128
+
129
+
130
+ def session_argument(
131
+ args: list[Any],
132
+ kwargs: dict[str, Any],
133
+ name: str,
134
+ position: int | None,
135
+ ) -> Any:
136
+ if name in kwargs:
137
+ return kwargs[name]
138
+ return args[position] if position is not None and position < len(args) else None
139
+
140
+
141
+ def replace_session_argument(
142
+ args: list[Any],
143
+ kwargs: dict[str, Any],
144
+ name: str,
145
+ position: int | None,
146
+ value: Any,
147
+ ) -> None:
148
+ if position is not None and position < len(args):
149
+ args[position] = value
150
+ kwargs.pop(name, None)
151
+ return
152
+ kwargs[name] = value
153
+
154
+
155
+ def configure_fsim_device() -> None:
156
+ """Open the fsim device in this process when the runner delegated it here.
157
+
158
+ hart keeps device state in the C++ runtime of the process that calls
159
+ set_fsim_env, so a script launcher has to open its own.
160
+ """
161
+ if os.environ.get("AGORA_FSIM_CONFIGURE_IN_CHILD", "").strip() != "1":
162
+ return
163
+ import hart
164
+
165
+ device_version = getattr(hart.HaDeviceVersion, os.environ["AGORA_FSIM_DEVICE_VERSION"])
166
+ compute_mode = getattr(hart.HaFSimComputeMode, os.environ["AGORA_FSIM_COMPUTE_MODE"])
167
+ hart.set_fsim_env(
168
+ device_version,
169
+ compute_mode,
170
+ os.environ["AGORA_FSIM_LOG_PATH"],
171
+ os.environ.get("AGORA_FSIM_LOG_LEVEL", "trace"),
172
+ )
173
+ if hart.get_device_count() == 0:
174
+ raise RuntimeError("no fsim devices available in launcher process")
175
+ hart.set_device(0)
176
+ print("[LEGATO_WORKER] fsim_device=ready", flush=True)
177
+
178
+
179
+ def main() -> None:
180
+ if len(sys.argv) < 2:
181
+ raise SystemExit("usage: legato_runner_script_wrapper.py <script> [args...]")
182
+ install_compat_modules()
183
+ import_paths = [path for path in os.environ.get("AGORA_LEGATO_IMPORT_PATHS", "").split(os.pathsep) if path]
184
+ sys.path[:0] = [path for path in import_paths if path not in sys.path]
185
+ configure_fsim_device()
186
+ install_legato_session_redirect()
187
+ script = sys.argv[1]
188
+ sys.argv = [script, *sys.argv[2:]]
189
+ runpy.run_path(script, run_name="__main__")
190
+
191
+
192
+ if __name__ == "__main__":
193
+ main()