tescmd 0.3.1__tar.gz → 0.5.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 (281) hide show
  1. {tescmd-0.3.1 → tescmd-0.5.0}/.github/workflows/test.yml +2 -1
  2. {tescmd-0.3.1 → tescmd-0.5.0}/.gitignore +1 -0
  3. {tescmd-0.3.1 → tescmd-0.5.0}/CHANGELOG.md +53 -0
  4. tescmd-0.5.0/PKG-INFO +301 -0
  5. tescmd-0.5.0/README.md +247 -0
  6. {tescmd-0.3.1 → tescmd-0.5.0}/docs/commands.md +4 -4
  7. tescmd-0.5.0/images/tescmd_mcp.png +0 -0
  8. tescmd-0.5.0/images/tescmd_serve.png +0 -0
  9. tescmd-0.5.0/images/tescmd_waypoints.png +0 -0
  10. {tescmd-0.3.1 → tescmd-0.5.0}/pyproject.toml +3 -1
  11. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/__init__.py +1 -1
  12. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/auth/oauth.py +10 -0
  13. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/auth.py +212 -145
  14. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/key.py +7 -7
  15. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/openclaw.py +3 -0
  16. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/serve.py +5 -0
  17. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/setup.py +134 -56
  18. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/deploy/github_pages.py +13 -2
  19. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/deploy/tailscale_serve.py +96 -8
  20. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/openclaw/bridge.py +45 -15
  21. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/openclaw/config.py +9 -32
  22. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/openclaw/dispatcher.py +10 -2
  23. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/openclaw/gateway.py +33 -1
  24. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/tailscale.py +78 -16
  25. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/triggers/models.py +2 -2
  26. tescmd-0.5.0/tests/auth/test_oauth_extended.py +243 -0
  27. tescmd-0.5.0/tests/cli/test_auth.py +831 -0
  28. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_setup.py +570 -2
  29. {tescmd-0.3.1 → tescmd-0.5.0}/tests/deploy/test_tailscale_serve.py +63 -7
  30. {tescmd-0.3.1 → tescmd-0.5.0}/tests/openclaw/test_bridge.py +66 -35
  31. {tescmd-0.3.1 → tescmd-0.5.0}/tests/openclaw/test_config.py +14 -6
  32. {tescmd-0.3.1 → tescmd-0.5.0}/tests/openclaw/test_dispatcher.py +24 -0
  33. {tescmd-0.3.1 → tescmd-0.5.0}/tests/openclaw/test_gateway.py +93 -23
  34. {tescmd-0.3.1 → tescmd-0.5.0}/tests/telemetry/test_tui.py +7 -6
  35. tescmd-0.3.1/PKG-INFO +0 -543
  36. tescmd-0.3.1/README.md +0 -490
  37. tescmd-0.3.1/tests/auth/test_oauth_extended.py +0 -125
  38. tescmd-0.3.1/tests/cli/test_auth.py +0 -301
  39. {tescmd-0.3.1 → tescmd-0.5.0}/.env.example +0 -0
  40. {tescmd-0.3.1 → tescmd-0.5.0}/.github/workflows/publish.yml +0 -0
  41. {tescmd-0.3.1 → tescmd-0.5.0}/CLAUDE.md +0 -0
  42. {tescmd-0.3.1 → tescmd-0.5.0}/LICENSE +0 -0
  43. {tescmd-0.3.1 → tescmd-0.5.0}/docs/api-costs.md +0 -0
  44. {tescmd-0.3.1 → tescmd-0.5.0}/docs/architecture.md +0 -0
  45. {tescmd-0.3.1 → tescmd-0.5.0}/docs/authentication.md +0 -0
  46. {tescmd-0.3.1 → tescmd-0.5.0}/docs/bot-integration.md +0 -0
  47. {tescmd-0.3.1 → tescmd-0.5.0}/docs/development.md +0 -0
  48. {tescmd-0.3.1 → tescmd-0.5.0}/docs/faq.md +0 -0
  49. {tescmd-0.3.1 → tescmd-0.5.0}/docs/mcp.md +0 -0
  50. {tescmd-0.3.1 → tescmd-0.5.0}/docs/openclaw.md +0 -0
  51. {tescmd-0.3.1 → tescmd-0.5.0}/docs/setup.md +0 -0
  52. {tescmd-0.3.1 → tescmd-0.5.0}/docs/vehicle-command-protocol.md +0 -0
  53. {tescmd-0.3.1 → tescmd-0.5.0}/images/tescmd_header.jpeg +0 -0
  54. {tescmd-0.3.1 → tescmd-0.5.0}/images/tescmd_logo.jpeg +0 -0
  55. {tescmd-0.3.1 → tescmd-0.5.0}/scripts/validate_fleet_api.py +0 -0
  56. {tescmd-0.3.1 → tescmd-0.5.0}/skills/tescmd/SKILL.md +0 -0
  57. {tescmd-0.3.1 → tescmd-0.5.0}/spec/fleet_api_spec.json +0 -0
  58. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/__main__.py +0 -0
  59. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/_internal/__init__.py +0 -0
  60. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/_internal/async_utils.py +0 -0
  61. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/_internal/permissions.py +0 -0
  62. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/_internal/vin.py +0 -0
  63. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/api/__init__.py +0 -0
  64. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/api/charging.py +0 -0
  65. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/api/client.py +0 -0
  66. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/api/command.py +0 -0
  67. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/api/energy.py +0 -0
  68. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/api/errors.py +0 -0
  69. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/api/partner.py +0 -0
  70. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/api/sharing.py +0 -0
  71. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/api/signed_command.py +0 -0
  72. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/api/user.py +0 -0
  73. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/api/vehicle.py +0 -0
  74. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/auth/__init__.py +0 -0
  75. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/auth/server.py +0 -0
  76. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/auth/token_store.py +0 -0
  77. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/ble/__init__.py +0 -0
  78. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cache/__init__.py +0 -0
  79. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cache/keys.py +0 -0
  80. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cache/response_cache.py +0 -0
  81. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/__init__.py +0 -0
  82. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/_client.py +0 -0
  83. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/_options.py +0 -0
  84. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/billing.py +0 -0
  85. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/cache.py +0 -0
  86. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/charge.py +0 -0
  87. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/climate.py +0 -0
  88. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/energy.py +0 -0
  89. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/main.py +0 -0
  90. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/mcp_cmd.py +0 -0
  91. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/media.py +0 -0
  92. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/nav.py +0 -0
  93. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/partner.py +0 -0
  94. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/raw.py +0 -0
  95. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/security.py +0 -0
  96. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/sharing.py +0 -0
  97. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/software.py +0 -0
  98. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/status.py +0 -0
  99. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/trunk.py +0 -0
  100. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/user.py +0 -0
  101. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/cli/vehicle.py +0 -0
  102. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/config/__init__.py +0 -0
  103. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/crypto/__init__.py +0 -0
  104. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/crypto/ecdh.py +0 -0
  105. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/crypto/keys.py +0 -0
  106. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/crypto/schnorr.py +0 -0
  107. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/deploy/__init__.py +0 -0
  108. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/mcp/__init__.py +0 -0
  109. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/mcp/server.py +0 -0
  110. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/models/__init__.py +0 -0
  111. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/models/auth.py +0 -0
  112. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/models/command.py +0 -0
  113. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/models/config.py +0 -0
  114. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/models/energy.py +0 -0
  115. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/models/sharing.py +0 -0
  116. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/models/user.py +0 -0
  117. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/models/vehicle.py +0 -0
  118. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/openclaw/__init__.py +0 -0
  119. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/openclaw/emitter.py +0 -0
  120. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/openclaw/filters.py +0 -0
  121. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/openclaw/telemetry_store.py +0 -0
  122. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/output/__init__.py +0 -0
  123. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/output/formatter.py +0 -0
  124. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/output/json_output.py +0 -0
  125. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/output/rich_output.py +0 -0
  126. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/protocol/__init__.py +0 -0
  127. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/protocol/commands.py +0 -0
  128. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/protocol/encoder.py +0 -0
  129. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/protocol/metadata.py +0 -0
  130. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/protocol/payloads.py +0 -0
  131. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/protocol/protobuf/__init__.py +0 -0
  132. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/protocol/protobuf/messages.py +0 -0
  133. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/protocol/session.py +0 -0
  134. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/protocol/signer.py +0 -0
  135. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/py.typed +0 -0
  136. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/__init__.py +0 -0
  137. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/cache_sink.py +0 -0
  138. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/csv_sink.py +0 -0
  139. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/dashboard.py +0 -0
  140. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/decoder.py +0 -0
  141. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/fanout.py +0 -0
  142. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/fields.py +0 -0
  143. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/flatbuf.py +0 -0
  144. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/mapper.py +0 -0
  145. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/protos/__init__.py +0 -0
  146. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/protos/vehicle_alert.proto +0 -0
  147. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/protos/vehicle_alert_pb2.py +0 -0
  148. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/protos/vehicle_alert_pb2.pyi +0 -0
  149. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/protos/vehicle_connectivity.proto +0 -0
  150. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/protos/vehicle_connectivity_pb2.py +0 -0
  151. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/protos/vehicle_connectivity_pb2.pyi +0 -0
  152. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/protos/vehicle_data.proto +0 -0
  153. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/protos/vehicle_data_pb2.py +0 -0
  154. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/protos/vehicle_data_pb2.pyi +0 -0
  155. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/protos/vehicle_error.proto +0 -0
  156. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/protos/vehicle_error_pb2.py +0 -0
  157. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/protos/vehicle_error_pb2.pyi +0 -0
  158. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/protos/vehicle_metric.proto +0 -0
  159. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/protos/vehicle_metric_pb2.py +0 -0
  160. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/protos/vehicle_metric_pb2.pyi +0 -0
  161. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/server.py +0 -0
  162. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/setup.py +0 -0
  163. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/telemetry/tui.py +0 -0
  164. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/triggers/__init__.py +0 -0
  165. {tescmd-0.3.1 → tescmd-0.5.0}/src/tescmd/triggers/manager.py +0 -0
  166. {tescmd-0.3.1 → tescmd-0.5.0}/tests/__init__.py +0 -0
  167. {tescmd-0.3.1 → tescmd-0.5.0}/tests/_internal/__init__.py +0 -0
  168. {tescmd-0.3.1 → tescmd-0.5.0}/tests/_internal/test_async_utils.py +0 -0
  169. {tescmd-0.3.1 → tescmd-0.5.0}/tests/_internal/test_vin.py +0 -0
  170. {tescmd-0.3.1 → tescmd-0.5.0}/tests/api/__init__.py +0 -0
  171. {tescmd-0.3.1 → tescmd-0.5.0}/tests/api/test_client.py +0 -0
  172. {tescmd-0.3.1 → tescmd-0.5.0}/tests/api/test_command_api.py +0 -0
  173. {tescmd-0.3.1 → tescmd-0.5.0}/tests/api/test_energy_api.py +0 -0
  174. {tescmd-0.3.1 → tescmd-0.5.0}/tests/api/test_partner_api.py +0 -0
  175. {tescmd-0.3.1 → tescmd-0.5.0}/tests/api/test_sharing_api.py +0 -0
  176. {tescmd-0.3.1 → tescmd-0.5.0}/tests/api/test_signed_command.py +0 -0
  177. {tescmd-0.3.1 → tescmd-0.5.0}/tests/api/test_user_api.py +0 -0
  178. {tescmd-0.3.1 → tescmd-0.5.0}/tests/api/test_vehicle_api.py +0 -0
  179. {tescmd-0.3.1 → tescmd-0.5.0}/tests/auth/__init__.py +0 -0
  180. {tescmd-0.3.1 → tescmd-0.5.0}/tests/auth/test_oauth.py +0 -0
  181. {tescmd-0.3.1 → tescmd-0.5.0}/tests/auth/test_server.py +0 -0
  182. {tescmd-0.3.1 → tescmd-0.5.0}/tests/auth/test_token_store.py +0 -0
  183. {tescmd-0.3.1 → tescmd-0.5.0}/tests/auth/test_token_store_fallback.py +0 -0
  184. {tescmd-0.3.1 → tescmd-0.5.0}/tests/auth/test_token_store_file.py +0 -0
  185. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cache/__init__.py +0 -0
  186. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cache/test_generic_cache.py +0 -0
  187. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cache/test_keys.py +0 -0
  188. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cache/test_response_cache.py +0 -0
  189. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/__init__.py +0 -0
  190. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/_helpers.py +0 -0
  191. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/conftest.py +0 -0
  192. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_auth_exec.py +0 -0
  193. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_bugfixes.py +0 -0
  194. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_cache.py +0 -0
  195. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_cached_api_call.py +0 -0
  196. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_charge_exec.py +0 -0
  197. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_cli_integration.py +0 -0
  198. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_climate_exec.py +0 -0
  199. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_e2e_smoke.py +0 -0
  200. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_energy.py +0 -0
  201. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_energy_exec.py +0 -0
  202. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_error_handlers.py +0 -0
  203. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_key.py +0 -0
  204. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_key_enroll.py +0 -0
  205. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_key_unenroll.py +0 -0
  206. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_main_errors.py +0 -0
  207. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_media.py +0 -0
  208. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_media_exec.py +0 -0
  209. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_nav.py +0 -0
  210. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_nav_exec.py +0 -0
  211. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_partner.py +0 -0
  212. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_raw.py +0 -0
  213. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_raw_exec.py +0 -0
  214. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_security_exec.py +0 -0
  215. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_setup_scope_check.py +0 -0
  216. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_sharing.py +0 -0
  217. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_sharing_exec.py +0 -0
  218. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_software.py +0 -0
  219. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_software_exec.py +0 -0
  220. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_status_exec.py +0 -0
  221. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_tier_enforcement.py +0 -0
  222. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_trunk_exec.py +0 -0
  223. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_user.py +0 -0
  224. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_user_exec.py +0 -0
  225. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_vcsec_guard.py +0 -0
  226. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_vehicle_exec.py +0 -0
  227. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_vehicle_power_exec.py +0 -0
  228. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_verbose.py +0 -0
  229. {tescmd-0.3.1 → tescmd-0.5.0}/tests/cli/test_wake_confirmation.py +0 -0
  230. {tescmd-0.3.1 → tescmd-0.5.0}/tests/conftest.py +0 -0
  231. {tescmd-0.3.1 → tescmd-0.5.0}/tests/crypto/__init__.py +0 -0
  232. {tescmd-0.3.1 → tescmd-0.5.0}/tests/crypto/test_ecdh.py +0 -0
  233. {tescmd-0.3.1 → tescmd-0.5.0}/tests/crypto/test_keys.py +0 -0
  234. {tescmd-0.3.1 → tescmd-0.5.0}/tests/crypto/test_schnorr.py +0 -0
  235. {tescmd-0.3.1 → tescmd-0.5.0}/tests/deploy/__init__.py +0 -0
  236. {tescmd-0.3.1 → tescmd-0.5.0}/tests/deploy/test_github_pages.py +0 -0
  237. {tescmd-0.3.1 → tescmd-0.5.0}/tests/integration/__init__.py +0 -0
  238. {tescmd-0.3.1 → tescmd-0.5.0}/tests/integration/test_serve.py +0 -0
  239. {tescmd-0.3.1 → tescmd-0.5.0}/tests/mcp/__init__.py +0 -0
  240. {tescmd-0.3.1 → tescmd-0.5.0}/tests/mcp/test_server.py +0 -0
  241. {tescmd-0.3.1 → tescmd-0.5.0}/tests/mcp/test_tools.py +0 -0
  242. {tescmd-0.3.1 → tescmd-0.5.0}/tests/models/__init__.py +0 -0
  243. {tescmd-0.3.1 → tescmd-0.5.0}/tests/models/test_auth.py +0 -0
  244. {tescmd-0.3.1 → tescmd-0.5.0}/tests/models/test_config.py +0 -0
  245. {tescmd-0.3.1 → tescmd-0.5.0}/tests/models/test_energy.py +0 -0
  246. {tescmd-0.3.1 → tescmd-0.5.0}/tests/models/test_sharing.py +0 -0
  247. {tescmd-0.3.1 → tescmd-0.5.0}/tests/models/test_user_models.py +0 -0
  248. {tescmd-0.3.1 → tescmd-0.5.0}/tests/models/test_vehicle.py +0 -0
  249. {tescmd-0.3.1 → tescmd-0.5.0}/tests/openclaw/__init__.py +0 -0
  250. {tescmd-0.3.1 → tescmd-0.5.0}/tests/openclaw/test_emitter.py +0 -0
  251. {tescmd-0.3.1 → tescmd-0.5.0}/tests/openclaw/test_filters.py +0 -0
  252. {tescmd-0.3.1 → tescmd-0.5.0}/tests/openclaw/test_telemetry_store.py +0 -0
  253. {tescmd-0.3.1 → tescmd-0.5.0}/tests/output/__init__.py +0 -0
  254. {tescmd-0.3.1 → tescmd-0.5.0}/tests/output/test_formatter.py +0 -0
  255. {tescmd-0.3.1 → tescmd-0.5.0}/tests/output/test_json_output.py +0 -0
  256. {tescmd-0.3.1 → tescmd-0.5.0}/tests/output/test_rich_output.py +0 -0
  257. {tescmd-0.3.1 → tescmd-0.5.0}/tests/protocol/__init__.py +0 -0
  258. {tescmd-0.3.1 → tescmd-0.5.0}/tests/protocol/conftest.py +0 -0
  259. {tescmd-0.3.1 → tescmd-0.5.0}/tests/protocol/test_boombox.py +0 -0
  260. {tescmd-0.3.1 → tescmd-0.5.0}/tests/protocol/test_commands.py +0 -0
  261. {tescmd-0.3.1 → tescmd-0.5.0}/tests/protocol/test_encoder.py +0 -0
  262. {tescmd-0.3.1 → tescmd-0.5.0}/tests/protocol/test_metadata.py +0 -0
  263. {tescmd-0.3.1 → tescmd-0.5.0}/tests/protocol/test_navigation.py +0 -0
  264. {tescmd-0.3.1 → tescmd-0.5.0}/tests/protocol/test_session.py +0 -0
  265. {tescmd-0.3.1 → tescmd-0.5.0}/tests/protocol/test_signer.py +0 -0
  266. {tescmd-0.3.1 → tescmd-0.5.0}/tests/telemetry/__init__.py +0 -0
  267. {tescmd-0.3.1 → tescmd-0.5.0}/tests/telemetry/conftest.py +0 -0
  268. {tescmd-0.3.1 → tescmd-0.5.0}/tests/telemetry/test_cache_sink.py +0 -0
  269. {tescmd-0.3.1 → tescmd-0.5.0}/tests/telemetry/test_csv_sink.py +0 -0
  270. {tescmd-0.3.1 → tescmd-0.5.0}/tests/telemetry/test_dashboard.py +0 -0
  271. {tescmd-0.3.1 → tescmd-0.5.0}/tests/telemetry/test_decoder.py +0 -0
  272. {tescmd-0.3.1 → tescmd-0.5.0}/tests/telemetry/test_fanout.py +0 -0
  273. {tescmd-0.3.1 → tescmd-0.5.0}/tests/telemetry/test_fields.py +0 -0
  274. {tescmd-0.3.1 → tescmd-0.5.0}/tests/telemetry/test_flatbuf.py +0 -0
  275. {tescmd-0.3.1 → tescmd-0.5.0}/tests/telemetry/test_mapper.py +0 -0
  276. {tescmd-0.3.1 → tescmd-0.5.0}/tests/telemetry/test_server.py +0 -0
  277. {tescmd-0.3.1 → tescmd-0.5.0}/tests/telemetry/test_stream_cmd.py +0 -0
  278. {tescmd-0.3.1 → tescmd-0.5.0}/tests/telemetry/test_tailscale.py +0 -0
  279. {tescmd-0.3.1 → tescmd-0.5.0}/tests/triggers/__init__.py +0 -0
  280. {tescmd-0.3.1 → tescmd-0.5.0}/tests/triggers/test_manager.py +0 -0
  281. {tescmd-0.3.1 → tescmd-0.5.0}/tests/triggers/test_models.py +0 -0
