tescmd 0.4.0__py3-none-any.whl → 0.5.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.
- tescmd/__init__.py +1 -1
- tescmd/cli/key.py +2 -1
- tescmd/cli/openclaw.py +3 -0
- tescmd/cli/serve.py +5 -0
- tescmd/cli/setup.py +6 -6
- tescmd/deploy/tailscale_serve.py +1 -1
- tescmd/openclaw/bridge.py +45 -15
- tescmd/openclaw/config.py +9 -32
- tescmd/openclaw/dispatcher.py +1 -0
- tescmd/openclaw/gateway.py +20 -1
- tescmd/triggers/models.py +2 -2
- {tescmd-0.4.0.dist-info → tescmd-0.5.0.dist-info}/METADATA +2 -1
- {tescmd-0.4.0.dist-info → tescmd-0.5.0.dist-info}/RECORD +16 -16
- {tescmd-0.4.0.dist-info → tescmd-0.5.0.dist-info}/WHEEL +0 -0
- {tescmd-0.4.0.dist-info → tescmd-0.5.0.dist-info}/entry_points.txt +0 -0
- {tescmd-0.4.0.dist-info → tescmd-0.5.0.dist-info}/licenses/LICENSE +0 -0
tescmd/__init__.py
CHANGED
tescmd/cli/key.py
CHANGED
|
@@ -604,7 +604,8 @@ async def _cmd_enroll(
|
|
|
604
604
|
formatter.rich.info(" [cyan]tescmd charge status --wake[/cyan]")
|
|
605
605
|
formatter.rich.info("")
|
|
606
606
|
formatter.rich.info(
|
|
607
|
-
"[dim]Tip: The QR code must be scanned on your phone
|
|
607
|
+
"[dim]Tip: The QR code must be scanned on your phone"
|
|
608
|
+
" that has the Tesla app installed.[/dim]"
|
|
608
609
|
)
|
|
609
610
|
|
|
610
611
|
|
tescmd/cli/openclaw.py
CHANGED
|
@@ -139,8 +139,11 @@ async def _cmd_bridge(
|
|
|
139
139
|
if formatter.format != "json":
|
|
140
140
|
formatter.rich.info(f"Connecting to OpenClaw Gateway: {config.gateway_url}")
|
|
141
141
|
await gw.connect_with_backoff(max_attempts=5)
|
|
142
|
+
lifecycle_ok = await bridge.send_connected()
|
|
142
143
|
if formatter.format != "json":
|
|
143
144
|
formatter.rich.info("[green]Connected to gateway.[/green]")
|
|
145
|
+
if not lifecycle_ok:
|
|
146
|
+
formatter.rich.info("[yellow]Warning: node.connected event failed[/yellow]")
|
|
144
147
|
else:
|
|
145
148
|
if formatter.format != "json":
|
|
146
149
|
formatter.rich.info("[yellow]Dry-run mode — events will be logged as JSONL.[/yellow]")
|
tescmd/cli/serve.py
CHANGED
|
@@ -401,8 +401,13 @@ async def _cmd_serve(
|
|
|
401
401
|
if is_rich:
|
|
402
402
|
formatter.rich.info(f"Connecting to OpenClaw Gateway: {config.gateway_url}")
|
|
403
403
|
await gw.connect_with_backoff(max_attempts=5)
|
|
404
|
+
lifecycle_ok = await oc_bridge.send_connected()
|
|
404
405
|
if is_rich:
|
|
405
406
|
formatter.rich.info("[green]Connected to OpenClaw gateway.[/green]")
|
|
407
|
+
if not lifecycle_ok:
|
|
408
|
+
formatter.rich.info(
|
|
409
|
+
"[yellow]Warning: node.connected event failed[/yellow]"
|
|
410
|
+
)
|
|
406
411
|
else:
|
|
407
412
|
if is_rich:
|
|
408
413
|
formatter.rich.info(
|
tescmd/cli/setup.py
CHANGED
|
@@ -187,15 +187,15 @@ def _check_key_mismatch(
|
|
|
187
187
|
|
|
188
188
|
# Fetch remote key (method-aware)
|
|
189
189
|
if settings.hosting_method == "tailscale":
|
|
190
|
-
from tescmd.deploy
|
|
190
|
+
from tescmd.deploy import tailscale_serve as _ts
|
|
191
191
|
|
|
192
|
-
url = get_key_url(domain)
|
|
193
|
-
remote_pem = fetch_tailscale_key_pem(domain)
|
|
192
|
+
url = _ts.get_key_url(domain)
|
|
193
|
+
remote_pem = _ts.fetch_tailscale_key_pem(domain)
|
|
194
194
|
else:
|
|
195
|
-
from tescmd.deploy
|
|
195
|
+
from tescmd.deploy import github_pages as _gh
|
|
196
196
|
|
|
197
|
-
url = get_key_url(domain)
|
|
198
|
-
remote_pem = fetch_key_pem(domain)
|
|
197
|
+
url = _gh.get_key_url(domain)
|
|
198
|
+
remote_pem = _gh.fetch_key_pem(domain)
|
|
199
199
|
|
|
200
200
|
if remote_pem is not None and remote_pem != pem.strip():
|
|
201
201
|
info("[yellow]The public key on your domain differs from your local key.[/yellow]")
|
tescmd/deploy/tailscale_serve.py
CHANGED
|
@@ -37,7 +37,7 @@ POLL_INTERVAL = 3 # seconds
|
|
|
37
37
|
class _KeyRequestHandler(BaseHTTPRequestHandler):
|
|
38
38
|
"""Serve the root (200 OK) and the ``.well-known`` PEM path."""
|
|
39
39
|
|
|
40
|
-
server: KeyServer
|
|
40
|
+
server: KeyServer
|
|
41
41
|
|
|
42
42
|
def do_GET(self) -> None:
|
|
43
43
|
if self.path == "/":
|
tescmd/openclaw/bridge.py
CHANGED
|
@@ -15,6 +15,7 @@ from typing import TYPE_CHECKING, Any
|
|
|
15
15
|
if TYPE_CHECKING:
|
|
16
16
|
from tescmd.cli.main import AppContext
|
|
17
17
|
from tescmd.openclaw.config import BridgeConfig
|
|
18
|
+
from tescmd.openclaw.dispatcher import CommandDispatcher
|
|
18
19
|
from tescmd.openclaw.emitter import EventEmitter
|
|
19
20
|
from tescmd.openclaw.filters import DualGateFilter
|
|
20
21
|
from tescmd.openclaw.gateway import GatewayClient
|
|
@@ -61,7 +62,6 @@ class TelemetryBridge:
|
|
|
61
62
|
self._event_count = 0
|
|
62
63
|
self._drop_count = 0
|
|
63
64
|
self._last_event_time: float | None = None
|
|
64
|
-
self._first_frame_received = False
|
|
65
65
|
self._reconnect_at: float = 0.0
|
|
66
66
|
self._reconnect_backoff: float = _RECONNECT_BASE
|
|
67
67
|
self._shutting_down = False
|
|
@@ -88,8 +88,6 @@ class TelemetryBridge:
|
|
|
88
88
|
logger.info("Attempting OpenClaw gateway reconnection...")
|
|
89
89
|
try:
|
|
90
90
|
await self._gateway.connect()
|
|
91
|
-
self._reconnect_backoff = _RECONNECT_BASE
|
|
92
|
-
logger.info("Reconnected to OpenClaw gateway")
|
|
93
91
|
except Exception:
|
|
94
92
|
self._reconnect_at = now + self._reconnect_backoff
|
|
95
93
|
logger.warning(
|
|
@@ -97,6 +95,13 @@ class TelemetryBridge:
|
|
|
97
95
|
self._reconnect_backoff,
|
|
98
96
|
)
|
|
99
97
|
self._reconnect_backoff = min(self._reconnect_backoff * 2, _RECONNECT_MAX)
|
|
98
|
+
return
|
|
99
|
+
self._reconnect_backoff = _RECONNECT_BASE
|
|
100
|
+
logger.info("Reconnected to OpenClaw gateway")
|
|
101
|
+
try:
|
|
102
|
+
await self.send_connected()
|
|
103
|
+
except Exception:
|
|
104
|
+
logger.warning("Failed to send connected event after reconnect", exc_info=True)
|
|
100
105
|
|
|
101
106
|
def _build_lifecycle_event(self, event_type: str) -> dict[str, Any]:
|
|
102
107
|
"""Build a ``req:agent`` lifecycle event (connecting/disconnecting)."""
|
|
@@ -148,6 +153,30 @@ class TelemetryBridge:
|
|
|
148
153
|
|
|
149
154
|
return _push_trigger_notification
|
|
150
155
|
|
|
156
|
+
async def send_connected(self) -> bool:
|
|
157
|
+
"""Send a ``node.connected`` lifecycle event to the gateway.
|
|
158
|
+
|
|
159
|
+
Returns ``True`` if the event was sent (or skipped due to dry-run),
|
|
160
|
+
``False`` if the gateway was disconnected or the send failed.
|
|
161
|
+
"""
|
|
162
|
+
if self._dry_run:
|
|
163
|
+
return True
|
|
164
|
+
if not self._gateway.is_connected:
|
|
165
|
+
logger.warning("Cannot send node.connected — gateway not connected")
|
|
166
|
+
return False
|
|
167
|
+
event = self._build_lifecycle_event("node.connected")
|
|
168
|
+
try:
|
|
169
|
+
await self._gateway.send_event(event)
|
|
170
|
+
except Exception:
|
|
171
|
+
logger.warning("Failed to send connected event", exc_info=True)
|
|
172
|
+
return False
|
|
173
|
+
# send_event() swallows errors and marks disconnected, so check again.
|
|
174
|
+
if not self._gateway.is_connected:
|
|
175
|
+
logger.warning("Failed to send connected event — gateway disconnected during send")
|
|
176
|
+
return False
|
|
177
|
+
logger.info("Sent node.connected event")
|
|
178
|
+
return True
|
|
179
|
+
|
|
151
180
|
async def send_disconnecting(self) -> None:
|
|
152
181
|
"""Send a ``node.disconnecting`` lifecycle event to the gateway.
|
|
153
182
|
|
|
@@ -175,17 +204,6 @@ class TelemetryBridge:
|
|
|
175
204
|
"""
|
|
176
205
|
now = time.monotonic()
|
|
177
206
|
|
|
178
|
-
# Send node.connected lifecycle event on the very first frame.
|
|
179
|
-
if not self._first_frame_received:
|
|
180
|
-
self._first_frame_received = True
|
|
181
|
-
if not self._dry_run and self._gateway.is_connected:
|
|
182
|
-
lifecycle_event = self._build_lifecycle_event("node.connected")
|
|
183
|
-
try:
|
|
184
|
-
await self._gateway.send_event(lifecycle_event)
|
|
185
|
-
logger.info("Sent node.connected event")
|
|
186
|
-
except Exception:
|
|
187
|
-
logger.warning("Failed to send connected event", exc_info=True)
|
|
188
|
-
|
|
189
207
|
for datum in frame.data:
|
|
190
208
|
if not self._filter.should_emit(datum.field_name, datum.value, now):
|
|
191
209
|
self._drop_count += 1
|
|
@@ -259,7 +277,7 @@ class OpenClawPipeline:
|
|
|
259
277
|
gateway: GatewayClient
|
|
260
278
|
bridge: TelemetryBridge
|
|
261
279
|
telemetry_store: TelemetryStore
|
|
262
|
-
dispatcher:
|
|
280
|
+
dispatcher: CommandDispatcher
|
|
263
281
|
|
|
264
282
|
|
|
265
283
|
def build_openclaw_pipeline(
|
|
@@ -301,6 +319,17 @@ def build_openclaw_pipeline(
|
|
|
301
319
|
|
|
302
320
|
from tescmd import __version__
|
|
303
321
|
|
|
322
|
+
# bridge is assigned below, but the closure captures it by reference —
|
|
323
|
+
# on_reconnect is only called during live reconnection, long after this
|
|
324
|
+
# function returns, so bridge is always initialised by then.
|
|
325
|
+
bridge: TelemetryBridge | None = None
|
|
326
|
+
|
|
327
|
+
async def _on_reconnect() -> None:
|
|
328
|
+
if bridge is not None:
|
|
329
|
+
await bridge.send_connected()
|
|
330
|
+
else:
|
|
331
|
+
logger.error("on_reconnect fired but bridge is None — this should never happen")
|
|
332
|
+
|
|
304
333
|
gateway = GatewayClient(
|
|
305
334
|
config.gateway_url,
|
|
306
335
|
token=config.gateway_token,
|
|
@@ -310,6 +339,7 @@ def build_openclaw_pipeline(
|
|
|
310
339
|
model_identifier=vin,
|
|
311
340
|
capabilities=config.capabilities,
|
|
312
341
|
on_request=dispatcher.dispatch,
|
|
342
|
+
on_reconnect=_on_reconnect,
|
|
313
343
|
)
|
|
314
344
|
bridge = TelemetryBridge(
|
|
315
345
|
gateway,
|
tescmd/openclaw/config.py
CHANGED
|
@@ -12,8 +12,16 @@ from pydantic import BaseModel, Field
|
|
|
12
12
|
class NodeCapabilities(BaseModel):
|
|
13
13
|
"""Advertised capabilities for the OpenClaw node role.
|
|
14
14
|
|
|
15
|
+
The node advertises only two commands to the gateway:
|
|
16
|
+
|
|
17
|
+
- ``location.get`` (read) — standard node location capability
|
|
18
|
+
- ``system.run`` (write) — single entry point; the gateway routes all
|
|
19
|
+
invocations through this method and the internal
|
|
20
|
+
:class:`~tescmd.openclaw.dispatcher.CommandDispatcher` fans out to
|
|
21
|
+
the full set of 34 handlers.
|
|
22
|
+
|
|
15
23
|
Maps to the gateway connect schema fields:
|
|
16
|
-
- ``caps``: broad capability categories (
|
|
24
|
+
- ``caps``: broad capability categories (``"location"``, ``"system"``)
|
|
17
25
|
- ``commands``: specific method names the node can handle
|
|
18
26
|
- ``permissions``: per-command permission booleans
|
|
19
27
|
|
|
@@ -23,39 +31,8 @@ class NodeCapabilities(BaseModel):
|
|
|
23
31
|
|
|
24
32
|
reads: list[str] = [
|
|
25
33
|
"location.get",
|
|
26
|
-
"battery.get",
|
|
27
|
-
"temperature.get",
|
|
28
|
-
"speed.get",
|
|
29
|
-
"charge_state.get",
|
|
30
|
-
"security.get",
|
|
31
|
-
# Trigger reads
|
|
32
|
-
"trigger.list",
|
|
33
|
-
"trigger.poll",
|
|
34
34
|
]
|
|
35
35
|
writes: list[str] = [
|
|
36
|
-
"door.lock",
|
|
37
|
-
"door.unlock",
|
|
38
|
-
"climate.on",
|
|
39
|
-
"climate.off",
|
|
40
|
-
"climate.set_temp",
|
|
41
|
-
"charge.start",
|
|
42
|
-
"charge.stop",
|
|
43
|
-
"charge.set_limit",
|
|
44
|
-
"trunk.open",
|
|
45
|
-
"frunk.open",
|
|
46
|
-
"flash_lights",
|
|
47
|
-
"honk_horn",
|
|
48
|
-
"sentry.on",
|
|
49
|
-
"sentry.off",
|
|
50
|
-
# Trigger writes
|
|
51
|
-
"trigger.create",
|
|
52
|
-
"trigger.delete",
|
|
53
|
-
# Convenience trigger aliases
|
|
54
|
-
"cabin_temp.trigger",
|
|
55
|
-
"outside_temp.trigger",
|
|
56
|
-
"battery.trigger",
|
|
57
|
-
"location.trigger",
|
|
58
|
-
# Meta-dispatch
|
|
59
36
|
"system.run",
|
|
60
37
|
]
|
|
61
38
|
|
tescmd/openclaw/dispatcher.py
CHANGED
|
@@ -438,6 +438,7 @@ class CommandDispatcher:
|
|
|
438
438
|
resolved = _METHOD_ALIASES.get(method, method)
|
|
439
439
|
if resolved == "system.run":
|
|
440
440
|
raise ValueError("system.run cannot invoke itself")
|
|
441
|
+
logger.info("system.run → %s", resolved)
|
|
441
442
|
inner_params = params.get("params", {})
|
|
442
443
|
result = await self.dispatch({"method": resolved, "params": inner_params})
|
|
443
444
|
if result is None:
|
tescmd/openclaw/gateway.py
CHANGED
|
@@ -229,6 +229,7 @@ class GatewayClient:
|
|
|
229
229
|
model_identifier: str | None = None,
|
|
230
230
|
capabilities: NodeCapabilities | None = None,
|
|
231
231
|
on_request: Callable[[dict[str, Any]], Awaitable[dict[str, Any] | None]] | None = None,
|
|
232
|
+
on_reconnect: Callable[[], Awaitable[None]] | None = None,
|
|
232
233
|
) -> None:
|
|
233
234
|
self._url = url
|
|
234
235
|
self._token = token
|
|
@@ -243,6 +244,7 @@ class GatewayClient:
|
|
|
243
244
|
self._model_identifier = model_identifier or "tescmd"
|
|
244
245
|
self._capabilities = capabilities
|
|
245
246
|
self._on_request = on_request
|
|
247
|
+
self._on_reconnect = on_reconnect
|
|
246
248
|
self._ws: ClientConnection | None = None
|
|
247
249
|
self._connected = False
|
|
248
250
|
self._send_count = 0
|
|
@@ -523,6 +525,12 @@ class GatewayClient:
|
|
|
523
525
|
logger.error("Reconnection failed — receive loop exiting")
|
|
524
526
|
break
|
|
525
527
|
|
|
528
|
+
if self._on_reconnect is not None:
|
|
529
|
+
try:
|
|
530
|
+
await self._on_reconnect()
|
|
531
|
+
except Exception:
|
|
532
|
+
logger.warning("on_reconnect callback failed", exc_info=True)
|
|
533
|
+
|
|
526
534
|
async def _try_reconnect(self) -> bool:
|
|
527
535
|
"""Attempt to re-establish the gateway connection with exponential backoff.
|
|
528
536
|
|
|
@@ -544,7 +552,6 @@ class GatewayClient:
|
|
|
544
552
|
invoke_id = payload.get("id", "")
|
|
545
553
|
command = payload.get("command", "")
|
|
546
554
|
params_json = payload.get("paramsJSON", "{}")
|
|
547
|
-
logger.info("Invoke request: id=%s command=%s", invoke_id, command)
|
|
548
555
|
|
|
549
556
|
if not self._on_request:
|
|
550
557
|
await self._send_invoke_result(invoke_id, ok=False, error="no handler configured")
|
|
@@ -563,6 +570,18 @@ class GatewayClient:
|
|
|
563
570
|
)
|
|
564
571
|
params = {}
|
|
565
572
|
|
|
573
|
+
# Log with the real command name — for system.run, peek at the
|
|
574
|
+
# inner method so the activity log shows what's actually invoked.
|
|
575
|
+
if command == "system.run":
|
|
576
|
+
inner = params.get("method", "") or params.get("command", "")
|
|
577
|
+
if isinstance(inner, list):
|
|
578
|
+
inner = inner[0] if inner else ""
|
|
579
|
+
logger.info(
|
|
580
|
+
"Invoke request: id=%s command=%s (via system.run)", invoke_id, inner or "?"
|
|
581
|
+
)
|
|
582
|
+
else:
|
|
583
|
+
logger.info("Invoke request: id=%s command=%s", invoke_id, command)
|
|
584
|
+
|
|
566
585
|
# Build the message dict the dispatcher expects
|
|
567
586
|
dispatch_msg: dict[str, Any] = {
|
|
568
587
|
"method": command,
|
tescmd/triggers/models.py
CHANGED
|
@@ -8,13 +8,13 @@ from __future__ import annotations
|
|
|
8
8
|
|
|
9
9
|
import uuid
|
|
10
10
|
from datetime import UTC, datetime
|
|
11
|
-
from enum import
|
|
11
|
+
from enum import StrEnum
|
|
12
12
|
from typing import Any
|
|
13
13
|
|
|
14
14
|
from pydantic import BaseModel, Field, model_validator
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
class TriggerOperator(
|
|
17
|
+
class TriggerOperator(StrEnum):
|
|
18
18
|
"""Supported comparison operators for trigger conditions."""
|
|
19
19
|
|
|
20
20
|
LT = "lt"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tescmd
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: A Python CLI for querying and controlling Tesla vehicles via the Fleet API
|
|
5
5
|
Project-URL: Homepage, https://github.com/oceanswave/tescmd
|
|
6
6
|
Project-URL: Repository, https://github.com/oceanswave/tescmd
|
|
@@ -46,6 +46,7 @@ Requires-Dist: mypy>=1.13; extra == 'dev'
|
|
|
46
46
|
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
47
47
|
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
48
48
|
Requires-Dist: pytest-httpx>=0.34; extra == 'dev'
|
|
49
|
+
Requires-Dist: pytest-timeout>=2.3; extra == 'dev'
|
|
49
50
|
Requires-Dist: pytest-xdist>=3.0; extra == 'dev'
|
|
50
51
|
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
51
52
|
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
tescmd/__init__.py,sha256=
|
|
1
|
+
tescmd/__init__.py,sha256=zsp8KaleLto_rLks6uJcsgiYgp2LakvcWLU3gv_oTE4,116
|
|
2
2
|
tescmd/__main__.py,sha256=ecNCDo0sINhjJZiauhAcUMU67U6XUCU23ocf7vQG45E,83
|
|
3
3
|
tescmd/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
tescmd/_internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -33,17 +33,17 @@ tescmd/cli/cache.py,sha256=LaOOfHS1ycF8LoCFdcUQfw11PYor2S__-SdWtRpA_pA,2729
|
|
|
33
33
|
tescmd/cli/charge.py,sha256=TOXRn7YGuFYj5GimBhh2bTOB_5vzU5sc86PODifHXGk,20088
|
|
34
34
|
tescmd/cli/climate.py,sha256=npekNHOcJ63oG1-2o-fZiTRWFmemdZ1Tl_pASWwWBlI,16890
|
|
35
35
|
tescmd/cli/energy.py,sha256=YUv-_UnbUu7u5nko15MSrS5s9bU6Y58IszVfURXRr34,11931
|
|
36
|
-
tescmd/cli/key.py,sha256=
|
|
36
|
+
tescmd/cli/key.py,sha256=KN2lyRhSwWwX7YUZQufCu_rKRIJDwXPvdbC_s_vRVQE,26315
|
|
37
37
|
tescmd/cli/main.py,sha256=WmERuesvxcmpI8zlgOAeSYw3KgEApAZMbiCasxJa7z4,22502
|
|
38
38
|
tescmd/cli/mcp_cmd.py,sha256=K6siov7O-dzyZKuHFHFpYraRE9uMcG13obWmdyND6DQ,4644
|
|
39
39
|
tescmd/cli/media.py,sha256=PQ-QJkjkIiM8IJ5CXtDOY0N1yC3DlaC5YLnebxT1nrI,4267
|
|
40
40
|
tescmd/cli/nav.py,sha256=JJr4uynwrBHZn1p2zuWlPEeGJPtyHFy7nlAwyij_QbA,7551
|
|
41
|
-
tescmd/cli/openclaw.py,sha256=
|
|
41
|
+
tescmd/cli/openclaw.py,sha256=uRhwT3kS3yQt9LNGL_lQexukK7CWdn7PX_yfudJFjv8,5567
|
|
42
42
|
tescmd/cli/partner.py,sha256=0GfDCwM_Kfy5g95JwUhrrsjDFn9lSbkuNgfquIQqcSo,3488
|
|
43
43
|
tescmd/cli/raw.py,sha256=hj5hZs8tHHHAeXtpf7kHXewciXDvl0RlMJkPK7i3ouY,2238
|
|
44
44
|
tescmd/cli/security.py,sha256=uHowY0b7CH7Ff0LdzqBHL4rjyM6W9AYXC_N9EXvE7pA,15937
|
|
45
|
-
tescmd/cli/serve.py,sha256=
|
|
46
|
-
tescmd/cli/setup.py,sha256=
|
|
45
|
+
tescmd/cli/serve.py,sha256=ZH1__p-AW4Cq1Z3VlxsYTWTTBpzSjHC9pKQD3jmOWm8,33618
|
|
46
|
+
tescmd/cli/setup.py,sha256=7fmEmTaVHnYuHtuoQvyzikVN32cdKyP-GeYSZBWefqk,35945
|
|
47
47
|
tescmd/cli/sharing.py,sha256=9H3MSM1ZvPq4sBPSyvgUXHTvwm1IUAh8PrIu71ZV1GY,6294
|
|
48
48
|
tescmd/cli/software.py,sha256=f3Jl5GRruE_wNHl3jfLbVQHEXQvQxe4y-UaNIY1j76Y,2711
|
|
49
49
|
tescmd/cli/status.py,sha256=_Ql5oMA6j03g16acjtWbFWk6v-pfMJhlTdCNmq7MPh4,3997
|
|
@@ -57,7 +57,7 @@ tescmd/crypto/keys.py,sha256=jzFZwZKMYFlHGPeTSrw5pVLBwjxvLV57LzTK9d4-caM,4037
|
|
|
57
57
|
tescmd/crypto/schnorr.py,sha256=qgISnRMDrH-LkinjLoapV8wsoVNdwBnCZvLPMgGIGyo,6626
|
|
58
58
|
tescmd/deploy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
59
59
|
tescmd/deploy/github_pages.py,sha256=i5M6U0SxYyasPx-MqG8hW8cJqYqKTrXde-P1cSBI8SQ,8756
|
|
60
|
-
tescmd/deploy/tailscale_serve.py,sha256=
|
|
60
|
+
tescmd/deploy/tailscale_serve.py,sha256=nLcwFwBaHSPO2QPkYVfN_7IZPiCae4P0Awe4XUbqf7I,7811
|
|
61
61
|
tescmd/mcp/__init__.py,sha256=zHLbMTNRql4hy1jNMc1zD6P0AzX8vFzgjm5QCAZSsQg,172
|
|
62
62
|
tescmd/mcp/server.py,sha256=o0cD1xMNyt8qmGZhN5O7cWTQTdBd9FTaOpQPzpVT3Xw,25414
|
|
63
63
|
tescmd/models/__init__.py,sha256=mo6ngQp9m-244UGykbgY-DoqnunLD4DwEqHdJwP9GLc,1767
|
|
@@ -69,12 +69,12 @@ tescmd/models/sharing.py,sha256=sJv4fCRT5AUkcqmdK8bN2Y8hpuHITEnxNp_BlbX7L4Y,609
|
|
|
69
69
|
tescmd/models/user.py,sha256=2hATFqUppheKtWDFg3axIRmxX0gmPTdwgMwZJGSQhtc,770
|
|
70
70
|
tescmd/models/vehicle.py,sha256=GXkQOAB406JQI4vI7xhEbWB1hK5H0SLhzwtJEXPEsTw,5733
|
|
71
71
|
tescmd/openclaw/__init__.py,sha256=J4Fb8zs69-KQTKgUZVm3MOhvKAafHGhIFF50NxqGNa4,722
|
|
72
|
-
tescmd/openclaw/bridge.py,sha256=
|
|
73
|
-
tescmd/openclaw/config.py,sha256=
|
|
74
|
-
tescmd/openclaw/dispatcher.py,sha256=
|
|
72
|
+
tescmd/openclaw/bridge.py,sha256=efp1WpO4nRGmzOg82d9pmC6L9EL1SrQ_dJ2Fp3GOQn8,12816
|
|
73
|
+
tescmd/openclaw/config.py,sha256=MZP5toDcVwaew8wlGpeKnbn2GbrCdYmvFNpTbPMko4w,5229
|
|
74
|
+
tescmd/openclaw/dispatcher.py,sha256=ZpjgJpqP2JtlIa0cfeLJLgCz0gEmM_YxcnZ7WTR3imo,22346
|
|
75
75
|
tescmd/openclaw/emitter.py,sha256=IAY_0tYduXif1JOcWtqhuGeYNN3irDNsnRWrzMdLnXU,6001
|
|
76
76
|
tescmd/openclaw/filters.py,sha256=QJeM8I0Sx_7Hjg4Uy7UjkIU7mAYScMRi_WGzUBnmw0w,4020
|
|
77
|
-
tescmd/openclaw/gateway.py,sha256=
|
|
77
|
+
tescmd/openclaw/gateway.py,sha256=bqTcnH6huUWrG1tm9Fky8BfgAuSAgPSalQHFVU9yJJs,25140
|
|
78
78
|
tescmd/openclaw/telemetry_store.py,sha256=C3VLUstw1_6nKFKGZJgvuWaaYXdclX0K1rbaDT4Rkls,1696
|
|
79
79
|
tescmd/output/__init__.py,sha256=uFvlXwHmKHkxOIVgP8JryZlQbHLHhbhLGswGo9xuFbI,120
|
|
80
80
|
tescmd/output/formatter.py,sha256=pQLes-gZJbD4S32-fRwKqcLepsiXb9AIWP-Wm_H1ca0,4658
|
|
@@ -120,9 +120,9 @@ tescmd/telemetry/protos/vehicle_metric_pb2.py,sha256=uFg2RgxwMy-ZRnlq5bK-_MbiTow
|
|
|
120
120
|
tescmd/telemetry/protos/vehicle_metric_pb2.pyi,sha256=hFjmnO_D41FYO39NvCakOczCGLVVNm0WGavbnaHXkqI,1676
|
|
121
121
|
tescmd/triggers/__init__.py,sha256=kFFbRlhCDbYtE_kZ_A65dcxzpvuDsgYZpYgATNggAgc,432
|
|
122
122
|
tescmd/triggers/manager.py,sha256=xon72FVI37JaqtNroRg_B8pn62zv2cuO3iREcESsnsM,8418
|
|
123
|
-
tescmd/triggers/models.py,sha256=
|
|
124
|
-
tescmd-0.
|
|
125
|
-
tescmd-0.
|
|
126
|
-
tescmd-0.
|
|
127
|
-
tescmd-0.
|
|
128
|
-
tescmd-0.
|
|
123
|
+
tescmd/triggers/models.py,sha256=qcsbAFkmtu4QlkRZ7zDh9aAqW7RkwNw5SKZvauEw4iQ,2813
|
|
124
|
+
tescmd-0.5.0.dist-info/METADATA,sha256=xCI7KcZ2-JETChqBiC2YbTWdSwMTNHVmR9c28sLPcs0,11813
|
|
125
|
+
tescmd-0.5.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
126
|
+
tescmd-0.5.0.dist-info/entry_points.txt,sha256=e-Uk81_gfLu4XzJl9bv6-bUIodJbnxAgfR5ugFyeD2E,48
|
|
127
|
+
tescmd-0.5.0.dist-info/licenses/LICENSE,sha256=gFEbRZ5xHSPxkT3OgbLFhDWVUxZv80kFDnv0t3G1E7M,1070
|
|
128
|
+
tescmd-0.5.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|