@switchbot/openapi-cli 3.2.1 → 3.3.0

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 (332) hide show
  1. package/README.md +3 -1
  2. package/dist/index.js +57419 -170
  3. package/package.json +9 -5
  4. package/dist/api/client.d.ts +0 -31
  5. package/dist/api/client.js +0 -236
  6. package/dist/api/client.js.map +0 -1
  7. package/dist/auth.d.ts +0 -1
  8. package/dist/auth.js +0 -21
  9. package/dist/auth.js.map +0 -1
  10. package/dist/commands/agent-bootstrap.d.ts +0 -10
  11. package/dist/commands/agent-bootstrap.js +0 -200
  12. package/dist/commands/agent-bootstrap.js.map +0 -1
  13. package/dist/commands/auth.d.ts +0 -18
  14. package/dist/commands/auth.js +0 -355
  15. package/dist/commands/auth.js.map +0 -1
  16. package/dist/commands/batch.d.ts +0 -2
  17. package/dist/commands/batch.js +0 -414
  18. package/dist/commands/batch.js.map +0 -1
  19. package/dist/commands/cache.d.ts +0 -2
  20. package/dist/commands/cache.js +0 -127
  21. package/dist/commands/cache.js.map +0 -1
  22. package/dist/commands/capabilities.d.ts +0 -31
  23. package/dist/commands/capabilities.js +0 -383
  24. package/dist/commands/capabilities.js.map +0 -1
  25. package/dist/commands/catalog.d.ts +0 -2
  26. package/dist/commands/catalog.js +0 -360
  27. package/dist/commands/catalog.js.map +0 -1
  28. package/dist/commands/completion.d.ts +0 -2
  29. package/dist/commands/completion.js +0 -386
  30. package/dist/commands/completion.js.map +0 -1
  31. package/dist/commands/config.d.ts +0 -21
  32. package/dist/commands/config.js +0 -377
  33. package/dist/commands/config.js.map +0 -1
  34. package/dist/commands/daemon.d.ts +0 -2
  35. package/dist/commands/daemon.js +0 -411
  36. package/dist/commands/daemon.js.map +0 -1
  37. package/dist/commands/device-meta.d.ts +0 -2
  38. package/dist/commands/device-meta.js +0 -160
  39. package/dist/commands/device-meta.js.map +0 -1
  40. package/dist/commands/devices.d.ts +0 -2
  41. package/dist/commands/devices.js +0 -949
  42. package/dist/commands/devices.js.map +0 -1
  43. package/dist/commands/doctor.d.ts +0 -3
  44. package/dist/commands/doctor.js +0 -1016
  45. package/dist/commands/doctor.js.map +0 -1
  46. package/dist/commands/events.d.ts +0 -31
  47. package/dist/commands/events.js +0 -564
  48. package/dist/commands/events.js.map +0 -1
  49. package/dist/commands/expand.d.ts +0 -2
  50. package/dist/commands/expand.js +0 -131
  51. package/dist/commands/expand.js.map +0 -1
  52. package/dist/commands/explain.d.ts +0 -2
  53. package/dist/commands/explain.js +0 -140
  54. package/dist/commands/explain.js.map +0 -1
  55. package/dist/commands/health.d.ts +0 -8
  56. package/dist/commands/health.js +0 -114
  57. package/dist/commands/health.js.map +0 -1
  58. package/dist/commands/history.d.ts +0 -2
  59. package/dist/commands/history.js +0 -321
  60. package/dist/commands/history.js.map +0 -1
  61. package/dist/commands/identity.d.ts +0 -45
  62. package/dist/commands/identity.js +0 -60
  63. package/dist/commands/identity.js.map +0 -1
  64. package/dist/commands/install.d.ts +0 -20
  65. package/dist/commands/install.js +0 -247
  66. package/dist/commands/install.js.map +0 -1
  67. package/dist/commands/mcp.d.ts +0 -14
  68. package/dist/commands/mcp.js +0 -2018
  69. package/dist/commands/mcp.js.map +0 -1
  70. package/dist/commands/plan.d.ts +0 -51
  71. package/dist/commands/plan.js +0 -654
  72. package/dist/commands/plan.js.map +0 -1
  73. package/dist/commands/policy.d.ts +0 -24
  74. package/dist/commands/policy.js +0 -587
  75. package/dist/commands/policy.js.map +0 -1
  76. package/dist/commands/quota.d.ts +0 -2
  77. package/dist/commands/quota.js +0 -79
  78. package/dist/commands/quota.js.map +0 -1
  79. package/dist/commands/rules.d.ts +0 -2
  80. package/dist/commands/rules.js +0 -876
  81. package/dist/commands/rules.js.map +0 -1
  82. package/dist/commands/scenes.d.ts +0 -2
  83. package/dist/commands/scenes.js +0 -265
  84. package/dist/commands/scenes.js.map +0 -1
  85. package/dist/commands/schema.d.ts +0 -2
  86. package/dist/commands/schema.js +0 -185
  87. package/dist/commands/schema.js.map +0 -1
  88. package/dist/commands/status-sync.d.ts +0 -2
  89. package/dist/commands/status-sync.js +0 -132
  90. package/dist/commands/status-sync.js.map +0 -1
  91. package/dist/commands/uninstall.d.ts +0 -20
  92. package/dist/commands/uninstall.js +0 -238
  93. package/dist/commands/uninstall.js.map +0 -1
  94. package/dist/commands/upgrade-check.d.ts +0 -2
  95. package/dist/commands/upgrade-check.js +0 -107
  96. package/dist/commands/upgrade-check.js.map +0 -1
  97. package/dist/commands/watch.d.ts +0 -2
  98. package/dist/commands/watch.js +0 -195
  99. package/dist/commands/watch.js.map +0 -1
  100. package/dist/commands/webhook.d.ts +0 -2
  101. package/dist/commands/webhook.js +0 -183
  102. package/dist/commands/webhook.js.map +0 -1
  103. package/dist/config.d.ts +0 -57
  104. package/dist/config.js +0 -259
  105. package/dist/config.js.map +0 -1
  106. package/dist/credentials/backends/file.d.ts +0 -18
  107. package/dist/credentials/backends/file.js +0 -102
  108. package/dist/credentials/backends/file.js.map +0 -1
  109. package/dist/credentials/backends/linux.d.ts +0 -16
  110. package/dist/credentials/backends/linux.js +0 -130
  111. package/dist/credentials/backends/linux.js.map +0 -1
  112. package/dist/credentials/backends/macos.d.ts +0 -18
  113. package/dist/credentials/backends/macos.js +0 -130
  114. package/dist/credentials/backends/macos.js.map +0 -1
  115. package/dist/credentials/backends/windows.d.ts +0 -23
  116. package/dist/credentials/backends/windows.js +0 -216
  117. package/dist/credentials/backends/windows.js.map +0 -1
  118. package/dist/credentials/keychain.d.ts +0 -83
  119. package/dist/credentials/keychain.js +0 -89
  120. package/dist/credentials/keychain.js.map +0 -1
  121. package/dist/credentials/prime.d.ts +0 -32
  122. package/dist/credentials/prime.js +0 -53
  123. package/dist/credentials/prime.js.map +0 -1
  124. package/dist/devices/cache.d.ts +0 -79
  125. package/dist/devices/cache.js +0 -294
  126. package/dist/devices/cache.js.map +0 -1
  127. package/dist/devices/catalog.d.ts +0 -138
  128. package/dist/devices/catalog.js +0 -768
  129. package/dist/devices/catalog.js.map +0 -1
  130. package/dist/devices/device-meta.d.ts +0 -15
  131. package/dist/devices/device-meta.js +0 -57
  132. package/dist/devices/device-meta.js.map +0 -1
  133. package/dist/devices/history-agg.d.ts +0 -37
  134. package/dist/devices/history-agg.js +0 -139
  135. package/dist/devices/history-agg.js.map +0 -1
  136. package/dist/devices/history-query.d.ts +0 -45
  137. package/dist/devices/history-query.js +0 -182
  138. package/dist/devices/history-query.js.map +0 -1
  139. package/dist/devices/param-validator.d.ts +0 -40
  140. package/dist/devices/param-validator.js +0 -434
  141. package/dist/devices/param-validator.js.map +0 -1
  142. package/dist/devices/resources.d.ts +0 -74
  143. package/dist/devices/resources.js +0 -271
  144. package/dist/devices/resources.js.map +0 -1
  145. package/dist/index.d.ts +0 -1
  146. package/dist/index.js.map +0 -1
  147. package/dist/install/default-steps.d.ts +0 -66
  148. package/dist/install/default-steps.js +0 -258
  149. package/dist/install/default-steps.js.map +0 -1
  150. package/dist/install/preflight.d.ts +0 -60
  151. package/dist/install/preflight.js +0 -213
  152. package/dist/install/preflight.js.map +0 -1
  153. package/dist/install/steps.d.ts +0 -61
  154. package/dist/install/steps.js +0 -68
  155. package/dist/install/steps.js.map +0 -1
  156. package/dist/lib/command-keywords.d.ts +0 -5
  157. package/dist/lib/command-keywords.js +0 -18
  158. package/dist/lib/command-keywords.js.map +0 -1
  159. package/dist/lib/daemon-state.d.ts +0 -24
  160. package/dist/lib/daemon-state.js +0 -47
  161. package/dist/lib/daemon-state.js.map +0 -1
  162. package/dist/lib/destructive-mode.d.ts +0 -2
  163. package/dist/lib/destructive-mode.js +0 -13
  164. package/dist/lib/destructive-mode.js.map +0 -1
  165. package/dist/lib/devices.d.ts +0 -151
  166. package/dist/lib/devices.js +0 -383
  167. package/dist/lib/devices.js.map +0 -1
  168. package/dist/lib/idempotency.d.ts +0 -46
  169. package/dist/lib/idempotency.js +0 -107
  170. package/dist/lib/idempotency.js.map +0 -1
  171. package/dist/lib/plan-store.d.ts +0 -19
  172. package/dist/lib/plan-store.js +0 -69
  173. package/dist/lib/plan-store.js.map +0 -1
  174. package/dist/lib/request-context.d.ts +0 -7
  175. package/dist/lib/request-context.js +0 -13
  176. package/dist/lib/request-context.js.map +0 -1
  177. package/dist/lib/scenes.d.ts +0 -7
  178. package/dist/lib/scenes.js +0 -11
  179. package/dist/lib/scenes.js.map +0 -1
  180. package/dist/logger.d.ts +0 -4
  181. package/dist/logger.js +0 -17
  182. package/dist/logger.js.map +0 -1
  183. package/dist/mcp/device-history.d.ts +0 -36
  184. package/dist/mcp/device-history.js +0 -146
  185. package/dist/mcp/device-history.js.map +0 -1
  186. package/dist/mcp/events-subscription.d.ts +0 -45
  187. package/dist/mcp/events-subscription.js +0 -214
  188. package/dist/mcp/events-subscription.js.map +0 -1
  189. package/dist/mqtt/client.d.ts +0 -25
  190. package/dist/mqtt/client.js +0 -181
  191. package/dist/mqtt/client.js.map +0 -1
  192. package/dist/mqtt/credential.d.ts +0 -16
  193. package/dist/mqtt/credential.js +0 -31
  194. package/dist/mqtt/credential.js.map +0 -1
  195. package/dist/policy/add-rule.d.ts +0 -21
  196. package/dist/policy/add-rule.js +0 -125
  197. package/dist/policy/add-rule.js.map +0 -1
  198. package/dist/policy/diff.d.ts +0 -21
  199. package/dist/policy/diff.js +0 -92
  200. package/dist/policy/diff.js.map +0 -1
  201. package/dist/policy/format.d.ts +0 -6
  202. package/dist/policy/format.js +0 -58
  203. package/dist/policy/format.js.map +0 -1
  204. package/dist/policy/load.d.ts +0 -32
  205. package/dist/policy/load.js +0 -62
  206. package/dist/policy/load.js.map +0 -1
  207. package/dist/policy/migrate.d.ts +0 -21
  208. package/dist/policy/migrate.js +0 -68
  209. package/dist/policy/migrate.js.map +0 -1
  210. package/dist/policy/schema.d.ts +0 -5
  211. package/dist/policy/schema.js +0 -19
  212. package/dist/policy/schema.js.map +0 -1
  213. package/dist/policy/validate.d.ts +0 -19
  214. package/dist/policy/validate.js +0 -263
  215. package/dist/policy/validate.js.map +0 -1
  216. package/dist/rules/action.d.ts +0 -65
  217. package/dist/rules/action.js +0 -217
  218. package/dist/rules/action.js.map +0 -1
  219. package/dist/rules/audit-query.d.ts +0 -51
  220. package/dist/rules/audit-query.js +0 -90
  221. package/dist/rules/audit-query.js.map +0 -1
  222. package/dist/rules/conflict-analyzer.d.ts +0 -57
  223. package/dist/rules/conflict-analyzer.js +0 -215
  224. package/dist/rules/conflict-analyzer.js.map +0 -1
  225. package/dist/rules/cron-scheduler.d.ts +0 -62
  226. package/dist/rules/cron-scheduler.js +0 -187
  227. package/dist/rules/cron-scheduler.js.map +0 -1
  228. package/dist/rules/destructive.d.ts +0 -20
  229. package/dist/rules/destructive.js +0 -53
  230. package/dist/rules/destructive.js.map +0 -1
  231. package/dist/rules/engine.d.ts +0 -193
  232. package/dist/rules/engine.js +0 -758
  233. package/dist/rules/engine.js.map +0 -1
  234. package/dist/rules/matcher.d.ts +0 -56
  235. package/dist/rules/matcher.js +0 -231
  236. package/dist/rules/matcher.js.map +0 -1
  237. package/dist/rules/pid-file.d.ts +0 -43
  238. package/dist/rules/pid-file.js +0 -96
  239. package/dist/rules/pid-file.js.map +0 -1
  240. package/dist/rules/quiet-hours.d.ts +0 -26
  241. package/dist/rules/quiet-hours.js +0 -46
  242. package/dist/rules/quiet-hours.js.map +0 -1
  243. package/dist/rules/suggest.d.ts +0 -20
  244. package/dist/rules/suggest.js +0 -96
  245. package/dist/rules/suggest.js.map +0 -1
  246. package/dist/rules/throttle.d.ts +0 -61
  247. package/dist/rules/throttle.js +0 -117
  248. package/dist/rules/throttle.js.map +0 -1
  249. package/dist/rules/types.d.ts +0 -117
  250. package/dist/rules/types.js +0 -35
  251. package/dist/rules/types.js.map +0 -1
  252. package/dist/rules/webhook-listener.d.ts +0 -63
  253. package/dist/rules/webhook-listener.js +0 -224
  254. package/dist/rules/webhook-listener.js.map +0 -1
  255. package/dist/rules/webhook-token.d.ts +0 -50
  256. package/dist/rules/webhook-token.js +0 -91
  257. package/dist/rules/webhook-token.js.map +0 -1
  258. package/dist/schema/field-aliases.d.ts +0 -34
  259. package/dist/schema/field-aliases.js +0 -132
  260. package/dist/schema/field-aliases.js.map +0 -1
  261. package/dist/sinks/dispatcher.d.ts +0 -7
  262. package/dist/sinks/dispatcher.js +0 -13
  263. package/dist/sinks/dispatcher.js.map +0 -1
  264. package/dist/sinks/file.d.ts +0 -6
  265. package/dist/sinks/file.js +0 -20
  266. package/dist/sinks/file.js.map +0 -1
  267. package/dist/sinks/format.d.ts +0 -20
  268. package/dist/sinks/format.js +0 -57
  269. package/dist/sinks/format.js.map +0 -1
  270. package/dist/sinks/homeassistant.d.ts +0 -18
  271. package/dist/sinks/homeassistant.js +0 -45
  272. package/dist/sinks/homeassistant.js.map +0 -1
  273. package/dist/sinks/openclaw.d.ts +0 -13
  274. package/dist/sinks/openclaw.js +0 -34
  275. package/dist/sinks/openclaw.js.map +0 -1
  276. package/dist/sinks/stdout.d.ts +0 -4
  277. package/dist/sinks/stdout.js +0 -6
  278. package/dist/sinks/stdout.js.map +0 -1
  279. package/dist/sinks/telegram.d.ts +0 -11
  280. package/dist/sinks/telegram.js +0 -29
  281. package/dist/sinks/telegram.js.map +0 -1
  282. package/dist/sinks/types.d.ts +0 -13
  283. package/dist/sinks/types.js +0 -2
  284. package/dist/sinks/types.js.map +0 -1
  285. package/dist/sinks/webhook.d.ts +0 -6
  286. package/dist/sinks/webhook.js +0 -23
  287. package/dist/sinks/webhook.js.map +0 -1
  288. package/dist/status-sync/manager.d.ts +0 -48
  289. package/dist/status-sync/manager.js +0 -269
  290. package/dist/status-sync/manager.js.map +0 -1
  291. package/dist/utils/arg-parsers.d.ts +0 -16
  292. package/dist/utils/arg-parsers.js +0 -67
  293. package/dist/utils/arg-parsers.js.map +0 -1
  294. package/dist/utils/audit.d.ts +0 -69
  295. package/dist/utils/audit.js +0 -122
  296. package/dist/utils/audit.js.map +0 -1
  297. package/dist/utils/filter.d.ts +0 -81
  298. package/dist/utils/filter.js +0 -190
  299. package/dist/utils/filter.js.map +0 -1
  300. package/dist/utils/flags.d.ts +0 -72
  301. package/dist/utils/flags.js +0 -187
  302. package/dist/utils/flags.js.map +0 -1
  303. package/dist/utils/format.d.ts +0 -9
  304. package/dist/utils/format.js +0 -118
  305. package/dist/utils/format.js.map +0 -1
  306. package/dist/utils/health.d.ts +0 -48
  307. package/dist/utils/health.js +0 -102
  308. package/dist/utils/health.js.map +0 -1
  309. package/dist/utils/help-json.d.ts +0 -39
  310. package/dist/utils/help-json.js +0 -55
  311. package/dist/utils/help-json.js.map +0 -1
  312. package/dist/utils/name-resolver.d.ts +0 -26
  313. package/dist/utils/name-resolver.js +0 -138
  314. package/dist/utils/name-resolver.js.map +0 -1
  315. package/dist/utils/output.d.ts +0 -73
  316. package/dist/utils/output.js +0 -405
  317. package/dist/utils/output.js.map +0 -1
  318. package/dist/utils/quota.d.ts +0 -61
  319. package/dist/utils/quota.js +0 -228
  320. package/dist/utils/quota.js.map +0 -1
  321. package/dist/utils/redact.d.ts +0 -23
  322. package/dist/utils/redact.js +0 -69
  323. package/dist/utils/redact.js.map +0 -1
  324. package/dist/utils/retry.d.ts +0 -72
  325. package/dist/utils/retry.js +0 -141
  326. package/dist/utils/retry.js.map +0 -1
  327. package/dist/utils/string.d.ts +0 -2
  328. package/dist/utils/string.js +0 -23
  329. package/dist/utils/string.js.map +0 -1
  330. package/dist/version.d.ts +0 -2
  331. package/dist/version.js +0 -5
  332. package/dist/version.js.map +0 -1
