tescmd 0.1.2__tar.gz → 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (282) hide show
  1. tescmd-0.3.1/.env.example +75 -0
  2. tescmd-0.3.1/.github/workflows/publish.yml +19 -0
  3. tescmd-0.3.1/.github/workflows/test.yml +23 -0
  4. {tescmd-0.1.2 → tescmd-0.3.1}/.gitignore +2 -1
  5. tescmd-0.3.1/CHANGELOG.md +158 -0
  6. tescmd-0.3.1/CLAUDE.md +131 -0
  7. {tescmd-0.1.2 → tescmd-0.3.1}/PKG-INFO +125 -40
  8. {tescmd-0.1.2 → tescmd-0.3.1}/README.md +118 -39
  9. {tescmd-0.1.2 → tescmd-0.3.1}/docs/api-costs.md +26 -11
  10. {tescmd-0.1.2 → tescmd-0.3.1}/docs/architecture.md +153 -11
  11. {tescmd-0.1.2 → tescmd-0.3.1}/docs/authentication.md +52 -8
  12. {tescmd-0.1.2 → tescmd-0.3.1}/docs/bot-integration.md +68 -0
  13. {tescmd-0.1.2 → tescmd-0.3.1}/docs/commands.md +331 -3
  14. {tescmd-0.1.2 → tescmd-0.3.1}/docs/development.md +33 -27
  15. tescmd-0.3.1/docs/faq.md +128 -0
  16. tescmd-0.3.1/docs/mcp.md +416 -0
  17. tescmd-0.3.1/docs/openclaw.md +463 -0
  18. tescmd-0.3.1/docs/setup.md +228 -0
  19. {tescmd-0.1.2 → tescmd-0.3.1}/docs/vehicle-command-protocol.md +43 -12
  20. tescmd-0.3.1/images/tescmd_header.jpeg +0 -0
  21. tescmd-0.3.1/images/tescmd_logo.jpeg +0 -0
  22. {tescmd-0.1.2 → tescmd-0.3.1}/pyproject.toml +25 -1
  23. tescmd-0.3.1/skills/tescmd/SKILL.md +524 -0
  24. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/__init__.py +1 -1
  25. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/api/client.py +49 -5
  26. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/api/command.py +1 -1
  27. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/api/errors.py +13 -0
  28. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/api/signed_command.py +19 -14
  29. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/api/vehicle.py +19 -1
  30. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/auth/oauth.py +5 -1
  31. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/auth/server.py +6 -1
  32. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/auth/token_store.py +8 -1
  33. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cache/response_cache.py +11 -3
  34. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/_client.py +142 -20
  35. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/_options.py +2 -4
  36. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/auth.py +121 -11
  37. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/energy.py +2 -0
  38. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/key.py +149 -14
  39. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/main.py +70 -7
  40. tescmd-0.3.1/src/tescmd/cli/mcp_cmd.py +153 -0
  41. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/nav.py +3 -1
  42. tescmd-0.3.1/src/tescmd/cli/openclaw.py +169 -0
  43. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/security.py +7 -1
  44. tescmd-0.3.1/src/tescmd/cli/serve.py +923 -0
  45. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/setup.py +244 -25
  46. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/sharing.py +2 -0
  47. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/status.py +1 -1
  48. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/trunk.py +8 -17
  49. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/user.py +16 -1
  50. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/vehicle.py +156 -20
  51. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/crypto/__init__.py +3 -1
  52. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/crypto/ecdh.py +9 -0
  53. tescmd-0.3.1/src/tescmd/crypto/schnorr.py +191 -0
  54. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/deploy/github_pages.py +8 -0
  55. tescmd-0.3.1/src/tescmd/deploy/tailscale_serve.py +154 -0
  56. tescmd-0.3.1/src/tescmd/mcp/__init__.py +7 -0
  57. tescmd-0.3.1/src/tescmd/mcp/server.py +648 -0
  58. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/models/__init__.py +0 -2
  59. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/models/auth.py +24 -2
  60. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/models/config.py +1 -0
  61. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/models/energy.py +0 -9
  62. tescmd-0.3.1/src/tescmd/openclaw/__init__.py +23 -0
  63. tescmd-0.3.1/src/tescmd/openclaw/bridge.py +330 -0
  64. tescmd-0.3.1/src/tescmd/openclaw/config.py +167 -0
  65. tescmd-0.3.1/src/tescmd/openclaw/dispatcher.py +522 -0
  66. tescmd-0.3.1/src/tescmd/openclaw/emitter.py +175 -0
  67. tescmd-0.3.1/src/tescmd/openclaw/filters.py +123 -0
  68. tescmd-0.3.1/src/tescmd/openclaw/gateway.py +687 -0
  69. tescmd-0.3.1/src/tescmd/openclaw/telemetry_store.py +53 -0
  70. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/output/rich_output.py +46 -14
  71. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/protocol/commands.py +2 -2
  72. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/protocol/encoder.py +16 -13
  73. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/protocol/payloads.py +132 -11
  74. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/protocol/session.py +18 -8
  75. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/protocol/signer.py +3 -17
  76. tescmd-0.3.1/src/tescmd/telemetry/__init__.py +28 -0
  77. tescmd-0.3.1/src/tescmd/telemetry/cache_sink.py +154 -0
  78. tescmd-0.3.1/src/tescmd/telemetry/csv_sink.py +180 -0
  79. tescmd-0.3.1/src/tescmd/telemetry/dashboard.py +227 -0
  80. tescmd-0.3.1/src/tescmd/telemetry/decoder.py +284 -0
  81. tescmd-0.3.1/src/tescmd/telemetry/fanout.py +49 -0
  82. tescmd-0.3.1/src/tescmd/telemetry/fields.py +427 -0
  83. tescmd-0.3.1/src/tescmd/telemetry/flatbuf.py +162 -0
  84. tescmd-0.3.1/src/tescmd/telemetry/mapper.py +239 -0
  85. tescmd-0.3.1/src/tescmd/telemetry/protos/__init__.py +4 -0
  86. tescmd-0.3.1/src/tescmd/telemetry/protos/vehicle_alert.proto +31 -0
  87. tescmd-0.3.1/src/tescmd/telemetry/protos/vehicle_alert_pb2.py +42 -0
  88. tescmd-0.3.1/src/tescmd/telemetry/protos/vehicle_alert_pb2.pyi +44 -0
  89. tescmd-0.3.1/src/tescmd/telemetry/protos/vehicle_connectivity.proto +23 -0
  90. tescmd-0.3.1/src/tescmd/telemetry/protos/vehicle_connectivity_pb2.py +40 -0
  91. tescmd-0.3.1/src/tescmd/telemetry/protos/vehicle_connectivity_pb2.pyi +33 -0
  92. tescmd-0.3.1/src/tescmd/telemetry/protos/vehicle_data.proto +768 -0
  93. tescmd-0.3.1/src/tescmd/telemetry/protos/vehicle_data_pb2.py +136 -0
  94. tescmd-0.3.1/src/tescmd/telemetry/protos/vehicle_data_pb2.pyi +1336 -0
  95. tescmd-0.3.1/src/tescmd/telemetry/protos/vehicle_error.proto +23 -0
  96. tescmd-0.3.1/src/tescmd/telemetry/protos/vehicle_error_pb2.py +44 -0
  97. tescmd-0.3.1/src/tescmd/telemetry/protos/vehicle_error_pb2.pyi +39 -0
  98. tescmd-0.3.1/src/tescmd/telemetry/protos/vehicle_metric.proto +22 -0
  99. tescmd-0.3.1/src/tescmd/telemetry/protos/vehicle_metric_pb2.py +44 -0
  100. tescmd-0.3.1/src/tescmd/telemetry/protos/vehicle_metric_pb2.pyi +37 -0
  101. tescmd-0.3.1/src/tescmd/telemetry/server.py +300 -0
  102. tescmd-0.3.1/src/tescmd/telemetry/setup.py +468 -0
  103. tescmd-0.3.1/src/tescmd/telemetry/tailscale.py +300 -0
  104. tescmd-0.3.1/src/tescmd/telemetry/tui.py +1716 -0
  105. tescmd-0.3.1/src/tescmd/triggers/__init__.py +18 -0
  106. tescmd-0.3.1/src/tescmd/triggers/manager.py +264 -0
  107. tescmd-0.3.1/src/tescmd/triggers/models.py +93 -0
  108. {tescmd-0.1.2 → tescmd-0.3.1}/tests/api/test_signed_command.py +2 -2
  109. tescmd-0.3.1/tests/cli/test_auth.py +301 -0
  110. tescmd-0.3.1/tests/cli/test_bugfixes.py +236 -0
  111. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_cli_integration.py +1 -1
  112. tescmd-0.3.1/tests/cli/test_e2e_smoke.py +747 -0
  113. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_key.py +169 -5
  114. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_main_errors.py +7 -3
  115. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_nav_exec.py +1 -1
  116. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_setup.py +332 -0
  117. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_trunk_exec.py +10 -23
  118. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_vehicle_exec.py +1 -1
  119. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_wake_confirmation.py +13 -1
  120. tescmd-0.3.1/tests/crypto/test_schnorr.py +245 -0
  121. tescmd-0.3.1/tests/deploy/test_tailscale_serve.py +270 -0
  122. tescmd-0.3.1/tests/integration/test_serve.py +163 -0
  123. tescmd-0.3.1/tests/mcp/test_server.py +407 -0
  124. tescmd-0.3.1/tests/mcp/test_tools.py +86 -0
  125. tescmd-0.3.1/tests/openclaw/__init__.py +0 -0
  126. tescmd-0.3.1/tests/openclaw/test_bridge.py +618 -0
  127. tescmd-0.3.1/tests/openclaw/test_config.py +196 -0
  128. tescmd-0.3.1/tests/openclaw/test_dispatcher.py +1128 -0
  129. tescmd-0.3.1/tests/openclaw/test_emitter.py +165 -0
  130. tescmd-0.3.1/tests/openclaw/test_filters.py +131 -0
  131. tescmd-0.3.1/tests/openclaw/test_gateway.py +943 -0
  132. tescmd-0.3.1/tests/openclaw/test_telemetry_store.py +106 -0
  133. tescmd-0.3.1/tests/output/__init__.py +0 -0
  134. {tescmd-0.1.2 → tescmd-0.3.1}/tests/output/test_rich_output.py +7 -7
  135. tescmd-0.3.1/tests/protocol/__init__.py +0 -0
  136. tescmd-0.3.1/tests/protocol/test_boombox.py +74 -0
  137. {tescmd-0.1.2 → tescmd-0.3.1}/tests/protocol/test_commands.py +15 -0
  138. {tescmd-0.1.2 → tescmd-0.3.1}/tests/protocol/test_encoder.py +22 -19
  139. tescmd-0.3.1/tests/protocol/test_navigation.py +142 -0
  140. {tescmd-0.1.2 → tescmd-0.3.1}/tests/protocol/test_session.py +3 -3
  141. {tescmd-0.1.2 → tescmd-0.3.1}/tests/protocol/test_signer.py +3 -13
  142. tescmd-0.3.1/tests/telemetry/__init__.py +0 -0
  143. tescmd-0.3.1/tests/telemetry/conftest.py +34 -0
  144. tescmd-0.3.1/tests/telemetry/test_cache_sink.py +277 -0
  145. tescmd-0.3.1/tests/telemetry/test_csv_sink.py +321 -0
  146. tescmd-0.3.1/tests/telemetry/test_dashboard.py +220 -0
  147. tescmd-0.3.1/tests/telemetry/test_decoder.py +280 -0
  148. tescmd-0.3.1/tests/telemetry/test_fanout.py +105 -0
  149. tescmd-0.3.1/tests/telemetry/test_fields.py +119 -0
  150. tescmd-0.3.1/tests/telemetry/test_flatbuf.py +179 -0
  151. tescmd-0.3.1/tests/telemetry/test_mapper.py +192 -0
  152. tescmd-0.3.1/tests/telemetry/test_server.py +219 -0
  153. tescmd-0.3.1/tests/telemetry/test_stream_cmd.py +44 -0
  154. tescmd-0.3.1/tests/telemetry/test_tailscale.py +289 -0
  155. tescmd-0.3.1/tests/telemetry/test_tui.py +600 -0
  156. tescmd-0.3.1/tests/triggers/__init__.py +0 -0
  157. tescmd-0.3.1/tests/triggers/test_manager.py +474 -0
  158. tescmd-0.3.1/tests/triggers/test_models.py +162 -0
  159. tescmd-0.1.2/.claude/settings.local.json +0 -47
  160. tescmd-0.1.2/CHANGELOG.md +0 -69
  161. tescmd-0.1.2/CLAUDE.md +0 -401
  162. tescmd-0.1.2/docs/plans/2025-01-29-mvp-design.md +0 -152
  163. tescmd-0.1.2/docs/plans/2025-01-29-mvp-implementation.md +0 -3073
  164. tescmd-0.1.2/docs/setup-enrollment-audit.md +0 -171
  165. tescmd-0.1.2/scripts/e2e_test.py +0 -307
  166. tescmd-0.1.2/tests/cli/test_auth.py +0 -74
  167. {tescmd-0.1.2 → tescmd-0.3.1}/LICENSE +0 -0
  168. {tescmd-0.1.2 → tescmd-0.3.1}/scripts/validate_fleet_api.py +0 -0
  169. {tescmd-0.1.2 → tescmd-0.3.1}/spec/fleet_api_spec.json +0 -0
  170. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/__main__.py +0 -0
  171. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/_internal/__init__.py +0 -0
  172. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/_internal/async_utils.py +0 -0
  173. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/_internal/permissions.py +0 -0
  174. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/_internal/vin.py +0 -0
  175. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/api/__init__.py +0 -0
  176. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/api/charging.py +0 -0
  177. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/api/energy.py +0 -0
  178. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/api/partner.py +0 -0
  179. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/api/sharing.py +0 -0
  180. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/api/user.py +0 -0
  181. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/auth/__init__.py +0 -0
  182. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/ble/__init__.py +0 -0
  183. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cache/__init__.py +0 -0
  184. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cache/keys.py +0 -0
  185. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/__init__.py +0 -0
  186. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/billing.py +0 -0
  187. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/cache.py +0 -0
  188. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/charge.py +0 -0
  189. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/climate.py +0 -0
  190. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/media.py +0 -0
  191. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/partner.py +0 -0
  192. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/raw.py +0 -0
  193. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/cli/software.py +0 -0
  194. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/config/__init__.py +0 -0
  195. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/crypto/keys.py +0 -0
  196. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/deploy/__init__.py +0 -0
  197. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/models/command.py +0 -0
  198. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/models/sharing.py +0 -0
  199. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/models/user.py +0 -0
  200. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/models/vehicle.py +0 -0
  201. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/output/__init__.py +0 -0
  202. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/output/formatter.py +0 -0
  203. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/output/json_output.py +0 -0
  204. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/protocol/__init__.py +0 -0
  205. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/protocol/metadata.py +0 -0
  206. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/protocol/protobuf/__init__.py +0 -0
  207. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/protocol/protobuf/messages.py +0 -0
  208. {tescmd-0.1.2 → tescmd-0.3.1}/src/tescmd/py.typed +0 -0
  209. {tescmd-0.1.2 → tescmd-0.3.1}/tests/__init__.py +0 -0
  210. {tescmd-0.1.2 → tescmd-0.3.1}/tests/_internal/__init__.py +0 -0
  211. {tescmd-0.1.2 → tescmd-0.3.1}/tests/_internal/test_async_utils.py +0 -0
  212. {tescmd-0.1.2 → tescmd-0.3.1}/tests/_internal/test_vin.py +0 -0
  213. {tescmd-0.1.2 → tescmd-0.3.1}/tests/api/__init__.py +0 -0
  214. {tescmd-0.1.2 → tescmd-0.3.1}/tests/api/test_client.py +0 -0
  215. {tescmd-0.1.2 → tescmd-0.3.1}/tests/api/test_command_api.py +0 -0
  216. {tescmd-0.1.2 → tescmd-0.3.1}/tests/api/test_energy_api.py +0 -0
  217. {tescmd-0.1.2 → tescmd-0.3.1}/tests/api/test_partner_api.py +0 -0
  218. {tescmd-0.1.2 → tescmd-0.3.1}/tests/api/test_sharing_api.py +0 -0
  219. {tescmd-0.1.2 → tescmd-0.3.1}/tests/api/test_user_api.py +0 -0
  220. {tescmd-0.1.2 → tescmd-0.3.1}/tests/api/test_vehicle_api.py +0 -0
  221. {tescmd-0.1.2 → tescmd-0.3.1}/tests/auth/__init__.py +0 -0
  222. {tescmd-0.1.2 → tescmd-0.3.1}/tests/auth/test_oauth.py +0 -0
  223. {tescmd-0.1.2 → tescmd-0.3.1}/tests/auth/test_oauth_extended.py +0 -0
  224. {tescmd-0.1.2 → tescmd-0.3.1}/tests/auth/test_server.py +0 -0
  225. {tescmd-0.1.2 → tescmd-0.3.1}/tests/auth/test_token_store.py +0 -0
  226. {tescmd-0.1.2 → tescmd-0.3.1}/tests/auth/test_token_store_fallback.py +0 -0
  227. {tescmd-0.1.2 → tescmd-0.3.1}/tests/auth/test_token_store_file.py +0 -0
  228. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cache/__init__.py +0 -0
  229. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cache/test_generic_cache.py +0 -0
  230. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cache/test_keys.py +0 -0
  231. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cache/test_response_cache.py +0 -0
  232. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/__init__.py +0 -0
  233. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/_helpers.py +0 -0
  234. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/conftest.py +0 -0
  235. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_auth_exec.py +0 -0
  236. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_cache.py +0 -0
  237. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_cached_api_call.py +0 -0
  238. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_charge_exec.py +0 -0
  239. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_climate_exec.py +0 -0
  240. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_energy.py +0 -0
  241. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_energy_exec.py +0 -0
  242. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_error_handlers.py +0 -0
  243. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_key_enroll.py +0 -0
  244. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_key_unenroll.py +0 -0
  245. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_media.py +0 -0
  246. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_media_exec.py +0 -0
  247. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_nav.py +0 -0
  248. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_partner.py +0 -0
  249. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_raw.py +0 -0
  250. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_raw_exec.py +0 -0
  251. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_security_exec.py +0 -0
  252. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_setup_scope_check.py +0 -0
  253. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_sharing.py +0 -0
  254. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_sharing_exec.py +0 -0
  255. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_software.py +0 -0
  256. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_software_exec.py +0 -0
  257. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_status_exec.py +0 -0
  258. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_tier_enforcement.py +0 -0
  259. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_user.py +0 -0
  260. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_user_exec.py +0 -0
  261. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_vcsec_guard.py +0 -0
  262. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_vehicle_power_exec.py +0 -0
  263. {tescmd-0.1.2 → tescmd-0.3.1}/tests/cli/test_verbose.py +0 -0
  264. {tescmd-0.1.2 → tescmd-0.3.1}/tests/conftest.py +0 -0
  265. {tescmd-0.1.2 → tescmd-0.3.1}/tests/crypto/__init__.py +0 -0
  266. {tescmd-0.1.2 → tescmd-0.3.1}/tests/crypto/test_ecdh.py +0 -0
  267. {tescmd-0.1.2 → tescmd-0.3.1}/tests/crypto/test_keys.py +0 -0
  268. {tescmd-0.1.2 → tescmd-0.3.1}/tests/deploy/__init__.py +0 -0
  269. {tescmd-0.1.2 → tescmd-0.3.1}/tests/deploy/test_github_pages.py +0 -0
  270. {tescmd-0.1.2/tests/models → tescmd-0.3.1/tests/integration}/__init__.py +0 -0
  271. {tescmd-0.1.2/tests/output → tescmd-0.3.1/tests/mcp}/__init__.py +0 -0
  272. {tescmd-0.1.2/tests/protocol → tescmd-0.3.1/tests/models}/__init__.py +0 -0
  273. {tescmd-0.1.2 → tescmd-0.3.1}/tests/models/test_auth.py +0 -0
  274. {tescmd-0.1.2 → tescmd-0.3.1}/tests/models/test_config.py +0 -0
  275. {tescmd-0.1.2 → tescmd-0.3.1}/tests/models/test_energy.py +0 -0
  276. {tescmd-0.1.2 → tescmd-0.3.1}/tests/models/test_sharing.py +0 -0
  277. {tescmd-0.1.2 → tescmd-0.3.1}/tests/models/test_user_models.py +0 -0
  278. {tescmd-0.1.2 → tescmd-0.3.1}/tests/models/test_vehicle.py +0 -0
  279. {tescmd-0.1.2 → tescmd-0.3.1}/tests/output/test_formatter.py +0 -0
  280. {tescmd-0.1.2 → tescmd-0.3.1}/tests/output/test_json_output.py +0 -0
  281. {tescmd-0.1.2 → tescmd-0.3.1}/tests/protocol/conftest.py +0 -0
  282. {tescmd-0.1.2 → tescmd-0.3.1}/tests/protocol/test_metadata.py +0 -0
