@switchbot/openapi-cli 3.2.0 → 3.2.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.
Files changed (331) hide show
  1. package/dist/api/client.d.ts +31 -0
  2. package/dist/api/client.js +236 -0
  3. package/dist/api/client.js.map +1 -0
  4. package/dist/auth.d.ts +1 -0
  5. package/dist/auth.js +21 -0
  6. package/dist/auth.js.map +1 -0
  7. package/dist/commands/agent-bootstrap.d.ts +10 -0
  8. package/dist/commands/agent-bootstrap.js +200 -0
  9. package/dist/commands/agent-bootstrap.js.map +1 -0
  10. package/dist/commands/auth.d.ts +18 -0
  11. package/dist/commands/auth.js +355 -0
  12. package/dist/commands/auth.js.map +1 -0
  13. package/dist/commands/batch.d.ts +2 -0
  14. package/dist/commands/batch.js +414 -0
  15. package/dist/commands/batch.js.map +1 -0
  16. package/dist/commands/cache.d.ts +2 -0
  17. package/dist/commands/cache.js +127 -0
  18. package/dist/commands/cache.js.map +1 -0
  19. package/dist/commands/capabilities.d.ts +31 -0
  20. package/dist/commands/capabilities.js +383 -0
  21. package/dist/commands/capabilities.js.map +1 -0
  22. package/dist/commands/catalog.d.ts +2 -0
  23. package/dist/commands/catalog.js +360 -0
  24. package/dist/commands/catalog.js.map +1 -0
  25. package/dist/commands/completion.d.ts +2 -0
  26. package/dist/commands/completion.js +386 -0
  27. package/dist/commands/completion.js.map +1 -0
  28. package/dist/commands/config.d.ts +21 -0
  29. package/dist/commands/config.js +377 -0
  30. package/dist/commands/config.js.map +1 -0
  31. package/dist/commands/daemon.d.ts +2 -0
  32. package/dist/commands/daemon.js +411 -0
  33. package/dist/commands/daemon.js.map +1 -0
  34. package/dist/commands/device-meta.d.ts +2 -0
  35. package/dist/commands/device-meta.js +160 -0
  36. package/dist/commands/device-meta.js.map +1 -0
  37. package/dist/commands/devices.d.ts +2 -0
  38. package/dist/commands/devices.js +949 -0
  39. package/dist/commands/devices.js.map +1 -0
  40. package/dist/commands/doctor.d.ts +3 -0
  41. package/dist/commands/doctor.js +1016 -0
  42. package/dist/commands/doctor.js.map +1 -0
  43. package/dist/commands/events.d.ts +31 -0
  44. package/dist/commands/events.js +564 -0
  45. package/dist/commands/events.js.map +1 -0
  46. package/dist/commands/expand.d.ts +2 -0
  47. package/dist/commands/expand.js +131 -0
  48. package/dist/commands/expand.js.map +1 -0
  49. package/dist/commands/explain.d.ts +2 -0
  50. package/dist/commands/explain.js +140 -0
  51. package/dist/commands/explain.js.map +1 -0
  52. package/dist/commands/health.d.ts +8 -0
  53. package/dist/commands/health.js +114 -0
  54. package/dist/commands/health.js.map +1 -0
  55. package/dist/commands/history.d.ts +2 -0
  56. package/dist/commands/history.js +321 -0
  57. package/dist/commands/history.js.map +1 -0
  58. package/dist/commands/identity.d.ts +45 -0
  59. package/dist/commands/identity.js +60 -0
  60. package/dist/commands/identity.js.map +1 -0
  61. package/dist/commands/install.d.ts +20 -0
  62. package/dist/commands/install.js +247 -0
  63. package/dist/commands/install.js.map +1 -0
  64. package/dist/commands/mcp.d.ts +14 -0
  65. package/dist/commands/mcp.js +2018 -0
  66. package/dist/commands/mcp.js.map +1 -0
  67. package/dist/commands/plan.d.ts +51 -0
  68. package/dist/commands/plan.js +654 -0
  69. package/dist/commands/plan.js.map +1 -0
  70. package/dist/commands/policy.d.ts +24 -0
  71. package/dist/commands/policy.js +587 -0
  72. package/dist/commands/policy.js.map +1 -0
  73. package/dist/commands/quota.d.ts +2 -0
  74. package/dist/commands/quota.js +79 -0
  75. package/dist/commands/quota.js.map +1 -0
  76. package/dist/commands/rules.d.ts +2 -0
  77. package/dist/commands/rules.js +876 -0
  78. package/dist/commands/rules.js.map +1 -0
  79. package/dist/commands/scenes.d.ts +2 -0
  80. package/dist/commands/scenes.js +265 -0
  81. package/dist/commands/scenes.js.map +1 -0
  82. package/dist/commands/schema.d.ts +2 -0
  83. package/dist/commands/schema.js +185 -0
  84. package/dist/commands/schema.js.map +1 -0
  85. package/dist/commands/status-sync.d.ts +2 -0
  86. package/dist/commands/status-sync.js +132 -0
  87. package/dist/commands/status-sync.js.map +1 -0
  88. package/dist/commands/uninstall.d.ts +20 -0
  89. package/dist/commands/uninstall.js +238 -0
  90. package/dist/commands/uninstall.js.map +1 -0
  91. package/dist/commands/upgrade-check.d.ts +2 -0
  92. package/dist/commands/upgrade-check.js +107 -0
  93. package/dist/commands/upgrade-check.js.map +1 -0
  94. package/dist/commands/watch.d.ts +2 -0
  95. package/dist/commands/watch.js +195 -0
  96. package/dist/commands/watch.js.map +1 -0
  97. package/dist/commands/webhook.d.ts +2 -0
  98. package/dist/commands/webhook.js +183 -0
  99. package/dist/commands/webhook.js.map +1 -0
  100. package/dist/config.d.ts +57 -0
  101. package/dist/config.js +259 -0
  102. package/dist/config.js.map +1 -0
  103. package/dist/credentials/backends/file.d.ts +18 -0
  104. package/dist/credentials/backends/file.js +102 -0
  105. package/dist/credentials/backends/file.js.map +1 -0
  106. package/dist/credentials/backends/linux.d.ts +16 -0
  107. package/dist/credentials/backends/linux.js +130 -0
  108. package/dist/credentials/backends/linux.js.map +1 -0
  109. package/dist/credentials/backends/macos.d.ts +18 -0
  110. package/dist/credentials/backends/macos.js +130 -0
  111. package/dist/credentials/backends/macos.js.map +1 -0
  112. package/dist/credentials/backends/windows.d.ts +23 -0
  113. package/dist/credentials/backends/windows.js +216 -0
  114. package/dist/credentials/backends/windows.js.map +1 -0
  115. package/dist/credentials/keychain.d.ts +83 -0
  116. package/dist/credentials/keychain.js +89 -0
  117. package/dist/credentials/keychain.js.map +1 -0
  118. package/dist/credentials/prime.d.ts +32 -0
  119. package/dist/credentials/prime.js +53 -0
  120. package/dist/credentials/prime.js.map +1 -0
  121. package/dist/devices/cache.d.ts +79 -0
  122. package/dist/devices/cache.js +294 -0
  123. package/dist/devices/cache.js.map +1 -0
  124. package/dist/devices/catalog.d.ts +138 -0
  125. package/dist/devices/catalog.js +768 -0
  126. package/dist/devices/catalog.js.map +1 -0
  127. package/dist/devices/device-meta.d.ts +15 -0
  128. package/dist/devices/device-meta.js +57 -0
  129. package/dist/devices/device-meta.js.map +1 -0
  130. package/dist/devices/history-agg.d.ts +37 -0
  131. package/dist/devices/history-agg.js +139 -0
  132. package/dist/devices/history-agg.js.map +1 -0
  133. package/dist/devices/history-query.d.ts +45 -0
  134. package/dist/devices/history-query.js +182 -0
  135. package/dist/devices/history-query.js.map +1 -0
  136. package/dist/devices/param-validator.d.ts +40 -0
  137. package/dist/devices/param-validator.js +434 -0
  138. package/dist/devices/param-validator.js.map +1 -0
  139. package/dist/devices/resources.d.ts +74 -0
  140. package/dist/devices/resources.js +271 -0
  141. package/dist/devices/resources.js.map +1 -0
  142. package/dist/index.d.ts +1 -0
  143. package/dist/index.js +170 -56946
  144. package/dist/index.js.map +1 -0
  145. package/dist/install/default-steps.d.ts +66 -0
  146. package/dist/install/default-steps.js +258 -0
  147. package/dist/install/default-steps.js.map +1 -0
  148. package/dist/install/preflight.d.ts +60 -0
  149. package/dist/install/preflight.js +213 -0
  150. package/dist/install/preflight.js.map +1 -0
  151. package/dist/install/steps.d.ts +61 -0
  152. package/dist/install/steps.js +68 -0
  153. package/dist/install/steps.js.map +1 -0
  154. package/dist/lib/command-keywords.d.ts +5 -0
  155. package/dist/lib/command-keywords.js +18 -0
  156. package/dist/lib/command-keywords.js.map +1 -0
  157. package/dist/lib/daemon-state.d.ts +24 -0
  158. package/dist/lib/daemon-state.js +47 -0
  159. package/dist/lib/daemon-state.js.map +1 -0
  160. package/dist/lib/destructive-mode.d.ts +2 -0
  161. package/dist/lib/destructive-mode.js +13 -0
  162. package/dist/lib/destructive-mode.js.map +1 -0
  163. package/dist/lib/devices.d.ts +151 -0
  164. package/dist/lib/devices.js +383 -0
  165. package/dist/lib/devices.js.map +1 -0
  166. package/dist/lib/idempotency.d.ts +46 -0
  167. package/dist/lib/idempotency.js +107 -0
  168. package/dist/lib/idempotency.js.map +1 -0
  169. package/dist/lib/plan-store.d.ts +19 -0
  170. package/dist/lib/plan-store.js +69 -0
  171. package/dist/lib/plan-store.js.map +1 -0
  172. package/dist/lib/request-context.d.ts +7 -0
  173. package/dist/lib/request-context.js +13 -0
  174. package/dist/lib/request-context.js.map +1 -0
  175. package/dist/lib/scenes.d.ts +7 -0
  176. package/dist/lib/scenes.js +11 -0
  177. package/dist/lib/scenes.js.map +1 -0
  178. package/dist/logger.d.ts +4 -0
  179. package/dist/logger.js +17 -0
  180. package/dist/logger.js.map +1 -0
  181. package/dist/mcp/device-history.d.ts +36 -0
  182. package/dist/mcp/device-history.js +146 -0
  183. package/dist/mcp/device-history.js.map +1 -0
  184. package/dist/mcp/events-subscription.d.ts +45 -0
  185. package/dist/mcp/events-subscription.js +214 -0
  186. package/dist/mcp/events-subscription.js.map +1 -0
  187. package/dist/mqtt/client.d.ts +25 -0
  188. package/dist/mqtt/client.js +181 -0
  189. package/dist/mqtt/client.js.map +1 -0
  190. package/dist/mqtt/credential.d.ts +16 -0
  191. package/dist/mqtt/credential.js +31 -0
  192. package/dist/mqtt/credential.js.map +1 -0
  193. package/dist/policy/add-rule.d.ts +21 -0
  194. package/dist/policy/add-rule.js +125 -0
  195. package/dist/policy/add-rule.js.map +1 -0
  196. package/dist/policy/diff.d.ts +21 -0
  197. package/dist/policy/diff.js +92 -0
  198. package/dist/policy/diff.js.map +1 -0
  199. package/dist/policy/format.d.ts +6 -0
  200. package/dist/policy/format.js +58 -0
  201. package/dist/policy/format.js.map +1 -0
  202. package/dist/policy/load.d.ts +32 -0
  203. package/dist/policy/load.js +62 -0
  204. package/dist/policy/load.js.map +1 -0
  205. package/dist/policy/migrate.d.ts +21 -0
  206. package/dist/policy/migrate.js +68 -0
  207. package/dist/policy/migrate.js.map +1 -0
  208. package/dist/policy/schema.d.ts +5 -0
  209. package/dist/policy/schema.js +19 -0
  210. package/dist/policy/schema.js.map +1 -0
  211. package/dist/policy/validate.d.ts +19 -0
  212. package/dist/policy/validate.js +263 -0
  213. package/dist/policy/validate.js.map +1 -0
  214. package/dist/rules/action.d.ts +65 -0
  215. package/dist/rules/action.js +217 -0
  216. package/dist/rules/action.js.map +1 -0
  217. package/dist/rules/audit-query.d.ts +51 -0
  218. package/dist/rules/audit-query.js +90 -0
  219. package/dist/rules/audit-query.js.map +1 -0
  220. package/dist/rules/conflict-analyzer.d.ts +57 -0
  221. package/dist/rules/conflict-analyzer.js +215 -0
  222. package/dist/rules/conflict-analyzer.js.map +1 -0
  223. package/dist/rules/cron-scheduler.d.ts +62 -0
  224. package/dist/rules/cron-scheduler.js +187 -0
  225. package/dist/rules/cron-scheduler.js.map +1 -0
  226. package/dist/rules/destructive.d.ts +20 -0
  227. package/dist/rules/destructive.js +53 -0
  228. package/dist/rules/destructive.js.map +1 -0
  229. package/dist/rules/engine.d.ts +193 -0
  230. package/dist/rules/engine.js +758 -0
  231. package/dist/rules/engine.js.map +1 -0
  232. package/dist/rules/matcher.d.ts +56 -0
  233. package/dist/rules/matcher.js +231 -0
  234. package/dist/rules/matcher.js.map +1 -0
  235. package/dist/rules/pid-file.d.ts +43 -0
  236. package/dist/rules/pid-file.js +96 -0
  237. package/dist/rules/pid-file.js.map +1 -0
  238. package/dist/rules/quiet-hours.d.ts +26 -0
  239. package/dist/rules/quiet-hours.js +46 -0
  240. package/dist/rules/quiet-hours.js.map +1 -0
  241. package/dist/rules/suggest.d.ts +20 -0
  242. package/dist/rules/suggest.js +96 -0
  243. package/dist/rules/suggest.js.map +1 -0
  244. package/dist/rules/throttle.d.ts +61 -0
  245. package/dist/rules/throttle.js +117 -0
  246. package/dist/rules/throttle.js.map +1 -0
  247. package/dist/rules/types.d.ts +117 -0
  248. package/dist/rules/types.js +35 -0
  249. package/dist/rules/types.js.map +1 -0
  250. package/dist/rules/webhook-listener.d.ts +63 -0
  251. package/dist/rules/webhook-listener.js +224 -0
  252. package/dist/rules/webhook-listener.js.map +1 -0
  253. package/dist/rules/webhook-token.d.ts +50 -0
  254. package/dist/rules/webhook-token.js +91 -0
  255. package/dist/rules/webhook-token.js.map +1 -0
  256. package/dist/schema/field-aliases.d.ts +34 -0
  257. package/dist/schema/field-aliases.js +132 -0
  258. package/dist/schema/field-aliases.js.map +1 -0
  259. package/dist/sinks/dispatcher.d.ts +7 -0
  260. package/dist/sinks/dispatcher.js +13 -0
  261. package/dist/sinks/dispatcher.js.map +1 -0
  262. package/dist/sinks/file.d.ts +6 -0
  263. package/dist/sinks/file.js +20 -0
  264. package/dist/sinks/file.js.map +1 -0
  265. package/dist/sinks/format.d.ts +20 -0
  266. package/dist/sinks/format.js +57 -0
  267. package/dist/sinks/format.js.map +1 -0
  268. package/dist/sinks/homeassistant.d.ts +18 -0
  269. package/dist/sinks/homeassistant.js +45 -0
  270. package/dist/sinks/homeassistant.js.map +1 -0
  271. package/dist/sinks/openclaw.d.ts +13 -0
  272. package/dist/sinks/openclaw.js +34 -0
  273. package/dist/sinks/openclaw.js.map +1 -0
  274. package/dist/sinks/stdout.d.ts +4 -0
  275. package/dist/sinks/stdout.js +6 -0
  276. package/dist/sinks/stdout.js.map +1 -0
  277. package/dist/sinks/telegram.d.ts +11 -0
  278. package/dist/sinks/telegram.js +29 -0
  279. package/dist/sinks/telegram.js.map +1 -0
  280. package/dist/sinks/types.d.ts +13 -0
  281. package/dist/sinks/types.js +2 -0
  282. package/dist/sinks/types.js.map +1 -0
  283. package/dist/sinks/webhook.d.ts +6 -0
  284. package/dist/sinks/webhook.js +23 -0
  285. package/dist/sinks/webhook.js.map +1 -0
  286. package/dist/status-sync/manager.d.ts +48 -0
  287. package/dist/status-sync/manager.js +269 -0
  288. package/dist/status-sync/manager.js.map +1 -0
  289. package/dist/utils/arg-parsers.d.ts +16 -0
  290. package/dist/utils/arg-parsers.js +67 -0
  291. package/dist/utils/arg-parsers.js.map +1 -0
  292. package/dist/utils/audit.d.ts +69 -0
  293. package/dist/utils/audit.js +122 -0
  294. package/dist/utils/audit.js.map +1 -0
  295. package/dist/utils/filter.d.ts +81 -0
  296. package/dist/utils/filter.js +190 -0
  297. package/dist/utils/filter.js.map +1 -0
  298. package/dist/utils/flags.d.ts +72 -0
  299. package/dist/utils/flags.js +187 -0
  300. package/dist/utils/flags.js.map +1 -0
  301. package/dist/utils/format.d.ts +9 -0
  302. package/dist/utils/format.js +118 -0
  303. package/dist/utils/format.js.map +1 -0
  304. package/dist/utils/health.d.ts +48 -0
  305. package/dist/utils/health.js +102 -0
  306. package/dist/utils/health.js.map +1 -0
  307. package/dist/utils/help-json.d.ts +39 -0
  308. package/dist/utils/help-json.js +55 -0
  309. package/dist/utils/help-json.js.map +1 -0
  310. package/dist/utils/name-resolver.d.ts +26 -0
  311. package/dist/utils/name-resolver.js +138 -0
  312. package/dist/utils/name-resolver.js.map +1 -0
  313. package/dist/utils/output.d.ts +73 -0
  314. package/dist/utils/output.js +405 -0
  315. package/dist/utils/output.js.map +1 -0
  316. package/dist/utils/quota.d.ts +61 -0
  317. package/dist/utils/quota.js +228 -0
  318. package/dist/utils/quota.js.map +1 -0
  319. package/dist/utils/redact.d.ts +23 -0
  320. package/dist/utils/redact.js +69 -0
  321. package/dist/utils/redact.js.map +1 -0
  322. package/dist/utils/retry.d.ts +72 -0
  323. package/dist/utils/retry.js +141 -0
  324. package/dist/utils/retry.js.map +1 -0
  325. package/dist/utils/string.d.ts +2 -0
  326. package/dist/utils/string.js +23 -0
  327. package/dist/utils/string.js.map +1 -0
  328. package/dist/version.d.ts +2 -0
  329. package/dist/version.js +5 -0
  330. package/dist/version.js.map +1 -0
  331. package/package.json +2 -2