@@ -1,131 +0,0 @@
1
- import { intArg, stringArg } from '../utils/arg-parsers.js';
2
- import { handleError, isJsonMode, printJson, UsageError, exitWithError } from '../utils/output.js';
3
- import { getCachedDevice } from '../devices/cache.js';
4
- import { executeCommand, isDestructiveCommand, getDestructiveReason } from '../lib/devices.js';
5
- import { isDryRun } from '../utils/flags.js';
6
- import { resolveDeviceId } from '../utils/name-resolver.js';
7
- import { DryRunSignal } from '../api/client.js';
8
- import { buildAcSetAll, buildCurtainSetPosition, buildBlindTiltSetPosition, buildRelaySetMode, } from '../devices/param-validator.js';
9
- // ---- Registration ----------------------------------------------------------
10
- export function registerExpandCommand(devices) {
11
- devices
12
- .command('expand')
13
- .description('Send a command with semantic flags instead of raw positional parameters')
14
- .argument('[deviceId]', 'Target device ID from "devices list" (or use --name)')
15
- .argument('[command]', 'Command name: setAll (AC), setPosition (Curtain/Blind Tilt), setMode (Relay Switch 2)')
16
- .option('--name <query>', 'Resolve device by fuzzy name instead of deviceId', stringArg('--name'))
17
- .option('--temp <celsius>', 'AC setAll: temperature in Celsius (16-30)', intArg('--temp', { min: 16, max: 30 }))
18
- .option('--mode <mode>', 'AC: auto|cool|dry|fan|heat Curtain: default|performance|silent Relay: toggle|edge|detached|momentary', stringArg('--mode'))
19
- .option('--fan <speed>', 'AC setAll: fan speed auto|low|mid|high', stringArg('--fan'))
20
- .option('--power <state>', 'AC setAll: on|off', stringArg('--power'))
21
- .option('--position <percent>', 'Curtain setPosition: 0-100 (0=open, 100=closed)', intArg('--position', { min: 0, max: 100 }))
22
- .option('--direction <dir>', 'Blind Tilt setPosition: up|down', stringArg('--direction'))
23
- .option('--angle <percent>', 'Blind Tilt setPosition: 0-100 (0=closed, 100=open)', intArg('--angle', { min: 0, max: 100 }))
24
- .option('--channel <n>', 'Relay Switch 2 setMode: channel 1 or 2', intArg('--channel', { min: 1, max: 2 }))
25
- .option('--yes', 'Confirm destructive commands')
26
- .addHelpText('after', `
27
- Translates semantic flags into the wire parameter format, then sends the command.
28
-
29
- Supported expansions:
30
-
31
- Air Conditioner — setAll
32
- --temp 26 --mode cool --fan low --power on → "26,2,2,on"
33
- --mode values: auto | cool | dry | fan | heat
34
- --fan values: auto | low | mid | high
35
-
36
- Curtain / Curtain 3 — setPosition
37
- --position 50 [--mode silent] → "0,1,50"
38
- --mode values: default (ff) | performance (0) | silent (1)
39
-
40
- Blind Tilt — setPosition
41
- --direction up --angle 50 → "up;50"
42
-
43
- Relay Switch 2PM — setMode
44
- --channel 1 --mode edge → "1;1"
45
- --mode values: toggle (0) | edge (1) | detached (2) | momentary (3)
46
-
47
- Examples:
48
- $ switchbot devices expand <acId> setAll --temp 26 --mode cool --fan low --power on
49
- $ switchbot devices expand <curtainId> setPosition --position 50 --mode silent
50
- $ switchbot devices expand <blindId> setPosition --direction up --angle 50
51
- $ switchbot devices expand <relayId> setMode --channel 1 --mode edge
52
- $ switchbot devices expand <acId> setAll --temp 22 --mode heat --fan auto --power on --dry-run
53
- $ switchbot devices expand --name "Living Room AC" setAll --temp 26 --mode cool --fan low --power on
54
- `)
55
- .action(async (deviceIdArg, commandArg, options) => {
56
- let deviceId = '';
57
- let command = '';
58
- try {
59
- // When --name is provided, Commander assigns the first positional to deviceIdArg
60
- // and leaves commandArg undefined. Detect and shift.
61
- let effectiveDeviceIdArg = deviceIdArg;
62
- let effectiveCommand = commandArg;
63
- if (options.name && deviceIdArg && !commandArg) {
64
- effectiveCommand = deviceIdArg;
65
- effectiveDeviceIdArg = undefined;
66
- }
67
- deviceId = resolveDeviceId(effectiveDeviceIdArg, options.name);
68
- if (!effectiveCommand)
69
- throw new UsageError('A command argument is required (setAll, setPosition, setMode).');
70
- command = effectiveCommand;
71
- const cached = getCachedDevice(deviceId);
72
- const deviceType = cached?.type ?? '';
73
- let parameter;
74
- if (command === 'setAll') {
75
- parameter = buildAcSetAll(options);
76
- }
77
- else if (command === 'setPosition') {
78
- if (!cached) {
79
- throw new UsageError(`Device ${deviceId} is not in the local cache — run 'switchbot devices list' first so 'expand' knows whether this is a Curtain or a Blind Tilt.`);
80
- }
81
- const isBlind = deviceType.startsWith('Blind Tilt');
82
- parameter = isBlind
83
- ? buildBlindTiltSetPosition(options)
84
- : buildCurtainSetPosition(options);
85
- }
86
- else if (command === 'setMode' && deviceType.startsWith('Relay Switch')) {
87
- parameter = buildRelaySetMode(options);
88
- }
89
- else {
90
- throw new UsageError(`'expand' does not support "${command}" for device type "${deviceType || 'unknown'}". ` +
91
- `Use 'switchbot devices command' to send raw parameters instead.`);
92
- }
93
- if (!options.yes && !isDryRun() && isDestructiveCommand(deviceType, command, 'command')) {
94
- const reason = getDestructiveReason(deviceType, command, 'command');
95
- exitWithError({
96
- code: 2,
97
- kind: 'guard',
98
- message: `"${command}" on ${deviceType || 'device'} is destructive and requires --yes.`,
99
- hint: reason ? `Re-run with --yes. Reason: ${reason}` : 'Re-run with --yes to confirm.',
100
- });
101
- }
102
- const body = await executeCommand(deviceId, command, parameter, 'command');
103
- const isIr = cached?.category === 'ir';
104
- if (isJsonMode()) {
105
- const result = { ok: true, command, deviceId, parameter };
106
- if (isIr)
107
- result.subKind = 'ir-no-feedback';
108
- if (body && typeof body === 'object' && Object.keys(body).length > 0)
109
- result.response = body;
110
- printJson(result);
111
- return;
112
- }
113
- console.log(`✓ Command sent: ${command} (${parameter})`);
114
- if (isIr)
115
- console.log(' Note: IR command sent — no device confirmation (fire-and-forget).');
116
- }
117
- catch (error) {
118
- if (error instanceof DryRunSignal) {
119
- if (isJsonMode()) {
120
- printJson({ ok: true, dryRun: true, command, deviceId });
121
- }
122
- else {
123
- console.log(`◦ dry-run: ${command} would be sent to ${deviceId}`);
124
- }
125
- return;
126
- }
127
- handleError(error);
128
- }
129
- });
130
- }
131
- //# sourceMappingURL=expand.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"expand.js","sourceRoot":"","sources":["../../src/commands/expand.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function registerExplainCommand(devices: Command): void;
@@ -1,140 +0,0 @@
1
- import { printJson, isJsonMode, handleError } from '../utils/output.js';
2
- import { describeDevice, fetchDeviceList, } from '../lib/devices.js';
3
- function deviceName(d) {
4
- return d.deviceName;
5
- }
6
- export function registerExplainCommand(devices) {
7
- devices
8
- .command('explain')
9
- .description('One-shot device summary: metadata + capabilities + live status + children (for Hubs)')
10
- .argument('<deviceId>', 'Device ID to explain')
11
- .option('--no-live', 'Skip the live status API call (catalog-only output)')
12
- .addHelpText('after', `
13
- 'explain' is the agent-friendly sibling of 'describe'. It combines:
14
- - metadata (id, name, type, category, role)
15
- - live status (unless --no-live)
16
- - commands with idempotent/destructive flags
17
- - children (for Hub devices: IR remotes bound to this hub)
18
- - suggested actions (pre-baked common usages)
19
- - warnings (deprecated types, missing cloud service, etc.)
20
-
21
- Examples:
22
- $ switchbot devices explain <id>
23
- $ switchbot --json devices explain <id> | jq '.commands[] | select(.destructive)'
24
- $ switchbot devices explain <id> --no-live
25
- `)
26
- .action(async (deviceId, options) => {
27
- try {
28
- const wantLive = options.live !== false;
29
- const desc = await describeDevice(deviceId, { live: wantLive });
30
- const warnings = [];
31
- if (desc.isPhysical && !desc.device.enableCloudService) {
32
- warnings.push('Cloud service disabled on this device — commands will fail.');
33
- }
34
- if (!desc.catalog) {
35
- warnings.push(`No catalog entry for type "${desc.typeName}". Commands cannot be validated offline.`);
36
- }
37
- let children = [];
38
- if (desc.catalog?.role === 'hub') {
39
- const body = await fetchDeviceList();
40
- children = body.infraredRemoteList
41
- .filter((ir) => ir.hubDeviceId === deviceId)
42
- .map((ir) => ({ deviceId: ir.deviceId, name: ir.deviceName, type: ir.remoteType }));
43
- }
44
- const caps = desc.capabilities;
45
- const commands = caps && 'commands' in caps
46
- ? caps.commands.map((c) => {
47
- const tier = c.safetyTier;
48
- return {
49
- command: c.command,
50
- parameter: c.parameter,
51
- idempotent: c.idempotent,
52
- ...(tier ? { safetyTier: tier } : {}),
53
- };
54
- })
55
- : [];
56
- const statusFields = caps && 'statusFields' in caps ? caps.statusFields : [];
57
- const liveStatus = caps && 'liveStatus' in caps ? caps.liveStatus : undefined;
58
- const location = desc.isPhysical
59
- ? {
60
- family: desc.device.familyName,
61
- room: desc.device.roomName ?? undefined,
62
- }
63
- : desc.inheritedLocation
64
- ? { family: desc.inheritedLocation.family, room: desc.inheritedLocation.room }
65
- : undefined;
66
- const result = {
67
- deviceId,
68
- type: desc.typeName,
69
- category: desc.isPhysical ? 'physical' : 'ir',
70
- name: deviceName(desc.device),
71
- role: desc.catalog?.role ?? null,
72
- readOnly: desc.catalog?.readOnly ?? false,
73
- location,
74
- liveStatus,
75
- commands,
76
- statusFields,
77
- children,
78
- suggestedActions: desc.suggestedActions,
79
- warnings,
80
- };
81
- if (isJsonMode()) {
82
- printJson(result);
83
- return;
84
- }
85
- printHuman(result);
86
- }
87
- catch (err) {
88
- handleError(err);
89
- }
90
- });
91
- }
92
- function printHuman(r) {
93
- console.log(`# ${r.name} (${r.deviceId})`);
94
- console.log(`type: ${r.type} [${r.category}${r.role ? ', ' + r.role : ''}${r.readOnly ? ', read-only' : ''}]`);
95
- if (r.location?.family || r.location?.room) {
96
- const loc = [r.location?.family, r.location?.room].filter(Boolean).join(' / ');
97
- console.log(`location: ${loc}`);
98
- }
99
- if (r.warnings.length) {
100
- console.log('warnings:');
101
- for (const w of r.warnings)
102
- console.log(` ! ${w}`);
103
- }
104
- if (r.liveStatus && !('error' in r.liveStatus)) {
105
- console.log('live status:');
106
- for (const [k, v] of Object.entries(r.liveStatus)) {
107
- console.log(` ${k}: ${JSON.stringify(v)}`);
108
- }
109
- }
110
- else if (r.liveStatus && 'error' in r.liveStatus) {
111
- console.log(`live status: error — ${r.liveStatus.error}`);
112
- }
113
- if (r.commands.length) {
114
- console.log('commands:');
115
- for (const c of r.commands) {
116
- const flags = [c.idempotent && 'idempotent', c.safetyTier === 'destructive' && 'destructive']
117
- .filter(Boolean)
118
- .join(', ');
119
- const suffix = flags ? ` [${flags}]` : '';
120
- console.log(` ${c.command}${c.parameter !== '—' ? ` <${c.parameter}>` : ''}${suffix}`);
121
- }
122
- }
123
- if (r.statusFields.length) {
124
- console.log(`status fields: ${r.statusFields.join(', ')}`);
125
- }
126
- if (r.children.length) {
127
- console.log(`children (${r.children.length}):`);
128
- for (const c of r.children) {
129
- console.log(` ${c.deviceId} ${c.name} [${c.type}]`);
130
- }
131
- }
132
- if (r.suggestedActions.length) {
133
- console.log('suggested:');
134
- for (const s of r.suggestedActions) {
135
- const param = s.parameter ? ` ${s.parameter}` : '';
136
- console.log(` ${s.description}: ${s.command}${param}`);
137
- }
138
- }
139
- }
140
- //# sourceMappingURL=explain.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"explain.js","sourceRoot":"","sources":["../../src/commands/explain.ts"],"names":[],"mappings":"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"}
@@ -1,8 +0,0 @@
1
- import http from 'node:http';
2
- import { Command } from 'commander';
3
- /**
4
- * Create an HTTP request handler for the health endpoints. Exposed separately
5
- * so integration tests can call it directly without binding a port.
6
- */
7
- export declare function createHealthHandler(auditLogPath?: string): http.RequestListener;
8
- export declare function registerHealthCommand(program: Command): void;
@@ -1,114 +0,0 @@
1
- import http from 'node:http';
2
- import { printJson, isJsonMode, printTable, handleError } from '../utils/output.js';
3
- import { getHealthReport, toPrometheusText } from '../utils/health.js';
4
- import { intArg } from '../utils/arg-parsers.js';
5
- const HEALTHZ_SCHEMA_VERSION = '1.1';
6
- /**
7
- * Create an HTTP request handler for the health endpoints. Exposed separately
8
- * so integration tests can call it directly without binding a port.
9
- */
10
- export function createHealthHandler(auditLogPath) {
11
- return (req, res) => {
12
- const url = (req.url ?? '/').split('?')[0];
13
- if (url === '/healthz') {
14
- const report = getHealthReport(auditLogPath);
15
- const statusCode = report.overall === 'down' ? 503 : 200;
16
- res.writeHead(statusCode, { 'Content-Type': 'application/json' });
17
- res.end(JSON.stringify({ schemaVersion: HEALTHZ_SCHEMA_VERSION, data: report }));
18
- }
19
- else if (url === '/metrics') {
20
- const report = getHealthReport(auditLogPath);
21
- res.writeHead(200, { 'Content-Type': 'text/plain; version=0.0.4; charset=utf-8' });
22
- res.end(toPrometheusText(report));
23
- }
24
- else {
25
- res.writeHead(404, { 'Content-Type': 'application/json' });
26
- res.end(JSON.stringify({ error: 'Not found', paths: ['/healthz', '/metrics'] }));
27
- }
28
- };
29
- }
30
- export function registerHealthCommand(program) {
31
- const health = program
32
- .command('health')
33
- .description('Report process health: quota, audit error rate, circuit breaker state.');
34
- health
35
- .command('check')
36
- .description('Print a one-shot health report.')
37
- .option('--prometheus', 'Emit Prometheus text format.')
38
- .option('--audit-log <path>', 'Audit log path (default: ~/.switchbot/audit.log).')
39
- .action((opts) => {
40
- const report = getHealthReport(opts.auditLog);
41
- if (opts.prometheus) {
42
- process.stdout.write(toPrometheusText(report));
43
- return;
44
- }
45
- if (isJsonMode()) {
46
- printJson(report);
47
- return;
48
- }
49
- const statusEmoji = report.overall === 'ok' ? '✓' : report.overall === 'degraded' ? '⚠' : '✗';
50
- console.log(`${statusEmoji} overall: ${report.overall} (${report.generatedAt})`);
51
- console.log('');
52
- printTable(['Component', 'Status', 'Detail'], [
53
- ['quota', report.quota.status,
54
- `${report.quota.used}/${report.quota.limit} (${report.quota.percentUsed}% used, ${report.quota.remaining} remaining)`],
55
- ['audit', report.audit.status,
56
- report.audit.present
57
- ? `${report.audit.recentErrors}/${report.audit.recentTotal} errors in 24h (${report.audit.errorRatePercent}%)`
58
- : 'log not present'],
59
- ['circuit', report.circuit.status,
60
- `${report.circuit.name}: ${report.circuit.state} (failures: ${report.circuit.failures})`],
61
- ['process', 'ok',
62
- `pid ${report.process.pid} · uptime ${report.process.uptimeSeconds}s · mem ${report.process.memoryMb}MB`],
63
- ]);
64
- if (report.overall !== 'ok')
65
- process.exit(1);
66
- });
67
- // switchbot health serve [--port <n>]
68
- health
69
- .command('serve')
70
- .description('Start an HTTP server exposing /healthz (JSON) and /metrics (Prometheus).')
71
- .option('--port <n>', 'Port to listen on.', intArg('--port'), '3100')
72
- .option('--host <host>', 'Bind address.', '127.0.0.1')
73
- .option('--audit-log <path>', 'Audit log path.')
74
- .addHelpText('after', `
75
- Endpoints:
76
- GET /healthz JSON health report (HTTP 200 ok/degraded, 503 when circuit is open).
77
- GET /metrics Prometheus text metrics.
78
-
79
- Example:
80
- $ switchbot health serve --port 3100
81
- $ curl http://127.0.0.1:3100/healthz
82
- `)
83
- .action((opts) => {
84
- const port = parseInt(opts.port, 10);
85
- const handler = createHealthHandler(opts.auditLog);
86
- const server = http.createServer(handler);
87
- server.on('error', (err) => {
88
- if (err.code === 'EADDRINUSE') {
89
- handleError(Object.assign(new Error(`Port ${port} is already in use. Choose a different port with --port.`), { code: err.code }));
90
- }
91
- else {
92
- handleError(err);
93
- }
94
- });
95
- server.listen(port, opts.host, () => {
96
- const addr = server.address();
97
- const boundPort = typeof addr === 'object' && addr !== null ? addr.port : port;
98
- if (isJsonMode()) {
99
- printJson({ status: 'listening', host: opts.host, port: boundPort, endpoints: ['/healthz', '/metrics'] });
100
- }
101
- else {
102
- console.log(`health server listening on ${opts.host}:${boundPort}`);
103
- console.log(' GET /healthz — JSON health report');
104
- console.log(' GET /metrics — Prometheus text metrics');
105
- }
106
- });
107
- function shutdown() {
108
- server.close(() => process.exit(0));
109
- }
110
- process.on('SIGTERM', shutdown);
111
- process.on('SIGINT', shutdown);
112
- });
113
- }
114
- //# sourceMappingURL=health.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/commands/health.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function registerHistoryCommand(program: Command): void;