@@ -0,0 +1,75 @@
1
+ # tescmd — Environment Variables
2
+ #
3
+ # Copy this file to .env and uncomment the variables you need.
4
+ # The setup wizard (tescmd setup) will create ~/.config/tescmd/.env
5
+ # for you automatically.
6
+ #
7
+ # Resolution order:
8
+ # 1. Shell environment variables (highest priority)
9
+ # 2. .env in the current working directory
10
+ # 3. ~/.config/tescmd/.env (created by tescmd setup)
11
+
12
+ # ─── Tesla Fleet API Credentials ─────────────────────────────────
13
+ # Required. Obtain from https://developer.tesla.com
14
+ # TESLA_CLIENT_ID=
15
+ # TESLA_CLIENT_SECRET=
16
+
17
+ # ─── Vehicle ──────────────────────────────────────────────────────
18
+ # Default vehicle VIN (avoids passing --vin on every command)
19
+ # TESLA_VIN=
20
+
21
+ # API region: na (North America), eu (Europe), cn (China)
22
+ # TESLA_REGION=na
23
+
24
+ # ─── Token Override / Storage ─────────────────────────────────────
25
+ # Direct token override (bypasses keyring / token file)
26
+ # TESLA_ACCESS_TOKEN=
27
+ # TESLA_REFRESH_TOKEN=
28
+
29
+ # File path for token storage (skips OS keyring)
30
+ # Useful for Docker, headless Linux, CI environments
31
+ # TESLA_TOKEN_FILE=~/.config/tescmd/tokens.json
32
+
33
+ # ─── Config & Cache ──────────────────────────────────────────────
34
+ # TESLA_CONFIG_DIR=~/.config/tescmd
35
+ # TESLA_CACHE_DIR=~/.cache/tescmd
36
+ # TESLA_CACHE_TTL=60
37
+ # TESLA_CACHE_ENABLED=true
38
+
39
+ # ─── Output Format & Display Units ───────────────────────────────
40
+ # Force output format: rich (TTY default), json (piped default), quiet
41
+ # TESLA_OUTPUT_FORMAT=
42
+
43
+ # Display unit preferences
44
+ # TESLA_TEMP_UNIT=F # F or C
45
+ # TESLA_DISTANCE_UNIT=mi # mi or km
46
+ # TESLA_PRESSURE_UNIT=psi # psi or bar
47
+
48
+ # ─── Command Protocol & Key Hosting ──────────────────────────────
49
+ # Command signing: auto (default), signed, unsigned
50
+ # TESLA_COMMAND_PROTOCOL=auto
51
+
52
+ # Domain for key hosting (set by tescmd setup)
53
+ # TESLA_DOMAIN=
54
+
55
+ # Key hosting method: github or tailscale
56
+ # TESLA_HOSTING_METHOD=
57
+
58
+ # GitHub repo for key deployment (e.g. username/username.github.io)
59
+ # TESLA_GITHUB_REPO=
60
+
61
+ # Setup tier: readonly or full
62
+ # TESLA_SETUP_TIER=
63
+
64
+ # Config profile name
65
+ # TESLA_PROFILE=default
66
+
67
+ # ─── MCP Server ──────────────────────────────────────────────────
68
+ # Credentials for MCP OAuth 2.1 authentication
69
+ # Required for tescmd serve and tescmd mcp serve
70
+ # TESCMD_MCP_CLIENT_ID=
71
+ # TESCMD_MCP_CLIENT_SECRET=
72
+
73
+ # ─── OpenClaw ────────────────────────────────────────────────────
74
+ # Gateway authentication token
75
+ # OPENCLAW_GATEWAY_TOKEN=
@@ -0,0 +1,19 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ permissions:
11
+ id-token: write # trusted publishing
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: actions/setup-python@v5
15
+ with:
16
+ python-version: "3.12"
17
+ - run: pip install build
18
+ - run: python -m build
19
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,23 @@
1
+ name: Test
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.11", "3.12", "3.13"]
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: ${{ matrix.python-version }}
19
+ - run: pip install -e ".[dev,telemetry]"
20
+ - run: ruff check src/ tests/
21
+ - run: ruff format --check src/ tests/
22
+ - run: mypy src/
23
+ - run: pytest
@@ -5,8 +5,9 @@ dist/
5
5
  build/
