tescmd 0.2.0__tar.gz → 0.4.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 (285) hide show
  1. tescmd-0.4.0/.env.example +75 -0
  2. {tescmd-0.2.0 → tescmd-0.4.0}/.gitignore +3 -1
  3. tescmd-0.4.0/CHANGELOG.md +192 -0
  4. tescmd-0.4.0/CLAUDE.md +131 -0
  5. tescmd-0.4.0/PKG-INFO +300 -0
  6. tescmd-0.4.0/README.md +247 -0
  7. {tescmd-0.2.0 → tescmd-0.4.0}/docs/api-costs.md +26 -11
  8. {tescmd-0.2.0 → tescmd-0.4.0}/docs/architecture.md +129 -11
  9. {tescmd-0.2.0 → tescmd-0.4.0}/docs/authentication.md +52 -8
  10. {tescmd-0.2.0 → tescmd-0.4.0}/docs/bot-integration.md +31 -1
  11. {tescmd-0.2.0 → tescmd-0.4.0}/docs/commands.md +267 -5
  12. {tescmd-0.2.0 → tescmd-0.4.0}/docs/development.md +13 -5
  13. {tescmd-0.2.0 → tescmd-0.4.0}/docs/faq.md +22 -2
  14. tescmd-0.4.0/docs/mcp.md +416 -0
  15. tescmd-0.4.0/docs/openclaw.md +463 -0
  16. {tescmd-0.2.0 → tescmd-0.4.0}/docs/setup.md +72 -31
  17. {tescmd-0.2.0 → tescmd-0.4.0}/docs/vehicle-command-protocol.md +43 -12
  18. tescmd-0.4.0/images/tescmd_header.jpeg +0 -0
  19. tescmd-0.4.0/images/tescmd_logo.jpeg +0 -0
  20. tescmd-0.4.0/images/tescmd_mcp.png +0 -0
  21. tescmd-0.4.0/images/tescmd_serve.png +0 -0
  22. tescmd-0.4.0/images/tescmd_waypoints.png +0 -0
  23. {tescmd-0.2.0 → tescmd-0.4.0}/pyproject.toml +14 -2
  24. tescmd-0.4.0/skills/tescmd/SKILL.md +524 -0
  25. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/__init__.py +1 -1
  26. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/api/client.py +41 -4
  27. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/api/command.py +1 -1
  28. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/api/errors.py +5 -0
  29. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/api/signed_command.py +19 -14
  30. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/auth/oauth.py +15 -1
  31. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/auth/server.py +6 -1
  32. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/auth/token_store.py +8 -1
  33. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cache/response_cache.py +8 -1
  34. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/_client.py +142 -20
  35. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/_options.py +2 -4
  36. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/auth.py +255 -106
  37. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/energy.py +2 -0
  38. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/key.py +6 -7
  39. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/main.py +27 -8
  40. tescmd-0.4.0/src/tescmd/cli/mcp_cmd.py +153 -0
  41. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/nav.py +3 -1
  42. tescmd-0.4.0/src/tescmd/cli/openclaw.py +169 -0
  43. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/security.py +7 -1
  44. tescmd-0.4.0/src/tescmd/cli/serve.py +923 -0
  45. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/setup.py +147 -58
  46. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/sharing.py +2 -0
  47. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/status.py +1 -1
  48. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/trunk.py +8 -17
  49. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/user.py +16 -1
  50. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/vehicle.py +135 -462
  51. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/deploy/github_pages.py +21 -2
  52. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/deploy/tailscale_serve.py +96 -8
  53. tescmd-0.4.0/src/tescmd/mcp/__init__.py +7 -0
  54. tescmd-0.4.0/src/tescmd/mcp/server.py +648 -0
  55. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/models/auth.py +5 -2
  56. tescmd-0.4.0/src/tescmd/openclaw/__init__.py +23 -0
  57. tescmd-0.4.0/src/tescmd/openclaw/bridge.py +330 -0
  58. tescmd-0.4.0/src/tescmd/openclaw/config.py +167 -0
  59. tescmd-0.4.0/src/tescmd/openclaw/dispatcher.py +529 -0
  60. tescmd-0.4.0/src/tescmd/openclaw/emitter.py +175 -0
  61. tescmd-0.4.0/src/tescmd/openclaw/filters.py +123 -0
  62. tescmd-0.4.0/src/tescmd/openclaw/gateway.py +700 -0
  63. tescmd-0.4.0/src/tescmd/openclaw/telemetry_store.py +53 -0
  64. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/output/rich_output.py +46 -14
  65. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/protocol/commands.py +2 -2
  66. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/protocol/encoder.py +16 -13
  67. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/protocol/payloads.py +132 -11
  68. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/protocol/session.py +8 -5
  69. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/protocol/signer.py +3 -17
  70. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/__init__.py +9 -0
  71. tescmd-0.4.0/src/tescmd/telemetry/cache_sink.py +154 -0
  72. tescmd-0.4.0/src/tescmd/telemetry/csv_sink.py +180 -0
  73. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/dashboard.py +4 -4
  74. tescmd-0.4.0/src/tescmd/telemetry/fanout.py +49 -0
  75. tescmd-0.4.0/src/tescmd/telemetry/fields.py +427 -0
  76. tescmd-0.4.0/src/tescmd/telemetry/mapper.py +239 -0
  77. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/server.py +26 -19
  78. tescmd-0.4.0/src/tescmd/telemetry/setup.py +468 -0
  79. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/tailscale.py +78 -16
  80. tescmd-0.4.0/src/tescmd/telemetry/tui.py +1716 -0
  81. tescmd-0.4.0/src/tescmd/triggers/__init__.py +18 -0
  82. tescmd-0.4.0/src/tescmd/triggers/manager.py +264 -0
  83. tescmd-0.4.0/src/tescmd/triggers/models.py +93 -0
  84. {tescmd-0.2.0 → tescmd-0.4.0}/tests/api/test_signed_command.py +2 -2
  85. tescmd-0.4.0/tests/auth/test_oauth_extended.py +243 -0
  86. tescmd-0.4.0/tests/cli/test_auth.py +831 -0
  87. tescmd-0.4.0/tests/cli/test_bugfixes.py +236 -0
  88. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_nav_exec.py +1 -1
  89. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_setup.py +644 -0
  90. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_trunk_exec.py +10 -23
  91. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_vehicle_exec.py +1 -1
  92. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_wake_confirmation.py +13 -1
  93. {tescmd-0.2.0 → tescmd-0.4.0}/tests/deploy/test_tailscale_serve.py +63 -7
  94. tescmd-0.4.0/tests/integration/test_serve.py +163 -0
  95. tescmd-0.4.0/tests/mcp/test_server.py +407 -0
  96. tescmd-0.4.0/tests/mcp/test_tools.py +86 -0
  97. tescmd-0.4.0/tests/openclaw/test_bridge.py +618 -0
  98. tescmd-0.4.0/tests/openclaw/test_config.py +196 -0
  99. tescmd-0.4.0/tests/openclaw/test_dispatcher.py +1152 -0
  100. tescmd-0.4.0/tests/openclaw/test_emitter.py +165 -0
  101. tescmd-0.4.0/tests/openclaw/test_filters.py +131 -0
  102. tescmd-0.4.0/tests/openclaw/test_gateway.py +973 -0
  103. tescmd-0.4.0/tests/openclaw/test_telemetry_store.py +106 -0
  104. tescmd-0.4.0/tests/output/__init__.py +0 -0
  105. {tescmd-0.2.0 → tescmd-0.4.0}/tests/output/test_rich_output.py +7 -7
  106. tescmd-0.4.0/tests/protocol/__init__.py +0 -0
  107. tescmd-0.4.0/tests/protocol/test_boombox.py +74 -0
  108. {tescmd-0.2.0 → tescmd-0.4.0}/tests/protocol/test_commands.py +15 -0
  109. {tescmd-0.2.0 → tescmd-0.4.0}/tests/protocol/test_encoder.py +22 -19
  110. tescmd-0.4.0/tests/protocol/test_navigation.py +142 -0
  111. {tescmd-0.2.0 → tescmd-0.4.0}/tests/protocol/test_session.py +3 -3
  112. {tescmd-0.2.0 → tescmd-0.4.0}/tests/protocol/test_signer.py +3 -13
  113. tescmd-0.4.0/tests/telemetry/__init__.py +0 -0
  114. tescmd-0.4.0/tests/telemetry/test_cache_sink.py +277 -0
  115. tescmd-0.4.0/tests/telemetry/test_csv_sink.py +321 -0
  116. tescmd-0.4.0/tests/telemetry/test_fanout.py +105 -0
  117. tescmd-0.4.0/tests/telemetry/test_fields.py +119 -0
  118. tescmd-0.4.0/tests/telemetry/test_mapper.py +192 -0
  119. {tescmd-0.2.0 → tescmd-0.4.0}/tests/telemetry/test_stream_cmd.py +2 -0
  120. tescmd-0.4.0/tests/telemetry/test_tui.py +600 -0
  121. tescmd-0.4.0/tests/triggers/__init__.py +0 -0
  122. tescmd-0.4.0/tests/triggers/test_manager.py +474 -0
  123. tescmd-0.4.0/tests/triggers/test_models.py +162 -0
  124. tescmd-0.2.0/CHANGELOG.md +0 -99
  125. tescmd-0.2.0/CLAUDE.md +0 -430
  126. tescmd-0.2.0/PKG-INFO +0 -495
  127. tescmd-0.2.0/README.md +0 -445
  128. tescmd-0.2.0/src/tescmd/telemetry/fields.py +0 -248
  129. tescmd-0.2.0/tests/auth/test_oauth_extended.py +0 -125
  130. tescmd-0.2.0/tests/cli/test_auth.py +0 -74
  131. tescmd-0.2.0/tests/telemetry/test_fields.py +0 -73
  132. {tescmd-0.2.0 → tescmd-0.4.0}/.github/workflows/publish.yml +0 -0
  133. {tescmd-0.2.0 → tescmd-0.4.0}/.github/workflows/test.yml +0 -0
  134. {tescmd-0.2.0 → tescmd-0.4.0}/LICENSE +0 -0
  135. {tescmd-0.2.0 → tescmd-0.4.0}/scripts/validate_fleet_api.py +0 -0
  136. {tescmd-0.2.0 → tescmd-0.4.0}/spec/fleet_api_spec.json +0 -0
  137. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/__main__.py +0 -0
  138. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/_internal/__init__.py +0 -0
  139. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/_internal/async_utils.py +0 -0
  140. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/_internal/permissions.py +0 -0
  141. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/_internal/vin.py +0 -0
  142. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/api/__init__.py +0 -0
  143. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/api/charging.py +0 -0
  144. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/api/energy.py +0 -0
  145. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/api/partner.py +0 -0
  146. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/api/sharing.py +0 -0
  147. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/api/user.py +0 -0
  148. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/api/vehicle.py +0 -0
  149. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/auth/__init__.py +0 -0
  150. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/ble/__init__.py +0 -0
  151. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cache/__init__.py +0 -0
  152. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cache/keys.py +0 -0
  153. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/__init__.py +0 -0
  154. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/billing.py +0 -0
  155. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/cache.py +0 -0
  156. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/charge.py +0 -0
  157. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/climate.py +0 -0
  158. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/media.py +0 -0
  159. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/partner.py +0 -0
  160. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/raw.py +0 -0
  161. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/cli/software.py +0 -0
  162. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/config/__init__.py +0 -0
  163. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/crypto/__init__.py +0 -0
  164. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/crypto/ecdh.py +0 -0
  165. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/crypto/keys.py +0 -0
  166. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/crypto/schnorr.py +0 -0
  167. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/deploy/__init__.py +0 -0
  168. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/models/__init__.py +0 -0
  169. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/models/command.py +0 -0
  170. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/models/config.py +0 -0
  171. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/models/energy.py +0 -0
  172. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/models/sharing.py +0 -0
  173. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/models/user.py +0 -0
  174. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/models/vehicle.py +0 -0
  175. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/output/__init__.py +0 -0
  176. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/output/formatter.py +0 -0
  177. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/output/json_output.py +0 -0
  178. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/protocol/__init__.py +0 -0
  179. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/protocol/metadata.py +0 -0
  180. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/protocol/protobuf/__init__.py +0 -0
  181. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/protocol/protobuf/messages.py +0 -0
  182. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/py.typed +0 -0
  183. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/decoder.py +0 -0
  184. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/flatbuf.py +0 -0
  185. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/protos/__init__.py +0 -0
  186. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/protos/vehicle_alert.proto +0 -0
  187. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/protos/vehicle_alert_pb2.py +0 -0
  188. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/protos/vehicle_alert_pb2.pyi +0 -0
  189. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/protos/vehicle_connectivity.proto +0 -0
  190. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/protos/vehicle_connectivity_pb2.py +0 -0
  191. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/protos/vehicle_connectivity_pb2.pyi +0 -0
  192. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/protos/vehicle_data.proto +0 -0
  193. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/protos/vehicle_data_pb2.py +0 -0
  194. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/protos/vehicle_data_pb2.pyi +0 -0
  195. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/protos/vehicle_error.proto +0 -0
  196. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/protos/vehicle_error_pb2.py +0 -0
  197. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/protos/vehicle_error_pb2.pyi +0 -0
  198. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/protos/vehicle_metric.proto +0 -0
  199. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/protos/vehicle_metric_pb2.py +0 -0
  200. {tescmd-0.2.0 → tescmd-0.4.0}/src/tescmd/telemetry/protos/vehicle_metric_pb2.pyi +0 -0
  201. {tescmd-0.2.0 → tescmd-0.4.0}/tests/__init__.py +0 -0
  202. {tescmd-0.2.0 → tescmd-0.4.0}/tests/_internal/__init__.py +0 -0
  203. {tescmd-0.2.0 → tescmd-0.4.0}/tests/_internal/test_async_utils.py +0 -0
  204. {tescmd-0.2.0 → tescmd-0.4.0}/tests/_internal/test_vin.py +0 -0
  205. {tescmd-0.2.0 → tescmd-0.4.0}/tests/api/__init__.py +0 -0
  206. {tescmd-0.2.0 → tescmd-0.4.0}/tests/api/test_client.py +0 -0
  207. {tescmd-0.2.0 → tescmd-0.4.0}/tests/api/test_command_api.py +0 -0
  208. {tescmd-0.2.0 → tescmd-0.4.0}/tests/api/test_energy_api.py +0 -0
  209. {tescmd-0.2.0 → tescmd-0.4.0}/tests/api/test_partner_api.py +0 -0
  210. {tescmd-0.2.0 → tescmd-0.4.0}/tests/api/test_sharing_api.py +0 -0
  211. {tescmd-0.2.0 → tescmd-0.4.0}/tests/api/test_user_api.py +0 -0
  212. {tescmd-0.2.0 → tescmd-0.4.0}/tests/api/test_vehicle_api.py +0 -0
  213. {tescmd-0.2.0 → tescmd-0.4.0}/tests/auth/__init__.py +0 -0
  214. {tescmd-0.2.0 → tescmd-0.4.0}/tests/auth/test_oauth.py +0 -0
  215. {tescmd-0.2.0 → tescmd-0.4.0}/tests/auth/test_server.py +0 -0
  216. {tescmd-0.2.0 → tescmd-0.4.0}/tests/auth/test_token_store.py +0 -0
  217. {tescmd-0.2.0 → tescmd-0.4.0}/tests/auth/test_token_store_fallback.py +0 -0
  218. {tescmd-0.2.0 → tescmd-0.4.0}/tests/auth/test_token_store_file.py +0 -0
  219. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cache/__init__.py +0 -0
  220. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cache/test_generic_cache.py +0 -0
  221. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cache/test_keys.py +0 -0
  222. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cache/test_response_cache.py +0 -0
  223. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/__init__.py +0 -0
  224. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/_helpers.py +0 -0
  225. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/conftest.py +0 -0
  226. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_auth_exec.py +0 -0
  227. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_cache.py +0 -0
  228. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_cached_api_call.py +0 -0
  229. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_charge_exec.py +0 -0
  230. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_cli_integration.py +0 -0
  231. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_climate_exec.py +0 -0
  232. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_e2e_smoke.py +0 -0
  233. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_energy.py +0 -0
  234. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_energy_exec.py +0 -0
  235. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_error_handlers.py +0 -0
  236. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_key.py +0 -0
  237. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_key_enroll.py +0 -0
  238. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_key_unenroll.py +0 -0
  239. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_main_errors.py +0 -0
  240. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_media.py +0 -0
  241. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_media_exec.py +0 -0
  242. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_nav.py +0 -0
  243. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_partner.py +0 -0
  244. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_raw.py +0 -0
  245. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_raw_exec.py +0 -0
  246. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_security_exec.py +0 -0
  247. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_setup_scope_check.py +0 -0
  248. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_sharing.py +0 -0
  249. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_sharing_exec.py +0 -0
  250. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_software.py +0 -0
  251. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_software_exec.py +0 -0
  252. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_status_exec.py +0 -0
  253. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_tier_enforcement.py +0 -0
  254. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_user.py +0 -0
  255. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_user_exec.py +0 -0
  256. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_vcsec_guard.py +0 -0
  257. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_vehicle_power_exec.py +0 -0
  258. {tescmd-0.2.0 → tescmd-0.4.0}/tests/cli/test_verbose.py +0 -0
  259. {tescmd-0.2.0 → tescmd-0.4.0}/tests/conftest.py +0 -0
  260. {tescmd-0.2.0 → tescmd-0.4.0}/tests/crypto/__init__.py +0 -0
  261. {tescmd-0.2.0 → tescmd-0.4.0}/tests/crypto/test_ecdh.py +0 -0
  262. {tescmd-0.2.0 → tescmd-0.4.0}/tests/crypto/test_keys.py +0 -0
  263. {tescmd-0.2.0 → tescmd-0.4.0}/tests/crypto/test_schnorr.py +0 -0
  264. {tescmd-0.2.0 → tescmd-0.4.0}/tests/deploy/__init__.py +0 -0
  265. {tescmd-0.2.0 → tescmd-0.4.0}/tests/deploy/test_github_pages.py +0 -0
  266. {tescmd-0.2.0/tests/models → tescmd-0.4.0/tests/integration}/__init__.py +0 -0
  267. {tescmd-0.2.0/tests/output → tescmd-0.4.0/tests/mcp}/__init__.py +0 -0
  268. {tescmd-0.2.0/tests/protocol → tescmd-0.4.0/tests/models}/__init__.py +0 -0
  269. {tescmd-0.2.0 → tescmd-0.4.0}/tests/models/test_auth.py +0 -0
  270. {tescmd-0.2.0 → tescmd-0.4.0}/tests/models/test_config.py +0 -0
  271. {tescmd-0.2.0 → tescmd-0.4.0}/tests/models/test_energy.py +0 -0
  272. {tescmd-0.2.0 → tescmd-0.4.0}/tests/models/test_sharing.py +0 -0
  273. {tescmd-0.2.0 → tescmd-0.4.0}/tests/models/test_user_models.py +0 -0
  274. {tescmd-0.2.0 → tescmd-0.4.0}/tests/models/test_vehicle.py +0 -0
  275. {tescmd-0.2.0/tests/telemetry → tescmd-0.4.0/tests/openclaw}/__init__.py +0 -0
  276. {tescmd-0.2.0 → tescmd-0.4.0}/tests/output/test_formatter.py +0 -0
  277. {tescmd-0.2.0 → tescmd-0.4.0}/tests/output/test_json_output.py +0 -0
  278. {tescmd-0.2.0 → tescmd-0.4.0}/tests/protocol/conftest.py +0 -0
  279. {tescmd-0.2.0 → tescmd-0.4.0}/tests/protocol/test_metadata.py +0 -0
  280. {tescmd-0.2.0 → tescmd-0.4.0}/tests/telemetry/conftest.py +0 -0
  281. {tescmd-0.2.0 → tescmd-0.4.0}/tests/telemetry/test_dashboard.py +0 -0
  282. {tescmd-0.2.0 → tescmd-0.4.0}/tests/telemetry/test_decoder.py +0 -0
  283. {tescmd-0.2.0 → tescmd-0.4.0}/tests/telemetry/test_flatbuf.py +0 -0
  284. {tescmd-0.2.0 → tescmd-0.4.0}/tests/telemetry/test_server.py +0 -0
  285. {tescmd-0.2.0 → tescmd-0.4.0}/tests/telemetry/test_tailscale.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=
