@switchbot/openapi-cli 1.1.0 → 1.2.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 (90) hide show
  1. package/README.md +174 -18
  2. package/dist/api/client.d.ts +7 -1
  3. package/dist/api/client.js +44 -8
  4. package/dist/api/client.js.map +1 -1
  5. package/dist/commands/batch.d.ts +2 -0
  6. package/dist/commands/batch.js +252 -0
  7. package/dist/commands/batch.js.map +1 -0
  8. package/dist/commands/cache.d.ts +2 -0
  9. package/dist/commands/cache.js +108 -0
  10. package/dist/commands/cache.js.map +1 -0
  11. package/dist/commands/capabilities.d.ts +2 -0
  12. package/dist/commands/capabilities.js +91 -0
  13. package/dist/commands/capabilities.js.map +1 -0
  14. package/dist/commands/catalog.d.ts +2 -0
  15. package/dist/commands/catalog.js +291 -0
  16. package/dist/commands/catalog.js.map +1 -0
  17. package/dist/commands/config.js +123 -10
  18. package/dist/commands/config.js.map +1 -1
  19. package/dist/commands/devices.js +234 -147
  20. package/dist/commands/devices.js.map +1 -1
  21. package/dist/commands/doctor.d.ts +2 -0
  22. package/dist/commands/doctor.js +147 -0
  23. package/dist/commands/doctor.js.map +1 -0
  24. package/dist/commands/events.d.ts +15 -0
  25. package/dist/commands/events.js +188 -0
  26. package/dist/commands/events.js.map +1 -0
  27. package/dist/commands/explain.d.ts +2 -0
  28. package/dist/commands/explain.js +137 -0
  29. package/dist/commands/explain.js.map +1 -0
  30. package/dist/commands/history.d.ts +2 -0
  31. package/dist/commands/history.js +104 -0
  32. package/dist/commands/history.js.map +1 -0
  33. package/dist/commands/mcp.d.ts +4 -0
  34. package/dist/commands/mcp.js +386 -0
  35. package/dist/commands/mcp.js.map +1 -0
  36. package/dist/commands/plan.d.ts +37 -0
  37. package/dist/commands/plan.js +344 -0
  38. package/dist/commands/plan.js.map +1 -0
  39. package/dist/commands/quota.d.ts +2 -0
  40. package/dist/commands/quota.js +77 -0
  41. package/dist/commands/quota.js.map +1 -0
  42. package/dist/commands/scenes.js +19 -13
  43. package/dist/commands/scenes.js.map +1 -1
  44. package/dist/commands/schema.d.ts +2 -0
  45. package/dist/commands/schema.js +77 -0
  46. package/dist/commands/schema.js.map +1 -0
  47. package/dist/commands/watch.d.ts +2 -0
  48. package/dist/commands/watch.js +161 -0
  49. package/dist/commands/watch.js.map +1 -0
  50. package/dist/commands/webhook.js +37 -22
  51. package/dist/commands/webhook.js.map +1 -1
  52. package/dist/config.d.ts +11 -0
  53. package/dist/config.js +32 -6
  54. package/dist/config.js.map +1 -1
  55. package/dist/devices/cache.d.ts +50 -0
  56. package/dist/devices/cache.js +152 -1
  57. package/dist/devices/cache.js.map +1 -1
  58. package/dist/devices/catalog.d.ts +49 -0
  59. package/dist/devices/catalog.js +362 -92
  60. package/dist/devices/catalog.js.map +1 -1
  61. package/dist/index.js +31 -1
  62. package/dist/index.js.map +1 -1
  63. package/dist/lib/devices.d.ts +144 -0
  64. package/dist/lib/devices.js +329 -0
  65. package/dist/lib/devices.js.map +1 -0
  66. package/dist/lib/scenes.d.ts +7 -0
  67. package/dist/lib/scenes.js +11 -0
  68. package/dist/lib/scenes.js.map +1 -0
  69. package/dist/utils/audit.d.ts +13 -0
  70. package/dist/utils/audit.js +43 -0
  71. package/dist/utils/audit.js.map +1 -0
  72. package/dist/utils/filter.d.ts +45 -0
  73. package/dist/utils/filter.js +96 -0
  74. package/dist/utils/filter.js.map +1 -0
  75. package/dist/utils/flags.d.ts +42 -0
  76. package/dist/utils/flags.js +108 -0
  77. package/dist/utils/flags.js.map +1 -1
  78. package/dist/utils/format.d.ts +9 -0
  79. package/dist/utils/format.js +109 -0
  80. package/dist/utils/format.js.map +1 -0
  81. package/dist/utils/output.d.ts +11 -0
  82. package/dist/utils/output.js +37 -6
  83. package/dist/utils/output.js.map +1 -1
  84. package/dist/utils/quota.d.ts +48 -0
  85. package/dist/utils/quota.js +144 -0
  86. package/dist/utils/quota.js.map +1 -0
  87. package/dist/utils/retry.d.ts +23 -0
  88. package/dist/utils/retry.js +60 -0
  89. package/dist/utils/retry.js.map +1 -0
  90. package/package.json +4 -1