6
6
  .venv/
7
7
  .env
8
+ .env.bak
8
9
  *.pem
9
10
  .mypy_cache/
10
11
  .pytest_cache/
11
12
  .ruff_cache/
12
- .coverage
13
+ .coverage
@@ -0,0 +1,158 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.3.1] - 2026-02-02
9
+
10
+ ### Added
11
+
12
+ - **README overhaul** — header banner, logo, new "What It Does" summary section, expanded Prerequisites table with Python 3.11+, pip, Tesla account, and helpful links
13
+ - **Tailscale Funnel auto-detection in auth setup** — `_interactive_setup` now detects Tailscale and offers to start Funnel so Tesla can verify the origin URL during Developer Portal configuration; cleans up Funnel on exit
14
+ - **Tailscale hostname passthrough** — setup wizard forwards detected Tailscale hostname to auth flow, showing a concrete "Also add" origin URL instead of the generic placeholder
15
+ - **Comprehensive agent skill documentation** — expanded skill covering all command groups, triggers, and OpenClaw dispatch
16
+
17
+ ### Fixed
18
+
19
+ - **Cross-platform file permissions** — OpenClaw gateway key file now uses `secure_file()` from `_internal.permissions` instead of raw `chmod(0o600)`, adding proper Windows support via `icacls`
20
+ - **12-factor app compliance** — config, disposability, and concurrency improvements across the codebase
21
+ - **Documentation accuracy** — corrected `media_adjust_volume` tool name in MCP docs; emphasized MCP/OpenClaw over direct CLI for cost savings in agent skill
22
+
23
+ ## [0.3.0] - 2026-02-01
24
+
25
+ ### Added
26
+
27
+ - **Unified `tescmd serve`** — single command combining MCP server, Fleet Telemetry streaming, cache warming, and optional OpenClaw bridge; full-screen TUI dashboard shows live telemetry, MCP status, tunnel URL, sink count, and connection health
28
+ - **TUI dashboard** — 8-panel Textual layout with telemetry field table, server info sidebar, activity log, request log, and filter status; command palette (`ctrl+p`), keybindings (`q` to quit, `f` to toggle filters), clean graceful shutdown
29
+ - **OpenClaw Bridge** — `tescmd openclaw bridge [VIN]` streams Fleet Telemetry to an OpenClaw Gateway with configurable delta+throttle filtering per field; supports `--dry-run` for JSONL output without a gateway connection
30
+ - **OpenClaw node role** — bidirectional command dispatch over the gateway WebSocket; bots send commands via the gateway that are forwarded as `node.invoke.request` events, routed through `CommandDispatcher` with read/write separation, tier enforcement, and VCSEC signing guards
31
+ - **Trigger subscription system** — `trigger.create`, `trigger.delete`, `trigger.list`, `trigger.poll` commands let bots register conditions on any telemetry field; supports operators `lt`, `gt`, `lte`, `gte`, `eq`, `neq`, `changed`, `enter`, `leave`; one-shot and persistent modes with configurable cooldown; max 100 triggers, 500 pending notifications
32
+ - **Geofence triggers** — `enter`/`leave` operators on Location field detect boundary crossings using haversine distance; fires only on actual crossing (not "already inside"), requires previous position for comparison
33
+ - **Trigger convenience aliases** — `cabin_temp.trigger`, `outside_temp.trigger`, `battery.trigger`, `location.trigger` pre-fill the field name so bots don't need to know raw telemetry field names
34
+ - **Trigger notification delivery** — dual-channel: OpenClaw push events (`trigger.fired`) for connected bots, and MCP polling via `trigger_poll` tool for agent frameworks
35
+ - **`system.run` meta-dispatch** — allows bots to invoke any registered handler by name with alias mapping (e.g., `door_lock` → `door.lock`, `auto_conditioning_start` → `climate.on`); guards against recursive self-dispatch
36
+ - **MCP Server** — `tescmd mcp serve` exposes all tescmd commands as MCP tools for Claude Desktop/Code and other agent frameworks; supports stdio and streamable-http transports with OAuth 2.1 authentication
37
+ - **MCP custom tool registry** — `MCPServer.register_custom_tool()` allows runtime registration of non-CLI tools (used by trigger system); custom tools appear alongside CLI-backed tools with proper schemas
38
+ - **Agent skill** — `skills/tescmd/SKILL.md` teaches AI agents how to use every tescmd command group with examples, parameter types, and common patterns
39
+ - **Reusable telemetry session** — extracted shared telemetry lifecycle (server → tunnel → partner registration → fleet config → cleanup) into `telemetry/setup.py` for use by serve, stream, and bridge commands
40
+ - **Dual-gate telemetry filter** — `openclaw/filters.py` combines delta threshold (value change) and throttle interval (minimum time between emissions) to reduce noise in telemetry streams; includes haversine distance for location fields
41
+ - **OpenClaw event emitter** — maps telemetry fields to OpenClaw `req:agent` event payloads (location, battery, temperature, speed, charge state transitions, security changes)
42
+ - **Gateway WebSocket client** — implements the OpenClaw operator protocol (challenge → connect → hello-ok handshake) with Ed25519 device key signing and exponential backoff reconnection
43
+ - **Bridge configuration** — `BridgeConfig` pydantic model with per-field filter settings, loadable from JSON file or CLI flags
44
+ - **CSV telemetry logging** — wide-format CSV log with one row per frame and one column per subscribed field; written to `~/.config/tescmd/logs/` by default, disable with `--no-log`
45
+ - **Cache sink** — telemetry-driven cache warming keeps read-command cache fresh while telemetry is active, making agent reads free
46
+ - **Frame fanout** — `FrameFanout` distributes decoded telemetry frames to multiple sinks (dashboard, CSV, cache, OpenClaw bridge, triggers) in parallel
47
+ - **Telemetry field mapper** — `telemetry/mapper.py` maps protobuf field names to tescmd model field names with unit conversion
48
+ - **Command guards in dispatcher** — extracted `check_command_guards()` (tier check + VCSEC signing requirement) into a shared function called by both CLI and OpenClaw dispatcher paths
49
+ - **Standard dependencies** — `websockets>=14.0`, `mcp>=1.0`, and `textual>=1.0` now included in default install
50
+
51
+ ### Changed
52
+
53
+ - Refactored `_cmd_telemetry_stream` in `cli/vehicle.py` to use the shared `telemetry_session()` context manager (no behavioral change)
54
+ - Proto-aligned telemetry field definitions with proper `interval_seconds` for delta fields
55
+ - Separated JSON serialization errors from WebSocket connection errors in gateway send path for clearer diagnostics
56
+ - Raised trigger push notification and lifecycle event failures from debug to warning level for observability
57
+
58
+ ### Fixed
59
+
60
+ - Fixed prompt for re-authentication when refresh token is expired or revoked (was failing silently)
61
+ - Fixed delta fields requiring `interval_seconds` configuration
62
+ - Fixed log file paths not shown on quit
63
+ - Added `exc_info` to MCP custom tool error logging for full stack traces
64
+ - Added JSON parse guards and explicit parameter validation in MCP tool wrappers
65
+ - Added `system.run` recursive self-dispatch guard
66
+
67
+ ## [0.2.0] - 2026-01-31
68
+
69
+ ### Added
70
+
71
+ - **Fleet Telemetry Streaming** — `tescmd vehicle telemetry stream [VIN]` starts a local WebSocket server, exposes it via Tailscale Funnel, configures the vehicle to push real-time telemetry, and displays it in an interactive Rich Live dashboard (TTY) or JSONL stream (piped)
72
+ - **Telemetry dashboard** — Rich Live TUI with field name, value, and last-update columns; unit conversion (°F/°C, mi/km, psi/bar); connection status; frame counter; uptime display
73
+ - **Protobuf telemetry decoder** — official Tesla protobuf definitions (`vehicle_data`, `vehicle_alert`, `vehicle_error`, `vehicle_metric`, `vehicle_connectivity`) for fully typed telemetry message parsing
74
+ - **FlatBuffer telemetry support** — `flatbuf.py` parser for Tesla's FlatBuffer-encoded telemetry payloads alongside protobuf
75
+ - **Field presets** — `--fields` option accepts preset names (`default`, `driving`, `charging`, `climate`, `all`) or comma-separated field names with 120+ registered telemetry fields
76
+ - **Interval override** — `--interval` option overrides the polling interval for all fields
77
+ - **Tailscale Funnel integration** — automatic Funnel start/stop with cert retrieval for Fleet Telemetry HTTPS requirement
78
+ - **JSONL output** — piped mode emits one JSON line per telemetry frame for scripting and log ingestion
79
+ - **TunnelError hierarchy** — `TunnelError` parent with `TailscaleError` subtype; actionable install/setup guidance
80
+ - **websockets dependency** — `websockets>=14.0` now included in default install
81
+ - **Tailscale key hosting** — `tescmd key deploy --method tailscale` hosts the public key via Tailscale Funnel at `https://<machine>.tailnet.ts.net/.well-known/appspecific/com.tesla.3p.public-key.pem`; auto-detected as second priority after GitHub Pages
82
+ - **Key hosting priority chain** — setup wizard and `key deploy` auto-detect the best hosting method: GitHub Pages → Tailscale Funnel → manual; `--method` flag overrides auto-detection
83
+ - **`TESLA_HOSTING_METHOD` setting** — persists the chosen key hosting method (`github`, `tailscale`) across sessions
84
+ - **Schnorr signature support** — `crypto/schnorr.py` for Schnorr-based authentication challenges used in telemetry server handshake
85
+ - **`auth import` command** — `tescmd auth import < tokens.json` imports tokens from a JSON file for headless/CI environments
86
+ - **Setup guide** — `docs/setup.md` with step-by-step walkthrough of all 7 setup phases
87
+ - **FAQ** — `docs/faq.md` covering common questions about tescmd, costs, hosting, and configuration
88
+ - **CI/CD workflows** — GitHub Actions for test-on-push (Python 3.11–3.13) and publish-to-PyPI-on-release via trusted publishing
89
+ - **README badges** — PyPI version, Python versions, CI build status, license, and GitHub release badges
90
+ - **E2E smoke tests** — `tests/cli/test_e2e_smoke.py` provides 179 pytest-based end-to-end tests covering every CLI command against the live Fleet API, with JSON envelope validation and save/restore for write commands (`pytest -m e2e`)
91
+
92
+ ### Fixed
93
+
94
+ - Fixed telemetry dashboard uptime counter not incrementing
95
+ - Improved tunnel start/stop success messages for clarity
96
+
97
+ ## [0.1.2] - 2025-01-31
98
+
99
+ ### Added
100
+
101
+ - **Universal read-command caching** — every read command is now transparently cached with tiered TTLs (STATIC 1h, SLOW 5m, DEFAULT 1m, FAST 30s); bots can call tescmd as often as needed — within the TTL window, responses are instant and free
102
+ - **Generic cache key scheme** — `generic_cache_key(scope, identifier, endpoint, params)` generates scope-aware keys (`vin`, `site`, `account`, `partner`) for any API endpoint
103
+ - **`cached_api_call()` helper** — unified async helper that handles cache lookup, fetch, serialisation (Pydantic/dict/list/scalar), and storage for all non-vehicle-state read commands
104
+ - **Site-scoped cache invalidation** — `invalidate_cache_for_site()` clears energy site entries after write commands; `invalidate_cache_for_vin()` now also clears generic vin-scoped keys
105
+ - **`cache clear` options** — `--site SITE_ID` and `--scope {account,partner}` flags for targeted cache clearing alongside existing `--vin`
106
+ - **Partner endpoints** — `partner public-key`, `partner telemetry-error-vins`, `partner telemetry-errors` for partner account data (require client credentials)
107
+ - **Billing endpoints** — `billing history`, `billing sessions`, `billing invoice` for Supercharger charging data
108
+ - **Cross-platform file permissions** — `_internal/permissions.py` provides `secure_file()` using `chmod 0600` on Unix and `icacls` on Windows
109
+ - **Token store file backend** — `_FileBackend` with atomic writes and restricted permissions as fallback when keyring is unavailable
110
+ - **Spec-driven Fleet API validation** — `scripts/validate_fleet_api.py` validates implementation against `spec/fleet_api_spec.json` using AST introspection
111
+ - **6 missing Fleet API commands** — added `managed_charging_set_amps`, `managed_charging_set_location`, `managed_charging_set_schedule`, `add_charge_schedule`, `remove_charge_schedule`, `clear_charge_schedules`
112
+ - **Configurable display units** — `--units metric` flag switches all display values to °C/km/bar; individual env vars (`TESLA_TEMP_UNIT`, `TESLA_DISTANCE_UNIT`, `TESLA_PRESSURE_UNIT`) for granular control
113
+
114
+ ### Fixed
115
+
116
+ - Aligned schedule/departure command parameters with Tesla Go SDK (correct param names and types)
117
+ - Fixed energy endpoint paths to match Fleet API spec
118
+ - Fixed Rich markup escaping bug in command output
119
+ - Aligned command parameters (3 param gaps) with Go SDK specs
120
+
121
+ ### Changed
122
+
123
+ - Response cache documentation in CLAUDE.md expanded to cover universal caching, TTL tiers, and generic cache key scheme
124
+
125
+ ## [0.1.1]
126
+
127
+ ### Added
128
+
129
+ - **`status` command** — `tescmd status` shows current configuration, auth, cache, and key status at a glance
130
+ - **Retry option in wake prompt** — when a vehicle is asleep, the interactive prompt now offers `[R] Retry` alongside `[W] Wake via API` and `[C] Cancel`, allowing users to wake the vehicle for free via the Tesla app and retry without restarting the command
131
+ - **Key enrollment** — `tescmd key enroll <VIN>` sends the public key to the vehicle and guides the user through Tesla app approval with interactive [C]heck/[R]esend/[Q]uit prompt, `--wait` auto-polling, and JSON mode support
132
+ - **Tier enforcement** — readonly tier now blocks write commands with a clear error and upgrade guidance (`tescmd setup`)
133
+ - **Vehicle Command Protocol** — ECDH session management, HMAC-SHA256 command signing, and protobuf RoutableMessage encoding for the `signed_command` endpoint; commands are automatically signed when keys are available (`command_protocol=auto`)
134
+ - **SignedCommandAPI** — composition wrapper that transparently routes signed commands through the Vehicle Command Protocol while falling back to unsigned REST for `wake_up` and unknown commands
135
+ - **`command_protocol` setting** — `auto` (default), `signed`, or `unsigned` to control command routing; configurable via `TESLA_COMMAND_PROTOCOL` env var
136
+ - **Enrollment step in setup wizard** — full-tier setup now offers to enroll the key on a vehicle after key generation
137
+ - **Friendly command output** — all vehicle commands now display descriptive success messages (e.g. "Climate control turned on.", "Doors locked.") instead of bare "OK"
138
+ - **E2E smoke tests** — `tests/cli/test_e2e_smoke.py` provides 179 pytest-based end-to-end tests covering every CLI command against the live Fleet API, with JSON envelope validation and save/restore for write commands (`pytest -m e2e`)
139
+
140
+ ## [0.1.0]
141
+
142
+ ### Added
143
+
144
+ - OAuth2 PKCE authentication with browser-based login flow
145
+ - Vehicle state queries: battery, charge, climate, drive, location, doors, windows, trunks, tire pressure
146
+ - Vehicle commands: charge start/stop/limit/schedule, climate on/off/set/seats/wheel, lock/unlock, sentry, trunk/frunk, windows, media, navigation, software updates, HomeLink, speed limits, PIN management
147
+ - Energy products: Powerwall live status, site info, backup reserve, operation mode, storm mode, TOU settings, charging history, calendar history, grid config
148
+ - User account: profile info, region, orders, feature config
149
+ - Vehicle sharing: add/remove drivers, create/redeem/revoke invites
150
+ - Rich terminal output with tables, panels, and status indicators
151
+ - JSON output mode for scripting and agent integration
152
+ - Configurable display units (F/C, mi/km, PSI/bar)
153
+ - Response caching with configurable TTL for API cost reduction
154
+ - Cost-aware wake confirmation (interactive prompt or `--wake` flag)
155
+ - Multi-profile configuration support
156
+ - EC key generation and Tesla Developer Portal registration
157
+ - Raw API access (`raw get`, `raw post`) for uncovered endpoints
158
+ - First-run setup wizard with Fleet Telemetry cost guidance
tescmd-0.3.1/CLAUDE.md ADDED
@@ -0,0 +1,131 @@
1
+ # CLAUDE.md — Project Context for Claude Code
2
+
3
+ ## Project Overview
4
+
5
+ **tescmd** is a Python 3.11+ CLI for querying and controlling Tesla vehicles via the [Tesla Fleet API](https://developer.tesla.com/docs/fleet-api). It covers auth, vehicle queries/commands, energy products, Supercharger billing, Fleet Telemetry streaming, OpenClaw bridge, and an MCP server for agent integration.
6
+
7
+ ## Tech Stack
8
+
9
+ - **Python 3.11+**, **pydantic v2**, **click**, **httpx** (async), **rich**, **cryptography**, **protobuf**, **keyring**, **python-dotenv**
10
+ - **websockets** (telemetry + OpenClaw), **mcp** (MCP server) — core dependencies
11
+ - Optional: **bleak** (`[ble]` extra — BLE key enrollment)
12
+
13
+ ## Project Structure
14
+
15
+ ```
16
+ src/tescmd/
17
+ ├── cli/ # Click CLI layer
18
+ │ ├── main.py # Root group, AppContext, _register_commands()
19
+ │ ├── _options.py # Shared Click options/decorators (@global_options)
20
+ │ ├── _client.py # API client builders, auto_wake, cached_vehicle_data, cached_api_call, TTL tiers
21
+ │ ├── auth.py, cache.py, charge.py, billing.py, climate.py, security.py
22
+ │ ├── status.py, trunk.py, vehicle.py, media.py, nav.py, partner.py
23
+ │ ├── software.py, energy.py, user.py, sharing.py, raw.py, key.py
24
+ │ ├── setup.py # Interactive first-run wizard
25
+ │ ├── serve.py # Unified MCP + telemetry + OpenClaw command
26
+ │ ├── openclaw.py # Standalone openclaw bridge command
27
+ │ └── mcp_cmd.py # mcp serve command
28
+ ├── api/ # HTTP client + domain APIs (composition pattern)
29
+ │ ├── client.py # TeslaFleetClient (base HTTP, auth headers, retries)
30
+ │ ├── vehicle.py, command.py, signed_command.py, energy.py
31
+ │ ├── charging.py, partner.py, sharing.py, user.py
32
+ │ └── errors.py # AuthError, VehicleAsleepError, TierError, TunnelError, etc.
33
+ ├── models/ # Pydantic v2 models (vehicle, energy, user, auth, command, config)
34
+ ├── auth/ # OAuth2 PKCE, token_store (keyring + file fallback), callback server
35
+ ├── protocol/ # Vehicle Command Protocol (ECDH sessions, HMAC signing, protobuf)
36
+ ├── crypto/ # EC key gen, ECDH, Schnorr signatures
37
+ ├── cache/ # File-based JSON cache with tiered TTLs
38
+ ├── output/ # OutputFormatter, RichOutput (DisplayUnits), JsonOutput
39
+ ├── telemetry/ # Fleet Telemetry streaming
40
+ │ ├── setup.py # Reusable telemetry_session() context manager
41
+ │ ├── server.py, decoder.py, fields.py, dashboard.py, tailscale.py
42
+ ├── openclaw/ # OpenClaw bridge
43
+ │ ├── config.py # BridgeConfig, FieldFilter, NodeCapabilities (pydantic)
44
+ │ ├── filters.py # DualGateFilter (delta + throttle), haversine()
45
+ │ ├── emitter.py # EventEmitter (telemetry → OpenClaw events)
46
+ │ ├── gateway.py # GatewayClient (WebSocket, node protocol, Ed25519 auth)
47
+ │ ├── bridge.py # TelemetryBridge orchestrator, build_openclaw_pipeline()
48
+ │ ├── dispatcher.py # CommandDispatcher (reads, writes, triggers, system.run)
49
+ │ └── telemetry_store.py # In-memory latest-value cache for telemetry fields
50
+ ├── triggers/ # Trigger subscription system
51
+ │ ├── models.py # TriggerOperator, TriggerCondition, TriggerDefinition, TriggerNotification
52
+ │ └── manager.py # TriggerManager (evaluation, cooldown, delivery, geofencing)
53
+ ├── mcp/ # MCP server
54
+ │ └── server.py # MCPServer (FastMCP, CliRunner + custom callable tools)
55
+ ├── deploy/ # Key hosting (GitHub Pages, Tailscale Funnel)
56
+ └── _internal/ # vin.py, async_utils.py, permissions.py
57
+ ```
58
+
59
+ ## Coding Conventions
60
+
61
+ - **Type hints everywhere** — all function signatures, all variables where non-obvious
62
+ - **async/await** — all API calls are async; CLI entry points use `run_async()` helper
63
+ - **Pydantic models** — all API request/response payloads; all configuration
64
+ - **src layout** — code in `src/tescmd/`, tests in `tests/`
65
+ - **No star imports** — explicit imports only
66
+ - **Single responsibility** — CLI modules handle args + output, API modules handle HTTP
67
+ - **Composition over inheritance** — API classes wrap `TeslaFleetClient`, don't extend it
68
+ - **Error stream routing** — JSON/piped mode writes errors to stderr; Rich/TTY mode uses stdout
69
+
70
+ ## Key Patterns
71
+
72
+ **CLI command registration:** New command groups are registered in `cli/main.py:_register_commands()`. Each CLI module defines a Click group and is imported there.
73
+
74
+ **Global options propagation:** Use `@global_options` decorator from `cli/_options.py` on commands that need VIN, format, wake, cache flags. Options flow through `AppContext` via `@click.pass_obj`.
75
+
76
+ **API client construction:** `cli/_client.py` provides `get_vehicle_api(app_ctx)` → returns `(client, api)` tuple. Also `get_command_api()` for write commands (handles signed vs unsigned routing).
77
+
78
+ **Cache:** All read commands use `cached_api_call()` with scope-aware TTLs (STATIC 1h, SLOW 5m, DEFAULT 1m, FAST 30s). Write commands invalidate via `invalidate_cache_for_vin()` / `invalidate_cache_for_site()`.
79
+
80
+ **Output:** `OutputFormatter` auto-detects TTY → Rich, piped → JSON, `--quiet` → stderr only. JSON output uses a consistent `{ok, command, data, error, timestamp}` envelope.
81
+
82
+ **Telemetry session lifecycle:** `telemetry/setup.py:telemetry_session()` is an async context manager handling: server start → Tailscale tunnel → partner domain re-registration → fleet config → yield → cleanup. Used by both `cli/vehicle.py` (stream) and `cli/openclaw.py` (bridge).
83
+
84
+ **OpenClaw pipeline:** `TelemetryServer.on_frame` → `DualGateFilter.should_emit()` → `EventEmitter.to_event()` → `GatewayClient.send_event()`. The `TelemetryBridge` class wires these together. `build_openclaw_pipeline()` is the shared factory used by both `cli/openclaw.py` (standalone) and `cli/serve.py` (combined mode). Inbound commands flow: gateway `node.invoke.request` → `CommandDispatcher.dispatch()` → handler → `node.invoke.result`.
85
+
86
+ **Trigger system:** `TriggerManager` evaluates conditions on every telemetry frame (independent of the dual-gate filter). Supports numeric comparison (`lt`, `gt`, `eq`, etc.), `changed` detection, and geofence `enter`/`leave` with haversine distance. One-shot and persistent (with cooldown) firing modes. Notifications delivered via OpenClaw push and MCP polling (`trigger.poll`).
87
+
88
+ **MCP tools:** `mcp/server.py` maps tool names to CLI arg lists via `_CliToolDef` dataclasses. `invoke_tool()` uses `CliRunner.invoke(cli, ["--format", "json", "--wake", *args], env=os.environ.copy())`. Custom tools (e.g. trigger CRUD) use `_CustomToolDef` with direct callable handlers registered via `register_custom_tool()`. Read/write tools are separated for `readOnlyHint` annotations. HTTP transport uses OAuth 2.1 via `_InMemoryOAuthProvider` (auto-approve authorization, dynamic client registration, in-memory token storage) with `_PermissiveClient` wrappers that accept any redirect URI. DNS rebinding protection is configured to allow the Tailscale Funnel hostname when `public_url` is set.
89
+
90
+ ## Build & Test
91
+
92
+ ```bash
93
+ # Build
94
+ python -m build # hatchling via pyproject.toml
95
+
96
+ # Test (parallel by default via pytest-xdist)
97
+ pytest # all ~1600 tests
98
+ pytest tests/openclaw/ -x -v # openclaw tests
99
+ pytest tests/triggers/ -x -v # trigger tests
100
+ pytest tests/mcp/ -x -v # mcp tests
101
+ pytest -m e2e # live API smoke tests (needs TESLA_ACCESS_TOKEN)
102
+
103
+ # Lint
104
+ ruff check src/ tests/
105
+ ruff format src/ tests/
106
+ mypy src/
107
+ ```
108
+
109
+ ## Environment Variables
110
+
111
+ | Variable | Description |
112
+ |---|---|
113
+ | `TESLA_CLIENT_ID` / `TESLA_CLIENT_SECRET` | OAuth2 app credentials |
114
+ | `TESLA_VIN` | Default vehicle VIN |
115
+ | `TESLA_REGION` | API region: `na`, `eu`, `cn` |
116
+ | `TESLA_ACCESS_TOKEN` / `TESLA_REFRESH_TOKEN` | Direct token override |
117
+ | `TESLA_TOKEN_FILE` | File path for token storage (skips keyring) |
118
+ | `TESLA_CONFIG_DIR` | Config directory (default: `~/.config/tescmd`) |
119
+ | `TESLA_CACHE_DIR` / `TESLA_CACHE_TTL` / `TESLA_CACHE_ENABLED` | Cache settings |
120
+ | `TESLA_OUTPUT_FORMAT` | Force format: `rich`, `json`, `quiet` |
121
+ | `TESLA_COMMAND_PROTOCOL` | `auto` (default), `signed`, `unsigned` |
122
+ | `TESLA_TEMP_UNIT` / `TESLA_DISTANCE_UNIT` / `TESLA_PRESSURE_UNIT` | Display units |
123
+ | `TESLA_DOMAIN` / `TESLA_HOSTING_METHOD` / `TESLA_GITHUB_REPO` | Key hosting |
124
+ | `TESLA_SETUP_TIER` | `readonly` or `full` |
125
+ | `TESLA_PROFILE` | Active config profile |
126
+ | `OPENCLAW_GATEWAY_TOKEN` | OpenClaw gateway auth token |
127
+
128
+
129
+ ## Additional Resources
130
+
131
+ Tesla's published vehicle-command proto omits some VehicleAction fields (e.g. navigation commands). The Teslemetry project maintains a more complete proto: https://github.com/Teslemetry/python-tesla-fleet-api/blob/main/proto/car_server.proto