@oceanswave/openclaw-tescmd 0.3.1

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.
package/telemetry.ts ADDED
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Telemetry event type definitions for the tescmd node.
3
+ *
4
+ * Documents all event types that the tescmd node emits to the OpenClaw
5
+ * Gateway via `req:agent` frames. These are derived from the Tesla Fleet
6
+ * Telemetry stream and transformed by the EventEmitter
7
+ * (src/tescmd/openclaw/emitter.py).
8
+ *
9
+ * Event envelope format:
10
+ * ```json
11
+ * {
12
+ * "method": "req:agent",
13
+ * "params": {
14
+ * "event_type": "<type>",
15
+ * "source": "<client_id>",
16
+ * "vin": "<vehicle_vin>",
17
+ * "timestamp": "<ISO 8601>",
18
+ * "data": { ... }
19
+ * }
20
+ * }
21
+ * ```
22
+ */
23
+
24
+ // ---------------------------------------------------------------------------
25
+ // Data event types (11)
26
+ // ---------------------------------------------------------------------------
27
+
28
+ export interface LocationEvent {
29
+ event_type: "location";
30
+ data: {
31
+ /** Latitude in decimal degrees. */
32
+ latitude: number;
33
+ /** Longitude in decimal degrees. */
34
+ longitude: number;
35
+ /** Heading in degrees (0-360). */
36
+ heading: number;
37
+ /** Speed in mph. */
38
+ speed: number;
39
+ };
40
+ }
41
+
42
+ export interface BatteryEvent {
43
+ event_type: "battery";
44
+ data: {
45
+ /** State of charge as a percentage (0-100). */
46
+ battery_level?: number;
47
+ /** Estimated range in miles. */
48
+ range_miles?: number;
49
+ };
50
+ }
51
+
52
+ export interface InsideTempEvent {
53
+ event_type: "inside_temp";
54
+ data: {
55
+ /** Inside cabin temperature in Fahrenheit. */
56
+ inside_temp_f: number;
57
+ };
58
+ }
59
+
60
+ export interface OutsideTempEvent {
61
+ event_type: "outside_temp";
62
+ data: {
63
+ /** Outside ambient temperature in Fahrenheit. */
64
+ outside_temp_f: number;
65
+ };
66
+ }
67
+
68
+ export interface SpeedEvent {
69
+ event_type: "speed";
70
+ data: {
71
+ /** Vehicle speed in mph. */
72
+ speed_mph: number;
73
+ };
74
+ }
75
+
76
+ export interface ChargeStartedEvent {
77
+ event_type: "charge_started";
78
+ data: {
79
+ /** Raw charge state string from the vehicle. */
80
+ state: string;
81
+ };
82
+ }
83
+
84
+ export interface ChargeCompleteEvent {
85
+ event_type: "charge_complete";
86
+ data: {
87
+ state: string;
88
+ };
89
+ }
90
+
91
+ export interface ChargeStoppedEvent {
92
+ event_type: "charge_stopped";
93
+ data: {
94
+ state: string;
95
+ };
96
+ }
97
+
98
+ export interface ChargeStateChangedEvent {
99
+ event_type: "charge_state_changed";
100
+ data: {
101
+ /** Raw charge state string (for transitions that don't match start/complete/stopped). */
102
+ state: string;
103
+ };
104
+ }
105
+
106
+ export interface SecurityChangedEvent {
107
+ event_type: "security_changed";
108
+ data: {
109
+ /** Which field changed: "locked" or "sentrymode". */
110
+ field: string;
111
+ /** New value of the field. */
112
+ value: unknown;
113
+ };
114
+ }
115
+
116
+ export interface GearChangedEvent {
117
+ event_type: "gear_changed";
118
+ data: {
119
+ /** Current gear: "P", "R", "N", "D", or other. */
120
+ gear: string;
121
+ };
122
+ }
123
+
124
+ // ---------------------------------------------------------------------------
125
+ // Lifecycle event types (3)
126
+ // ---------------------------------------------------------------------------
127
+
128
+ export interface NodeConnectedEvent {
129
+ event_type: "node.connected";
130
+ data: {
131
+ client_id: string;
132
+ };
133
+ }
134
+
135
+ export interface NodeDisconnectingEvent {
136
+ event_type: "node.disconnecting";
137
+ data: {
138
+ client_id: string;
139
+ };
140
+ }
141
+
142
+ export interface TriggerFiredEvent {
143
+ event_type: "trigger.fired";
144
+ data: {
145
+ trigger_id: string;
146
+ field: string;
147
+ value: unknown;
148
+ };
149
+ }
150
+
151
+ // ---------------------------------------------------------------------------
152
+ // Union type
153
+ // ---------------------------------------------------------------------------
154
+
155
+ /** All possible telemetry event types emitted by the tescmd node. */
156
+ export type TescmdTelemetryEvent =
157
+ | LocationEvent
158
+ | BatteryEvent
159
+ | InsideTempEvent
160
+ | OutsideTempEvent
161
+ | SpeedEvent
162
+ | ChargeStartedEvent
163
+ | ChargeCompleteEvent
164
+ | ChargeStoppedEvent
165
+ | ChargeStateChangedEvent
166
+ | SecurityChangedEvent
167
+ | GearChangedEvent
168
+ | NodeConnectedEvent
169
+ | NodeDisconnectingEvent
170
+ | TriggerFiredEvent;
171
+
172
+ // ---------------------------------------------------------------------------
173
+ // Event type constants (for use in hooks, filters, etc.)
174
+ // ---------------------------------------------------------------------------
175
+
176
+ /** All data event type names. */
177
+ export const DATA_EVENT_TYPES = [
178
+ "location",
179
+ "battery",
180
+ "inside_temp",
181
+ "outside_temp",
182
+ "speed",
183
+ "charge_started",
184
+ "charge_complete",
185
+ "charge_stopped",
186
+ "charge_state_changed",
187
+ "security_changed",
188
+ "gear_changed",
189
+ ] as const;
190
+
191
+ /** All lifecycle event type names. */
192
+ export const LIFECYCLE_EVENT_TYPES = [
193
+ "node.connected",
194
+ "node.disconnecting",
195
+ "trigger.fired",
196
+ ] as const;
197
+
198
+ /** All event type names combined. */
199
+ export const ALL_EVENT_TYPES = [...DATA_EVENT_TYPES, ...LIFECYCLE_EVENT_TYPES] as const;
200
+
201
+ // ---------------------------------------------------------------------------
202
+ // Telemetry field documentation
203
+ // ---------------------------------------------------------------------------
204
+
205
+ /**
206
+ * Maps Tesla Fleet Telemetry field names to their OpenClaw event types.
207
+ * Used for documentation and filtering configuration.
208
+ */
209
+ export const TELEMETRY_FIELD_MAP: Record<string, string> = {
210
+ Location: "location",
211
+ Soc: "battery",
212
+ BatteryLevel: "battery",
213
+ EstBatteryRange: "battery",
214
+ InsideTemp: "inside_temp",
215
+ OutsideTemp: "outside_temp",
216
+ VehicleSpeed: "speed",
217
+ ChargeState: "charge_started | charge_complete | charge_stopped",
218
+ DetailedChargeState: "charge_state_changed",
219
+ Locked: "security_changed",
220
+ SentryMode: "security_changed",
221
+ Gear: "gear_changed",
222
+ };
223
+
224
+ /**
225
+ * Default filter thresholds for telemetry emission.
226
+ * Matches the tescmd bridge defaults in BridgeConfig.
227
+ */
228
+ export const DEFAULT_FILTER_CONFIG: Record<
229
+ string,
230
+ { granularity: number; throttle_seconds: number }
231
+ > = {
232
+ Location: { granularity: 50.0, throttle_seconds: 1.0 },
233
+ Soc: { granularity: 5.0, throttle_seconds: 10.0 },
234
+ InsideTemp: { granularity: 5.0, throttle_seconds: 30.0 },
235
+ OutsideTemp: { granularity: 5.0, throttle_seconds: 30.0 },
236
+ VehicleSpeed: { granularity: 5.0, throttle_seconds: 2.0 },
237
+ ChargeState: { granularity: 0.0, throttle_seconds: 0.0 },
238
+ DetailedChargeState: { granularity: 0.0, throttle_seconds: 0.0 },
239
+ Locked: { granularity: 0.0, throttle_seconds: 0.0 },
240
+ SentryMode: { granularity: 0.0, throttle_seconds: 0.0 },
241
+ BatteryLevel: { granularity: 1.0, throttle_seconds: 10.0 },
242
+ EstBatteryRange: { granularity: 5.0, throttle_seconds: 30.0 },
243
+ Odometer: { granularity: 1.0, throttle_seconds: 60.0 },
244
+ Gear: { granularity: 0.0, throttle_seconds: 0.0 },
245
+ };
@@ -0,0 +1,341 @@
1
+ /**
2
+ * Capabilities meta-tool — on-demand help for the agent.
3
+ *
4
+ * Provides a structured overview of all available Tesla vehicle tools,
5
+ * common workflows, telemetry event types, and usage examples. The agent
6
+ * can call this tool to understand what's available before taking action.
7
+ */
8
+
9
+ import { Type } from "@sinclair/typebox";
10
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
11
+
12
+ const CAPABILITIES_TEXT = `# Tesla Vehicle Tools (tescmd)
13
+
14
+ You have access to a Tesla vehicle through the tescmd node. Here's what you can do and when to use each tool.
15
+
16
+ **Source repositories:**
17
+ - tescmd node: https://github.com/oceanswave/tescmd
18
+ - OpenClaw plugin: https://github.com/oceanswave/openclaw-tescmd
19
+
20
+ ## Quick Reference
21
+
22
+ ### Reading Vehicle State (no side effects, safe to call anytime)
23
+ | Tool | Use When... |
24
+ |------|------------|
25
+ | tescmd_get_location | User asks where the car is, needs GPS coordinates, or you need to check proximity |
26
+ | tescmd_get_battery | User asks about charge level, range, or you need to decide if charging is needed |
27
+ | tescmd_get_speed | User asks if the car is moving, or you need to check if it's parked before taking action |
28
+ | tescmd_get_charge_state | User asks about charging status — is it plugged in, charging, complete? |
29
+ | tescmd_get_temperature | User asks about cabin/outside temp, or you need to decide about climate control |
30
+ | tescmd_get_security | User asks if the car is locked, or you need to check sentry mode status |
31
+
32
+ ### Controlling the Vehicle (side effects — confirm intent with user when appropriate)
33
+ | Tool | Use When... |
34
+ |------|------------|
35
+ | tescmd_lock_doors / tescmd_unlock_doors | User wants to lock/unlock. Unlock is sensitive — confirm first |
36
+ | tescmd_climate_on / tescmd_climate_off | User wants to precondition the cabin or stop climate |
37
+ | tescmd_set_climate_temp | User specifies a desired temperature (in °F) |
38
+ | tescmd_start_charge / tescmd_stop_charge | User wants to start/stop charging. Check charge_state first |
39
+ | tescmd_set_charge_limit | User wants to change the charge limit (50-100%) |
40
+ | tescmd_open_trunk / tescmd_open_frunk | User needs trunk/frunk opened. Frunk can't be closed remotely |
41
+ | tescmd_flash_lights / tescmd_honk_horn | User wants to locate the car or signal |
42
+ | tescmd_sentry_on / tescmd_sentry_off | User wants camera monitoring on/off. Note: uses ~1-2% battery/hour |
43
+
44
+ ### Navigation (send destinations to the vehicle)
45
+ | Tool | Use When... |
46
+ |------|------------|
47
+ | tescmd_nav_send | User says 'navigate to [place]' or 'send directions to the car'. Pass a full address or place name |
48
+ | tescmd_nav_gps | User provides lat/lon coordinates, or you have coordinates from a location lookup |
49
+ | tescmd_nav_supercharger | User says 'find a Supercharger' or battery is low. Pair with tescmd_get_battery first |
50
+ | tescmd_nav_waypoints | User wants a multi-stop road trip using Google Place IDs as waypoints |
51
+ | tescmd_homelink | User says 'open the garage'. Get location first with tescmd_get_location, then pass lat/lon |
52
+
53
+ ### Triggers (subscribe to telemetry conditions)
54
+ | Tool | Use When... |
55
+ |------|------------|
56
+ | tescmd_create_trigger | User wants alerts on conditions (low battery, high temp, geofence) |
57
+ | tescmd_battery_trigger | Shortcut: alert on battery level (e.g., below 20%) |
58
+ | tescmd_cabin_temp_trigger | Shortcut: alert on cabin temp (e.g., above 100°F for hot car alert) |
59
+ | tescmd_outside_temp_trigger | Shortcut: alert on outside temp (e.g., below freezing) |
60
+ | tescmd_location_trigger | Shortcut: geofence alert (enter/leave an area) |
61
+ | tescmd_list_triggers | Check what triggers are already active |
62
+ | tescmd_poll_triggers | Check if any triggers have fired recently |
63
+ | tescmd_delete_trigger | Remove a trigger that's no longer needed |
64
+
65
+ ### Advanced
66
+ | Tool | Use When... |
67
+ |------|------------|
68
+ | tescmd_run_command | You need a command not covered by a dedicated tool, or the method name is dynamic |
69
+
70
+ ## Common Workflows
71
+
72
+ ### "Is my car ready to go?"
73
+ 1. tescmd_get_battery → check charge level and range
74
+ 2. tescmd_get_charge_state → check if still charging
75
+ 3. tescmd_get_temperature → check cabin comfort
76
+ 4. tescmd_get_security → verify doors are locked
77
+ 5. Summarize: battery %, range, charging status, cabin temp, lock state
78
+
79
+ ### "Precondition the cabin"
80
+ 1. tescmd_get_temperature → check current cabin temp
81
+ 2. tescmd_climate_on → start climate control
82
+ 3. Optionally: tescmd_set_climate_temp → set specific temperature
83
+ 4. Confirm: "Climate control is on, targeting X°F"
84
+
85
+ ### "Set up for overnight charging"
86
+ 1. tescmd_get_charge_state → verify cable is connected
87
+ 2. tescmd_set_charge_limit → set to user's desired limit (typically 80%)
88
+ 3. tescmd_start_charge → begin charging
89
+ 4. Optionally: tescmd_battery_trigger → alert when charge reaches target
90
+
91
+ ### "Keep an eye on the car" (parking/security)
92
+ 1. tescmd_lock_doors → ensure locked
93
+ 2. tescmd_sentry_on → enable camera monitoring
94
+ 3. tescmd_location_trigger → geofence alert if car moves
95
+ 4. Confirm setup
96
+
97
+ ### "Navigate somewhere"
98
+ 1. tescmd_nav_send → pass the address or place name
99
+ 2. Or: tescmd_nav_gps → if you have exact lat/lon coordinates
100
+ 3. For multi-stop: tescmd_nav_waypoints → comma-separated Place IDs
101
+
102
+ ### "Open the garage"
103
+ 1. tescmd_get_location → get the vehicle's current GPS
104
+ 2. tescmd_homelink → pass lat/lon to trigger HomeLink
105
+
106
+ ### "Find my car"
107
+ 1. tescmd_get_location → get GPS coordinates
108
+ 2. tescmd_flash_lights → visual signal
109
+ 3. Optionally: tescmd_honk_horn → audible signal
110
+
111
+ ### "Hot car alert"
112
+ 1. tescmd_cabin_temp_trigger with operator='gt', value=100 → alert over 100°F
113
+ 2. When triggered: tescmd_climate_on → auto-start climate
114
+ 3. tescmd_get_temperature → verify cooling
115
+
116
+ ## Error Handling
117
+
118
+ ### Node Not Connected
119
+ If commands fail with "no node connected" or similar errors:
120
+ 1. Call **tescmd_node_status** to confirm the node is offline
121
+ 2. Tell the user: "No tescmd node is connected. Start one with:"
122
+ \`tescmd serve <VIN> --openclaw <gateway_url> --openclaw-token <token>\`
123
+ 3. Call **tescmd_help** with topic='setup' for full setup instructions if needed
124
+
125
+ ### Vehicle Asleep
126
+ Write commands auto-wake the vehicle, but this is a **billable API call**.
127
+ - If a read returns \`{pending: true}\`, the vehicle data is being fetched. Wait 3-5 seconds and retry.
128
+ - If the wake fails (rare), suggest the user wake the vehicle from the Tesla app (free).
129
+ - Avoid unnecessary write commands to sleeping vehicles — check state with reads first.
130
+
131
+ ### Authentication Expired
132
+ If commands fail with auth/token errors:
133
+ - The tescmd node handles token refresh automatically
134
+ - If refresh fails, the user needs to re-authenticate: \`tescmd auth login\`
135
+ - Check auth status: \`tescmd auth status\`
136
+
137
+ ### Rate Limiting
138
+ Tesla's API has rate limits (429 responses). tescmd caches read responses to minimize API calls:
139
+ - Static data (specs, warranty): cached 1 hour
140
+ - Fleet lists: cached 5 minutes
141
+ - Standard queries: cached 1 minute
142
+ - Location/speed: cached 30 seconds
143
+ - If you get rate limit errors, wait and avoid rapid repeated calls
144
+
145
+ ### Command Failures
146
+ If a write command fails:
147
+ - Check if the vehicle is in a valid state (e.g., charge cable connected for charge.start)
148
+ - Check if the vehicle is online (tescmd_get_speed returns non-null when driving)
149
+ - Try tescmd_run_command as a fallback — it accepts both dot-notation and Fleet API names
150
+
151
+ ### Common Error Patterns
152
+ | Error | Cause | Resolution |
153
+ |-------|-------|------------|
154
+ | "no handler configured" | Node has no dispatcher | Restart node with full serve command |
155
+ | "unknown command: X" | Command not in whitelist | Check tescmd_help for valid commands |
156
+ | "handler timeout (30s)" | Vehicle/API unresponsive | Retry after brief wait |
157
+ | "Triggers not available" | Node started without telemetry | Restart with telemetry enabled |
158
+ | {pending: true} | Data being fetched from API | Retry in 3-5 seconds |
159
+
160
+ ## Important Notes
161
+
162
+ - **Auto-wake:** Write commands automatically wake the vehicle if it's asleep. This is a billable API call — avoid unnecessary wake-ups.
163
+ - **Pending responses:** If a read returns {pending: true}, the data is being fetched from the API. Wait briefly and retry.
164
+ - **Telemetry vs API:** When the telemetry stream is active, reads are instant (from memory). When telemetry is offline, reads hit the Fleet API (slower, may need wake).
165
+ - **Signed commands:** Security-sensitive commands (lock, unlock, trunk) use cryptographically signed commands via the Vehicle Command Protocol when available.
166
+ - **Trigger operators:** lt, gt, lte, gte, eq, neq (numeric), changed (any change), enter/leave (geofence).
167
+ - **Temperature units:** climate.set_temp takes Fahrenheit. temperature.get returns Celsius. Telemetry events emit Fahrenheit for temp.
168
+ - **Node status:** Always call tescmd_node_status before your first vehicle command in a conversation to verify the node is online.
169
+
170
+ ## Telemetry Events (streamed automatically)
171
+
172
+ The tescmd node streams these events to the Gateway in real-time:
173
+ - **location** — GPS updates (filtered: 50m movement threshold)
174
+ - **battery** — charge level changes (filtered: 5% threshold, 10s throttle)
175
+ - **inside_temp / outside_temp** — temperature changes (5° threshold, 30s throttle)
176
+ - **speed** — speed changes (5mph threshold, 2s throttle)
177
+ - **charge_started / charge_complete / charge_stopped** — charging state transitions (immediate)
178
+ - **security_changed** — lock or sentry mode changed (immediate)
179
+ - **gear_changed** — gear shift (immediate)
180
+ - **trigger.fired** — a trigger condition was met
181
+
182
+ ## Starting the tescmd Node
183
+
184
+ If no tescmd node is currently connected, you can spawn one. The node is a Python CLI that bridges the Tesla Fleet API to the OpenClaw Gateway.
185
+
186
+ ### Prerequisites
187
+ - **Python 3.11+** (required)
188
+ - **pip** (required — ships with Python)
189
+ - **Tesla account** linked to a vehicle (required)
190
+ - **Git** (required — for key hosting setup)
191
+ - **GitHub CLI** (\`gh\`) (recommended — auto-creates key hosting via GitHub Pages)
192
+ - **Tailscale** (recommended — provides public HTTPS for telemetry streaming with zero infra)
193
+
194
+ ### Installation
195
+ \`\`\`bash
196
+ pip install tescmd
197
+ \`\`\`
198
+
199
+ ### First-Time Setup
200
+ Run the interactive setup wizard (only needed once):
201
+ \`\`\`bash
202
+ tescmd setup
203
+ \`\`\`
204
+ This walks through: Tesla Developer app creation, EC key generation, public key hosting (GitHub Pages or Tailscale Funnel), Fleet API registration, OAuth2 login, and key enrollment on the vehicle.
205
+
206
+ ### Launching the Node
207
+ \`\`\`bash
208
+ # Full mode: MCP server + telemetry streaming + OpenClaw bridge
209
+ tescmd serve <VIN> --openclaw <gateway_ws_url> --openclaw-token <gateway_token>
210
+
211
+ # Example:
212
+ tescmd serve 5YJ3E1EA1NF000000 --openclaw ws://gateway.example.com:18789 --openclaw-token my-token
213
+
214
+ # With explicit MCP credentials:
215
+ tescmd serve <VIN> --client-id my-agent --client-secret my-secret --openclaw <url> --openclaw-token <token>
216
+
217
+ # OpenClaw bridge only (no MCP server):
218
+ tescmd serve <VIN> --no-mcp --openclaw <url> --openclaw-token <token>
219
+
220
+ # Telemetry + OpenClaw without MCP:
221
+ tescmd serve <VIN> --no-mcp --openclaw <url>
222
+
223
+ # Standalone OpenClaw bridge (alternative command):
224
+ tescmd openclaw bridge --gateway <url> --token <token>
225
+ \`\`\`
226
+
227
+ ### Serve Command Key Flags
228
+ | Flag | Description |
229
+ |------|-------------|
230
+ | \`<VIN>\` | Vehicle Identification Number (positional argument) |
231
+ | \`--openclaw <ws_url>\` | OpenClaw Gateway WebSocket URL (e.g. ws://host:18789) |
232
+ | \`--openclaw-token <token>\` | Authentication token for the Gateway |
233
+ | \`--openclaw-config <path>\` | Path to bridge config JSON (default: ~/.config/tescmd/bridge.json) |
234
+ | \`--transport <type>\` | MCP transport: streamable-http (default), stdio |
235
+ | \`--port <num>\` | MCP HTTP port (default: 8080) |
236
+ | \`--host <addr>\` | MCP bind address (default: 127.0.0.1) |
237
+ | \`--telemetry-port <num>\` | Telemetry WebSocket port (default: 4443) |
238
+ | \`--fields <preset>\` | Telemetry field preset: driving, charging, all |
239
+ | \`--interval <sec>\` | Telemetry polling interval in seconds |
240
+ | \`--no-telemetry\` | Disable telemetry streaming (MCP only) |
241
+ | \`--no-mcp\` | Disable MCP server (telemetry + OpenClaw only) |
242
+ | \`--no-log\` | Disable CSV telemetry logging |
243
+ | \`--dry-run\` | Log events as JSONL without connecting to Gateway |
244
+ | \`--tailscale\` | Expose MCP via Tailscale Funnel |
245
+ | \`--client-id <id>\` | MCP OAuth client ID |
246
+ | \`--client-secret <secret>\` | MCP OAuth client secret |
247
+
248
+ ### Environment Variables
249
+ Instead of CLI flags, you can set these in \`~/.config/tescmd/.env\`:
250
+ \`\`\`bash
251
+ TESLA_CLIENT_ID=your-client-id
252
+ TESLA_CLIENT_SECRET=your-client-secret
253
+ TESLA_VIN=5YJ3E1EA1NF000000
254
+ TESLA_REGION=na # na, eu, or cn
255
+ OPENCLAW_GATEWAY_URL=ws://gateway.example.com:18789
256
+ OPENCLAW_GATEWAY_TOKEN=your-token
257
+ TESLA_COMMAND_PROTOCOL=auto # auto, signed, or unsigned
258
+ \`\`\`
259
+
260
+ ### tescmd CLI Quick Reference
261
+ Beyond the serve command, tescmd offers 100+ CLI commands for direct vehicle interaction:
262
+ \`\`\`bash
263
+ tescmd charge status # Check battery and charging state
264
+ tescmd charge start --wake # Start charging (wakes vehicle)
265
+ tescmd charge limit 80 # Set charge limit to 80%
266
+ tescmd climate on --wake # Turn on climate
267
+ tescmd climate set 72 --wake # Set temperature to 72°F
268
+ tescmd security lock --wake # Lock doors
269
+ tescmd security status # Check lock/sentry state
270
+ tescmd vehicle location # Get GPS coordinates
271
+ tescmd vehicle info # Full vehicle data snapshot
272
+ tescmd vehicle list # List all vehicles on account
273
+ tescmd trunk open --wake # Open rear trunk
274
+ tescmd trunk frunk --wake # Open frunk
275
+ tescmd security flash --wake # Flash headlights
276
+ tescmd security honk --wake # Honk horn
277
+ tescmd security sentry on --wake # Enable Sentry Mode
278
+ tescmd cache status # Check cache stats
279
+ tescmd auth status # Check auth token status
280
+ \`\`\`
281
+
282
+ All read commands are cached (tiered TTLs: 30s-1h). Write commands auto-invalidate the cache. The \`--wake\` flag is required for commands that need the vehicle awake (billable API call). Use \`--format json\` for structured output.
283
+ `;
284
+
285
+ export function registerCapabilitiesTool(api: OpenClawPluginApi): void {
286
+ api.registerTool(
287
+ {
288
+ name: "tescmd_help",
289
+ label: "Tesla Tools Help",
290
+ description:
291
+ "Get a comprehensive guide to all available Tesla vehicle tools, " +
292
+ "common workflows, and usage examples. Call this tool when you need " +
293
+ "to understand what Tesla vehicle capabilities are available, how to " +
294
+ "chain tools together for common tasks, or when you're unsure which " +
295
+ "tool to use for a vehicle-related request. Returns a structured " +
296
+ "reference with tool descriptions, workflow recipes, and important notes.",
297
+ parameters: Type.Object({
298
+ topic: Type.Optional(
299
+ Type.String({
300
+ description:
301
+ "Optional topic to focus on: 'tools', 'workflows', 'triggers', " +
302
+ "'errors', 'telemetry', 'setup', 'cli', or 'all' (default: 'all')",
303
+ }),
304
+ ),
305
+ }),
306
+ async execute(_toolCallId: string, params: Record<string, unknown>) {
307
+ const topic = (params.topic as string) ?? "all";
308
+
309
+ let text = CAPABILITIES_TEXT;
310
+
311
+ // Filter to specific section if requested
312
+ if (topic !== "all") {
313
+ const sectionMap: Record<string, string> = {
314
+ tools: "## Quick Reference",
315
+ workflows: "## Common Workflows",
316
+ triggers: "### Triggers",
317
+ errors: "## Error Handling",
318
+ telemetry: "## Telemetry Events",
319
+ setup: "## Starting the tescmd Node",
320
+ cli: "### tescmd CLI Quick Reference",
321
+ };
322
+ const header = sectionMap[topic];
323
+ if (header) {
324
+ const start = text.indexOf(header);
325
+ if (start !== -1) {
326
+ // Find the next ## heading after the section
327
+ const nextSection = text.indexOf("\n## ", start + header.length);
328
+ text = nextSection !== -1 ? text.slice(start, nextSection) : text.slice(start);
329
+ }
330
+ }
331
+ }
332
+
333
+ return {
334
+ content: [{ type: "text" as const, text: text.trim() }],
335
+ details: { topic },
336
+ };
337
+ },
338
+ },
339
+ { name: "tescmd_help" },
340
+ );
341
+ }