@@ -1,3 +1,4 @@
1
+ .DS_Store
1
2
  __pycache__/
2
3
  *.pyc
3
4
  *.egg-info/
@@ -5,8 +6,9 @@ dist/
5
6
  build/
6
7
  .venv/
7
8
  .env
9
+ .env.bak
8
10
  *.pem
9
11
  .mypy_cache/
10
12
  .pytest_cache/
11
13
  .ruff_cache/
12
- .coverage
14
+ .coverage
@@ -0,0 +1,192 @@
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.4.0] - 2026-02-02
9
+
10
+ ### Added
11
+
12
+ - **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
13
+ - **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
14
+ - **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
15
+ - **`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()`
16
+ - **`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()`
17
+
18
+ ### Changed
19
+
20
+ - **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
21
+ - **Credentials always required** — both Client ID and Client Secret are mandatory with retry loops (3 attempts each); empty input no longer silently skips setup
22
+ - **Auto-save credentials** — `.env` file is written automatically after credential entry; removed the "Save to .env?" prompt
23
+ - **`--force` regenerates app name** — passing `--force` to setup now generates a fresh `tescmd-<hex>` name instead of reusing the saved one
24
+ - **Atomic Tailscale serve + Funnel** — `start_key_serving()` uses a single `tailscale serve --bg --funnel --set-path / <dir>` command instead of separate serve + funnel calls
25
+ - **`TailscaleManager.start_serve()` API** — added `port` and `funnel` keyword arguments for configurable HTTPS port and inline Funnel enablement
26
+ - **Enrollment messaging** — streamlined to focus on QR code scanning; removed duplicate URL display and the "Open in browser?" prompt (browser opens automatically)
27
+ - **GitHub Pages note** — clarified that Tailscale is used alongside GitHub Pages for telemetry streaming, not as a replacement
28
+ - **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
29
+
30
+ ### Fixed
31
+
32
+ - **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)
33
+
34
+ ## [0.3.2] - 2026-02-02
35
+
36
+ ### Fixed
37
+
38
+ - **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
39
+ - **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"
40
+ - **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
41
+
42
+ ## [0.3.1] - 2026-02-02
43
+
44
+ ### Added
45
+
46
+ - **README overhaul** — header banner, logo, new "What It Does" summary section, expanded Prerequisites table with Python 3.11+, pip, Tesla account, and helpful links
47
+ - **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
48
+ - **Tailscale hostname passthrough** — setup wizard forwards detected Tailscale hostname to auth flow, showing a concrete "Also add" origin URL instead of the generic placeholder
49
+ - **Comprehensive agent skill documentation** — expanded skill covering all command groups, triggers, and OpenClaw dispatch
50
+
51
+ ### Fixed
52
+
53
+ - **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`
54
+ - **12-factor app compliance** — config, disposability, and concurrency improvements across the codebase
55
+ - **Documentation accuracy** — corrected `media_adjust_volume` tool name in MCP docs; emphasized MCP/OpenClaw over direct CLI for cost savings in agent skill
56
+
57
+ ## [0.3.0] - 2026-02-01
58
+
59
+ ### Added
60
+
61
+ - **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
62
+ - **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
63
+ - **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
64
+ - **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
65
+ - **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
66
+ - **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
67
+ - **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
68
+ - **Trigger notification delivery** — dual-channel: OpenClaw push events (`trigger.fired`) for connected bots, and MCP polling via `trigger_poll` tool for agent frameworks
69
+ - **`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
70
+ - **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
71
+ - **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
72
+ - **Agent skill** — `skills/tescmd/SKILL.md` teaches AI agents how to use every tescmd command group with examples, parameter types, and common patterns
73
+ - **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
74
+ - **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
75
+ - **OpenClaw event emitter** — maps telemetry fields to OpenClaw `req:agent` event payloads (location, battery, temperature, speed, charge state transitions, security changes)
76
+ - **Gateway WebSocket client** — implements the OpenClaw operator protocol (challenge → connect → hello-ok handshake) with Ed25519 device key signing and exponential backoff reconnection
77
+ - **Bridge configuration** — `BridgeConfig` pydantic model with per-field filter settings, loadable from JSON file or CLI flags
78
+ - **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`
79
+ - **Cache sink** — telemetry-driven cache warming keeps read-command cache fresh while telemetry is active, making agent reads free
80
+ - **Frame fanout** — `FrameFanout` distributes decoded telemetry frames to multiple sinks (dashboard, CSV, cache, OpenClaw bridge, triggers) in parallel
81
+ - **Telemetry field mapper** — `telemetry/mapper.py` maps protobuf field names to tescmd model field names with unit conversion
82
+ - **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
83
+ - **Standard dependencies** — `websockets>=14.0`, `mcp>=1.0`, and `textual>=1.0` now included in default install
84
+
85
+ ### Changed
86
+
87
+ - Refactored `_cmd_telemetry_stream` in `cli/vehicle.py` to use the shared `telemetry_session()` context manager (no behavioral change)
88
+ - Proto-aligned telemetry field definitions with proper `interval_seconds` for delta fields
89
+ - Separated JSON serialization errors from WebSocket connection errors in gateway send path for clearer diagnostics
90
+ - Raised trigger push notification and lifecycle event failures from debug to warning level for observability
91
+
92
+ ### Fixed
93
+
94
+ - Fixed prompt for re-authentication when refresh token is expired or revoked (was failing silently)
95
+ - Fixed delta fields requiring `interval_seconds` configuration
96
+ - Fixed log file paths not shown on quit
97
+ - Added `exc_info` to MCP custom tool error logging for full stack traces
98
+ - Added JSON parse guards and explicit parameter validation in MCP tool wrappers
99
+ - Added `system.run` recursive self-dispatch guard
100
+
101
+ ## [0.2.0] - 2026-01-31
102
+
103
+ ### Added
104
+
105
+ - **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)
106
+ - **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
107
+ - **Protobuf telemetry decoder** — official Tesla protobuf definitions (`vehicle_data`, `vehicle_alert`, `vehicle_error`, `vehicle_metric`, `vehicle_connectivity`) for fully typed telemetry message parsing
108
+ - **FlatBuffer telemetry support** — `flatbuf.py` parser for Tesla's FlatBuffer-encoded telemetry payloads alongside protobuf
109
+ - **Field presets** — `--fields` option accepts preset names (`default`, `driving`, `charging`, `climate`, `all`) or comma-separated field names with 120+ registered telemetry fields
110
+ - **Interval override** — `--interval` option overrides the polling interval for all fields
111
+ - **Tailscale Funnel integration** — automatic Funnel start/stop with cert retrieval for Fleet Telemetry HTTPS requirement
112
+ - **JSONL output** — piped mode emits one JSON line per telemetry frame for scripting and log ingestion
113
+ - **TunnelError hierarchy** — `TunnelError` parent with `TailscaleError` subtype; actionable install/setup guidance
114
+ - **websockets dependency** — `websockets>=14.0` now included in default install
115
+ - **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
116
+ - **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
117
+ - **`TESLA_HOSTING_METHOD` setting** — persists the chosen key hosting method (`github`, `tailscale`) across sessions
118
+ - **Schnorr signature support** — `crypto/schnorr.py` for Schnorr-based authentication challenges used in telemetry server handshake
119
+ - **`auth import` command** — `tescmd auth import < tokens.json` imports tokens from a JSON file for headless/CI environments
120
+ - **Setup guide** — `docs/setup.md` with step-by-step walkthrough of all 7 setup phases
121
+ - **FAQ** — `docs/faq.md` covering common questions about tescmd, costs, hosting, and configuration
122
+ - **CI/CD workflows** — GitHub Actions for test-on-push (Python 3.11–3.13) and publish-to-PyPI-on-release via trusted publishing
123
+ - **README badges** — PyPI version, Python versions, CI build status, license, and GitHub release badges
124
+ - **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`)
125
+
126
+ ### Fixed
127
+
128
+ - Fixed telemetry dashboard uptime counter not incrementing
129
+ - Improved tunnel start/stop success messages for clarity
130
+
131
+ ## [0.1.2] - 2025-01-31
132
+
133
+ ### Added
134
+
135
+ - **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
136
+ - **Generic cache key scheme** — `generic_cache_key(scope, identifier, endpoint, params)` generates scope-aware keys (`vin`, `site`, `account`, `partner`) for any API endpoint
137
+ - **`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
138
+ - **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
139
+ - **`cache clear` options** — `--site SITE_ID` and `--scope {account,partner}` flags for targeted cache clearing alongside existing `--vin`
140
+ - **Partner endpoints** — `partner public-key`, `partner telemetry-error-vins`, `partner telemetry-errors` for partner account data (require client credentials)
141
+ - **Billing endpoints** — `billing history`, `billing sessions`, `billing invoice` for Supercharger charging data
142
+ - **Cross-platform file permissions** — `_internal/permissions.py` provides `secure_file()` using `chmod 0600` on Unix and `icacls` on Windows
143
+ - **Token store file backend** — `_FileBackend` with atomic writes and restricted permissions as fallback when keyring is unavailable
144
+ - **Spec-driven Fleet API validation** — `scripts/validate_fleet_api.py` validates implementation against `spec/fleet_api_spec.json` using AST introspection
145
+ - **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`
146
+ - **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
147
+
148
+ ### Fixed
149
+
150
+ - Aligned schedule/departure command parameters with Tesla Go SDK (correct param names and types)
151
+ - Fixed energy endpoint paths to match Fleet API spec
152
+ - Fixed Rich markup escaping bug in command output
153
+ - Aligned command parameters (3 param gaps) with Go SDK specs
154
+
155
+ ### Changed
156
+
157
+ - Response cache documentation in CLAUDE.md expanded to cover universal caching, TTL tiers, and generic cache key scheme
158
+
159
+ ## [0.1.1]
160
+
161
+ ### Added
162
+
163
+ - **`status` command** — `tescmd status` shows current configuration, auth, cache, and key status at a glance
164
+ - **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
165
+ - **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
166
+ - **Tier enforcement** — readonly tier now blocks write commands with a clear error and upgrade guidance (`tescmd setup`)
167
+ - **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`)
168
+ - **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
169
+ - **`command_protocol` setting** — `auto` (default), `signed`, or `unsigned` to control command routing; configurable via `TESLA_COMMAND_PROTOCOL` env var
170
+ - **Enrollment step in setup wizard** — full-tier setup now offers to enroll the key on a vehicle after key generation
171
+ - **Friendly command output** — all vehicle commands now display descriptive success messages (e.g. "Climate control turned on.", "Doors locked.") instead of bare "OK"
172
+ - **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`)
173
+
174
+ ## [0.1.0]
175
+
176
+ ### Added
177
+
178
+ - OAuth2 PKCE authentication with browser-based login flow
179
+ - Vehicle state queries: battery, charge, climate, drive, location, doors, windows, trunks, tire pressure
180
+ - 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
181
+ - Energy products: Powerwall live status, site info, backup reserve, operation mode, storm mode, TOU settings, charging history, calendar history, grid config
182
+ - User account: profile info, region, orders, feature config
183
+ - Vehicle sharing: add/remove drivers, create/redeem/revoke invites
184
+ - Rich terminal output with tables, panels, and status indicators
185
+ - JSON output mode for scripting and agent integration
186
+ - Configurable display units (F/C, mi/km, PSI/bar)
187
+ - Response caching with configurable TTL for API cost reduction
188
+ - Cost-aware wake confirmation (interactive prompt or `--wake` flag)
189
+ - Multi-profile configuration support
190
+ - EC key generation and Tesla Developer Portal registration
191
+ - Raw API access (`raw get`, `raw post`) for uncovered endpoints
192
+ - First-run setup wizard with Fleet Telemetry cost guidance
tescmd-0.4.0/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