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 CHANGED
@@ -1,3 +1,3 @@
1
1
  """tescmd — A Python CLI for querying and controlling Tesla vehicles via the Fleet API."""
2
2
 
3
- __version__ = "0.4.0"
3
+ __version__ = "0.5.0"
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 that has the Tesla app installed.[/dim]"
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.tailscale_serve import fetch_tailscale_key_pem, get_key_url
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.github_pages import fetch_key_pem, get_key_url
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]")
@@ -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 # type: ignore[assignment]
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: Any # CommandDispatcher — avoids circular import
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 (e.g. ``"location"``, ``"climate"``)
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
 
@@ -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:
@@ -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 Enum
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(str, Enum):
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.4.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=5McRfiCZ4XFvlU9hlnml5SecuYhXarzh3HAVGhcE0ZQ,116
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=bIiBJG3Xu0xhvvg33VpAjLUuQCORQg2u9ajzhApAoAo,26304
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=_xe8hZ_ToQ8WmohlrUVEXtq_RD_Q_6B3wXDjx_Xy2yg,5388
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=dM61NpiON3ZcJ-HT1D_RNUN6d8fpr6OnvVJyvpTT9lU,33358
46
- tescmd/cli/setup.py,sha256=Ep1iaUiF9NIUDXGsY6m3gxNFgEjiHsJeK60-tPWzpbA,35979
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=IOWgmhRp7fF6oZA-sLihsen-o7aLxDxB5BOFfoDSsO0,7839
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=_HYO4L5J7aHS4BPIbRumcaHpPHHoIFGzgrVAtOGWT9Y,11665
73
- tescmd/openclaw/config.py,sha256=73lH7f8hNXJvpUdQcYEdNyz8wTtudTsP1nskw4ybekg,5643
74
- tescmd/openclaw/dispatcher.py,sha256=LuBsriutiMSOsOIVDCHg0L0RUdXrX_n1n9TTIjZ6CSo,22295
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=pTQ5ZG3PPjXhwmljU4DlsMCe4By4HwOUkTKnMnsCU38,24301
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=t-Bg7renbVaXKDtxPna2z4bdUhJ1_5wGMs4ahwHPVhM,2812
124
- tescmd-0.4.0.dist-info/METADATA,sha256=-emZGYAYJ7gWthCwpUguC56PWnFFsJ4nkHeOBD8FAF0,11762
125
- tescmd-0.4.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
126
- tescmd-0.4.0.dist-info/entry_points.txt,sha256=e-Uk81_gfLu4XzJl9bv6-bUIodJbnxAgfR5ugFyeD2E,48
127
- tescmd-0.4.0.dist-info/licenses/LICENSE,sha256=gFEbRZ5xHSPxkT3OgbLFhDWVUxZv80kFDnv0t3G1E7M,1070
128
- tescmd-0.4.0.dist-info/RECORD,,
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