hypha-debugger 0.2.0__tar.gz → 0.2.1__tar.gz
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.
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/PKG-INFO +1 -1
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger/__init__.py +1 -1
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger/cli.py +170 -33
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger/services/source.py +7 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger.egg-info/PKG-INFO +1 -1
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/pyproject.toml +1 -1
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/tests/test_cli.py +53 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/README.md +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger/__main__.py +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger/debugger.py +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger/services/__init__.py +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger/services/execute.py +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger/services/filesystem.py +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger/services/info.py +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger/services/inspect_vars.py +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger/services/shell.py +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger/utils/__init__.py +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger/utils/env.py +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger.egg-info/SOURCES.txt +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger.egg-info/dependency_links.txt +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger.egg-info/entry_points.txt +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger.egg-info/requires.txt +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/hypha_debugger.egg-info/top_level.txt +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/setup.cfg +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/tests/test_services.py +0 -0
- {hypha_debugger-0.2.0 → hypha_debugger-0.2.1}/tests/test_shell.py +0 -0
|
@@ -114,6 +114,29 @@ def _normalize_url(url: str) -> str:
|
|
|
114
114
|
return url.rstrip("/")
|
|
115
115
|
|
|
116
116
|
|
|
117
|
+
# ---- profile type (terminal vs browser) ----------------------------------
|
|
118
|
+
def _profile_type(profile: dict) -> str:
|
|
119
|
+
return profile.get("type", "terminal")
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _infer_type(url: str) -> str:
|
|
123
|
+
"""Guess the profile type from the service id in the URL."""
|
|
124
|
+
u = url.lower()
|
|
125
|
+
if "web-navigator" in u or "web-debugger" in u or "navigator" in u:
|
|
126
|
+
return "browser"
|
|
127
|
+
return "terminal"
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _print_value(value) -> None:
|
|
131
|
+
"""Print a service result: strings verbatim, everything else as JSON."""
|
|
132
|
+
if value is None:
|
|
133
|
+
return
|
|
134
|
+
if isinstance(value, str):
|
|
135
|
+
sys.stdout.write(value if value.endswith("\n") else value + "\n")
|
|
136
|
+
else:
|
|
137
|
+
print(json.dumps(value, indent=2, default=str))
|
|
138
|
+
|
|
139
|
+
|
|
117
140
|
def _resolve_profile(explicit: str = "") -> tuple:
|
|
118
141
|
"""Return (name, profile_dict). Priority: -p flag > $HYD_PROFILE > sole profile."""
|
|
119
142
|
profiles = _load_profiles()
|
|
@@ -175,17 +198,7 @@ def _extract_opts(args: list) -> tuple:
|
|
|
175
198
|
return opts, rest
|
|
176
199
|
|
|
177
200
|
|
|
178
|
-
def
|
|
179
|
-
if bare:
|
|
180
|
-
opts, command_parts = {"profile": "", "timeout": None, "cwd": ""}, args
|
|
181
|
-
else:
|
|
182
|
-
opts, command_parts = _extract_opts(args)
|
|
183
|
-
command = " ".join(command_parts).strip()
|
|
184
|
-
if not command:
|
|
185
|
-
raise CliError("nothing to run. Usage: hyd sh '<command>'")
|
|
186
|
-
_name, profile = _resolve_profile(opts["profile"])
|
|
187
|
-
cwd = opts["cwd"] or _env_cwd()
|
|
188
|
-
timeout = opts["timeout"] if opts["timeout"] is not None else 30
|
|
201
|
+
def _run_shell(profile: dict, command: str, cwd: str, timeout: int) -> int:
|
|
189
202
|
data = _call_remote(
|
|
190
203
|
profile, "execute_bash",
|
|
191
204
|
{"command": command, "cwd": cwd, "timeout": timeout},
|
|
@@ -200,12 +213,113 @@ def cmd_sh(args: list, bare: bool = False) -> int:
|
|
|
200
213
|
return int(data.get("exit_code", 0) or 0)
|
|
201
214
|
|
|
202
215
|
|
|
216
|
+
def _run_js(profile: dict, code: str, timeout: int) -> int:
|
|
217
|
+
data = _call_remote(profile, "execute_script", {"code": code}, http_timeout=(timeout or 60) + 15)
|
|
218
|
+
if isinstance(data, dict):
|
|
219
|
+
if data.get("error"):
|
|
220
|
+
sys.stderr.write(f"hyd: {data['error']}\n")
|
|
221
|
+
return 1
|
|
222
|
+
# execute_script returns {result, type, ...}; print just the result.
|
|
223
|
+
_print_value(data["result"] if "result" in data else data)
|
|
224
|
+
else:
|
|
225
|
+
_print_value(data)
|
|
226
|
+
return 0
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def cmd_run(args: list, bare: bool = False) -> int:
|
|
230
|
+
"""Type-adaptive run: shell on a terminal profile, JavaScript on a browser one."""
|
|
231
|
+
if bare:
|
|
232
|
+
opts, parts = {"profile": "", "timeout": None, "cwd": ""}, args
|
|
233
|
+
else:
|
|
234
|
+
opts, parts = _extract_opts(args)
|
|
235
|
+
payload = " ".join(parts).strip()
|
|
236
|
+
if not payload:
|
|
237
|
+
raise CliError("nothing to run. Usage: hyd '<shell command or JS>'")
|
|
238
|
+
name, profile = _resolve_profile(opts["profile"])
|
|
239
|
+
timeout = opts["timeout"] if opts["timeout"] is not None else 30
|
|
240
|
+
if _profile_type(profile) == "browser":
|
|
241
|
+
return _run_js(profile, payload, timeout)
|
|
242
|
+
return _run_shell(profile, payload, opts["cwd"] or _env_cwd(), timeout)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def cmd_sh(args: list) -> int:
|
|
246
|
+
opts, parts = _extract_opts(args)
|
|
247
|
+
command = " ".join(parts).strip()
|
|
248
|
+
if not command:
|
|
249
|
+
raise CliError("nothing to run. Usage: hyd sh '<command>'")
|
|
250
|
+
name, profile = _resolve_profile(opts["profile"])
|
|
251
|
+
if _profile_type(profile) == "browser":
|
|
252
|
+
raise CliError(f"profile '{name}' is a browser profile — use `hyd js '<code>'` (or bare `hyd '<code>'`).")
|
|
253
|
+
timeout = opts["timeout"] if opts["timeout"] is not None else 30
|
|
254
|
+
return _run_shell(profile, command, opts["cwd"] or _env_cwd(), timeout)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def cmd_js(args: list) -> int:
|
|
258
|
+
opts, parts = _extract_opts(args)
|
|
259
|
+
code = " ".join(parts).strip()
|
|
260
|
+
if not code:
|
|
261
|
+
raise CliError("nothing to run. Usage: hyd js '<javascript>'")
|
|
262
|
+
name, profile = _resolve_profile(opts["profile"])
|
|
263
|
+
if _profile_type(profile) != "browser":
|
|
264
|
+
raise CliError(f"profile '{name}' is a terminal profile — use `hyd sh '<command>'`.")
|
|
265
|
+
timeout = opts["timeout"] if opts["timeout"] is not None else 30
|
|
266
|
+
return _run_js(profile, code, timeout)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def cmd_call(args: list) -> int:
|
|
270
|
+
"""Generic passthrough: call any service function. `hyd call <fn> [--json '{...}'] [k=v ...]`."""
|
|
271
|
+
opts, rest = _extract_opts(args)
|
|
272
|
+
if not rest:
|
|
273
|
+
raise CliError("usage: hyd call <function> [--json '{...}'] [key=value ...]")
|
|
274
|
+
fn, params = rest[0], {}
|
|
275
|
+
i = 1
|
|
276
|
+
while i < len(rest):
|
|
277
|
+
a = rest[i]
|
|
278
|
+
if a == "--json" and i + 1 < len(rest):
|
|
279
|
+
params.update(json.loads(rest[i + 1])); i += 2; continue
|
|
280
|
+
if "=" in a:
|
|
281
|
+
k, v = a.split("=", 1)
|
|
282
|
+
params[k] = v; i += 1; continue
|
|
283
|
+
i += 1
|
|
284
|
+
_name, profile = _resolve_profile(opts["profile"])
|
|
285
|
+
_print_value(_call_remote(profile, fn, params))
|
|
286
|
+
return 0
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def cmd_nav(args: list) -> int:
|
|
290
|
+
if not args:
|
|
291
|
+
raise CliError("usage: hyd nav <url>")
|
|
292
|
+
name, profile = _resolve_profile()
|
|
293
|
+
if _profile_type(profile) != "browser":
|
|
294
|
+
raise CliError(f"profile '{name}' is not a browser profile.")
|
|
295
|
+
_print_value(_call_remote(profile, "navigate", {"url": args[0]}))
|
|
296
|
+
return 0
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def cmd_shot(args: list) -> int:
|
|
300
|
+
import base64
|
|
301
|
+
name, profile = _resolve_profile()
|
|
302
|
+
if _profile_type(profile) != "browser":
|
|
303
|
+
raise CliError(f"profile '{name}' is not a browser profile.")
|
|
304
|
+
data = _call_remote(profile, "take_screenshot", {})
|
|
305
|
+
b64 = data.get("base64") or (data.get("data_url", "").split(",", 1)[-1] if data.get("data_url") else "")
|
|
306
|
+
if not b64:
|
|
307
|
+
raise CliError(f"no screenshot data: {data.get('error', data)}")
|
|
308
|
+
path = args[0] if args else "screenshot.png"
|
|
309
|
+
with open(path, "wb") as f:
|
|
310
|
+
f.write(base64.b64decode(b64))
|
|
311
|
+
print(path)
|
|
312
|
+
return 0
|
|
313
|
+
|
|
314
|
+
|
|
203
315
|
def cmd_py(args: list) -> int:
|
|
204
316
|
opts, code_parts = _extract_opts(args)
|
|
205
317
|
code = " ".join(code_parts).strip()
|
|
206
318
|
if not code:
|
|
207
319
|
raise CliError("nothing to run. Usage: hyd py '<python code>'")
|
|
208
|
-
|
|
320
|
+
name, profile = _resolve_profile(opts["profile"])
|
|
321
|
+
if _profile_type(profile) == "browser":
|
|
322
|
+
raise CliError(f"profile '{name}' is a browser profile — use `hyd js '<code>'`.")
|
|
209
323
|
data = _call_remote(profile, "execute_code", {"code": code})
|
|
210
324
|
if isinstance(data, dict):
|
|
211
325
|
if data.get("stdout"):
|
|
@@ -243,26 +357,30 @@ def cmd_profile_add(args: list) -> int:
|
|
|
243
357
|
i = 0
|
|
244
358
|
while i < len(args):
|
|
245
359
|
a = args[i]
|
|
246
|
-
if a in ("--token", "--workspace") and i + 1 < len(args):
|
|
360
|
+
if a in ("--token", "--workspace", "--type") and i + 1 < len(args):
|
|
247
361
|
opts[a.lstrip("-")] = args[i + 1]; i += 2; continue
|
|
248
362
|
pos.append(a); i += 1
|
|
249
363
|
if len(pos) < 2:
|
|
250
|
-
raise CliError("usage: hyd profile add <name> <service_url> [--
|
|
364
|
+
raise CliError("usage: hyd profile add <name> <service_url> [--type terminal|browser] [--token T] [--use]")
|
|
251
365
|
name, url = pos[0], _normalize_url(pos[1])
|
|
366
|
+
ptype = opts.get("type")
|
|
367
|
+
if ptype and ptype not in ("terminal", "browser"):
|
|
368
|
+
raise CliError("--type must be 'terminal' or 'browser'")
|
|
252
369
|
profiles = _load_profiles()
|
|
253
370
|
entry = profiles.get(name, {})
|
|
254
371
|
entry["service_url"] = url
|
|
372
|
+
entry["type"] = ptype or entry.get("type") or _infer_type(url)
|
|
255
373
|
if opts.get("token"):
|
|
256
374
|
entry["token"] = opts["token"]
|
|
257
375
|
if opts.get("workspace"):
|
|
258
376
|
entry["workspace"] = opts["workspace"]
|
|
259
377
|
profiles[name] = entry
|
|
260
378
|
_save_profiles(profiles)
|
|
379
|
+
label = f"{url} [{entry['type']}]"
|
|
261
380
|
if use:
|
|
262
|
-
_emit_state({"HYD_PROFILE": name}, human=f"profile '{name}' -> {
|
|
381
|
+
_emit_state({"HYD_PROFILE": name}, human=f"profile '{name}' -> {label} (now active)")
|
|
263
382
|
else:
|
|
264
|
-
#
|
|
265
|
-
print(f"# profile '{name}' -> {url} (activate: export HYD_PROFILE={name})")
|
|
383
|
+
print(f"# profile '{name}' -> {label} (activate: export HYD_PROFILE={name})")
|
|
266
384
|
return 0
|
|
267
385
|
|
|
268
386
|
|
|
@@ -275,7 +393,7 @@ def cmd_profile_list(_args: list) -> int:
|
|
|
275
393
|
for name, p in profiles.items():
|
|
276
394
|
mark = "*" if name == active else " "
|
|
277
395
|
tok = " (token)" if p.get("token") else ""
|
|
278
|
-
print(f"{mark} {name} {p.get('service_url', '')}{tok}")
|
|
396
|
+
print(f"{mark} {name} [{_profile_type(p)}] {p.get('service_url', '')}{tok}")
|
|
279
397
|
return 0
|
|
280
398
|
|
|
281
399
|
|
|
@@ -331,11 +449,16 @@ def cmd_status(_args: list) -> int:
|
|
|
331
449
|
name, profile = _resolve_profile()
|
|
332
450
|
except CliError as e:
|
|
333
451
|
print(e); return 1
|
|
334
|
-
|
|
452
|
+
ptype = _profile_type(profile)
|
|
453
|
+
print(f"profile: {name} [{ptype}] cwd: {_env_cwd() or '(remote default)'} (HYD_PROFILE/HYD_CWD)")
|
|
335
454
|
print(f"url: {_normalize_url(profile['service_url'])}")
|
|
336
455
|
try:
|
|
337
|
-
|
|
338
|
-
|
|
456
|
+
if ptype == "browser":
|
|
457
|
+
info = _call_remote(profile, "get_page_info", {})
|
|
458
|
+
print(f"connected: url={info.get('url')} title={info.get('title')}")
|
|
459
|
+
else:
|
|
460
|
+
info = _call_remote(profile, "get_process_info", {})
|
|
461
|
+
print(f"connected: pid={info.get('pid')} host={info.get('hostname')} py={info.get('python_version')}")
|
|
339
462
|
except CliError as e:
|
|
340
463
|
print(f"UNREACHABLE: {e}"); return 1
|
|
341
464
|
return 0
|
|
@@ -359,17 +482,20 @@ def cmd_shell_init(_args: list) -> int:
|
|
|
359
482
|
|
|
360
483
|
def _print_help() -> int:
|
|
361
484
|
print(
|
|
362
|
-
"""hyd — Hypha remote
|
|
485
|
+
"""hyd — Hypha remote CLI: drive a terminal (Python process) OR a browser with minimal overhead
|
|
363
486
|
|
|
364
|
-
USAGE
|
|
365
|
-
hyd
|
|
366
|
-
hyd '<command>'
|
|
367
|
-
hyd
|
|
368
|
-
hyd
|
|
487
|
+
USAGE (adapts to the active profile's type)
|
|
488
|
+
hyd '<x>' Bare: runs <x> as SHELL on a terminal profile, JAVASCRIPT on a browser one
|
|
489
|
+
hyd sh '<command>' Force a shell command (terminal profile; cwd via HYD_CWD)
|
|
490
|
+
hyd js '<javascript>' Force JavaScript (browser profile) — returns the result
|
|
491
|
+
hyd py '<python>' Run Python via execute_code (terminal profile)
|
|
492
|
+
hyd call <fn> [--json '{…}'] [k=v …] Call ANY service function (either type)
|
|
493
|
+
hyd nav <url> | shot [file] Browser: navigate / save a screenshot (PNG)
|
|
494
|
+
hyd -p <profile> … Run against a specific profile (overrides HYD_PROFILE)
|
|
369
495
|
|
|
370
|
-
PROFILES (machines — stored on disk)
|
|
371
|
-
hyd profile add <name> <service_url> [--
|
|
372
|
-
hyd profile list | show <name> | rm <name>
|
|
496
|
+
PROFILES (machines — stored on disk; each has a type: terminal|browser)
|
|
497
|
+
hyd profile add <name> <service_url> [--type terminal|browser] [--token T] [--use]
|
|
498
|
+
hyd profile list | show <name> | rm <name> (type inferred from the URL if omitted)
|
|
373
499
|
|
|
374
500
|
CURRENT STATE (env vars, per-terminal — NOT on disk)
|
|
375
501
|
export HYD_PROFILE=<name> Select the active profile for this shell
|
|
@@ -397,10 +523,20 @@ def main(argv=None) -> int:
|
|
|
397
523
|
from hypha_debugger import __version__
|
|
398
524
|
print(f"hyd (hypha-debugger) {__version__}")
|
|
399
525
|
return 0
|
|
400
|
-
if cmd in ("
|
|
526
|
+
if cmd in ("run", "exec"):
|
|
527
|
+
return cmd_run(argv[1:])
|
|
528
|
+
if cmd == "sh":
|
|
401
529
|
return cmd_sh(argv[1:])
|
|
530
|
+
if cmd == "js":
|
|
531
|
+
return cmd_js(argv[1:])
|
|
402
532
|
if cmd == "py":
|
|
403
533
|
return cmd_py(argv[1:])
|
|
534
|
+
if cmd == "call":
|
|
535
|
+
return cmd_call(argv[1:])
|
|
536
|
+
if cmd == "nav":
|
|
537
|
+
return cmd_nav(argv[1:])
|
|
538
|
+
if cmd == "shot":
|
|
539
|
+
return cmd_shot(argv[1:])
|
|
404
540
|
if cmd in ("profile", "profiles"):
|
|
405
541
|
return cmd_profile(argv[1:] if cmd == "profile" else ["list"] + argv[1:])
|
|
406
542
|
if cmd == "use":
|
|
@@ -413,8 +549,9 @@ def main(argv=None) -> int:
|
|
|
413
549
|
return cmd_status(argv[1:])
|
|
414
550
|
if cmd == "shell-init":
|
|
415
551
|
return cmd_shell_init(argv[1:])
|
|
416
|
-
# Bare fallback: the whole argv
|
|
417
|
-
|
|
552
|
+
# Bare fallback: run the whole argv, dispatching by profile type
|
|
553
|
+
# (shell on a terminal profile, JavaScript on a browser one).
|
|
554
|
+
return cmd_run(argv, bare=True)
|
|
418
555
|
except CliError as e:
|
|
419
556
|
sys.stderr.write(f"hyd: {e}\n")
|
|
420
557
|
return 2
|
|
@@ -122,6 +122,13 @@ Key ideas:
|
|
|
122
122
|
`hyd sh`.
|
|
123
123
|
- **Multiple machines**: add more profiles (`hyd profile add other "<url>" --token …`)
|
|
124
124
|
and switch with `export HYD_PROFILE=other` or a one-off `hyd -p other sh '…'`.
|
|
125
|
+
- **Terminal *or* browser**: each profile has a `type` (inferred from the URL). A
|
|
126
|
+
terminal profile (this Python debugger) runs shell/Python; a `browser` profile (a
|
|
127
|
+
Hypha Navigator web service) runs JavaScript. The SAME bare `hyd '<x>'` adapts —
|
|
128
|
+
shell on a terminal profile, JS on a browser one — or force it with `hyd sh` /
|
|
129
|
+
`hyd js`. `hyd call <fn> [--json '{…}']` calls any function; `hyd nav <url>` /
|
|
130
|
+
`hyd shot [file]` are browser shortcuts. Example:
|
|
131
|
+
`hyd profile add web "<navigator-url>" --type browser --use && hyd 'document.title'`.
|
|
125
132
|
- `hyd sh` streams stdout/stderr and exits with the remote command's exit code, so
|
|
126
133
|
it behaves like a local shell. Run `hyd` (no args) for full help.
|
|
127
134
|
|
|
@@ -116,6 +116,59 @@ def test_bare_fallback_runs_as_command(cfg, monkeypatch):
|
|
|
116
116
|
assert seen["command"] == "ls -la"
|
|
117
117
|
|
|
118
118
|
|
|
119
|
+
def test_type_inference_browser_and_terminal(cfg):
|
|
120
|
+
cli.main(["profile", "add", "web", "https://h.io/services/web-navigator-abc"])
|
|
121
|
+
cli.main(["profile", "add", "box", "https://h.io/services/py-debugger-xyz"])
|
|
122
|
+
profs = cli._load_profiles()
|
|
123
|
+
assert profs["web"]["type"] == "browser"
|
|
124
|
+
assert profs["box"]["type"] == "terminal"
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def test_type_explicit_override(cfg):
|
|
128
|
+
cli.main(["profile", "add", "x", "https://h.io/services/anything", "--type", "browser"])
|
|
129
|
+
assert cli._load_profiles()["x"]["type"] == "browser"
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def test_bare_dispatches_by_type(cfg, monkeypatch):
|
|
133
|
+
cli.main(["profile", "add", "web", "https://h.io/services/web-navigator-abc"])
|
|
134
|
+
monkeypatch.setenv("HYD_PROFILE", "web")
|
|
135
|
+
seen = {}
|
|
136
|
+
monkeypatch.setattr(cli, "_call_remote", lambda profile, fn, params, http_timeout=75: seen.update(fn=fn, params=params) or {"result": "My Page", "type": "string"})
|
|
137
|
+
rc = cli.main(["document.title"]) # bare, browser profile -> execute_script
|
|
138
|
+
assert rc == 0 and seen["fn"] == "execute_script" and seen["params"]["code"] == "document.title"
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def test_js_result_printed(cfg, monkeypatch, capsys):
|
|
142
|
+
cli.main(["profile", "add", "web", "https://h.io/services/web-navigator-abc"])
|
|
143
|
+
monkeypatch.setenv("HYD_PROFILE", "web")
|
|
144
|
+
monkeypatch.setattr(cli, "_call_remote", lambda *a, **k: {"result": {"a": 1}, "type": "object"})
|
|
145
|
+
cli.main(["js", "({a:1})"])
|
|
146
|
+
assert '"a": 1' in capsys.readouterr().out
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def test_sh_rejects_browser_profile(cfg, monkeypatch, capsys):
|
|
150
|
+
cli.main(["profile", "add", "web", "https://h.io/services/web-navigator-abc"])
|
|
151
|
+
monkeypatch.setenv("HYD_PROFILE", "web")
|
|
152
|
+
rc = cli.main(["sh", "ls"])
|
|
153
|
+
assert rc == 2 and "browser profile" in capsys.readouterr().err
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_js_rejects_terminal_profile(cfg, monkeypatch, capsys):
|
|
157
|
+
cli.main(["profile", "add", "box", "https://h.io/services/py-debugger-xyz"])
|
|
158
|
+
monkeypatch.setenv("HYD_PROFILE", "box")
|
|
159
|
+
rc = cli.main(["js", "1+1"])
|
|
160
|
+
assert rc == 2 and "terminal profile" in capsys.readouterr().err
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def test_call_generic_passthrough(cfg, monkeypatch):
|
|
164
|
+
cli.main(["profile", "add", "web", "https://h.io/services/web-navigator-abc"])
|
|
165
|
+
monkeypatch.setenv("HYD_PROFILE", "web")
|
|
166
|
+
seen = {}
|
|
167
|
+
monkeypatch.setattr(cli, "_call_remote", lambda profile, fn, params, http_timeout=75: seen.update(fn=fn, params=params) or {"ok": True})
|
|
168
|
+
cli.main(["call", "navigate", "--json", '{"url":"https://x.com"}'])
|
|
169
|
+
assert seen["fn"] == "navigate" and seen["params"]["url"] == "https://x.com"
|
|
170
|
+
|
|
171
|
+
|
|
119
172
|
def test_p_flag_selects_profile(cfg, monkeypatch):
|
|
120
173
|
cli.main(["profile", "add", "a", "https://a.io/s/1"])
|
|
121
174
|
cli.main(["profile", "add", "b", "https://b.io/s/2"])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|