@@ -0,0 +1,31 @@
1
+ import { type AxiosInstance } from 'axios';
2
+ import { CircuitBreaker, CircuitOpenError } from '../utils/retry.js';
3
+ /** Thrown by the request interceptor when --dry-run intercepts a mutating call. */
4
+ export declare class DryRunSignal extends Error {
5
+ readonly method: string;
6
+ readonly url: string;
7
+ constructor(method: string, url: string);
8
+ }
9
+ /**
10
+ * Module-level circuit breaker for the SwitchBot API. Shared across all
11
+ * client instances in the process. Opens after 5 consecutive 5xx / network
12
+ * errors; resets to half-open after 60 s.
13
+ * Exported for health-check inspection.
14
+ */
15
+ export declare const apiCircuitBreaker: CircuitBreaker;
16
+ export { CircuitOpenError };
17
+ export declare function createClient(): AxiosInstance;
18
+ export interface ApiErrorMeta {
19
+ retryable?: boolean;
20
+ hint?: string;
21
+ retryAfterMs?: number;
22
+ transient?: boolean;
23
+ }
24
+ export declare class ApiError extends Error {
25
+ readonly code: number;
26
+ readonly retryable: boolean;
27
+ readonly hint?: string;
28
+ readonly retryAfterMs?: number;
29
+ readonly transient: boolean;
30
+ constructor(message: string, code: number, meta?: ApiErrorMeta);
31
+ }
@@ -0,0 +1,236 @@
1
+ import axios from 'axios';
2
+ import chalk from 'chalk';
3
+ import { buildAuthHeaders } from '../auth.js';
4
+ import { loadConfig } from '../config.js';
5
+ import { isVerbose, isDryRun, getTimeout, getRetryOn429, getRetryOn5xx, getBackoffStrategy, isQuotaDisabled, } from '../utils/flags.js';
6
+ import { nextRetryDelayMs, sleep, CircuitBreaker, CircuitOpenError } from '../utils/retry.js';
7
+ import { recordRequest, checkDailyCap } from '../utils/quota.js';
8
+ import { readProfileMeta } from '../config.js';
9
+ import { getActiveProfile } from '../lib/request-context.js';
10
+ import { redactHeaders, warnOnceIfUnsafe } from '../utils/redact.js';
11
+ class DailyCapExceededError extends Error {
12
+ cap;
13
+ total;
14
+ profile;
15
+ constructor(cap, total, profile) {
16
+ super(`Local daily cap reached: ${total}/${cap} SwitchBot API calls used today${profile ? ` for profile "${profile}"` : ''}. ` +
17
+ `Raise with: switchbot ${profile ? `--profile ${profile} ` : ''}config set-token --daily-cap <N>`);
18
+ this.cap = cap;
19
+ this.total = total;
20
+ this.profile = profile;
21
+ this.name = 'DailyCapExceededError';
22
+ }
23
+ }
24
+ const API_ERROR_MESSAGES = {
25
+ 151: 'Device type does not support this command',
26
+ 152: 'Device ID does not exist',
27
+ 160: 'This device does not support this command',
28
+ 161: 'Device offline (check Wi-Fi / Bluetooth connection)',
29
+ 171: 'Hub device offline (BLE devices require a Hub to communicate)',
30
+ 190: 'Device internal error — often an invalid deviceId, unsupported parameter, or device busy',
31
+ };
32
+ /** Thrown by the request interceptor when --dry-run intercepts a mutating call. */
33
+ export class DryRunSignal extends Error {
34
+ method;
35
+ url;
36
+ constructor(method, url) {
37
+ super('dry-run');
38
+ this.method = method;
39
+ this.url = url;
40
+ this.name = 'DryRunSignal';
41
+ }
42
+ }
43
+ /**
44
+ * Module-level circuit breaker for the SwitchBot API. Shared across all
45
+ * client instances in the process. Opens after 5 consecutive 5xx / network
46
+ * errors; resets to half-open after 60 s.
47
+ * Exported for health-check inspection.
48
+ */
49
+ export const apiCircuitBreaker = new CircuitBreaker('switchbot-api', {
50
+ failureThreshold: 5,
51
+ resetTimeoutMs: 60_000,
52
+ });
53
+ export { CircuitOpenError };
54
+ export function createClient() {
55
+ const { token, secret } = loadConfig();
56
+ const verbose = isVerbose();
57
+ const dryRun = isDryRun();
58
+ const maxRetries = getRetryOn429();
59
+ const max5xxRetries = getRetryOn5xx();
60
+ const backoff = getBackoffStrategy();
61
+ const quotaEnabled = !isQuotaDisabled();
62
+ const profile = getActiveProfile();
63
+ const profileMeta = readProfileMeta(profile);
64
+ const dailyCap = profileMeta?.limits?.dailyCap;
65
+ const client = axios.create({
66
+ baseURL: 'https://api.switch-bot.com',
67
+ timeout: getTimeout(),
68
+ });
69
+ // Inject auth headers; optionally log the request; short-circuit on --dry-run.
70
+ client.interceptors.request.use((config) => {
71
+ // Circuit breaker check — fail fast when the API is consistently down.
72
+ apiCircuitBreaker.checkAndAllow();
73
+ // Pre-flight cap check: refuse the call before it touches the network.
74
+ if (dailyCap) {
75
+ const check = checkDailyCap(dailyCap);
76
+ if (check.over) {
77
+ throw new DailyCapExceededError(dailyCap, check.total, profile);
78
+ }
79
+ }
80
+ const authHeaders = buildAuthHeaders(token, secret);
81
+ Object.assign(config.headers, authHeaders);
82
+ const method = (config.method ?? 'get').toUpperCase();
83
+ const url = `${config.baseURL ?? ''}${config.url ?? ''}`;
84
+ if (verbose) {
85
+ warnOnceIfUnsafe();
86
+ process.stderr.write(chalk.grey(`[verbose] ${method} ${url}\n`));
87
+ const { safe, redactedCount } = redactHeaders(config.headers);
88
+ process.stderr.write(chalk.grey(`[verbose] headers: ${JSON.stringify(safe)}\n`));
89
+ if (redactedCount > 0) {
90
+ process.stderr.write(chalk.grey(`[verbose] 🔒 ${redactedCount} sensitive header(s) redacted.\n`));
91
+ }
92
+ if (config.data !== undefined) {
93
+ process.stderr.write(chalk.grey(`[verbose] body: ${JSON.stringify(config.data)}\n`));
94
+ }
95
+ }
96
+ if (dryRun && method !== 'GET') {
97
+ process.stderr.write(chalk.yellow(`[dry-run] Would ${method} ${url}\n`));
98
+ if (config.data !== undefined) {
99
+ process.stderr.write(chalk.yellow(`[dry-run] body: ${JSON.stringify(config.data)}\n`));
100
+ }
101
+ throw new DryRunSignal(method, url);
102
+ }
103
+ // P8: record the quota attempt BEFORE the request is dispatched so
104
+ // failures (timeouts / DNS errors / 5xx / aborted) also count. Only
105
+ // pre-flight refusals (daily-cap, --dry-run) above skip recording
106
+ // since they never touch the network. Retries re-enter this
107
+ // interceptor and record again, which matches the SwitchBot API
108
+ // billing model (every dispatched HTTP request consumes quota).
109
+ if (quotaEnabled) {
110
+ recordRequest(method, url);
111
+ }
112
+ return config;
113
+ });
114
+ // Handle API-level errors (HTTP 200 but statusCode !== 100)
115
+ client.interceptors.response.use((response) => {
116
+ if (verbose) {
117
+ process.stderr.write(chalk.grey(`[verbose] ${response.status} ${response.statusText}\n`));
118
+ }
119
+ const data = response.data;
120
+ if (data.statusCode !== undefined && data.statusCode !== 100) {
121
+ const msg = API_ERROR_MESSAGES[data.statusCode] ??
122
+ data.message ??
123
+ `API error code: ${data.statusCode}`;
124
+ throw new ApiError(msg, data.statusCode);
125
+ }
126
+ // Successful HTTP response — record for circuit breaker.
127
+ apiCircuitBreaker.recordSuccess();
128
+ return response;
129
+ }, (error) => {
130
+ if (error instanceof DryRunSignal)
131
+ throw error;
132
+ if (axios.isAxiosError(error)) {
133
+ const config = error.config;
134
+ const method = (config?.method ?? 'get').toUpperCase();
135
+ const isIdempotentRead = method === 'GET';
136
+ if (error.code === 'ECONNABORTED' || error.code === 'ETIMEDOUT') {
137
+ // Retry idempotent GETs on timeout up to `max5xxRetries` times.
138
+ if (isIdempotentRead && config && max5xxRetries > 0) {
139
+ const attempt = config.__retryCount ?? 0;
140
+ if (attempt < max5xxRetries) {
141
+ config.__retryCount = attempt + 1;
142
+ const delay = nextRetryDelayMs(attempt, backoff, undefined);
143
+ if (verbose) {
144
+ process.stderr.write(chalk.grey(`[verbose] timeout — retry ${attempt + 1}/${max5xxRetries} in ${delay}ms\n`));
145
+ }
146
+ return sleep(delay).then(() => client.request(config));
147
+ }
148
+ }
149
+ // Network-level failure — record for circuit breaker.
150
+ apiCircuitBreaker.recordFailure();
151
+ throw new ApiError(`Request timed out after ${getTimeout()}ms (override with --timeout <ms>)`, 0, { transient: true, retryable: isIdempotentRead });
152
+ }
153
+ const status = error.response?.status;
154
+ // 429 → transparent retry with Retry-After / exponential backoff.
155
+ // Skipped when: no config (shouldn't happen for real axios errors),
156
+ // retries disabled, or we've already used our budget.
157
+ if (status === 429 && config && maxRetries > 0) {
158
+ const attempt = config.__retryCount ?? 0;
159
+ if (attempt < maxRetries) {
160
+ config.__retryCount = attempt + 1;
161
+ const delay = nextRetryDelayMs(attempt, backoff, error.response?.headers?.['retry-after']);
162
+ if (verbose) {
163
+ process.stderr.write(chalk.grey(`[verbose] 429 received — retry ${attempt + 1}/${maxRetries} in ${delay}ms\n`));
164
+ }
165
+ return sleep(delay).then(() => client.request(config));
166
+ }
167
+ }
168
+ // 502/503/504 on idempotent GETs → transparent retry. Mutating calls
169
+ // never auto-retry; use --idempotency-key for safe POST retries.
170
+ if (isIdempotentRead &&
171
+ status !== undefined &&
172
+ (status === 502 || status === 503 || status === 504) &&
173
+ config &&
174
+ max5xxRetries > 0) {
175
+ const attempt = config.__retryCount ?? 0;
176
+ if (attempt < max5xxRetries) {
177
+ config.__retryCount = attempt + 1;
178
+ const delay = nextRetryDelayMs(attempt, backoff, error.response?.headers?.['retry-after']);
179
+ if (verbose) {
180
+ process.stderr.write(chalk.grey(`[verbose] ${status} received — retry ${attempt + 1}/${max5xxRetries} in ${delay}ms\n`));
181
+ }
182
+ return sleep(delay).then(() => client.request(config));
183
+ }
184
+ }
185
+ // Record 5xx and network errors for circuit breaker. 4xx errors are
186
+ // expected business responses — don't count toward circuit threshold.
187
+ if (status === undefined || status >= 500) {
188
+ apiCircuitBreaker.recordFailure();
189
+ }
190
+ // P8: quota already recorded in the request interceptor before
191
+ // dispatch — no extra bookkeeping needed here on the error path.
192
+ // Timeouts, DNS failures, 5xx, and exhausted retries all counted
193
+ // when the attempt was first made.
194
+ if (status === 401) {
195
+ throw new ApiError('Authentication failed: invalid token or daily 10,000-request quota exceeded', 401, {
196
+ transient: false,
197
+ retryable: false,
198
+ hint: 'Run `switchbot config set-token <token> <secret>` to re-enter credentials, or `switchbot quota status` to check today\'s local count.'
199
+ });
200
+ }
201
+ if (status === 429) {
202
+ const retryAfter = error.response?.headers?.['retry-after'];
203
+ const retryAfterMs = nextRetryDelayMs(maxRetries - 1, backoff, retryAfter);
204
+ throw new ApiError('Request rate too high: daily 10,000-request quota exceeded (retries exhausted)', 429, {
205
+ retryable: true,
206
+ transient: true,
207
+ retryAfterMs,
208
+ hint: 'Use `switchbot quota status` to see today\'s usage; raise `--retry-on-429 <n>` for more retries.'
209
+ });
210
+ }
211
+ throw new ApiError(`HTTP ${status ?? '?'}: ${error.message}`, status ?? 0, {
212
+ retryable: status !== undefined && status >= 500,
213
+ transient: status !== undefined && (status >= 500 || status === 0) // 5xx, 0 = connection error
214
+ });
215
+ }
216
+ throw error;
217
+ });
218
+ return client;
219
+ }
220
+ export class ApiError extends Error {
221
+ code;
222
+ retryable;
223
+ hint;
224
+ retryAfterMs;
225
+ transient;
226
+ constructor(message, code, meta = {}) {
227
+ super(message);
228
+ this.code = code;
229
+ this.name = 'ApiError';
230
+ this.retryable = meta.retryable ?? false;
231
+ this.hint = meta.hint;
232
+ this.retryAfterMs = meta.retryAfterMs;
233
+ this.transient = meta.transient ?? false;
234
+ }
235
+ }
236
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
package/dist/auth.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function buildAuthHeaders(token: string, secret: string): Record<string, string>;
package/dist/auth.js ADDED
@@ -0,0 +1,21 @@
1
+ import crypto from 'node:crypto';
2
+ import { v4 as uuidv4 } from 'uuid';
3
+ export function buildAuthHeaders(token, secret) {
4
+ const t = String(Date.now()); // 13-digit millisecond timestamp
5
+ const nonce = uuidv4(); // unique per request
6
+ const data = token + t + nonce;
7
+ const sign = crypto
8
+ .createHmac('sha256', secret)
9
+ .update(data)
10
+ .digest('base64')
11
+ .toUpperCase(); // API requires uppercase
12
+ return {
13
+ Authorization: token,
14
+ t,
15
+ sign,
16
+ nonce,
17
+ src: 'OpenClaw',
18
+ 'Content-Type': 'application/json',
19
+ };
20
+ }
21
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AAEpC,MAAM,UAAU,gBAAgB,CAAC,KAAa,EAAE,MAAc;IAC5D,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAE,iCAAiC;IAChE,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,CAAQ,qBAAqB;IACpD,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC;IAC/B,MAAM,IAAI,GAAG,MAAM;SAChB,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC;SAC5B,MAAM,CAAC,IAAI,CAAC;SACZ,MAAM,CAAC,QAAQ,CAAC;SAChB,WAAW,EAAE,CAAC,CAAc,yBAAyB;IAExD,OAAO;QACL,aAAa,EAAE,KAAK;QACpB,CAAC;QACD,IAAI;QACJ,KAAK;QACL,GAAG,EAAE,UAAU;QACf,cAAc,EAAE,kBAAkB;KACnC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { Command } from 'commander';
2
+ /**
3
+ * Schema version of the agent-bootstrap payload. Must stay in lockstep
4
+ * with the catalog schema — bootstrap consumers (AI agents) reason about
5
+ * catalog-derived fields (safetyTier, destructive flag), so a drift
6
+ * between the two would silently break their assumptions. `doctor`
7
+ * fails the `catalog-schema` check when these differ.
8
+ */
9
+ export declare const AGENT_BOOTSTRAP_SCHEMA_VERSION = "1.0";
10
+ export declare function registerAgentBootstrapCommand(program: Command): void;
@@ -0,0 +1,200 @@
1
+ import { printJson, exitWithError } from '../utils/output.js';
2
+ import { loadCache } from '../devices/cache.js';
3
+ import { getEffectiveCatalog, deriveSafetyTier, CATALOG_SCHEMA_VERSION, } from '../devices/catalog.js';
4
+ import { readProfileMeta } from '../config.js';
5
+ import { todayUsage, DAILY_QUOTA } from '../utils/quota.js';
6
+ import { ALL_STRATEGIES } from '../utils/name-resolver.js';
7
+ import { IDENTITY } from './identity.js';
8
+ import { resolvePolicyPath, loadPolicyFile, PolicyFileNotFoundError, PolicyYamlParseError, } from '../policy/load.js';
9
+ import { validateLoadedPolicy } from '../policy/validate.js';
10
+ import { selectCredentialStore } from '../credentials/keychain.js';
11
+ import { VERSION as pkgVersion } from '../version.js';
12
+ /**
13
+ * Schema version of the agent-bootstrap payload. Must stay in lockstep
14
+ * with the catalog schema — bootstrap consumers (AI agents) reason about
15
+ * catalog-derived fields (safetyTier, destructive flag), so a drift
16
+ * between the two would silently break their assumptions. `doctor`
17
+ * fails the `catalog-schema` check when these differ.
18
+ */
19
+ export const AGENT_BOOTSTRAP_SCHEMA_VERSION = CATALOG_SCHEMA_VERSION;
20
+ const SAFETY_TIERS = {
21
+ read: 'No state mutation; safe to call freely.',
22
+ action: 'Mutates device/cloud state but reversible (turnOn, setColor).',
23
+ destructive: 'Hard to reverse / physical-world side effects (unlock). Requires confirmation.',
24
+ };
25
+ const QUICK_REFERENCE = {
26
+ discovery: ['devices list', 'devices describe <id>', 'devices status <id>'],
27
+ action: ['devices command <id> <cmd>', 'devices command --name <q> <cmd>', 'scenes execute <id>'],
28
+ safety: ['--dry-run', '--idempotency-key <k>', '--audit-log', '--no-quota'],
29
+ observability: ['doctor --json', 'quota status', 'cache status', 'events mqtt-tail'],
30
+ history: ['history range <id> --since 7d', 'history stats <id>'],
31
+ meta: ['devices meta set <id> --alias <name>', 'devices meta list', 'devices meta get <id>'],
32
+ policy: ['policy validate', 'policy new', 'policy migrate'],
33
+ auth: ['auth keychain describe', 'auth keychain migrate', 'auth keychain get'],
34
+ };
35
+ function readPolicyStatus() {
36
+ // Lightweight read — used by the bootstrap payload so agents know whether
37
+ // a policy file exists and is healthy without shelling out to
38
+ // `switchbot policy validate`. Parallel to `checkPolicy` in doctor but
39
+ // returns a more compact shape (no first-error drill-down; agents who
40
+ // want that run the dedicated command).
41
+ const policyPath = resolvePolicyPath();
42
+ try {
43
+ const loaded = loadPolicyFile(policyPath);
44
+ const result = validateLoadedPolicy(loaded);
45
+ return {
46
+ present: true,
47
+ valid: result.valid,
48
+ path: policyPath,
49
+ schemaVersion: result.schemaVersion,
50
+ errorCount: result.valid ? 0 : result.errors.length,
51
+ };
52
+ }
53
+ catch (err) {
54
+ if (err instanceof PolicyFileNotFoundError) {
55
+ return { present: false, valid: null, path: policyPath };
56
+ }
57
+ if (err instanceof PolicyYamlParseError) {
58
+ return { present: true, valid: false, path: policyPath, errorCount: 1 };
59
+ }
60
+ return { present: false, valid: null, path: policyPath };
61
+ }
62
+ }
63
+ async function readCredentialsBackend() {
64
+ try {
65
+ const store = await selectCredentialStore();
66
+ const desc = store.describe();
67
+ return { name: store.name, label: desc.backend, writable: desc.writable };
68
+ }
69
+ catch {
70
+ return { name: 'file', label: 'File (~/.switchbot/config.json)', writable: true };
71
+ }
72
+ }
73
+ export function registerAgentBootstrapCommand(program) {
74
+ program
75
+ .command('agent-bootstrap')
76
+ .description('Print a compact, aggregate JSON snapshot for agent onboarding — combines identity, cached devices, catalog summary, quota usage, and profile in a single call. Offline-safe; does not hit the API.')
77
+ .option('--compact', 'Emit an even smaller payload by dropping catalog descriptions and non-essential fields (target: <20 KB).')
78
+ .option('--sections <csv>', 'Comma-separated top-level sections to include (e.g. identity,devices,catalog). Omit for all sections.')
79
+ .addHelpText('after', `
80
+ Output is always JSON (this command ignores --format). It is a one-shot
81
+ orientation document for an agent/LLM to understand what's available without
82
+ spending quota. It reads from local cache (devices + quota + profile) and the
83
+ bundled catalog — no network calls.
84
+
85
+ For fresher device state, have the agent follow up with:
86
+ $ switchbot devices list --json # refreshes cache
87
+ $ switchbot devices status <id> --json
88
+
89
+ Examples:
90
+ $ switchbot agent-bootstrap --compact | wc -c # fit in agent context window
91
+ $ switchbot agent-bootstrap | jq '.devices | length'
92
+ $ switchbot agent-bootstrap --compact | jq '.quickReference'
93
+ `)
94
+ .action(async (opts) => {
95
+ const compact = Boolean(opts.compact);
96
+ const cache = loadCache();
97
+ const catalog = getEffectiveCatalog();
98
+ const usage = todayUsage();
99
+ const meta = readProfileMeta(undefined);
100
+ const credentialsBackend = await readCredentialsBackend();
101
+ const cachedDevices = cache
102
+ ? Object.entries(cache.devices).map(([id, d]) => ({
103
+ deviceId: id,
104
+ type: d.type,
105
+ name: d.name,
106
+ category: d.category,
107
+ roomName: d.roomName ?? null,
108
+ }))
109
+ : [];
110
+ const usedTypes = new Set(cachedDevices.map((d) => d.type.toLowerCase()));
111
+ const relevantCatalog = cachedDevices.length > 0
112
+ ? catalog.filter((e) => usedTypes.has(e.type.toLowerCase()) ||
113
+ (e.aliases ?? []).some((a) => usedTypes.has(a.toLowerCase())))
114
+ : catalog;
115
+ const catalogTypes = relevantCatalog.map((e) => {
116
+ if (compact) {
117
+ return {
118
+ type: e.type,
119
+ category: e.category,
120
+ role: e.role ?? null,
121
+ readOnly: e.readOnly ?? false,
122
+ commands: e.commands.map((c) => c.command),
123
+ statusFields: e.statusFields ?? [],
124
+ };
125
+ }
126
+ return {
127
+ type: e.type,
128
+ category: e.category,
129
+ role: e.role ?? null,
130
+ readOnly: e.readOnly ?? false,
131
+ commands: e.commands.map((c) => {
132
+ const tier = deriveSafetyTier(c, e);
133
+ return {
134
+ command: c.command,
135
+ parameter: c.parameter,
136
+ safetyTier: tier,
137
+ idempotent: Boolean(c.idempotent),
138
+ };
139
+ }),
140
+ statusFields: e.statusFields ?? [],
141
+ };
142
+ });
143
+ const payload = {
144
+ schemaVersion: AGENT_BOOTSTRAP_SCHEMA_VERSION,
145
+ generatedAt: new Date().toISOString(),
146
+ cliVersion: pkgVersion,
147
+ identity: IDENTITY,
148
+ quickReference: QUICK_REFERENCE,
149
+ safetyTiers: SAFETY_TIERS,
150
+ nameStrategies: [...ALL_STRATEGIES],
151
+ profile: meta
152
+ ? {
153
+ label: meta.label ?? null,
154
+ description: meta.description ?? null,
155
+ dailyCap: meta.limits?.dailyCap ?? null,
156
+ defaultFlags: meta.defaults?.flags ?? null,
157
+ }
158
+ : null,
159
+ quota: {
160
+ date: usage.date,
161
+ total: usage.total,
162
+ remaining: usage.remaining,
163
+ dailyLimit: DAILY_QUOTA,
164
+ },
165
+ policyStatus: readPolicyStatus(),
166
+ credentialsBackend,
167
+ devices: cachedDevices,
168
+ catalog: {
169
+ scope: cachedDevices.length > 0 ? 'used' : 'all',
170
+ types: catalogTypes,
171
+ },
172
+ // hints: empty array means no hints to report; always emitted, never null.
173
+ // An empty array signals "nothing to act on" — agents should not treat
174
+ // it as a disabled or missing field.
175
+ hints: cachedDevices.length === 0
176
+ ? ['Run `switchbot devices list` once to populate the device cache for richer bootstrap output.']
177
+ : [],
178
+ };
179
+ const VALID_SECTIONS = new Set([
180
+ 'schemaVersion', 'generatedAt', 'cliVersion', 'identity', 'quickReference',
181
+ 'safetyTiers', 'nameStrategies', 'profile', 'quota', 'policyStatus',
182
+ 'credentialsBackend', 'devices', 'catalog', 'hints',
183
+ ]);
184
+ let finalPayload = payload;
185
+ if (opts.sections) {
186
+ const requested = opts.sections.split(',').map((s) => s.trim()).filter(Boolean);
187
+ const unknown = requested.filter((s) => !VALID_SECTIONS.has(s));
188
+ if (unknown.length > 0) {
189
+ exitWithError({
190
+ code: 2,
191
+ kind: 'usage',
192
+ message: `Unknown section(s): ${unknown.join(', ')}. Valid sections: ${[...VALID_SECTIONS].join(', ')}.`,
193
+ });
194
+ }
195
+ finalPayload = Object.fromEntries(Object.entries(finalPayload).filter(([k]) => requested.includes(k)));
196
+ }
197
+ printJson(finalPayload);
198
+ });
199
+ }
200
+ //# sourceMappingURL=agent-bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-bootstrap.js","sourceRoot":"","sources":["../../src/commands/agent-bootstrap.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * `switchbot auth` command group (v2.9 preview, part of Phase 3A).
3
+ *
4
+ * Surfaces the credential store abstraction added in F1/F2 so users
5
+ * can introspect, write to, delete from, and migrate into the OS
6
+ * keychain without editing `~/.switchbot/config.json` by hand.
7
+ *
8
+ * All subcommands honour the active `--profile <name>` flag so a user
9
+ * who runs multiple accounts keeps the keychain entries cleanly
10
+ * partitioned.
11
+ *
12
+ * No credential material is ever printed in plain text. `get` emits
13
+ * a masked summary only; `set` reads via a TTY prompt (echo-off) or a
14
+ * file passed via `--stdin-file <path>`. `migrate` never touches the
15
+ * keychain unless the backend reports `writable: true`.
16
+ */
17
+ import { Command } from 'commander';
18
+ export declare function registerAuthCommand(program: Command): void;