@oceanswave/openclaw-tescmd 0.3.1 → 0.4.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/index.ts CHANGED
@@ -34,10 +34,8 @@
34
34
  */
35
35
 
36
36
  import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
37
- import { registerCliCommands } from "./commands/cli.js";
38
37
  import { registerSlashCommands } from "./commands/slash.js";
39
38
  import { type TescmdConfig, tescmdConfigSchema } from "./config.js";
40
- import { registerPlatform } from "./platform.js";
41
39
  import { registerCapabilitiesTool } from "./tools/capabilities.js";
42
40
  import { registerChargeTools } from "./tools/charge.js";
43
41
  import { registerClimateTools } from "./tools/climate.js";
@@ -68,9 +66,6 @@ export default {
68
66
  api.logger.info("openclaw-tescmd: debug mode enabled");
69
67
  }
70
68
 
71
- // Register the Tesla platform + command whitelist
72
- registerPlatform(api);
73
-
74
69
  // Register all agent-callable tools by domain
75
70
  registerCapabilitiesTool(api);
76
71
  registerStatusTool(api);
@@ -83,9 +78,8 @@ export default {
83
78
  registerTriggerTools(api);
84
79
  registerSystemTools(api);
85
80
 
86
- // Register slash commands and CLI subcommands
81
+ // Register slash commands
87
82
  registerSlashCommands(api);
88
- registerCliCommands(api);
89
83
 
90
84
  // Register a service for lifecycle logging
91
85
  api.registerService({
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@oceanswave/openclaw-tescmd",
3
- "version": "0.3.1",
3
+ "version": "0.4.1",
4
4
  "description": "OpenClaw platform plugin for Tesla vehicle control and telemetry via tescmd",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/oceanswave/openclaw-tescmd.git"
9
+ "url": "git+https://github.com/Oceanswave/openclaw-tescmd.git"
10
10
  },
11
- "homepage": "https://github.com/oceanswave/openclaw-tescmd",
11
+ "homepage": "https://github.com/Oceanswave/openclaw-tescmd",
12
12
  "files": [
13
13
  "index.ts",
14
14
  "config.ts",
package/platform.ts CHANGED
@@ -10,7 +10,7 @@
10
10
  * `CommandDispatcher` handler map (src/tescmd/openclaw/dispatcher.py).
11
11
  */
12
12
 
13
- import type { OpenClawPluginApi, PlatformCommand } from "openclaw/plugin-sdk";
13
+ import type { PlatformCommand } from "openclaw/plugin-sdk";
14
14
 
15
15
  // ---------------------------------------------------------------------------
16
16
  // Read commands (8)
@@ -328,34 +328,8 @@ const WRITE_COMMANDS: PlatformCommand[] = [
328
328
  export const ALL_COMMANDS: PlatformCommand[] = [...READ_COMMANDS, ...WRITE_COMMANDS];
329
329
 
330
330
  // ---------------------------------------------------------------------------
331
- // Registration
331
+ // Command metadata helpers
332
332
  // ---------------------------------------------------------------------------
333
333
 
334
- /**
335
- * Register the Tesla platform with the OpenClaw Gateway.
336
- *
337
- * This whitelists all 34 commands so the Gateway will dispatch
338
- * `node.invoke.request` events to connected tescmd nodes.
339
- */
340
- export function registerPlatform(api: OpenClawPluginApi): void {
341
- api.registerPlatform({
342
- id: "tesla",
343
- label: "Tesla Vehicle",
344
- description:
345
- "Tesla vehicle control and real-time telemetry via tescmd. " +
346
- "Supports 34 commands across vehicle status, charging, climate, " +
347
- "security, trunk, sentry mode, navigation, and trigger subscriptions. " +
348
- "The tescmd node connects to the Tesla Fleet API and streams " +
349
- "telemetry data including GPS location, battery, temperature, " +
350
- "speed, charge state, and security events.",
351
- nodeRole: "node",
352
- scopes: ["node.telemetry", "node.command"],
353
- commands: ALL_COMMANDS,
354
- });
355
-
356
- api.logger.info(
357
- `Registered tesla platform with ${ALL_COMMANDS.length} whitelisted commands ` +
358
- `(${READ_COMMANDS.length} reads, ${WRITE_COMMANDS.length} writes, ` +
359
- `including system.run meta-dispatch)`,
360
- );
361
- }
334
+ /** All command method names, useful for documentation and config generation. */
335
+ export const ALL_COMMAND_METHODS: string[] = ALL_COMMANDS.map((cmd) => cmd.method);
package/skill.md CHANGED
@@ -1,37 +1,33 @@
1
1
  ---
2
2
  name: openclaw-tescmd
3
- version: 0.3.1
4
- description: Agent handbook for Tesla vehicle control and telemetry via the tescmd node — covers 37 tools, 34 commands, 8 slash commands, and 14 telemetry event types.
3
+ slug: openclaw-tescmd
4
+ displayName: OpenClaw Tesla (tescmd)
5
+ version: 0.4.1
6
+ description: Installation and setup guide for Tesla vehicle control and telemetry via the tescmd node.
5
7
  homepage: https://github.com/oceanswave/openclaw-tescmd
6
8
  metadata: {"category":"platform","platform":"tesla","node":"tescmd"}
7
9
  ---
8
10
 
9
- # OpenClaw Tesla (tescmd) — Agent Handbook
11
+ # OpenClaw Tesla (tescmd) — Setup Guide
10
12
 
11
- This plugin gives agents full control of a Tesla vehicle through the OpenClaw Gateway. It registers **37 agent-callable tools**, **34 whitelisted commands**, **8 slash commands**, and **14 telemetry event types** backed by real-time Fleet Telemetry streaming.
13
+ This plugin connects Tesla vehicles to the OpenClaw Gateway via the [tescmd](https://github.com/oceanswave/tescmd) node. Once installed and paired, the plugin automatically registers all tools, commands, slash commands, and telemetry event types.
14
+
15
+ This document covers **installation and setup only**. Runtime tool usage, workflows, and error handling are provided by the plugin's registered tools (call `tescmd_help` for the full reference).
12
16
 
13
17
  **Repositories:**
14
- - Plugin (this repo): https://github.com/oceanswave/openclaw-tescmd
18
+ - Plugin: https://github.com/oceanswave/openclaw-tescmd
15
19
  - tescmd node (Python CLI): https://github.com/oceanswave/tescmd
16
20
 
17
- This document is an installation and configuration reference. Once installed, the plugin will automatically register tools, commands, and events.
18
-
19
21
  ---
20
22
 
21
23
  ## Architecture
22
24
 
23
- ### System Layers
24
-
25
25
  ```
26
26
  Agent (you)
27
27
  ↓ tool calls
28
28
  OpenClaw Gateway
29
29
  ↓ node.invoke.request
30
30
  openclaw-tescmd Plugin
31
- ├─ 37 Tools (schema + routing)
32
- ├─ 34 Whitelisted Commands
33
- ├─ 8 Slash Commands
34
- └─ 14 Telemetry Event Types
35
31
  ↓ WebSocket dispatch
36
32
  tescmd Node (Python)
37
33
  ├─ Tesla Fleet API (REST)
@@ -41,21 +37,7 @@ tescmd Node (Python)
41
37
  Tesla Vehicle
42
38
  ```
43
39
 
44
- ### Three Operating Modes
45
-
46
- | Mode | What It Does | Flag |
47
- |------|-------------|------|
48
- | **Full** (default) | MCP server + telemetry + OpenClaw bridge | `tescmd serve <VIN> --openclaw <url>` |
49
- | **Bridge only** | Telemetry + OpenClaw, no MCP server | `--no-mcp` |
50
- | **Dry run** | Log events as JSONL, no Gateway connection | `--dry-run` |
51
-
52
- ### Data Flow
53
-
54
- **Read path:** Agent calls read tool → Plugin routes to Gateway → Gateway dispatches `node.invoke.request` to tescmd node → Node checks in-memory telemetry store first (instant, free) → Falls back to Fleet API if telemetry unavailable (may need vehicle wake, slower).
55
-
56
- **Write path:** Agent calls write tool → Plugin routes to Gateway → Gateway dispatches to node → Node sends command to vehicle via Fleet API or Vehicle Command Protocol (VCSEC for security commands) → Vehicle executes → Node returns result. Write commands auto-wake sleeping vehicles (billable API call).
57
-
58
- **Telemetry path:** Vehicle → Tesla Fleet Telemetry stream → tescmd node filters/throttles → Node emits `req:agent` frames to Gateway → Gateway broadcasts to agents. Agents receive real-time events without polling.
40
+ The plugin is the **Gateway-side counterpart** to the tescmd node. It defines tool schemas and routes invocations. The tescmd node handles all direct communication with Tesla.
59
41
 
60
42
  ---
61
43
 
@@ -137,14 +119,6 @@ Wait for the user to confirm before continuing.
137
119
  openclaw plugins install @oceanswave/openclaw-tescmd
138
120
  ```
139
121
 
140
- #### Development install (symlink, editable):
141
-
142
- ```bash
143
- git clone https://github.com/oceanswave/openclaw-tescmd.git
144
- cd openclaw-tescmd && bun install && cd ..
145
- openclaw plugins install -l ./openclaw-tescmd
146
- ```
147
-
148
122
  #### Verify installation:
149
123
 
150
124
  ```bash
@@ -225,34 +199,68 @@ Note the VIN — it is needed for the serve command.
225
199
 
226
200
  ---
227
201
 
228
- ### Step 6: Start the tescmd Node
202
+ ### Step 6: Start the tescmd Node and Pair with the Gateway
229
203
 
230
- The node bridges the Tesla Fleet API to the OpenClaw Gateway. It needs:
231
- - The vehicle's VIN
232
- - The Gateway's WebSocket URL
233
- - A Gateway authentication token
204
+ The tescmd node bridges the Tesla Fleet API to the OpenClaw Gateway. The first connection requires a one-time pairing approval.
234
205
 
235
- #### Full mode (MCP server + telemetry + OpenClaw bridge):
206
+ #### First-time pairing:
207
+
208
+ Start the node with just the Gateway URL (no token needed):
236
209
  ```bash
237
- tescmd serve <VIN> --openclaw <gateway_ws_url> --openclaw-token <gateway_token>
210
+ tescmd serve <VIN> --openclaw <gateway_ws_url>
238
211
  ```
239
212
 
240
- #### OpenClaw bridge only (no MCP server):
213
+ The node sends a `node.pair.request` to the Gateway and waits for approval. The pending request expires after **5 minutes**, so approve it promptly.
214
+
215
+ **In a separate terminal**, approve the pairing:
241
216
  ```bash
242
- tescmd serve <VIN> --no-mcp --openclaw <gateway_ws_url> --openclaw-token <gateway_token>
217
+ openclaw nodes pending # View waiting pair requests
218
+ openclaw nodes approve <requestId> # Approve the node
243
219
  ```
244
220
 
245
- #### With Tailscale (exposes MCP via Tailscale Funnel):
221
+ On approval the Gateway issues an authentication token. The node receives it, saves it to `~/.config/tescmd/bridge.json`, and establishes the authenticated connection. No manual token handling is needed.
222
+
223
+ **Tell the user:** "Start the tescmd node with `tescmd serve <VIN> --openclaw <gateway_url>`, then in another terminal run `openclaw nodes pending` and `openclaw nodes approve <requestId>` to complete pairing."
224
+
225
+ **Wait for the user to confirm pairing is complete before continuing.**
226
+
227
+ #### Subsequent connections (already paired):
228
+
229
+ Once paired, the node reconnects automatically using the stored token:
230
+ ```bash
231
+ tescmd serve <VIN> --openclaw <gateway_ws_url>
232
+ ```
233
+
234
+ You can also pass the token explicitly if needed:
246
235
  ```bash
247
- tescmd serve <VIN> --tailscale --openclaw <gateway_ws_url> --openclaw-token <gateway_token>
236
+ tescmd serve <VIN> --openclaw <gateway_ws_url> --openclaw-token <gateway_token>
248
237
  ```
249
238
 
239
+ #### Node management commands:
240
+
241
+ | Command | Purpose |
242
+ |---------|---------|
243
+ | `openclaw nodes pending` | View pending pair requests |
244
+ | `openclaw nodes approve <id>` | Approve a node |
245
+ | `openclaw nodes reject <id>` | Reject a node |
246
+ | `openclaw nodes status` | List paired nodes and their status |
247
+
248
+ #### Operating modes:
249
+
250
+ | Mode | Command | Description |
251
+ |------|---------|-------------|
252
+ | **Full** (default) | `tescmd serve <VIN> --openclaw <url>` | MCP server + telemetry + OpenClaw bridge |
253
+ | **Bridge only** | `tescmd serve <VIN> --no-mcp --openclaw <url>` | Telemetry + OpenClaw, no MCP server |
254
+ | **With Tailscale** | `tescmd serve <VIN> --tailscale --openclaw <url>` | Exposes MCP via Tailscale Funnel |
255
+ | **Dry run** | `tescmd serve <VIN> --dry-run` | Log events as JSONL, no Gateway connection |
256
+
250
257
  #### Key flags reference:
258
+
251
259
  | Flag | Description |
252
260
  |------|-------------|
253
261
  | `<VIN>` | Vehicle Identification Number (positional) |
254
262
  | `--openclaw <ws_url>` | Gateway WebSocket URL (e.g. `ws://host:18789`) |
255
- | `--openclaw-token <token>` | Gateway authentication token |
263
+ | `--openclaw-token <token>` | Gateway authentication token (auto-stored after pairing) |
256
264
  | `--openclaw-config <path>` | Bridge config JSON (default: `~/.config/tescmd/bridge.json`) |
257
265
  | `--transport <type>` | MCP transport: `streamable-http` (default) or `stdio` |
258
266
  | `--port <num>` | MCP HTTP port (default: 8080) |
@@ -269,6 +277,7 @@ tescmd serve <VIN> --tailscale --openclaw <gateway_ws_url> --openclaw-token <gat
269
277
  | `--client-secret <secret>` | MCP OAuth client secret |
270
278
 
271
279
  #### Environment variables (alternative to flags):
280
+
272
281
  These can be set in `~/.config/tescmd/.env`:
273
282
  ```bash
274
283
  TESLA_CLIENT_ID=your-client-id
@@ -284,7 +293,7 @@ TESLA_COMMAND_PROTOCOL=auto # auto, signed, or unsigned
284
293
 
285
294
  ### Step 7: Verify the Connection
286
295
 
287
- Once the node is running, confirm it connected to the Gateway:
296
+ Once the node is running and paired, confirm it connected to the Gateway:
288
297
  ```bash
289
298
  openclaw tescmd status
290
299
  ```
@@ -292,392 +301,42 @@ openclaw tescmd status
292
301
  Or use the agent tool:
293
302
  - Call `tescmd_node_status` to check connection status
294
303
 
295
- If connected, you now have access to all 37 Tesla vehicle tools.
304
+ If connected, the plugin's tools are ready. Call `tescmd_help` for the full runtime reference including tool usage, workflows, and error handling.
296
305
 
297
306
  ---
298
307
 
299
- ## Agent Behavior Guide
300
-
301
- ### Session Start Protocol
302
-
303
- **Always call `tescmd_node_status` first** before invoking any vehicle command in a new conversation. If the node is offline, all other vehicle tools will fail. Suggest starting one:
304
- ```
305
- tescmd serve <VIN> --openclaw <gateway_url> --openclaw-token <token>
306
- ```
307
-
308
- ### Read Before Write
309
-
310
- Always check current state before sending write commands:
311
- - Before `tescmd_start_charge` → call `tescmd_get_charge_state` (is cable connected?)
312
- - Before `tescmd_climate_on` → call `tescmd_get_temperature` (what's the current temp?)
313
- - Before `tescmd_sentry_on` → call `tescmd_get_battery` (is battery too low for sentry?)
314
- - Before `tescmd_homelink` → call `tescmd_get_location` (need lat/lon for proximity check)
315
- - Before `tescmd_nav_supercharger` → call `tescmd_get_battery` (does the user actually need to charge?)
316
-
317
- ### Confirm Before Sensitive Actions
318
-
319
- These actions require explicit user confirmation before executing:
320
- - **`tescmd_unlock_doors`** — Grants physical access to the vehicle. Never unlock proactively.
321
- - **`tescmd_open_frunk`** — Cannot be closed remotely; must be physically pushed down.
322
- - **`tescmd_honk_horn`** — Audible alert in public; may disturb others.
323
- - **Starting charge** when battery is above 90% — User may not want to charge to 100% daily.
324
-
325
- ### Escalation Rules
326
-
327
- Escalate to the user (ask, don't act) when:
328
- - Any security-related action (unlock, sentry off) without explicit request
329
- - Node is offline and cannot auto-recover
330
- - Vehicle is asleep and the action would trigger a billable wake-up
331
- - Rate limits are hit — suggest waiting rather than retrying
332
- - Auth tokens are expired — user needs to re-authenticate manually
333
-
334
- ### Proactive Monitoring via Triggers
335
-
336
- When the user asks you to "keep an eye on" something, set up triggers instead of polling:
337
- - "Watch my battery" → `tescmd_battery_trigger` with operator='lt', value=20
338
- - "Alert if the cabin gets hot" → `tescmd_cabin_temp_trigger` with operator='gt', value=100
339
- - "Tell me if the car moves" → `tescmd_location_trigger` with operator='leave'
340
- - Then periodically call `tescmd_poll_triggers` to check for fired notifications.
341
-
342
- ### Battery-Aware Decision Making
343
-
344
- Before enabling battery-draining features:
345
- 1. Check battery level with `tescmd_get_battery`
346
- 2. If battery < 20%, warn the user before enabling Sentry Mode (~1-2%/hr drain)
347
- 3. If battery < 10%, strongly advise against Sentry Mode and suggest charging
348
- 4. Climate pre-conditioning uses battery too — mention this on low charge
349
-
350
- ---
351
-
352
- ## Tool Reference
353
-
354
- ### System & Meta Tools
355
-
356
- | Tool | Use When... | Parameters | Returns |
357
- |------|------------|------------|---------|
358
- | `tescmd_node_status` | **Session start**, diagnostics, before first command | _none_ | `{connected, node_id?, platform, commands_available?, last_seen?}` |
359
- | `tescmd_help` | Need detailed workflow recipes, error handling reference, or tescmd CLI commands | `topic?` (tools, workflows, triggers, errors, telemetry, setup, cli, all) | Markdown reference text |
360
- | `tescmd_run_command` | Need a command without a dedicated tool, or method name is dynamic | `method` (string), `params?` (object) | Varies by command |
361
-
362
- ### Reading Vehicle State (no side effects, safe to call anytime)
363
-
364
- | Tool | Use When... | Parameters | Returns |
365
- |------|------------|------------|---------|
366
- | `tescmd_get_location` | "Where is my car?", need GPS, proximity checks, before HomeLink | _none_ | `{latitude, longitude, heading, speed}` |
367
- | `tescmd_get_battery` | Charge level, range, "do I need to charge?", trip planning | _none_ | `{battery_level, range_miles}` |
368
- | `tescmd_get_speed` | "Is the car moving?", verify parked before commands | _none_ | `{speed_mph}` |
369
- | `tescmd_get_charge_state` | "Is it charging?", before start/stop charge | _none_ | `{charge_state}` — Charging, Complete, Stopped, Disconnected |
370
- | `tescmd_get_temperature` | "Is the car hot/cold?", before climate decisions | _none_ | `{inside_temp_c, outside_temp_c}` |
371
- | `tescmd_get_security` | "Is my car locked?", sentry status, before lock/unlock | _none_ | `{locked, sentry_mode}` |
372
-
373
- **Data source priority:** All reads check in-memory telemetry first (instant, zero cost when streaming). Falls back to Fleet API (may require vehicle wake, slower, cached 30s-1h TTL).
374
-
375
- ### Vehicle Control (side effects — confirm intent when appropriate)
376
-
377
- | Tool | Use When... | Parameters | Returns |
378
- |------|------------|------------|---------|
379
- | `tescmd_lock_doors` | User wants to lock; part of parking workflow | _none_ | `{result: true, reason: 'ok'}` |
380
- | `tescmd_unlock_doors` | **User explicitly asks** — always confirm first | _none_ | `{result: true, reason: 'ok'}` |
381
- | `tescmd_climate_on` | Precondition cabin, "warm up/cool down the car" | _none_ | `{result: true, reason: 'ok'}` |
382
- | `tescmd_climate_off` | Stop climate, save battery | _none_ | `{result: true, reason: 'ok'}` |
383
- | `tescmd_set_climate_temp` | "Set it to 72 degrees" — takes **Fahrenheit** | `temp` (number, °F) | `{result: true, reason: 'ok'}` |
384
- | `tescmd_start_charge` | Start charging — verify cable connected first | _none_ | `{result: true, reason: 'ok'}` |
385
- | `tescmd_stop_charge` | Stop an active charge session | _none_ | `{result: true, reason: 'ok'}` |
386
- | `tescmd_set_charge_limit` | "Charge to 80%" — 50-100 range | `percent` (50-100) | `{result: true, reason: 'ok'}` |
387
- | `tescmd_open_trunk` | Open/close rear trunk (toggles on power liftgate models) | _none_ | `{result: true, reason: 'ok'}` |
388
- | `tescmd_open_frunk` | Open front trunk — **cannot close remotely** | _none_ | `{result: true, reason: 'ok'}` |
389
- | `tescmd_flash_lights` | Locate vehicle, visual signal | _none_ | `{result: true, reason: 'ok'}` |
390
- | `tescmd_honk_horn` | Locate vehicle, audible signal | _none_ | `{result: true, reason: 'ok'}` |
391
- | `tescmd_sentry_on` | Camera monitoring — uses ~1-2% battery/hr | _none_ | `{result: true, reason: 'ok'}` |
392
- | `tescmd_sentry_off` | Stop camera monitoring, reduce battery drain | _none_ | `{result: true, reason: 'ok'}` |
393
-
394
- ### Navigation (send destinations to the vehicle)
395
-
396
- | Tool | Use When... | Parameters | Returns |
397
- |------|------------|------------|---------|
398
- | `tescmd_nav_send` | "Navigate to [place]", send address/place name | `address` (string) | Destination sent |
399
- | `tescmd_nav_gps` | Have exact lat/lon coordinates | `lat`, `lon`, `order?` (waypoint order) | Coordinates sent |
400
- | `tescmd_nav_supercharger` | "Find a Supercharger", low battery | _none_ | Routing to nearest |
401
- | `tescmd_nav_waypoints` | Multi-stop road trip with Google Place IDs | `waypoints` (comma-separated refIds) | Route sent |
402
- | `tescmd_homelink` | "Open the garage" — needs vehicle GPS | `lat`, `lon` (from `tescmd_get_location`) | HomeLink triggered |
403
-
404
- ### Triggers (telemetry subscriptions)
405
-
406
- | Tool | Use When... | Parameters | Returns |
407
- |------|------------|------------|---------|
408
- | `tescmd_create_trigger` | Subscribe to any telemetry condition | `field`, `operator`, `value?`, `once?`, `cooldown_seconds?` | `{id, field, operator}` |
409
- | `tescmd_battery_trigger` | Low battery alert shortcut | `operator`, `value?`, `once?`, `cooldown_seconds?` | `{id, field, operator}` |
410
- | `tescmd_cabin_temp_trigger` | Hot/cold cabin alert shortcut | `operator`, `value?`, `once?`, `cooldown_seconds?` | `{id, field, operator}` |
411
- | `tescmd_outside_temp_trigger` | Weather/freezing alert shortcut | `operator`, `value?`, `once?`, `cooldown_seconds?` | `{id, field, operator}` |
412
- | `tescmd_location_trigger` | Geofence (enter/leave area) | `operator` (enter/leave), `lat?`, `lon?`, `radius?`, `value?`, `once?`, `cooldown_seconds?` | `{id, field, operator}` |
413
- | `tescmd_list_triggers` | Check what triggers are active | _none_ | `{triggers: [{id, field, operator, value, once, cooldown_seconds}]}` |
414
- | `tescmd_poll_triggers` | Check for fired trigger notifications | _none_ | `{notifications: [{trigger_id, field, value, fired_at}]}` |
415
- | `tescmd_delete_trigger` | Remove a trigger no longer needed | `id` (string) | `{deleted, id}` |
416
-
417
- **Trigger fields:** Soc, BatteryLevel, InsideTemp, OutsideTemp, VehicleSpeed, ChargeState, DetailedChargeState, Locked, SentryMode, Location, Gear, EstBatteryRange
418
-
419
- **Trigger operators:** `lt`, `gt`, `lte`, `gte`, `eq`, `neq` (numeric); `changed` (any change); `enter`, `leave` (geofence)
420
-
421
- ---
422
-
423
- ## Workflows & Decision Trees
424
-
425
- ### Intent-Based Routing
426
-
427
- When the user mentions... → Start with:
428
-
429
- | User Intent | First Tool | Then... |
430
- |-------------|-----------|---------|
431
- | Charging | `tescmd_get_charge_state` | Assess → start/stop/set limit |
432
- | Temperature, comfort | `tescmd_get_temperature` | Assess → climate on/off/set temp |
433
- | Security, locking | `tescmd_get_security` | Assess → lock/unlock/sentry |
434
- | Location, directions | `tescmd_get_location` | Report or navigate |
435
- | Battery, range | `tescmd_get_battery` | Report or suggest charging |
436
- | "Watch the car" | `tescmd_lock_doors` | Then sentry + geofence trigger |
437
- | "Status", "how's the car" | `tescmd_get_battery` | Then charge_state + temperature + security + location |
438
-
439
- ### Workflow 1: "Is my car ready to go?"
440
-
441
- 1. `tescmd_get_battery` → check charge level and range
442
- 2. `tescmd_get_charge_state` → check if still charging
443
- 3. `tescmd_get_temperature` → check cabin comfort
444
- 4. `tescmd_get_security` → verify doors are locked
445
- 5. Summarize: battery %, range, charging status, cabin temp, lock state
446
-
447
- ### Workflow 2: "Precondition the cabin"
448
-
449
- 1. `tescmd_get_temperature` → check current cabin temp
450
- 2. `tescmd_climate_on` → start climate control
451
- 3. Optionally: `tescmd_set_climate_temp` → set specific temperature
452
- 4. Confirm: "Climate control is on, targeting X°F"
453
-
454
- ### Workflow 3: "Set up for overnight charging"
455
-
456
- **Pre-check:** Call `tescmd_get_charge_state` to verify cable is connected. If 'Disconnected', tell the user to plug in first.
457
-
458
- 1. `tescmd_set_charge_limit` → set to user's desired limit (typically 80%)
459
- 2. `tescmd_start_charge` → begin charging
460
- 3. Optionally: `tescmd_battery_trigger` → alert when charge reaches target
461
-
462
- ### Workflow 4: "Keep an eye on the car" (parking/security)
463
-
464
- 1. `tescmd_lock_doors` → ensure locked
465
- 2. `tescmd_sentry_on` → enable camera monitoring (warn about ~1-2%/hr battery drain)
466
- 3. `tescmd_location_trigger` → geofence alert if car moves
467
- 4. Confirm setup
468
-
469
- ### Workflow 5: "Navigate somewhere"
470
-
471
- 1. `tescmd_nav_send` → pass the address or place name
472
- 2. Or: `tescmd_nav_gps` → if you have exact lat/lon coordinates
473
- 3. For multi-stop: `tescmd_nav_waypoints` → comma-separated Place IDs
474
-
475
- ### Workflow 6: "Open the garage"
476
-
477
- 1. `tescmd_get_location` → get the vehicle's current GPS
478
- 2. `tescmd_homelink` → pass lat/lon to trigger HomeLink
479
-
480
- ### Workflow 7: "Find my car"
481
-
482
- 1. `tescmd_get_location` → get GPS coordinates
483
- 2. `tescmd_flash_lights` → visual signal
484
- 3. Optionally: `tescmd_honk_horn` → audible signal
485
-
486
- ### Workflow 8: "Hot car alert"
487
-
488
- 1. `tescmd_cabin_temp_trigger` with operator='gt', value=100 → alert over 100°F
489
- 2. When triggered: `tescmd_climate_on` → auto-start climate
490
- 3. `tescmd_get_temperature` → verify cooling
491
-
492
- ---
493
-
494
- ## Error Handling & Recovery
495
-
496
- ### Node Offline
497
-
498
- If commands fail with "no node connected" or similar:
499
- 1. Call `tescmd_node_status` to confirm the node is offline
500
- 2. Tell the user: "No tescmd node is connected. Start one with:"
501
- `tescmd serve <VIN> --openclaw <gateway_url> --openclaw-token <token>`
502
- 3. Do not retry vehicle commands — they will all fail until the node reconnects
503
-
504
- ### Vehicle Asleep
505
-
506
- Write commands auto-wake the vehicle, but this is a **billable API call**.
507
- - If a read returns `{pending: true}`, data is being fetched. Wait 3-5 seconds and retry.
508
- - If wake fails (rare), suggest the user wake from the Tesla app (free).
509
- - Avoid unnecessary write commands to sleeping vehicles — check state with reads first.
510
- - Reads from telemetry are instant and don't require a wake.
511
-
512
- ### Authentication Expired
513
-
514
- If commands fail with auth/token errors:
515
- - The tescmd node handles token refresh automatically.
516
- - If refresh fails, the user needs to re-authenticate: `tescmd auth login`
517
- - Check auth status: `tescmd auth status`
518
- - If persistent, re-run: `tescmd setup`
519
-
520
- ### Rate Limiting
521
-
522
- Tesla's API has rate limits (429 responses). tescmd caches read responses to minimize API calls:
523
- - Static data (specs, warranty): cached 1 hour
524
- - Fleet lists: cached 5 minutes
525
- - Standard queries: cached 1 minute
526
- - Location/speed: cached 30 seconds
527
- - If you get rate limit errors, **wait and avoid rapid repeated calls**. Do not retry immediately.
528
-
529
- ### Command Failures
530
-
531
- If a write command fails:
532
- - Check if the vehicle is in a valid state (e.g., charge cable connected for `charge.start`)
533
- - Check if the vehicle is online (call `tescmd_node_status`)
534
- - Try `tescmd_run_command` as a fallback — it accepts both dot-notation and Fleet API names
535
-
536
- ### Trigger Failures
537
-
538
- If triggers aren't working:
539
- - "Triggers not available" → Node started without telemetry. Restart with telemetry enabled (remove `--no-telemetry`).
540
- - Triggers require the telemetry stream to be active to detect condition changes.
541
- - Check `tescmd_list_triggers` to verify the trigger was created.
542
-
543
- ### Common Error Pattern Table
544
-
545
- | Error | Cause | Resolution |
546
- |-------|-------|------------|
547
- | "no node connected" | tescmd node is not running or disconnected | Start node: `tescmd serve <VIN> --openclaw <url> --openclaw-token <token>` |
548
- | "no handler configured" | Node has no dispatcher registered | Restart node with full serve command |
549
- | "unknown command: X" | Command not in the 34-command whitelist | Check tool reference or use `tescmd_run_command` |
550
- | "handler timeout (30s)" | Vehicle/API unresponsive | Retry after brief wait; vehicle may be in a dead zone |
551
- | `{pending: true}` | Data being fetched from API | Retry in 3-5 seconds — vehicle is waking or API is slow |
552
- | "Triggers not available" | Node started without telemetry | Restart with `--fields all` or remove `--no-telemetry` |
553
- | Auth/token errors | OAuth2 token expired and refresh failed | User runs `tescmd auth login` |
554
- | 429 / rate limit | Too many API calls | Wait 30-60 seconds; reduce call frequency |
555
- | "vehicle offline" | Vehicle has no cellular connectivity | User must move vehicle to an area with signal |
556
- | "charge cable not connected" | Attempted `charge.start` without cable | Tell user to plug in the charge cable |
557
- | "not signed in" | No Tesla account linked | User runs `tescmd setup` from scratch |
558
- | "command protocol mismatch" | Signed command failed, unsigned fallback needed | Set `TESLA_COMMAND_PROTOCOL=unsigned` in `.env` or pass flag |
559
-
560
- ---
561
-
562
- ## Cost & Impact Awareness
563
-
564
- ### Wake-Ups Are Billable
565
-
566
- Every write command to a sleeping vehicle triggers a wake-up API call. Tesla counts these. Minimize unnecessary wake-ups by:
567
- - Checking state with reads first (reads from telemetry don't wake)
568
- - Batching multiple write commands in one session rather than waking for each
569
- - Using triggers instead of polling for condition changes
570
-
571
- ### Sentry Mode Drains Battery
572
-
573
- Sentry Mode uses ~1-2% battery per hour. Before enabling:
574
- 1. Check battery with `tescmd_get_battery`
575
- 2. If below 20%, warn the user about the drain
576
- 3. If below 10%, strongly advise against it
577
-
578
- ### Telemetry Reads Are Free When Streaming
579
-
580
- When the telemetry stream is active, all read tools pull from the node's in-memory store — no API calls, no wake-ups, instant response. This is the optimal operating mode.
581
-
582
- When telemetry is offline (node started with `--no-telemetry`), reads fall back to the Fleet API which:
583
- - May require waking the vehicle
584
- - Are subject to rate limits
585
- - Are cached (30s-1h TTL depending on data type)
586
-
587
- ### Rate Limit Budget
588
-
589
- Tesla's Fleet API rate limits apply per-vehicle. Approximate budget:
590
- - ~200 requests/day for most endpoints
591
- - Location/speed endpoints have tighter limits
592
- - Cached reads don't count (served from node memory)
593
- - Write commands always hit the API
594
-
595
- ---
596
-
597
- ## Anti-Patterns
598
-
599
- | Don't Do This | Why | Do This Instead |
600
- |---------------|-----|-----------------|
601
- | Call `tescmd_start_charge` without checking charge state | Will fail if cable is not connected | Call `tescmd_get_charge_state` first |
602
- | Call `tescmd_unlock_doors` without user confirmation | Grants physical access — security risk | Always confirm: "Do you want me to unlock the doors?" |
603
- | Call `tescmd_open_frunk` without warning | Cannot be closed remotely | Warn: "The frunk can only be closed by hand. Open it?" |
604
- | Enable Sentry Mode on low battery (<20%) | Sentry drains ~1-2%/hr — could kill the battery | Check battery first, warn about drain |
605
- | Repeatedly wake a sleeping vehicle | Each wake is a billable API call | Batch commands, use telemetry for reads |
606
- | Ignore `{pending: true}` responses | Data is still loading | Wait 3-5 seconds and retry once |
607
- | Set temperature in Celsius | `tescmd_set_climate_temp` takes **Fahrenheit** | Convert to °F: `(C × 9/5) + 32` |
608
- | Read temperature expecting Fahrenheit | `tescmd_get_temperature` returns **Celsius** | Convert to °F if user expects it |
609
- | Poll in a loop instead of using triggers | Wastes API calls and may hit rate limits | Use `tescmd_create_trigger` + `tescmd_poll_triggers` |
610
- | Send multiple nav destinations rapidly | Only the last one takes effect | Send one destination, confirm it appeared |
611
- | Skip `tescmd_node_status` at session start | All commands will fail silently if node is offline | Always check connectivity first |
612
- | Assume `tescmd_get_location` returns before `tescmd_homelink` | HomeLink needs lat/lon from location | Chain: get_location → extract lat/lon → homelink |
613
-
614
- ---
615
-
616
- ## Troubleshooting
308
+ ## Troubleshooting Setup
617
309
 
618
310
  | Problem | Solution |
619
311
  |---------|----------|
620
- | "no node connected" | Start the node: `tescmd serve <VIN> --openclaw <url> --openclaw-token <token>` |
312
+ | "no node connected" | Start the node: `tescmd serve <VIN> --openclaw <url>` |
313
+ | Pairing request not visible | Check `openclaw nodes pending` — requests expire after 5 minutes. Restart the node to generate a new request. |
314
+ | Node connects then disconnects | Check Gateway URL. Run `tescmd auth status` to verify Tesla auth. |
621
315
  | Auth/token errors | Re-authenticate: `tescmd auth login` |
622
- | Vehicle asleep / pending responses | Write commands auto-wake. If wake fails, wake from Tesla app. Wait 3-5s and retry reads. |
623
- | Rate limit (429) | Wait 30-60s and reduce call frequency. Reads are cached (30s-1h TTL). |
624
- | "no handler configured" | Restart node with full `tescmd serve` command |
625
316
  | Setup wizard issues | Re-run `tescmd setup` or check https://github.com/oceanswave/tescmd |
626
- | Triggers not firing | Verify telemetry is enabled (no `--no-telemetry` flag). Check `tescmd_list_triggers`. |
627
- | Triggers say "not available" | Restart node with telemetry: remove `--no-telemetry` or add `--fields all` |
628
- | Commands return "unknown command" | Command not in whitelist. Use `tescmd_run_command` with the correct method name. |
629
- | Temperature values seem wrong | Reads return °C, set_climate_temp takes °F. Convert as needed. |
630
- | Frunk won't close | The frunk **cannot** be closed remotely. Must be physically pushed down. |
631
- | HomeLink won't trigger | Vehicle must be near the programmed device. Get location first, pass lat/lon. |
632
317
  | Plugin not loading | Run `openclaw plugins doctor`. Check `openclaw plugins list` for the plugin entry. |
633
- | Node connects then disconnects | Check Gateway URL/token. Run `tescmd auth status` to verify Tesla auth. |
318
+ | Triggers say "not available" | Restart node with telemetry: remove `--no-telemetry` or add `--fields all` |
634
319
 
635
320
  ---
636
321
 
637
- ## Telemetry Events
638
-
639
- The tescmd node streams these events to the Gateway via `req:agent` frames. Each event includes `event_type`, `source` (client_id), `vin`, `timestamp` (ISO 8601), and `data`.
640
-
641
- ### Data Events (11)
642
-
643
- | Event Type | Data Fields | Filter Threshold | Throttle |
644
- |------------|------------|-----------------|----------|
645
- | `location` | latitude, longitude, heading, speed | 50m movement | 1s |
646
- | `battery` | battery_level, range_miles | Soc: 5% / BatteryLevel: 1% / EstBatteryRange: 5mi | 10s / 10s / 30s |
647
- | `inside_temp` | inside_temp_f | 5°F change | 30s |
648
- | `outside_temp` | outside_temp_f | 5°F change | 30s |
649
- | `speed` | speed_mph | 5mph change | 2s |
650
- | `charge_started` | state | Immediate | None |
651
- | `charge_complete` | state | Immediate | None |
652
- | `charge_stopped` | state | Immediate | None |
653
- | `charge_state_changed` | state | Immediate | None |
654
- | `security_changed` | field (locked/sentrymode), value | Immediate | None |
655
- | `gear_changed` | gear (P/R/N/D) | Immediate | None |
656
-
657
- ### Lifecycle Events (3)
658
-
659
- | Event Type | Data Fields | When |
660
- |------------|------------|------|
661
- | `node.connected` | client_id | Node connects to Gateway |
662
- | `node.disconnecting` | client_id | Node is shutting down |
663
- | `trigger.fired` | trigger_id, field, value | A trigger condition was met |
664
-
665
- ### Tesla Telemetry Field → Event Mapping
666
-
667
- | Fleet Telemetry Field | OpenClaw Event |
668
- |----------------------|----------------|
669
- | Location | `location` |
670
- | Soc | `battery` |
671
- | BatteryLevel | `battery` |
672
- | EstBatteryRange | `battery` |
673
- | InsideTemp | `inside_temp` |
674
- | OutsideTemp | `outside_temp` |
675
- | VehicleSpeed | `speed` |
676
- | ChargeState | `charge_started` / `charge_complete` / `charge_stopped` |
677
- | DetailedChargeState | `charge_state_changed` |
678
- | Locked | `security_changed` |
679
- | SentryMode | `security_changed` |
680
- | Gear | `gear_changed` |
322
+ ## Configuration
323
+
324
+ Minimal — the tescmd node handles all vehicle-specific configuration.
325
+
326
+ ```json
327
+ {
328
+ "plugins": {
329
+ "entries": {
330
+ "openclaw-tescmd": {
331
+ "enabled": true,
332
+ "config": {
333
+ "debug": false
334
+ }
335
+ }
336
+ }
337
+ }
338
+ }
339
+ ```
681
340
 
682
341
  ---
683
342
 
@@ -694,44 +353,12 @@ openclaw tescmd events # List telemetry event types
694
353
  ### tescmd CLI Commands
695
354
 
696
355
  ```bash
697
- tescmd serve <VIN> --openclaw <url> --openclaw-token <token> # Start node
356
+ tescmd serve <VIN> --openclaw <url> # Start node (uses stored token)
357
+ tescmd serve <VIN> --openclaw <url> --openclaw-token <token> # Start node (explicit token)
698
358
  tescmd setup # Interactive setup wizard
699
359
  tescmd auth status # Check auth token status
700
360
  tescmd auth login # Re-authenticate with Tesla
701
361
  tescmd vehicle list # List vehicles on account
702
362
  tescmd vehicle info # Full vehicle data snapshot
703
- tescmd vehicle location # Get GPS coordinates
704
- tescmd charge status # Battery and charging state
705
- tescmd charge start --wake # Start charging (wakes vehicle)
706
- tescmd charge limit 80 # Set charge limit to 80%
707
- tescmd climate on --wake # Turn on climate
708
- tescmd climate set 72 --wake # Set temperature to 72°F
709
- tescmd climate status # Check climate state
710
- tescmd security lock --wake # Lock doors
711
- tescmd security status # Check lock/sentry state
712
- tescmd security flash --wake # Flash headlights
713
- tescmd security honk --wake # Honk horn
714
- tescmd security sentry on --wake # Enable Sentry Mode
715
- tescmd trunk open --wake # Open rear trunk
716
- tescmd trunk frunk --wake # Open frunk
717
363
  tescmd cache status # Check cache stats
718
364
  ```
719
-
720
- 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. Use `--format json` for structured output.
721
-
722
- ---
723
-
724
- ## Slash Commands
725
-
726
- Quick-action shortcuts users can type directly in chat. All require authentication.
727
-
728
- | Command | Arguments | Description |
729
- |---------|-----------|-------------|
730
- | `/battery` | _none_ | Check battery level and range |
731
- | `/charge` | `start`, `stop`, or a number (e.g. `80`) | Charge status, start/stop, or set limit |
732
- | `/climate` | `on`, `off`, or a number (e.g. `72`) | Temperature check, HVAC on/off, or set °F |
733
- | `/lock` | _none_ | Lock all doors |
734
- | `/unlock` | _none_ | Unlock all doors |
735
- | `/sentry` | `on` or `off` | Check or toggle Sentry Mode |
736
- | `/location` | _none_ | Get GPS location |
737
- | `/vehicle` | _none_ | Full status: battery + charge + temp + security + location |
package/tools/status.ts CHANGED
@@ -37,7 +37,7 @@ export function registerStatusTool(api: OpenClawPluginApi): void {
37
37
  ],
38
38
  details: {
39
39
  gatewayQuery: "node.status",
40
- platform: "tesla",
40
+ platform: "tescmd",
41
41
  },
42
42
  };
43
43
  },
package/tools/system.ts CHANGED
@@ -40,7 +40,7 @@ export function registerSystemTools(api: OpenClawPluginApi): void {
40
40
  description: "Command method name — dot-notation (door.lock) or snake_case (door_lock)",
41
41
  }),
42
42
  params: Type.Optional(
43
- Type.Record(Type.String(), Type.Unknown(), {
43
+ Type.Record(Type.String(), Type.Object({}), {
44
44
  description: "Optional parameters to pass to the command",
45
45
  }),
46
46
  ),
package/tools/triggers.ts CHANGED
@@ -110,11 +110,9 @@ export function registerTriggerTools(api: OpenClawPluginApi): void {
110
110
  parameters: Type.Object({
111
111
  field: stringEnum(TRIGGER_FIELDS),
112
112
  operator: stringEnum(TRIGGER_OPERATORS),
113
- value: Type.Optional(
114
- Type.Union([Type.Number(), Type.String(), Type.Boolean()], {
115
- description: "Threshold value for the condition",
116
- }),
117
- ),
113
+ value: Type.Any({
114
+ description: "Threshold value for the condition",
115
+ }),
118
116
  once: Type.Optional(
119
117
  Type.Boolean({
120
118
  description: "If true, the trigger fires only once then auto-deletes (default: false)",
@@ -287,7 +285,7 @@ export function registerTriggerTools(api: OpenClawPluginApi): void {
287
285
  Type.Number({ description: "Geofence radius in meters", minimum: 0 }),
288
286
  ),
289
287
  value: Type.Optional(
290
- Type.Unknown({ description: "Alternative: pass {lat, lon, radius} as value object" }),
288
+ Type.Object({}, { description: "Alternative: pass {lat, lon, radius} as value object" }),
291
289
  ),
292
290
  once: Type.Optional(Type.Boolean({ description: "Fire only once (default: false)" })),
293
291
  cooldown_seconds: Type.Optional(
@@ -36,17 +36,7 @@ declare module "openclaw/plugin-sdk" {
36
36
  name: string;
37
37
  }
38
38
 
39
- /** Platform definition for node registration. */
40
- interface PlatformDefinition {
41
- id: string;
42
- label: string;
43
- description: string;
44
- nodeRole: string;
45
- scopes: string[];
46
- commands: PlatformCommand[];
47
- }
48
-
49
- /** A whitelisted command for a platform. */
39
+ /** A command descriptor for a platform (used in plugin metadata and documentation). */
50
40
  interface PlatformCommand {
51
41
  method: string;
52
42
  label: string;
@@ -89,18 +79,37 @@ declare module "openclaw/plugin-sdk" {
89
79
 
90
80
  /** The main plugin API surface. */
91
81
  interface OpenClawPluginApi {
82
+ id: string;
83
+ name: string;
84
+ version: string;
85
+ description: string;
86
+ source: string;
87
+ config: Record<string, unknown>;
92
88
  pluginConfig: unknown;
89
+ runtime: unknown;
93
90
  logger: PluginLogger;
94
91
  registerTool(tool: ToolDefinition, options: ToolOptions): void;
92
+ registerHook(
93
+ events: string | string[],
94
+ handler: (...args: unknown[]) => unknown,
95
+ opts?: { name?: string; description?: string; register?: boolean },
96
+ ): void;
97
+ registerHttpHandler(handler: (req: unknown, res: unknown) => void): void;
98
+ registerHttpRoute(params: {
99
+ path: string;
100
+ handler: (req: unknown, res: unknown) => void;
101
+ }): void;
102
+ registerChannel(registration: unknown): void;
103
+ registerProvider(provider: { id: string; [key: string]: unknown }): void;
95
104
  registerCommand(command: CommandDefinition): void;
96
105
  registerCli(
97
106
  handler: (ctx: { program: unknown }) => void,
98
107
  options?: { commands: string[] },
99
108
  ): void;
100
109
  registerService(service: ServiceDefinition): void;
101
- registerPlatform(platform: PlatformDefinition): void;
102
110
  registerGatewayMethod(method: string, handler: (ctx: GatewayMethodContext) => void): void;
103
- on(event: string, handler: (...args: unknown[]) => unknown): void;
111
+ resolvePath(input: string): string;
112
+ on(event: string, handler: (...args: unknown[]) => unknown, opts?: { priority?: number }): void;
104
113
  }
105
114
 
106
115
  /** Helper to create TypeBox-compatible string enums. */
package/commands/cli.ts DELETED
@@ -1,74 +0,0 @@
1
- /**
2
- * CLI subcommands — terminal commands under `openclaw tescmd`.
3
- *
4
- * Registered commands:
5
- * openclaw tescmd status — show plugin and node connection status
6
- * openclaw tescmd commands — list all whitelisted commands
7
- * openclaw tescmd events — list all telemetry event types
8
- */
9
-
10
- import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
11
- import { ALL_COMMANDS } from "../platform.js";
12
- import { ALL_EVENT_TYPES, TELEMETRY_FIELD_MAP } from "../telemetry.js";
13
-
14
- interface CliCommand {
15
- command(name: string): CliCommand;
16
- description(desc: string): CliCommand;
17
- action(fn: () => void): CliCommand;
18
- }
19
-
20
- export function registerCliCommands(api: OpenClawPluginApi): void {
21
- api.registerCli(
22
- ({ program }: { program: unknown }) => {
23
- const tescmd = (program as CliCommand)
24
- .command("tescmd")
25
- .description("Tesla vehicle platform (tescmd)");
26
-
27
- tescmd
28
- .command("status")
29
- .description("Show plugin and node connection status")
30
- .action(() => {
31
- console.log("openclaw-tescmd plugin status");
32
- console.log("─".repeat(40));
33
- console.log(` Platform: tesla`);
34
- console.log(` Commands: ${ALL_COMMANDS.length} whitelisted`);
35
- console.log(` Events: ${ALL_EVENT_TYPES.length} telemetry types`);
36
- console.log(` Node: https://github.com/oceanswave/tescmd`);
37
- console.log(` Plugin: https://github.com/oceanswave/openclaw-tescmd`);
38
- });
39
-
40
- tescmd
41
- .command("commands")
42
- .description("List all whitelisted commands")
43
- .action(() => {
44
- console.log("Whitelisted commands:");
45
- console.log("");
46
- const reads = ALL_COMMANDS.filter((c) => c.direction === "read");
47
- const writes = ALL_COMMANDS.filter((c) => c.direction === "write");
48
- console.log(` Reads (${reads.length}):`);
49
- for (const cmd of reads) {
50
- console.log(` ${cmd.method.padEnd(22)} ${cmd.label}`);
51
- }
52
- console.log("");
53
- console.log(` Writes (${writes.length}):`);
54
- for (const cmd of writes) {
55
- console.log(` ${cmd.method.padEnd(22)} ${cmd.label}`);
56
- }
57
- });
58
-
59
- tescmd
60
- .command("events")
61
- .description("List all telemetry event types")
62
- .action(() => {
63
- console.log("Telemetry event types:");
64
- console.log("");
65
- for (const [field, eventType] of Object.entries(TELEMETRY_FIELD_MAP)) {
66
- console.log(` ${field.padEnd(22)} → ${eventType}`);
67
- }
68
- });
69
- },
70
- { commands: ["tescmd"] },
71
- );
72
-
73
- api.logger.info("Registered CLI commands: openclaw tescmd {status,commands,events}");
74
- }