@@ -0,0 +1,344 @@
1
+ import fs from 'node:fs';
2
+ import { printJson, isJsonMode, handleError } from '../utils/output.js';
3
+ import { executeCommand, isDestructiveCommand } from '../lib/devices.js';
4
+ import { executeScene } from '../lib/scenes.js';
5
+ import { getCachedDevice } from '../devices/cache.js';
6
+ const PLAN_JSON_SCHEMA = {
7
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
8
+ $id: 'https://switchbot.dev/plan-1.0.json',
9
+ title: 'SwitchBot Plan',
10
+ description: 'Declarative batch of SwitchBot operations. Agent-authored; CLI validates and executes. No LLM inside the CLI — the schema is the contract.',
11
+ type: 'object',
12
+ required: ['version', 'steps'],
13
+ properties: {
14
+ version: { const: '1.0' },
15
+ description: { type: 'string' },
16
+ steps: {
17
+ type: 'array',
18
+ items: {
19
+ oneOf: [
20
+ {
21
+ type: 'object',
22
+ required: ['type', 'deviceId', 'command'],
23
+ properties: {
24
+ type: { const: 'command' },
25
+ deviceId: { type: 'string', minLength: 1 },
26
+ command: { type: 'string', minLength: 1 },
27
+ parameter: {},
28
+ commandType: { enum: ['command', 'customize'] },
29
+ note: { type: 'string' },
30
+ },
31
+ additionalProperties: false,
32
+ },
33
+ {
34
+ type: 'object',
35
+ required: ['type', 'sceneId'],
36
+ properties: {
37
+ type: { const: 'scene' },
38
+ sceneId: { type: 'string', minLength: 1 },
39
+ note: { type: 'string' },
40
+ },
41
+ additionalProperties: false,
42
+ },
43
+ {
44
+ type: 'object',
45
+ required: ['type', 'ms'],
46
+ properties: {
47
+ type: { const: 'wait' },
48
+ ms: { type: 'integer', minimum: 0, maximum: 600000 },
49
+ note: { type: 'string' },
50
+ },
51
+ additionalProperties: false,
52
+ },
53
+ ],
54
+ },
55
+ },
56
+ },
57
+ additionalProperties: false,
58
+ };
59
+ export function validatePlan(raw) {
60
+ const issues = [];
61
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
62
+ return { ok: false, issues: [{ path: '$', message: 'plan must be a JSON object' }] };
63
+ }
64
+ const p = raw;
65
+ if (p.version !== '1.0') {
66
+ issues.push({ path: 'version', message: 'must equal "1.0"' });
67
+ }
68
+ if (!Array.isArray(p.steps)) {
69
+ issues.push({ path: 'steps', message: 'must be an array' });
70
+ return { ok: false, issues };
71
+ }
72
+ p.steps.forEach((step, i) => {
73
+ const at = `steps[${i}]`;
74
+ if (!step || typeof step !== 'object') {
75
+ issues.push({ path: at, message: 'must be an object' });
76
+ return;
77
+ }
78
+ const s = step;
79
+ switch (s.type) {
80
+ case 'command':
81
+ if (typeof s.deviceId !== 'string' || !s.deviceId) {
82
+ issues.push({ path: `${at}.deviceId`, message: 'must be a non-empty string' });
83
+ }
84
+ if (typeof s.command !== 'string' || !s.command) {
85
+ issues.push({ path: `${at}.command`, message: 'must be a non-empty string' });
86
+ }
87
+ if (s.commandType !== undefined &&
88
+ s.commandType !== 'command' &&
89
+ s.commandType !== 'customize') {
90
+ issues.push({
91
+ path: `${at}.commandType`,
92
+ message: 'must be "command" or "customize"',
93
+ });
94
+ }
95
+ break;
96
+ case 'scene':
97
+ if (typeof s.sceneId !== 'string' || !s.sceneId) {
98
+ issues.push({ path: `${at}.sceneId`, message: 'must be a non-empty string' });
99
+ }
100
+ break;
101
+ case 'wait':
102
+ if (typeof s.ms !== 'number' || !Number.isInteger(s.ms) || s.ms < 0 || s.ms > 600_000) {
103
+ issues.push({
104
+ path: `${at}.ms`,
105
+ message: 'must be an integer in [0, 600000]',
106
+ });
107
+ }
108
+ break;
109
+ default:
110
+ issues.push({
111
+ path: `${at}.type`,
112
+ message: 'must be one of "command" | "scene" | "wait"',
113
+ });
114
+ }
115
+ });
116
+ if (issues.length > 0)
117
+ return { ok: false, issues };
118
+ return { ok: true, plan: raw };
119
+ }
120
+ async function readPlanSource(file) {
121
+ const text = file === undefined || file === '-'
122
+ ? await readStdin()
123
+ : fs.readFileSync(file, 'utf8');
124
+ if (!text.trim()) {
125
+ throw new Error(file === undefined || file === '-'
126
+ ? 'no plan received on stdin'
127
+ : `plan file is empty: ${file}`);
128
+ }
129
+ try {
130
+ return JSON.parse(text);
131
+ }
132
+ catch (err) {
133
+ throw new Error(`plan is not valid JSON: ${err.message}`);
134
+ }
135
+ }
136
+ function readStdin() {
137
+ return new Promise((resolve, reject) => {
138
+ let buf = '';
139
+ process.stdin.setEncoding('utf8');
140
+ process.stdin.on('data', (chunk) => (buf += chunk));
141
+ process.stdin.on('end', () => resolve(buf));
142
+ process.stdin.on('error', reject);
143
+ });
144
+ }
145
+ export function registerPlanCommand(program) {
146
+ const plan = program
147
+ .command('plan')
148
+ .description('Agent-authored batch plans: schema, validate, run')
149
+ .addHelpText('after', `
150
+ A "plan" is a JSON document describing a sequence of commands/scenes/waits.
151
+ The schema is fixed — agents emit plans, the CLI executes them. No LLM inside.
152
+
153
+ { "version": "1.0", "description": "...", "steps": [
154
+ { "type": "command", "deviceId": "...", "command": "turnOff" },
155
+ { "type": "wait", "ms": 500 },
156
+ { "type": "scene", "sceneId": "..." }
157
+ ]}
158
+
159
+ Workflow:
160
+ $ switchbot plan schema > plan.schema.json # export the contract
161
+ $ switchbot plan validate my-plan.json # check shape without running
162
+ $ switchbot --dry-run plan run my-plan.json # preview (mutations skipped)
163
+ $ switchbot plan run my-plan.json --yes # execute destructive steps
164
+ $ cat plan.json | switchbot plan run - # or stream via stdin
165
+ `);
166
+ plan
167
+ .command('schema')
168
+ .description('Print the JSON Schema for the plan format')
169
+ .action(() => {
170
+ printJson(PLAN_JSON_SCHEMA);
171
+ });
172
+ plan
173
+ .command('validate')
174
+ .description('Validate a plan file (or stdin) against the schema')
175
+ .argument('[file]', 'Path to plan.json, or "-" / omit to read stdin')
176
+ .action(async (file) => {
177
+ let raw;
178
+ try {
179
+ raw = await readPlanSource(file);
180
+ }
181
+ catch (err) {
182
+ handleError(err);
183
+ }
184
+ const result = validatePlan(raw);
185
+ if (!result.ok) {
186
+ if (isJsonMode()) {
187
+ printJson({ valid: false, issues: result.issues });
188
+ }
189
+ else {
190
+ console.error('✗ plan invalid:');
191
+ for (const i of result.issues) {
192
+ console.error(` ${i.path}: ${i.message}`);
193
+ }
194
+ }
195
+ process.exit(2);
196
+ }
197
+ if (isJsonMode()) {
198
+ printJson({ valid: true, steps: result.plan.steps.length });
199
+ }
200
+ else {
201
+ console.log(`✓ plan valid (${result.plan.steps.length} step${result.plan.steps.length === 1 ? '' : 's'})`);
202
+ }
203
+ });
204
+ plan
205
+ .command('run')
206
+ .description('Validate + execute a plan. Respects --dry-run; destructive steps require --yes')
207
+ .argument('[file]', 'Path to plan.json, or "-" / omit to read stdin')
208
+ .option('--yes', 'Authorize destructive commands (e.g. Smart Lock unlock, Garage open)')
209
+ .option('--continue-on-error', 'Keep running after a failed step (default: stop at first error)')
210
+ .action(async (file, options) => {
211
+ let raw;
212
+ try {
213
+ raw = await readPlanSource(file);
214
+ }
215
+ catch (err) {
216
+ handleError(err);
217
+ }
218
+ const v = validatePlan(raw);
219
+ if (!v.ok) {
220
+ if (isJsonMode()) {
221
+ printJson({ ran: false, issues: v.issues });
222
+ }
223
+ else {
224
+ console.error('✗ plan invalid, refusing to run:');
225
+ for (const i of v.issues)
226
+ console.error(` ${i.path}: ${i.message}`);
227
+ }
228
+ process.exit(2);
229
+ }
230
+ const out = {
231
+ plan: v.plan,
232
+ results: [],
233
+ summary: { total: v.plan.steps.length, ok: 0, error: 0, skipped: 0 },
234
+ };
235
+ try {
236
+ for (let i = 0; i < v.plan.steps.length; i++) {
237
+ const step = v.plan.steps[i];
238
+ const idx = i + 1;
239
+ if (step.type === 'wait') {
240
+ await new Promise((r) => setTimeout(r, step.ms));
241
+ out.results.push({ step: idx, type: 'wait', ms: step.ms, status: 'ok' });
242
+ out.summary.ok++;
243
+ if (!isJsonMode())
244
+ console.log(` ${idx}. wait ${step.ms}ms`);
245
+ continue;
246
+ }
247
+ if (step.type === 'scene') {
248
+ try {
249
+ await executeScene(step.sceneId);
250
+ out.results.push({ step: idx, type: 'scene', sceneId: step.sceneId, status: 'ok' });
251
+ out.summary.ok++;
252
+ if (!isJsonMode())
253
+ console.log(` ${idx}. ✓ scene ${step.sceneId}`);
254
+ }
255
+ catch (err) {
256
+ const msg = err instanceof Error ? err.message : String(err);
257
+ out.results.push({ step: idx, type: 'scene', sceneId: step.sceneId, status: 'error', error: msg });
258
+ out.summary.error++;
259
+ if (!isJsonMode())
260
+ console.log(` ${idx}. ✗ scene ${step.sceneId}: ${msg}`);
261
+ if (!options.continueOnError)
262
+ break;
263
+ }
264
+ continue;
265
+ }
266
+ // command
267
+ const deviceType = getCachedDevice(step.deviceId)?.type;
268
+ const commandType = step.commandType ?? 'command';
269
+ const destructive = isDestructiveCommand(deviceType, step.command, commandType);
270
+ if (destructive && !options.yes) {
271
+ out.results.push({
272
+ step: idx,
273
+ type: 'command',
274
+ deviceId: step.deviceId,
275
+ command: step.command,
276
+ status: 'skipped',
277
+ error: 'destructive — rerun with --yes',
278
+ });
279
+ out.summary.skipped++;
280
+ if (!isJsonMode())
281
+ console.log(` ${idx}. ⚠ skipped ${step.command} on ${step.deviceId} (destructive — pass --yes)`);
282
+ if (!options.continueOnError)
283
+ break;
284
+ continue;
285
+ }
286
+ try {
287
+ await executeCommand(step.deviceId, step.command, step.parameter, commandType);
288
+ out.results.push({
289
+ step: idx,
290
+ type: 'command',
291
+ deviceId: step.deviceId,
292
+ command: step.command,
293
+ status: 'ok',
294
+ });
295
+ out.summary.ok++;
296
+ if (!isJsonMode())
297
+ console.log(` ${idx}. ✓ ${step.command} on ${step.deviceId}`);
298
+ }
299
+ catch (err) {
300
+ if (err instanceof Error && err.name === 'DryRunSignal') {
301
+ out.results.push({
302
+ step: idx,
303
+ type: 'command',
304
+ deviceId: step.deviceId,
305
+ command: step.command,
306
+ status: 'ok',
307
+ });
308
+ out.summary.ok++;
309
+ if (!isJsonMode())
310
+ console.log(` ${idx}. ◦ dry-run ${step.command} on ${step.deviceId}`);
311
+ continue;
312
+ }
313
+ const msg = err instanceof Error ? err.message : String(err);
314
+ out.results.push({
315
+ step: idx,
316
+ type: 'command',
317
+ deviceId: step.deviceId,
318
+ command: step.command,
319
+ status: 'error',
320
+ error: msg,
321
+ });
322
+ out.summary.error++;
323
+ if (!isJsonMode())
324
+ console.log(` ${idx}. ✗ ${step.command} on ${step.deviceId}: ${msg}`);
325
+ if (!options.continueOnError)
326
+ break;
327
+ }
328
+ }
329
+ if (isJsonMode()) {
330
+ printJson({ ran: true, ...out });
331
+ }
332
+ else {
333
+ const { ok, error, skipped, total } = out.summary;
334
+ console.log(`\nsummary: ok=${ok} error=${error} skipped=${skipped} total=${total}`);
335
+ }
336
+ }
337
+ catch (err) {
338
+ handleError(err);
339
+ }
340
+ if (out.summary.error > 0)
341
+ process.exit(1);
342
+ });
343
+ }
344
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/commands/plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerQuotaCommand(program: Command): void;
@@ -0,0 +1,77 @@
1
+ import { printJson, isJsonMode } from '../utils/output.js';
2
+ import { DAILY_QUOTA, loadQuota, resetQuota, todayUsage, } from '../utils/quota.js';
3
+ export function registerQuotaCommand(program) {
4
+ const quota = program
5
+ .command('quota')
6
+ .description('Inspect and manage the local SwitchBot API request counter')
7
+ .addHelpText('after', `
8
+ Every request the CLI makes is counted locally in ~/.switchbot/quota.json.
9
+ Counts are bucketed by local date, one record per endpoint pattern. This
10
+ is a best-effort mirror of the SwitchBot 10,000/day limit — it does not
11
+ include requests made outside this CLI (mobile app, other scripts).
12
+
13
+ Subcommands:
14
+ status Show today's usage and the last 7 days
15
+ reset Delete the local counter file
16
+
17
+ Examples:
18
+ $ switchbot quota status
19
+ $ switchbot quota status --json
20
+ $ switchbot quota reset
21
+ `);
22
+ quota
23
+ .command('status')
24
+ .description("Show today's usage and the last 7 days")
25
+ .action(() => {
26
+ const usage = todayUsage();
27
+ const history = loadQuota();
28
+ if (isJsonMode()) {
29
+ printJson({
30
+ today: {
31
+ date: usage.date,
32
+ total: usage.total,
33
+ remaining: usage.remaining,
34
+ dailyLimit: DAILY_QUOTA,
35
+ endpoints: usage.endpoints,
36
+ },
37
+ history: history.days,
38
+ });
39
+ return;
40
+ }
41
+ console.log(`Today (${usage.date}):`);
42
+ console.log(` Requests used: ${usage.total} / ${DAILY_QUOTA}`);
43
+ console.log(` Remaining budget: ${usage.remaining}`);
44
+ if (Object.keys(usage.endpoints).length === 0) {
45
+ console.log(' (no requests recorded yet)');
46
+ }
47
+ else {
48
+ console.log(' Endpoint breakdown:');
49
+ const entries = Object.entries(usage.endpoints).sort((a, b) => b[1] - a[1]);
50
+ for (const [endpoint, count] of entries) {
51
+ console.log(` ${endpoint.padEnd(48)} ${count}`);
52
+ }
53
+ }
54
+ const otherDays = Object.entries(history.days)
55
+ .filter(([d]) => d !== usage.date)
56
+ .sort((a, b) => b[0].localeCompare(a[0]));
57
+ if (otherDays.length > 0) {
58
+ console.log('\nRecent history:');
59
+ for (const [date, bucket] of otherDays) {
60
+ console.log(` ${date} ${bucket.total}`);
61
+ }
62
+ }
63
+ });
64
+ quota
65
+ .command('reset')
66
+ .description('Delete the local quota counter file')
67
+ .action(() => {
68
+ resetQuota();
69
+ if (isJsonMode()) {
70
+ printJson({ reset: true });
71
+ }
72
+ else {
73
+ console.log('Quota counter reset.');
74
+ }
75
+ });
76
+ }
77
+ //# sourceMappingURL=quota.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota.js","sourceRoot":"","sources":["../../src/commands/quota.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
- import { createClient } from '../api/client.js';
2
- import { printTable, printJson, isJsonMode, handleError } from '../utils/output.js';
1
+ import { printJson, isJsonMode, handleError } from '../utils/output.js';
2
+ import { resolveFormat, resolveFields, renderRows } from '../utils/format.js';
3
+ import { fetchScenes, executeScene } from '../lib/scenes.js';
3
4
  export function registerScenesCommand(program) {
4
5
  const scenes = program
5
6
  .command('scenes')
@@ -10,25 +11,26 @@ export function registerScenesCommand(program) {
10
11
  .description('List all manual scenes (scenes created in the SwitchBot app)')
11
12
  .addHelpText('after', `
12
13
  Output columns: sceneId, sceneName
14
+ --fields accepts any subset of these names (exit 2 on unknown names).
13
15
 
14
16
  Examples:
15
17
  $ switchbot scenes list
18
+ $ switchbot scenes list --format tsv --fields sceneId,sceneName
19
+ $ switchbot scenes list --format id
16
20
  $ switchbot scenes list --json
17
21
  `)
18
22
  .action(async () => {
19
23
  try {
20
- const client = createClient();
21
- const res = await client.get('/v1.1/scenes');
22
- if (isJsonMode()) {
23
- printJson(res.data.body);
24
+ const scenes = await fetchScenes();
25
+ const fmt = resolveFormat();
26
+ if (fmt === 'json' && process.argv.includes('--json')) {
27
+ printJson(scenes);
24
28
  return;
25
29
  }
26
- const scenes = res.data.body;
27
- if (scenes.length === 0) {
30
+ renderRows(['sceneId', 'sceneName'], scenes.map((s) => [s.sceneId, s.sceneName]), fmt, resolveFields());
31
+ if (fmt === 'table' && scenes.length === 0) {
28
32
  console.log('No scenes found');
29
- return;
30
33
  }
31
- printTable(['sceneId', 'sceneName'], scenes.map((s) => [s.sceneId, s.sceneName]));
32
34
  }
33
35
  catch (error) {
34
36
  handleError(error);
@@ -45,9 +47,13 @@ Example:
45
47
  `)
46
48
  .action(async (sceneId) => {
47
49
  try {
48
- const client = createClient();
49
- await client.post(`/v1.1/scenes/${sceneId}/execute`);
50
- console.log(`✓ Scene executed: ${sceneId}`);
50
+ await executeScene(sceneId);
51
+ if (isJsonMode()) {
52
+ printJson({ ok: true, sceneId });
53
+ }
54
+ else {
55
+ console.log(`✓ Scene executed: ${sceneId}`);
56
+ }
51
57
  }
52
58
  catch (error) {
53
59
  handleError(error);
@@ -1 +1 @@
1
- {"version":3,"file":"scenes.js","sourceRoot":"","sources":["../../src/commands/scenes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAOpF,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,MAAM,MAAM,GAAG,OAAO;SACnB,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,qCAAqC,CAAC,CAAC;IAEtD,wBAAwB;IACxB,MAAM;SACH,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,8DAA8D,CAAC;SAC3E,WAAW,CAAC,OAAO,EAAE;;;;;;CAMzB,CAAC;SACG,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,CAAoB,cAAc,CAAC,CAAC;YAEhE,IAAI,UAAU,EAAE,EAAE,CAAC;gBACjB,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACzB,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;gBAC/B,OAAO;YACT,CAAC;YAED,UAAU,CACR,CAAC,SAAS,EAAE,WAAW,CAAC,EACxB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAC5C,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,WAAW,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,qCAAqC;IACrC,MAAM;SACH,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,kCAAkC,CAAC;SAC/C,QAAQ,CAAC,WAAW,EAAE,6BAA6B,CAAC;SACpD,WAAW,CAAC,OAAO,EAAE;;;CAGzB,CAAC;SACG,MAAM,CAAC,KAAK,EAAE,OAAe,EAAE,EAAE;QAChC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;YAC9B,MAAM,MAAM,CAAC,IAAI,CAAC,gBAAgB,OAAO,UAAU,CAAC,CAAC;YACrD,OAAO,CAAC,GAAG,CAAC,qBAAqB,OAAO,EAAE,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,WAAW,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {"version":3,"file":"scenes.js","sourceRoot":"","sources":["../../src/commands/scenes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAE7D,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,MAAM,MAAM,GAAG,OAAO;SACnB,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,qCAAqC,CAAC,CAAC;IAEtD,wBAAwB;IACxB,MAAM;SACH,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,8DAA8D,CAAC;SAC3E,WAAW,CAAC,OAAO,EAAE;;;;;;;;;CASzB,CAAC;SACG,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,WAAW,EAAE,CAAC;YACnC,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;YAE5B,IAAI,GAAG,KAAK,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACtD,SAAS,CAAC,MAAM,CAAC,CAAC;gBAClB,OAAO;YACT,CAAC;YAED,UAAU,CACR,CAAC,SAAS,EAAE,WAAW,CAAC,EACxB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAC3C,GAAG,EACH,aAAa,EAAE,CAChB,CAAC;YACF,IAAI,GAAG,KAAK,OAAO,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC3C,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,WAAW,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,qCAAqC;IACrC,MAAM;SACH,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,kCAAkC,CAAC;SAC/C,QAAQ,CAAC,WAAW,EAAE,6BAA6B,CAAC;SACpD,WAAW,CAAC,OAAO,EAAE;;;CAGzB,CAAC;SACG,MAAM,CAAC,KAAK,EAAE,OAAe,EAAE,EAAE;QAChC,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC;YAC5B,IAAI,UAAU,EAAE,EAAE,CAAC;gBACjB,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;YACnC,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,qBAAqB,OAAO,EAAE,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,WAAW,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerSchemaCommand(program: Command): void;
@@ -0,0 +1,77 @@
1
+ import { printJson, isJsonMode } from '../utils/output.js';
2
+ import { getEffectiveCatalog } from '../devices/catalog.js';
3
+ function toSchemaEntry(e) {
4
+ return {
5
+ type: e.type,
6
+ description: e.description ?? '',
7
+ category: e.category,
8
+ aliases: e.aliases ?? [],
9
+ role: e.role ?? null,
10
+ readOnly: e.readOnly ?? false,
11
+ commands: e.commands.map(toSchemaCommand),
12
+ statusFields: e.statusFields ?? [],
13
+ };
14
+ }
15
+ function toSchemaCommand(c) {
16
+ return {
17
+ command: c.command,
18
+ parameter: c.parameter,
19
+ description: c.description,
20
+ commandType: (c.commandType ?? 'command'),
21
+ idempotent: Boolean(c.idempotent),
22
+ destructive: Boolean(c.destructive),
23
+ ...(c.exampleParams ? { exampleParams: c.exampleParams } : {}),
24
+ };
25
+ }
26
+ export function registerSchemaCommand(program) {
27
+ const schema = program
28
+ .command('schema')
29
+ .description('Export the device catalog as structured JSON (for agent prompts / tooling)');
30
+ schema
31
+ .command('export')
32
+ .description('Print the full catalog as structured JSON (one object per type)')
33
+ .option('--type <type>', 'Restrict to a single device type (e.g. "Strip Light")')
34
+ .option('--role <role>', 'Restrict to a functional role: lighting, security, sensor, climate, media, cleaning, curtain, fan, power, hub, other')
35
+ .option('--category <cat>', 'Restrict to "physical" or "ir"')
36
+ .addHelpText('after', `
37
+ Output is always JSON (this command ignores --format). The output is a
38
+ catalog export — not a formal JSON Schema standard document — suitable for
39
+ pre-baking LLM prompts or regenerating docs when the catalog changes.
40
+
41
+ Examples:
42
+ $ switchbot schema export > catalog.json
43
+ $ switchbot schema export --type Bot | jq '.types[0].commands'
44
+ $ switchbot schema export --role lighting | jq '[.types[].type]'
45
+ $ switchbot schema export --role security --category physical
46
+ `)
47
+ .action((options) => {
48
+ const catalog = getEffectiveCatalog();
49
+ let filtered = catalog;
50
+ if (options.type) {
51
+ const q = options.type.toLowerCase();
52
+ filtered = filtered.filter((e) => e.type.toLowerCase() === q ||
53
+ (e.aliases ?? []).some((a) => a.toLowerCase() === q));
54
+ }
55
+ if (options.role) {
56
+ const q = options.role.toLowerCase();
57
+ filtered = filtered.filter((e) => (e.role ?? 'other') === q);
58
+ }
59
+ if (options.category) {
60
+ const q = options.category.toLowerCase();
61
+ filtered = filtered.filter((e) => e.category === q);
62
+ }
63
+ const payload = {
64
+ version: '1.0',
65
+ generatedAt: new Date().toISOString(),
66
+ types: filtered.map(toSchemaEntry),
67
+ };
68
+ // Always JSON — schema export without JSON would be a category error.
69
+ if (isJsonMode()) {
70
+ printJson(payload);
71
+ }
72
+ else {
73
+ console.log(JSON.stringify(payload, null, 2));
74
+ }
75
+ });
76
+ }
77
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/commands/schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAA6C,MAAM,uBAAuB,CAAC;AAqBvG,SAAS,aAAa,CAAC,CAAqB;IAC1C,OAAO;QACL,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,EAAE;QAChC,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,EAAE;QACxB,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI;QACpB,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,KAAK;QAC7B,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC;QACzC,YAAY,EAAE,CAAC,CAAC,YAAY,IAAI,EAAE;KACnC,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,CAAc;IACrC,OAAO;QACL,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,WAAW,EAAE,CAAC,CAAC,CAAC,WAAW,IAAI,SAAS,CAA4B;QACpE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;QACjC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC;QACnC,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,MAAM,MAAM,GAAG,OAAO;SACnB,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,4EAA4E,CAAC,CAAC;IAE7F,MAAM;SACH,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,iEAAiE,CAAC;SAC9E,MAAM,CAAC,eAAe,EAAE,uDAAuD,CAAC;SAChF,MAAM,CAAC,eAAe,EAAE,sHAAsH,CAAC;SAC/I,MAAM,CAAC,kBAAkB,EAAE,gCAAgC,CAAC;SAC5D,WAAW,CAAC,OAAO,EAAE;;;;;;;;;;CAUzB,CAAC;SACG,MAAM,CAAC,CAAC,OAA4D,EAAE,EAAE;QACvE,MAAM,OAAO,GAAG,mBAAmB,EAAE,CAAC;QACtC,IAAI,QAAQ,GAAG,OAAO,CAAC;QACvB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACrC,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAC/B,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC;gBAC1B,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CACrD,CAAC;QACJ,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACrC,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;YACzC,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC;QACtD,CAAC;QACD,MAAM,OAAO,GAAG;YACd,OAAO,EAAE,KAAK;YACd,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACrC,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC;SACnC,CAAC;QACF,sEAAsE;QACtE,IAAI,UAAU,EAAE,EAAE,CAAC;YACjB,SAAS,CAAC,OAAO,CAAC,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAChD,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerWatchCommand(devices: Command): void;