RemoteRF 2.12.2__tar.gz → 2.13.0__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.
Files changed (125) hide show
  1. {remoterf-2.12.2/src/remoterf.egg-info → remoterf-2.13.0}/PKG-INFO +7 -2
  2. {remoterf-2.12.2 → remoterf-2.13.0}/README.md +5 -0
  3. {remoterf-2.12.2 → remoterf-2.13.0}/pyproject.toml +2 -2
  4. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/admin.py +7 -5
  5. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/agent_cli.py +11 -7
  6. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/agent_docs.py +1 -1
  7. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/common/utils/banner.py +3 -6
  8. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/config/config.py +4 -4
  9. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/core/app.py +175 -109
  10. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/core/grpc_acc.py +7 -7
  11. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/core/grpc_client.py +61 -7
  12. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/core/messages.py +4 -4
  13. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/data/agent_guide.md +6 -1
  14. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/dynamic_device.py +27 -0
  15. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/ops.py +21 -0
  16. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/remoterf_cli.py +25 -30
  17. {remoterf-2.12.2 → remoterf-2.13.0/src/remoterf.egg-info}/PKG-INFO +7 -2
  18. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_agent_cli.py +1 -1
  19. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_banner.py +4 -4
  20. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_bundled_drivers.py +2 -2
  21. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_device_routes.py +144 -9
  22. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_homes.py +1 -1
  23. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_messages.py +11 -10
  24. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_ops.py +21 -0
  25. {remoterf-2.12.2 → remoterf-2.13.0}/LICENSE +0 -0
  26. {remoterf-2.12.2 → remoterf-2.13.0}/setup.cfg +0 -0
  27. {remoterf-2.12.2 → remoterf-2.13.0}/setup.py +0 -0
  28. {remoterf-2.12.2 → remoterf-2.13.0}/src/_remoterf_alias.py +0 -0
  29. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/__init__.py +0 -0
  30. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/common/__init__.py +0 -0
  31. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/common/grpc/__init__.py +0 -0
  32. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/common/grpc/deployment_capabilities.proto +0 -0
  33. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/common/grpc/deployment_capabilities_pb2.py +0 -0
  34. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/common/grpc/deployment_capabilities_pb2_grpc.py +0 -0
  35. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/common/grpc/grpc.proto +0 -0
  36. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/common/grpc/grpc_pb2.py +0 -0
  37. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/common/grpc/grpc_pb2_grpc.py +0 -0
  38. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/common/grpc/v2_codec.py +0 -0
  39. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/common/tos_notice.txt +0 -0
  40. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/common/utils/__init__.py +0 -0
  41. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/common/utils/ansi_codes.py +0 -0
  42. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/common/utils/api_token.py +0 -0
  43. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/common/utils/list_string.py +0 -0
  44. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/common/utils/process_arg.py +0 -0
  45. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/config/__init__.py +0 -0
  46. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/config/cert_fetcher.py +0 -0
  47. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/core/__init__.py +0 -0
  48. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/core/acc_login.py +0 -0
  49. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/core/availability.py +0 -0
  50. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/core/banner_note.txt +0 -0
  51. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/core/direct_path.py +0 -0
  52. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/core/dynamic_v2_transport.py +0 -0
  53. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/core/secure_channel.py +0 -0
  54. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/core/v2_errors.py +0 -0
  55. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/data/mcp_tools.json +0 -0
  56. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/deployment/__init__.py +0 -0
  57. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/deployment/backend.py +0 -0
  58. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/deployment/direct.py +0 -0
  59. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/deployment/homes.py +0 -0
  60. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/deployment/http.py +0 -0
  61. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/deployment/lanpass.py +0 -0
  62. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/deployment/state.py +0 -0
  63. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/__init__.py +0 -0
  64. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/_virtual.py +0 -0
  65. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/adalm_pluto/__init__.py +0 -0
  66. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/adalm_pluto/adalm_pluto_remote.py +0 -0
  67. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/dynamic_v2.py +0 -0
  68. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/hackrf/__init__.py +0 -0
  69. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/hackrf/hackrf_remote.py +0 -0
  70. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/rtl_sdr/__init__.py +0 -0
  71. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/rtl_sdr/rtl_sdr_remote.py +0 -0
  72. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/schema_review.py +0 -0
  73. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/sim_sdr/__init__.py +0 -0
  74. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/sim_sdr/sim_sdr_remote.py +0 -0
  75. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/support/__init__.py +0 -0
  76. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/support/ti_mmwave.py +0 -0
  77. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/support/uhd.py +0 -0
  78. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/support/uhd_dsp.py +0 -0
  79. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/support/uhd_v2.py +0 -0
  80. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/ti_mmwave/__init__.py +0 -0
  81. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/ti_mmwave/ti_mmwave_remote.py +0 -0
  82. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/usrp/__init__.py +0 -0
  83. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/usrp/usrp_remote.py +0 -0
  84. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/drivers/usrp/usrp_remote.pyi +0 -0
  85. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/mcp_server.py +0 -0
  86. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf/version.py +0 -0
  87. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf.egg-info/SOURCES.txt +0 -0
  88. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf.egg-info/dependency_links.txt +0 -0
  89. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf.egg-info/entry_points.txt +0 -0
  90. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf.egg-info/requires.txt +0 -0
  91. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf.egg-info/top_level.txt +0 -0
  92. {remoterf-2.12.2 → remoterf-2.13.0}/src/remoterf.py +0 -0
  93. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_agent_docs.py +0 -0
  94. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_batch.py +0 -0
  95. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_cli_login_fresh.py +0 -0
  96. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_config_address.py +0 -0
  97. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_deployment_accounts.py +0 -0
  98. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_devices_api.py +0 -0
  99. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_direct_path_fixed.py +0 -0
  100. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_direct_path_global.py +0 -0
  101. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_direct_path_partner.py +0 -0
  102. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_direct_path_race.py +0 -0
  103. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_direct_path_relay.py +0 -0
  104. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_dynamic_device_codegen.py +0 -0
  105. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_dynamic_v2.py +0 -0
  106. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_federated_devices.py +0 -0
  107. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_fetch_idl_fallback.py +0 -0
  108. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_finish_prompt.py +0 -0
  109. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_gate_i_direct_path.py +0 -0
  110. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_grpc_client_target.py +0 -0
  111. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_lan_fallback.py +0 -0
  112. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_mcp_server.py +0 -0
  113. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_native_account_credentials.py +0 -0
  114. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_native_devices.py +0 -0
  115. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_old_import_name.py +0 -0
  116. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_partner_dynamic_v2.py +0 -0
  117. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_pluto_virtual.py +0 -0
  118. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_process_arg.py +0 -0
  119. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_relay_paging.py +0 -0
  120. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_remote_admin.py +0 -0
  121. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_remoterf_cli.py +0 -0
  122. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_rx_readahead.py +0 -0
  123. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_schema_review.py +0 -0
  124. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_ti_mmwave.py +0 -0
  125. {remoterf-2.12.2 → remoterf-2.13.0}/tests/test_upgrade_rescue.py +0 -0
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: remoterf
3
- Version: 2.12.2
3
+ Version: 2.13.0
4
4
  Summary: A python API to remotely access signal centric hardware. Client-side only! Courtesy of Wireless Lab @ UCLA & Prof. Ian Roberts.