@@ -8,6 +8,7 @@ on:
8
8
  jobs:
9
9
  test:
10
10
  runs-on: ubuntu-latest
11
+ timeout-minutes: 10
11
12
  strategy:
12
13
  matrix:
13
14
  python-version: ["3.11", "3.12", "3.13"]
@@ -20,4 +21,4 @@ jobs:
20
21
  - run: ruff check src/ tests/
21
22
  - run: ruff format --check src/ tests/
22
23
  - run: mypy src/
23
- - run: pytest
24
+ - run: pytest -v --timeout=30
@@ -1,3 +1,4 @@
1
+ .DS_Store
1
2
  __pycache__/
2
3
  *.pyc
3
4
  *.egg-info/
@@ -5,6 +5,59 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.5.0] - 2026-02-03
9
+
10
+ ### Changed
11
+
12
+ - **Slim node capabilities** — node now advertises only `location.get` + `system.run` to the gateway (was 29 individual commands); all 34 handlers remain available via `system.run` meta-dispatch, reducing handshake payload and simplifying capability negotiation
13
+ - **Explicit `send_connected()` lifecycle** — `node.connected` event is now sent explicitly after `connect_with_backoff()` and after successful reconnection, replacing the implicit first-frame trigger; CLI callers show a warning if the lifecycle event fails while the connection itself succeeded
14
+ - **`send_connected()` returns bool** — callers can now detect lifecycle event failure; both `openclaw bridge` and `serve` commands display a yellow warning when the event fails to send
15
+ - **Separated reconnect error handling** — `_maybe_reconnect()` now handles connection failure and lifecycle event failure independently; a failed `node.connected` no longer incorrectly doubles the reconnect backoff timer
16
+
17
+ ### Added
18
+
19
+ - **`on_reconnect` gateway callback** — `GatewayClient` accepts an `on_reconnect` callback invoked after the receive loop successfully reconnects, ensuring `node.connected` is sent on every reconnection (not just the initial connect)
20
+ - **`system.run` activity logging** — dispatcher logs the resolved inner method when routing through `system.run`, so operational logs show `system.run → door.lock` instead of just `system.run`
21
+
22
+ ### Fixed
23
+
24
+ - **`send_connected()` false-positive logging** — no longer logs "Sent node.connected event" when the gateway is disconnected (the event was being silently dropped by `send_event()`)
25
+ - **`OpenClawPipeline.dispatcher` typing** — changed from `Any` to `CommandDispatcher` for static analysis support
26
+
27
+ ## [0.4.0] - 2026-02-02
28
+
29
+ ### Added
30
+
31
+ - **Unique app name generation** — setup wizard generates a `tescmd-<hex>` application name to prevent collisions on the Tesla Developer Portal; reused on re-runs unless `--force` is passed
32
+ - **In-process KeyServer** — ephemeral HTTP server (`KeyServer`) serves the PEM public key on localhost during interactive setup so Tailscale Funnel can proxy it without writing to the serve directory
33
+ - **Key mismatch warning** — setup wizard detects when the remote public key (GitHub Pages or Tailscale) differs from the local key and warns before Phase 2, so the user knows a redeploy is coming
34
+ - **`fetch_tailscale_key_pem()`** — synchronous helper in the deploy module to fetch the raw PEM from a Tailscale Funnel URL, mirroring `github_pages.fetch_key_pem()`
35
+ - **`TailscaleManager.start_proxy()`** — reverse-proxy mode (`tailscale serve --bg http://127.0.0.1:<port>`) for forwarding to a local HTTP server, distinct from the static-file `start_serve()`
36
+
37
+ ### Changed
38
+
39
+ - **Setup phase reorder** — phases now run: keys → Fleet API registration → OAuth login → key enrollment (was: keys → enrollment → registration → OAuth); registration happens while credentials are fresh, enrollment is last so the user finishes in the Tesla app
40
+ - **Credentials always required** — both Client ID and Client Secret are mandatory with retry loops (3 attempts each); empty input no longer silently skips setup
41
+ - **Auto-save credentials** — `.env` file is written automatically after credential entry; removed the "Save to .env?" prompt
42
+ - **`--force` regenerates app name** — passing `--force` to setup now generates a fresh `tescmd-<hex>` name instead of reusing the saved one
43
+ - **Atomic Tailscale serve + Funnel** — `start_key_serving()` uses a single `tailscale serve --bg --funnel --set-path / <dir>` command instead of separate serve + funnel calls
44
+ - **`TailscaleManager.start_serve()` API** — added `port` and `funnel` keyword arguments for configurable HTTPS port and inline Funnel enablement
45
+ - **Enrollment messaging** — streamlined to focus on QR code scanning; removed duplicate URL display and the "Open in browser?" prompt (browser opens automatically)
46
+ - **GitHub Pages note** — clarified that Tailscale is used alongside GitHub Pages for telemetry streaming, not as a replacement
47
+ - **Funnel cleanup uses `stop_funnel()`** — finally block in `_interactive_setup` now calls the proper `TailscaleManager.stop_funnel()` method instead of the low-level `_run()` static method, preserving state tracking and idempotency
48
+
49
+ ### Fixed
50
+
51
+ - **CLI module HTTP isolation** — moved direct `httpx.get()` call out of `setup.py` into `tailscale_serve.fetch_tailscale_key_pem()` to comply with single-responsibility layering (CLI handles args + output, deploy modules handle HTTP)
52
+
53
+ ## [0.3.2] - 2026-02-02
54
+
55
+ ### Fixed
56
+
57
+ - **OAuth URL printed for manual fallback** — `login_flow()` now prints the authorization URL before opening the browser so users can copy-paste it when `webbrowser.open()` fails
58
+ - **422 "already registered" treated as success** — `register_partner_account()` now treats HTTP 422 with "already been taken" as idempotent success instead of raising `AuthError`; re-running setup or `auth register` shows "Already registered — no action needed"
59
+ - **GitHub key comparison on re-deploy** — `_deploy_key_github()` fetches the remote public key and compares it to the local key; if they match, deployment is skipped; if they differ, the user is prompted before overwriting
60
+
8
61
  ## [0.3.1] - 2026-02-02