5
- Author-email: Ethan Ge <ethoGalaxy@gmail.com>
5
+ Author-email: Ethan Ge <84103791+ethange1@users.noreply.github.com>
6
6
  License-Expression: GPL-3.0-or-later
7
7
  Classifier: Programming Language :: Python :: 3
8
8
  Classifier: Operating System :: OS Independent
@@ -373,6 +373,11 @@ Pluto_02@deployment pluto online in use until 13:45 -
373
373
  Pluto_03@deployment pluto offline yours until 15:00 -
374
374
  ```
375
375
 
376
+ Using a handle as `token=` with no live reservation of yours on that device
377
+ reserves the current slot for you if it is free (the same booking `resdev` makes,
378
+ with your usual limits), and says so on stderr. Set `REMOTERF_AUTO_RESERVE=0`
379
+ to require a reservation first.
380
+
376
381
  Each account may ask once every 10 seconds; a repeat call within that reprints the last table with the remaining wait.
377
382
 
378
383
  ## Closing
@@ -346,6 +346,11 @@ Pluto_02@deployment pluto online in use until 13:45 -
346
346
  Pluto_03@deployment pluto offline yours until 15:00 -
347
347
  ```
348
348
 
349
+ Using a handle as `token=` with no live reservation of yours on that device
350
+ reserves the current slot for you if it is free (the same booking `resdev` makes,
351
+ with your usual limits), and says so on stderr. Set `REMOTERF_AUTO_RESERVE=0`
352
+ to require a reservation first.
353
+
349
354
  Each account may ask once every 10 seconds; a repeat call within that reprints the last table with the remaining wait.
350
355
 
351
356
  ## Closing
@@ -4,12 +4,12 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "remoterf"
7
- version = "2.12.2"
7
+ version = "2.13.0"
8
8
  description = "A python API to remotely access signal centric hardware. Client-side only! Courtesy of Wireless Lab @ UCLA & Prof. Ian Roberts."
9
9
  readme = "README.md"
10
10
  license = "GPL-3.0-or-later"
11
11
  license-files = ["LICENSE"]
12
- authors = [{ name = "Ethan Ge", email = "ethoGalaxy@gmail.com" }]
12
+ authors = [{ name = "Ethan Ge", email = "84103791+ethange1@users.noreply.github.com" }]
13
13
  requires-python = ">=3.10"
14
14
  dependencies = [
15
15
  "remoterf-federation-core==0.16.0",
@@ -340,9 +340,11 @@ def cmd_login(target: str | None) -> int:
340
340
  alias = entry.get("alias") or _resolve(lab)[3]
341
341
  strict = trusted(alias)
342
342
  if not strict:
343
- print(f"This machine has not trusted {lab}'s admin host key. Safer: a code from the lab console, "
344
- f"`remoterf --remote-admin trust {lab} SHA256:…` with the fingerprint from a trusted place, or a "
345
- f"copy of {known_hosts_path()} from a paired machine. Accepting it below on first sight trusts the "
343
+ print(f"This machine has not trusted {lab}'s admin host key. Safer options:\n"
344
+ "• Use a code from the lab console.\n"
345
+ f"• Or run `remoterf --remote-admin trust {lab} SHA256:…` with a verified fingerprint.\n"
346
+ f"• Copy {known_hosts_path()} from a paired machine.\n"
347
+ "Accepting it below on first sight trusts the "
346
348
  "network you are on.", file=sys.stderr)
347
349
  _save_lab(lab, {**entry, "user": user, "alias": alias})
348
350
  return _exec(ssh_argv(lab, user, alias, strict=strict))
@@ -371,9 +373,9 @@ def cmd_hostkey(lab: str) -> int:
371
373
 
372
374
 
373
375
  USAGE = """Usage:
374
- remoterf --remote-admin [<user>@]<lab> the lab's console (a menu with no lab)
376
+ remoterf --remote-admin [<user>@]<lab> open a lab's admin console (prompts if <lab> is omitted)
375
377
  remoterf --remote-admin pair <user>@<lab> <code> first time on this machine (code from: serverrf admins add/code)
376
- remoterf --remote-admin trust <lab> SHA256:… trust a host key fingerprint read somewhere trusted
378
+ remoterf --remote-admin trust <lab> SHA256:… trust a verified host key fingerprint
377
379
  remoterf --remote-admin hostkey <lab> show the lab's current host key"""
378
380
 
379
381
 
@@ -182,13 +182,13 @@ def _apps(a):
182
182
 
183
183
  def _reserve(a):
184
184
  if not a.confirm:
185
- raise RemoteRFOpsError("usage", "Reserving changes the deployment's schedule: re-run with --confirm.")
185
+ raise RemoteRFOpsError("usage", "Dry run only. Re-run with --confirm to reserve this slot.")
186
186
  return ops.reserve(ops.saved_session(), a.handle, a.start, a.end, reveal_token=a.reveal_token)
187
187
 
188
188
 
189
189
  def _cancel(a):
190
190
  if not a.confirm:
191
- raise RemoteRFOpsError("usage", "Cancelling gives the slot up: re-run with --confirm.")
191
+ raise RemoteRFOpsError("usage", "Dry run only. Re-run with --confirm to cancel this reservation.")
192
192
  return ops.cancel(ops.saved_session(), a.reservation_id)
193
193
 
194
194
 
@@ -271,6 +271,9 @@ def _ref(x):
271
271
 
272
272
 
273
273
  def _show_reservations(r, out):
274
+ if not r["reservations"]:
275
+ print("No reservations.", file=out)
276
+ return
274
277
  _table(out, [[_ref(x), x["handle"] or x["device"], _local(x["start_ts"]), "-", _local(x["end_ts"])]
275
278
  for x in r["reservations"]])
276
279
 
@@ -316,12 +319,13 @@ def _parser():
316
319
  p.add_argument("--user", required=True, help="NAME, or NAME@deployment")
317
320
  p.add_argument("--password-stdin", action="store_true", required=True, help="read the password from stdin")
318
321
  p.add_argument("--accept-tos", action="store_true", help="agree to the RemoteRF Terms of Service")
319
- command(auth, "status", lambda a: ops.whoami(ops.saved_session()), _show_whoami, "who the saved login is")
322
+ command(auth, "status", lambda a: ops.whoami(ops.saved_session()), _show_whoami, "show active login and deployments")
323
+ command(sub, "whoami", lambda a: ops.whoami(ops.saved_session()), _show_whoami, "same as `auth status`")
320
324
  command(auth, "logout", _logout, lambda r, out: print("Logged out.", file=out), "end and forget the saved login")
321
325
  p = command(auth, "apps", _apps, _show_apps, "apps connected through the RemoteRF Global connector (not available yet)")
322
326
  p.add_argument("--revoke", metavar="CLIENT_ID", help="disconnect one app")
323
327
  p = command(sub, "devices", lambda a: ops.list_devices(ops.saved_session(), deployment=a.deployment, online_only=not a.all),
324
- _show_devices, "devices and their state now")
328
+ _show_devices, "list devices and current availability")
325
329
  p.add_argument("--deployment", help="only this deployment's devices")
326
330
  p.add_argument("--all", action="store_true", help="include offline devices")
327
331
  p = command(sub, "slots", lambda a: ops.find_slots(ops.saved_session(), a.handle, days=a.days),
@@ -333,12 +337,12 @@ def _parser():
333
337
  p.add_argument("handle")
334
338
  p.add_argument("--start", required=True, help="RFC 3339, for example 2026-10-15T14:00:00Z")
335
339
  p.add_argument("--end", required=True)
336
- p.add_argument("--confirm", action="store_true", help="really reserve")
340
+ p.add_argument("--confirm", action="store_true", help="confirm reservation")
337
341
  p.add_argument("--reveal-token", action="store_true", help="include the raw reservation token")
338
- p = command(sub, "cancel", _cancel, lambda r, out: print("Cancelled.", file=out),
342
+ p = command(sub, "cancel", _cancel, lambda r, out: print("Canceled.", file=out),
339
343
  "cancel a reservation (needs --confirm)")
340
344
  p.add_argument("reservation_id", help="as `remoterf reservations` shows it, or a JSON reservation_id")
341
- p.add_argument("--confirm", action="store_true", help="really cancel")
345
+ p.add_argument("--confirm", action="store_true", help="confirm cancellation")
342
346
  command(sub, "doctor", _doctor, _show_doctor, "check this install, its home and its login")
343
347
  return parser
344
348
 
@@ -188,7 +188,7 @@ def _print_api(api):
188
188
  if methods:
189
189
  print(f"\n{kind}s:")
190
190
  for m in methods:
191
- doc = " ".join(m["doc"].split())
191
+ doc = " ".join(m["doc"].split()).removeprefix(f"{m['name']}:").strip()
192
192
  print(_clean(f" {m['name']}" + (f" {doc}" if doc else "")))
193
193
  for note in api["notes"]:
194
194
  print(f"\n{_clean(note)}")
@@ -108,11 +108,10 @@ def _panel_lines(
108
108
  top_left, top_right = ("╭", "╮") if unicode_supported else ("+", "+")
109
109
  bottom_left, bottom_right = ("╰", "╯") if unicode_supported else ("+", "+")
110
110
  vertical = "│" if unicode_supported else "|"
111
- marker = "◆" if unicode_supported else "*"
112
111
  label = f"{horizontal} REMOTERF CLIENT "
113
112
  top = f"{top_left}{label}{horizontal * (PANEL_INNER_WIDTH - len(label))}{top_right}"
114
113
  content = [
115
- f"{marker} www.remoterf.net",
114
+ "www.remoterf.net",
116
115
  "Created by the Wireless Lab at UCLA",
117
116
  f"VERSION {version}",
118
117
  ]
@@ -139,12 +138,11 @@ def _internal_panel_lines(
139
138
  top_left, top_right = ("╭", "╮") if unicode_supported else ("+", "+")
140
139
  bottom_left, bottom_right = ("╰", "╯") if unicode_supported else ("+", "+")
141
140
  vertical = "│" if unicode_supported else "|"
142
- marker = "◆" if unicode_supported else "*"
143
141
  label = f"{horizontal} REMOTERF SESSION "
144
142
  top = f"{top_left}{label}{horizontal * (PANEL_INNER_WIDTH - len(label))}{top_right}"
145
143
  display_tos = str(tos_url).removeprefix("https://").removeprefix("http://")
146
144
  content = (
147
- f"{marker} www.remoterf.net",
145
+ "www.remoterf.net",
148
146
  f"VERSION {version}",
149
147
  f"SERVER {server or 'NA'}",
150
148
  f"TOS {display_tos}",
@@ -165,9 +163,8 @@ def _compact_lines(
165
163
  unicode_supported: bool,
166
164
  ) -> list[str]:
167
165
  width = max(1, int(columns))
168
- marker = "◆" if unicode_supported else "*"
169
166
  separator = "·" if unicode_supported else "-"
170
- heading = f"{marker} REMOTERF CLIENT"
167
+ heading = "REMOTERF CLIENT"
171
168
  if len(heading) > width:
172
169
  heading = COMPACT_BANNER[:width]
173
170
 
@@ -110,7 +110,7 @@ def _confirm_wipe(root: Path) -> bool:
110
110
  try:
111
111
  return input(prompt).strip().lower() == "wipe"
112
112
  except KeyboardInterrupt:
113
- print("\nCancelled.")
113
+ print("\nCanceled.")
114
114
  return False
115
115
 
116
116
  def _wipe_config(root: Path) -> None:
@@ -174,7 +174,7 @@ def _print_config_summary(host: str, grpc_port: int, cert_port: int, ca_out: Pat
174
174
 
175
175
 
176
176
  def _confirm_tos(question: str = "Continue with configuration? [y/N]: ",
177
- cancelled: str = "Configuration cancelled.") -> bool:
177
+ cancelled: str = "Configuration canceled.") -> bool:
178
178
  _print_separator()
179
179
  _print_tos_notice()
180
180
  _print_separator()
@@ -219,7 +219,7 @@ def require_tos_for_login() -> bool:
219
219
  """Ask once, then remember -- until a registration clears it."""
220
220
  if tos_agreed():
221
221
  return True
222
- if not _confirm_tos("Do you agree to the RemoteRF Terms of Service? [y/N]: ", "Login cancelled."):
222
+ if not _confirm_tos("Do you agree to the RemoteRF Terms of Service? [y/N]: ", "Login canceled."):
223
223
  return False
224
224
  remember_tos_agreement()
225
225
  return True
@@ -252,7 +252,7 @@ def configure(host: str, port: int, cert_port: int) -> int:
252
252
  overwrite = True
253
253
 
254
254
  if not _confirm_tos():
255
- print("Configuration cancelled. Accept the Terms of Service to continue.")
255
+ print("Configuration canceled. Accept the Terms of Service to continue.")
256
256
  return 1
257
257
 
258
258
  certs_dir = _certs_dir()