9
62
 
10
63
  ### Added
tescmd-0.5.0/PKG-INFO ADDED
@@ -0,0 +1,301 @@
1
+ Metadata-Version: 2.4
2
+ Name: tescmd
3
+ Version: 0.5.0
4
+ Summary: A Python CLI for querying and controlling Tesla vehicles via the Fleet API
5
+ Project-URL: Homepage, https://github.com/oceanswave/tescmd
6
+ Project-URL: Repository, https://github.com/oceanswave/tescmd
7
+ Project-URL: Issues, https://github.com/oceanswave/tescmd/issues
8
+ Project-URL: Documentation, https://github.com/oceanswave/tescmd#readme
9
+ Author: oceanswave
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: cli,ev,fleet-api,tesla,vehicle
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Software Development :: Libraries
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.11
25
+ Requires-Dist: click>=8.1
26
+ Requires-Dist: cryptography>=42.0
27
+ Requires-Dist: httpx>=0.27
28
+ Requires-Dist: keyring>=25.0
29
+ Requires-Dist: mcp>=1.0
30
+ Requires-Dist: protobuf>=5.29
31
+ Requires-Dist: pydantic-settings>=2.0
32
+ Requires-Dist: pydantic>=2.0
33
+ Requires-Dist: python-dotenv>=1.0
34
+ Requires-Dist: rich>=13.0
35
+ Requires-Dist: starlette>=0.37
36
+ Requires-Dist: textual>=1.0
37
+ Requires-Dist: uvicorn>=0.30
38
+ Requires-Dist: websockets>=14.0
39
+ Provides-Extra: ble
40
+ Requires-Dist: bleak>=0.22; extra == 'ble'
41
+ Provides-Extra: dev
42
+ Requires-Dist: build>=1.0; extra == 'dev'
43
+ Requires-Dist: grpcio-tools>=1.68; extra == 'dev'
44
+ Requires-Dist: mypy-protobuf>=3.6; extra == 'dev'
45
+ Requires-Dist: mypy>=1.13; extra == 'dev'
46
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
47
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
48
+ Requires-Dist: pytest-httpx>=0.34; extra == 'dev'
49
+ Requires-Dist: pytest-timeout>=2.3; extra == 'dev'
50
+ Requires-Dist: pytest-xdist>=3.0; extra == 'dev'
51
+ Requires-Dist: pytest>=8.0; extra == 'dev'
52
+ Requires-Dist: ruff>=0.8; extra == 'dev'
53
+ Description-Content-Type: text/markdown
54
+
55
+ <p align="center">
56
+ <img src="images/tescmd_header.jpeg" alt="tescmd — Python CLI for Tesla Fleet API" width="100%">
57
+ </p>
58
+
59
+ # tescmd
60
+
61
+ <p align="center">
62
+ <a href="https://pypi.org/project/tescmd/"><img src="https://img.shields.io/pypi/v/tescmd" alt="PyPI"></a>
63
+ <a href="https://pypi.org/project/tescmd/"><img src="https://img.shields.io/pypi/pyversions/tescmd" alt="Python"></a>
64
+ <a href="https://github.com/oceanswave/tescmd/actions/workflows/test.yml"><img src="https://img.shields.io/github/actions/workflow/status/oceanswave/tescmd/test.yml?branch=main&label=build" alt="Build"></a>
65
+ <a href="LICENSE"><img src="https://img.shields.io/github/license/oceanswave/tescmd" alt="License"></a>
66
+ <a href="https://github.com/oceanswave/tescmd/releases"><img src="https://img.shields.io/github/v/release/oceanswave/tescmd" alt="GitHub Release"></a>
67
+ </p>
68
+
69
+ <p align="center">
70
+ <strong>The complete Python CLI for Tesla's Fleet API — built for humans and AI agents alike.</strong>
71
+ </p>
72
+
73
+ <p align="center">
74
+ Check your battery. Lock your doors. Stream live telemetry. Let Claude control your car.<br>
75
+ Two commands to install. One wizard to set up. Every API endpoint at your fingertips.
76
+ </p>
77
+
78
+ ---
79
+
80
+ ## Quick Start
81
+
82
+ ```bash
83
+ pip install tescmd
84
+ tescmd setup
85
+ ```
86
+
87
+ The setup wizard handles everything — Tesla Developer app creation, key generation, public key hosting, Fleet API registration, OAuth2 authentication, and vehicle key enrollment. Then you're ready:
88
+
89
+ ```bash
90
+ tescmd charge status # Battery and charging state
91
+ tescmd climate on --wake # Turn on climate (wakes if asleep)
92
+ tescmd security lock --wake # Lock the car
93
+ tescmd nav waypoints "Home" "Work" # Multi-stop navigation
94
+ tescmd serve 5YJ3... # Launch the live dashboard
95
+ ```
96
+
97
+ ---
98
+
99
+ ## See It in Action
100
+
101
+ ### Live TUI Dashboard
102
+
103
+ `tescmd serve` launches a full-screen terminal dashboard with real-time telemetry, MCP server status, tunnel info, and connection metrics — powered by Textual.
104
+
105
+ <p align="center">
106
+ <img src="images/tescmd_serve.png" alt="tescmd serve — live TUI dashboard" width="700">
107
+ </p>
108
+
109
+ ### AI Agent Integration
110
+
111
+ Every command doubles as an MCP tool. Claude Desktop, Claude Code, and other agent frameworks can query your vehicle, send commands, and react to telemetry — all through structured JSON with built-in cost protection.
112
+
113
+ <p align="center">
114
+ <img src="images/tescmd_mcp.png" alt="tescmd MCP server — Claude Desktop integration" width="700">
115
+ </p>
116
+
117
+ ### Rich Terminal Output
118
+
119
+ Formatted tables in your terminal, structured JSON when piped — tescmd auto-detects the right output for the context.
120
+
121
+ <p align="center">
122
+ <img src="images/tescmd_waypoints.png" alt="tescmd nav waypoints" width="500">
123
+ </p>
124
+
125
+ ---
126
+
127
+ ## What You Get
128
+
129
+ ### Query & Control
130
+
131
+ Full read/write access to Tesla's Fleet API: battery, charge, climate, locks, trunks, windows, sentry, navigation, media, speed limits, PINs, Powerwalls, and more. Every read command is cached with smart TTLs — bots can call tescmd as often as they want and only pay for the first request.
132
+
133
+ ### Fleet Telemetry Streaming
134
+
135
+ Your vehicle pushes data directly to your machine via Tailscale Funnel — no polling, no per-request charges. Choose from field presets (`driving`, `charging`, `all`) or subscribe to 120+ individual fields. Sessions produce a wide-format CSV log by default.
136
+
137
+ ```bash
138
+ tescmd serve 5YJ3... --fields driving # Speed, location, power
139
+ tescmd serve 5YJ3... --fields all # Everything
140
+ ```
141
+
142
+ ### MCP Server for AI Agents
143
+
144
+ `tescmd serve` exposes every command as an MCP tool with OAuth 2.1 authentication. Agents get deterministic JSON output, meaningful exit codes, and a `--wake` opt-in flag so they never trigger billable wake calls by accident.
145
+
146
+ ### OpenClaw Bridge
147
+
148
+ Stream filtered telemetry to an [OpenClaw](https://openclaw.ai/) Gateway with per-field delta and throttle filtering. Bots on the gateway can send commands back — lock doors, start charging, set climate — through bidirectional dispatch.
149
+
150
+ ### Trigger Subscriptions
151
+
152
+ Register conditions on any telemetry field — battery below 20%, speed above 80, location enters a geofence — and get notified via OpenClaw push events or MCP polling. Supports one-shot and persistent modes with cooldown.
153
+
154
+ ### Signed Vehicle Commands
155
+
156
+ tescmd implements the [Vehicle Command Protocol](https://github.com/teslamotors/vehicle-command) with ECDH session management and HMAC-SHA256 signing. Once your key is enrolled, commands are signed transparently — no agent-side crypto needed.
157
+
158
+ ---
159
+
160
+ ## Cost Protection Built In
161
+
162
+ Tesla's Fleet API is pay-per-use. A naive polling script can generate hundreds of dollars in monthly charges from a single vehicle. tescmd implements four layers of defense:
163
+
164
+ | Layer | What it does |
165
+ |---|---|
166
+ | **Tiered caching** | Specs cached 1h, fleet lists 5m, standard queries 1m, location 30s |
167
+ | **Wake confirmation** | Prompts before billable wake calls; `--wake` flag for scripts |
168
+ | **Smart wake state** | Tracks recent wake confirmations, skips redundant attempts |
169
+ | **Write invalidation** | Write commands auto-invalidate the relevant cache scope |
170
+
171
+ Streaming telemetry via `tescmd serve` replaces polling entirely — flat cost regardless of data volume. See [API Costs](docs/api-costs.md) for the full breakdown.
172
+
173
+ ---
174
+
175
+ ## Commands
176
+
177
+ | Group | Description |
178
+ |---|---|
179
+ | `setup` | Interactive first-run wizard |
180
+ | `auth` | OAuth2 login, logout, token management, export/import |
181
+ | `vehicle` | State queries, wake, rename, telemetry streaming, fleet status |
182
+ | `charge` | Charge control, scheduling, departure, fleet management |
183
+ | `climate` | HVAC, seats, steering wheel, bioweapon defense, overheat protection |
184
+ | `security` | Lock/unlock, sentry, valet, PINs, speed limits, remote start |
185
+ | `trunk` | Trunk, frunk, windows, sunroof, tonneau |
186
+ | `media` | Playback control, volume, favorites |
187
+ | `nav` | Send destinations, GPS coordinates, multi-stop waypoints, HomeLink |
188
+ | `software` | Update status, scheduling, cancellation |
189
+ | `energy` | Powerwall status, backup reserve, storm mode, grid config, history |
190
+ | `billing` | Supercharger billing history and invoices |
191
+ | `user` | Account info, region, orders, feature flags |
192
+ | `sharing` | Driver management, vehicle sharing invites |
193
+ | `key` | Key generation, deployment, enrollment, validation |
194
+ | `serve` | Combined MCP + telemetry + OpenClaw TUI dashboard |
195
+ | `mcp` | Standalone MCP server |
196
+ | `openclaw` | Standalone OpenClaw bridge |
197
+ | `cache` | Cache status and management |
198
+ | `raw` | Direct Fleet API endpoint access |
199
+
200
+ Every command supports `--format json` for scripting and `--help` for detailed usage. See the [Command Reference](docs/commands.md) for the full list.
201
+
202
+ ---
203
+
204
+ ## Installation
205
+
206
+ ```bash
207
+ pip install tescmd
208
+ ```
209
+
210
+ **Requirements:** Python 3.11+ and a [Tesla account](https://www.tesla.com) with a linked vehicle or energy product.
211
+
212
+ **Recommended:** [GitHub CLI](https://cli.github.com) (`gh`) for automated key hosting via GitHub Pages, or [Tailscale](https://tailscale.com) for zero-config key hosting and telemetry streaming via Funnel.
213
+
214
+ <details>
215
+ <summary>Install from source</summary>
216
+
217
+ ```bash
218
+ git clone https://github.com/oceanswave/tescmd.git
219
+ cd tescmd
220
+ pip install -e ".[dev]"
221
+ ```
222
+
223
+ </details>
224
+
225
+ ---
226
+
227
+ ## Configuration
228
+
229
+ tescmd resolves settings from CLI flags, environment variables (`.env` files loaded automatically), and defaults — in that order.
230
+
231
+ <details>
232
+ <summary>Environment variables</summary>
233
+
234
+ ```dotenv
235
+ TESLA_CLIENT_ID=your-client-id
236
+ TESLA_CLIENT_SECRET=your-client-secret
237
+ TESLA_VIN=5YJ3E1EA1NF000000
238
+ TESLA_REGION=na # na, eu, cn
239
+
240
+ # Display units (optional — defaults to US)
241
+ TESLA_TEMP_UNIT=F # F or C
242
+ TESLA_DISTANCE_UNIT=mi # mi or km
243
+ TESLA_PRESSURE_UNIT=psi # psi or bar
244
+
245
+ # Or switch everything at once:
246
+ # tescmd --units metric charge status
247
+ ```
248
+
249
+ See [docs/commands.md](docs/commands.md) for the full environment variable reference.
250
+
251
+ </details>
252
+
253
+ <details>
254
+ <summary>Token storage</summary>
255
+
256
+ Tokens are stored in the OS keyring by default (macOS Keychain, GNOME Keyring, Windows Credential Manager). On headless systems, tescmd falls back to a file-based store with restricted permissions. Transfer tokens between machines with `tescmd auth export` and `tescmd auth import`.
257
+
258
+ </details>
259
+
260
+ ---
261
+
262
+ ## Documentation
263
+
264
+ | | |
265
+ |---|---|
266
+ | [Setup Guide](docs/setup.md) | Step-by-step walkthrough of `tescmd setup` |
267
+ | [Command Reference](docs/commands.md) | Detailed usage for every command |
268
+ | [API Costs](docs/api-costs.md) | Cost breakdown, savings calculations, streaming comparison |
269
+ | [Bot Integration](docs/bot-integration.md) | JSON schema, exit codes, headless auth |
270
+ | [OpenClaw Bridge](docs/openclaw.md) | Gateway protocol, bidirectional commands, triggers, geofencing |
271
+ | [MCP Server](docs/mcp.md) | Tool reference, OAuth 2.1, custom tools, trigger polling |
272
+ | [Vehicle Command Protocol](docs/vehicle-command-protocol.md) | ECDH sessions and signed commands |
273
+ | [Authentication](docs/authentication.md) | OAuth2 PKCE flow, token storage, scopes |
274
+ | [Architecture](docs/architecture.md) | Layered design, module responsibilities |
275
+ | [FAQ](docs/faq.md) | Common questions about costs, hosting, and configuration |
276
+ | [Development](docs/development.md) | Contributing, testing, linting |
277
+
278
+ ---
279
+
280
+ ## Development
281
+
282
+ ```bash
283
+ git clone https://github.com/oceanswave/tescmd.git && cd tescmd
284
+ pip install -e ".[dev]"
285
+ pytest # 1600+ tests
286
+ ruff check src/ tests/ && mypy src/
287
+ ```
288
+
289
+ ---
290
+
291
+ ## Changelog
292
+
293
+ See [CHANGELOG.md](CHANGELOG.md) for release history.
294
+
295
+ ## License
296
+
297
+ MIT
298
+
299
+ <p align="center">
300
+ <img src="images/tescmd_logo.jpeg" alt="tescmd logo" width="300">
301
+ </p>
tescmd-0.5.0/README.md ADDED
@@ -0,0 +1,247 @@
1
+ <p align="center">
2
+ <img src="images/tescmd_header.jpeg" alt="tescmd — Python CLI for Tesla Fleet API" width="100%">
3
+ </p>
4
+
5
+ # tescmd
6
+
7
+ <p align="center">
8
+ <a href="https://pypi.org/project/tescmd/"><img src="https://img.shields.io/pypi/v/tescmd" alt="PyPI"></a>
9
+ <a href="https://pypi.org/project/tescmd/"><img src="https://img.shields.io/pypi/pyversions/tescmd" alt="Python"></a>
10
+ <a href="https://github.com/oceanswave/tescmd/actions/workflows/test.yml"><img src="https://img.shields.io/github/actions/workflow/status/oceanswave/tescmd/test.yml?branch=main&label=build" alt="Build"></a>
11
+ <a href="LICENSE"><img src="https://img.shields.io/github/license/oceanswave/tescmd" alt="License"></a>
12
+ <a href="https://github.com/oceanswave/tescmd/releases"><img src="https://img.shields.io/github/v/release/oceanswave/tescmd" alt="GitHub Release"></a>
13
+ </p>
14
+
15
+ <p align="center">
16
+ <strong>The complete Python CLI for Tesla's Fleet API — built for humans and AI agents alike.</strong>
17
+ </p>
18
+
19
+ <p align="center">
20
+ Check your battery. Lock your doors. Stream live telemetry. Let Claude control your car.<br>
21
+ Two commands to install. One wizard to set up. Every API endpoint at your fingertips.
22
+ </p>
23
+
24
+ ---
25
+
26
+ ## Quick Start
27
+
28
+ ```bash
29
+ pip install tescmd
30
+ tescmd setup
31
+ ```
32
+
33
+ The setup wizard handles everything — Tesla Developer app creation, key generation, public key hosting, Fleet API registration, OAuth2 authentication, and vehicle key enrollment. Then you're ready:
34
+
35
+ ```bash
36
+ tescmd charge status # Battery and charging state
37
+ tescmd climate on --wake # Turn on climate (wakes if asleep)
38
+ tescmd security lock --wake # Lock the car
39
+ tescmd nav waypoints "Home" "Work" # Multi-stop navigation
40
+ tescmd serve 5YJ3... # Launch the live dashboard
41
+ ```
42
+
43
+ ---
44
+
45
+ ## See It in Action
46
+
47
+ ### Live TUI Dashboard
48
+
49
+ `tescmd serve` launches a full-screen terminal dashboard with real-time telemetry, MCP server status, tunnel info, and connection metrics — powered by Textual.
50
+
51
+ <p align="center">
52
+ <img src="images/tescmd_serve.png" alt="tescmd serve — live TUI dashboard" width="700">
53
+ </p>
54
+
55
+ ### AI Agent Integration
56
+
57
+ Every command doubles as an MCP tool. Claude Desktop, Claude Code, and other agent frameworks can query your vehicle, send commands, and react to telemetry — all through structured JSON with built-in cost protection.
58
+
59
+ <p align="center">
60
+ <img src="images/tescmd_mcp.png" alt="tescmd MCP server — Claude Desktop integration" width="700">
61
+ </p>
62
+
63
+ ### Rich Terminal Output
64
+
65
+ Formatted tables in your terminal, structured JSON when piped — tescmd auto-detects the right output for the context.
66
+
67
+ <p align="center">
68
+ <img src="images/tescmd_waypoints.png" alt="tescmd nav waypoints" width="500">
69
+ </p>
70
+
71
+ ---
72
+
73
+ ## What You Get
74
+
75
+ ### Query & Control
76
+
77
+ Full read/write access to Tesla's Fleet API: battery, charge, climate, locks, trunks, windows, sentry, navigation, media, speed limits, PINs, Powerwalls, and more. Every read command is cached with smart TTLs — bots can call tescmd as often as they want and only pay for the first request.
78
+
79
+ ### Fleet Telemetry Streaming
80
+
81
+ Your vehicle pushes data directly to your machine via Tailscale Funnel — no polling, no per-request charges. Choose from field presets (`driving`, `charging`, `all`) or subscribe to 120+ individual fields. Sessions produce a wide-format CSV log by default.
82
+
83
+ ```bash
84
+ tescmd serve 5YJ3... --fields driving # Speed, location, power
85
+ tescmd serve 5YJ3... --fields all # Everything
86
+ ```
87
+
88
+ ### MCP Server for AI Agents
89
+
90
+ `tescmd serve` exposes every command as an MCP tool with OAuth 2.1 authentication. Agents get deterministic JSON output, meaningful exit codes, and a `--wake` opt-in flag so they never trigger billable wake calls by accident.
91
+
92
+ ### OpenClaw Bridge
93
+
94
+ Stream filtered telemetry to an [OpenClaw](https://openclaw.ai/) Gateway with per-field delta and throttle filtering. Bots on the gateway can send commands back — lock doors, start charging, set climate — through bidirectional dispatch.
95
+
96
+ ### Trigger Subscriptions
97
+
98
+ Register conditions on any telemetry field — battery below 20%, speed above 80, location enters a geofence — and get notified via OpenClaw push events or MCP polling. Supports one-shot and persistent modes with cooldown.
99
+
100
+ ### Signed Vehicle Commands
101
+
102
+ tescmd implements the [Vehicle Command Protocol](https://github.com/teslamotors/vehicle-command) with ECDH session management and HMAC-SHA256 signing. Once your key is enrolled, commands are signed transparently — no agent-side crypto needed.
103
+
104
+ ---
105
+
106
+ ## Cost Protection Built In
107
+
108
+ Tesla's Fleet API is pay-per-use. A naive polling script can generate hundreds of dollars in monthly charges from a single vehicle. tescmd implements four layers of defense:
109
+
110
+ | Layer | What it does |
111
+ |---|---|
112
+ | **Tiered caching** | Specs cached 1h, fleet lists 5m, standard queries 1m, location 30s |
113
+ | **Wake confirmation** | Prompts before billable wake calls; `--wake` flag for scripts |
114
+ | **Smart wake state** | Tracks recent wake confirmations, skips redundant attempts |
115
+ | **Write invalidation** | Write commands auto-invalidate the relevant cache scope |
116
+
117
+ Streaming telemetry via `tescmd serve` replaces polling entirely — flat cost regardless of data volume. See [API Costs](docs/api-costs.md) for the full breakdown.
118
+
119
+ ---
120
+
121
+ ## Commands
122
+
123
+ | Group | Description |
124
+ |---|---|
125
+ | `setup` | Interactive first-run wizard |
126
+ | `auth` | OAuth2 login, logout, token management, export/import |
127
+ | `vehicle` | State queries, wake, rename, telemetry streaming, fleet status |
128
+ | `charge` | Charge control, scheduling, departure, fleet management |
129
+ | `climate` | HVAC, seats, steering wheel, bioweapon defense, overheat protection |
130
+ | `security` | Lock/unlock, sentry, valet, PINs, speed limits, remote start |
131
+ | `trunk` | Trunk, frunk, windows, sunroof, tonneau |
132
+ | `media` | Playback control, volume, favorites |
133
+ | `nav` | Send destinations, GPS coordinates, multi-stop waypoints, HomeLink |
134
+ | `software` | Update status, scheduling, cancellation |
135
+ | `energy` | Powerwall status, backup reserve, storm mode, grid config, history |
136
+ | `billing` | Supercharger billing history and invoices |
137
+ | `user` | Account info, region, orders, feature flags |
138
+ | `sharing` | Driver management, vehicle sharing invites |
139
+ | `key` | Key generation, deployment, enrollment, validation |
140
+ | `serve` | Combined MCP + telemetry + OpenClaw TUI dashboard |
141
+ | `mcp` | Standalone MCP server |
142
+ | `openclaw` | Standalone OpenClaw bridge |
143
+ | `cache` | Cache status and management |
144
+ | `raw` | Direct Fleet API endpoint access |
145
+
146
+ Every command supports `--format json` for scripting and `--help` for detailed usage. See the [Command Reference](docs/commands.md) for the full list.
147
+
148
+ ---
149
+
150
+ ## Installation
151
+
152
+ ```bash
153
+ pip install tescmd
154
+ ```
155
+
156
+ **Requirements:** Python 3.11+ and a [Tesla account](https://www.tesla.com) with a linked vehicle or energy product.
157
+
158
+ **Recommended:** [GitHub CLI](https://cli.github.com) (`gh`) for automated key hosting via GitHub Pages, or [Tailscale](https://tailscale.com) for zero-config key hosting and telemetry streaming via Funnel.
159
+
160
+ <details>
161
+ <summary>Install from source</summary>
162
+
163
+ ```bash
164
+ git clone https://github.com/oceanswave/tescmd.git
165
+ cd tescmd
166
+ pip install -e ".[dev]"
167
+ ```
168
+
169
+ </details>
170
+
171
+ ---
172
+
173
+ ## Configuration
174
+
175
+ tescmd resolves settings from CLI flags, environment variables (`.env` files loaded automatically), and defaults — in that order.
176
+
177
+ <details>
178
+ <summary>Environment variables</summary>
179
+
180
+ ```dotenv
181
+ TESLA_CLIENT_ID=your-client-id
182
+ TESLA_CLIENT_SECRET=your-client-secret
183
+ TESLA_VIN=5YJ3E1EA1NF000000
184
+ TESLA_REGION=na # na, eu, cn
185
+
186
+ # Display units (optional — defaults to US)
187
+ TESLA_TEMP_UNIT=F # F or C
188
+ TESLA_DISTANCE_UNIT=mi # mi or km
189
+ TESLA_PRESSURE_UNIT=psi # psi or bar
190
+
191
+ # Or switch everything at once:
192
+ # tescmd --units metric charge status
193
+ ```
194
+
195
+ See [docs/commands.md](docs/commands.md) for the full environment variable reference.
196
+
197
+ </details>
198
+
199
+ <details>
200
+ <summary>Token storage</summary>
201
+
202
+ Tokens are stored in the OS keyring by default (macOS Keychain, GNOME Keyring, Windows Credential Manager). On headless systems, tescmd falls back to a file-based store with restricted permissions. Transfer tokens between machines with `tescmd auth export` and `tescmd auth import`.
203
+
204
+ </details>
205
+
206
+ ---
207
+
208
+ ## Documentation
209
+
210
+ | | |
211
+ |---|---|
212
+ | [Setup Guide](docs/setup.md) | Step-by-step walkthrough of `tescmd setup` |
213
+ | [Command Reference](docs/commands.md) | Detailed usage for every command |
214
+ | [API Costs](docs/api-costs.md) | Cost breakdown, savings calculations, streaming comparison |
215
+ | [Bot Integration](docs/bot-integration.md) | JSON schema, exit codes, headless auth |
216
+ | [OpenClaw Bridge](docs/openclaw.md) | Gateway protocol, bidirectional commands, triggers, geofencing |
217
+ | [MCP Server](docs/mcp.md) | Tool reference, OAuth 2.1, custom tools, trigger polling |
218
+ | [Vehicle Command Protocol](docs/vehicle-command-protocol.md) | ECDH sessions and signed commands |
219
+ | [Authentication](docs/authentication.md) | OAuth2 PKCE flow, token storage, scopes |
220
+ | [Architecture](docs/architecture.md) | Layered design, module responsibilities |
221
+ | [FAQ](docs/faq.md) | Common questions about costs, hosting, and configuration |
222
+ | [Development](docs/development.md) | Contributing, testing, linting |
223
+
224
+ ---
225
+
226
+ ## Development
227
+
228
+ ```bash
229
+ git clone https://github.com/oceanswave/tescmd.git && cd tescmd
230
+ pip install -e ".[dev]"
231
+ pytest # 1600+ tests
232
+ ruff check src/ tests/ && mypy src/
233
+ ```
234
+
235
+ ---
236
+
237
+ ## Changelog
238
+
239
+ See [CHANGELOG.md](CHANGELOG.md) for release history.
240
+
241
+ ## License
242
+
243
+ MIT
244
+
245
+ <p align="center">
246
+ <img src="images/tescmd_logo.jpeg" alt="tescmd logo" width="300">
247
+ </p>
@@ -364,10 +364,10 @@ ACTION REQUIRED: Add virtual key in the Tesla app
364
364
 
365
365
  Enrollment URL: https://tesla.com/_ak/yourdomain.github.io
366
366
 
367
- 1. Open the URL above on your phone
368
- 2. Tap Finish Setup on the web page
369
- 3. The Tesla app will show an Add Virtual Key prompt
370
- 4. Approve it
367
+ 1. Scan the QR code on the page above with your phone
368
+ 2. The Tesla app will show an Add Virtual Key prompt
369
+ 3. Approve it
370
+
371
371
  ```
372
372
 
373
373
  **JSON mode:** Returns a single envelope with `"status": "ready"`, `enroll_url`, and instructions.
Binary file
Binary file
Binary file
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "tescmd"
7
- version = "0.3.1"
7
+ version = "0.5.0"
8
8
  description = "A Python CLI for querying and controlling Tesla vehicles via the Fleet API"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -49,6 +49,7 @@ dev = [
49
49
  "pytest-httpx>=0.34",
50
50
  "pytest-xdist>=3.0",
51
51
  "pytest-cov>=5.0",
52
+ "pytest-timeout>=2.3",
52
53
  "ruff>=0.8",
53
54
  "mypy>=1.13",
54
55
  "mypy-protobuf>=3.6",
@@ -88,6 +89,7 @@ plugins = ["pydantic.mypy"]
88
89
  testpaths = ["tests"]
89
90
  asyncio_mode = "auto"
90
91
  addopts = "-n auto -m 'not e2e'"
92
+ timeout = 30
91
93
  markers = [
92
94
  "e2e: End-to-end smoke tests against the live Tesla Fleet API (requires TESLA_ACCESS_TOKEN)",
93
95
  ]