@switchbot/openapi-cli 1.1.0 → 1.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.
- package/README.md +174 -18
- package/dist/api/client.d.ts +7 -1
- package/dist/api/client.js +44 -8
- package/dist/api/client.js.map +1 -1
- package/dist/commands/batch.d.ts +2 -0
- package/dist/commands/batch.js +252 -0
- package/dist/commands/batch.js.map +1 -0
- package/dist/commands/cache.d.ts +2 -0
- package/dist/commands/cache.js +108 -0
- package/dist/commands/cache.js.map +1 -0
- package/dist/commands/capabilities.d.ts +2 -0
- package/dist/commands/capabilities.js +91 -0
- package/dist/commands/capabilities.js.map +1 -0
- package/dist/commands/catalog.d.ts +2 -0
- package/dist/commands/catalog.js +291 -0
- package/dist/commands/catalog.js.map +1 -0
- package/dist/commands/config.js +123 -10
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/device-meta.d.ts +2 -0
- package/dist/commands/device-meta.js +142 -0
- package/dist/commands/device-meta.js.map +1 -0
- package/dist/commands/devices.js +272 -152
- package/dist/commands/devices.js.map +1 -1
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +147 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/events.d.ts +15 -0
- package/dist/commands/events.js +188 -0
- package/dist/commands/events.js.map +1 -0
- package/dist/commands/expand.d.ts +2 -0
- package/dist/commands/expand.js +192 -0
- package/dist/commands/expand.js.map +1 -0
- package/dist/commands/explain.d.ts +2 -0
- package/dist/commands/explain.js +137 -0
- package/dist/commands/explain.js.map +1 -0
- package/dist/commands/history.d.ts +2 -0
- package/dist/commands/history.js +104 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/mcp.d.ts +4 -0
- package/dist/commands/mcp.js +386 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/plan.d.ts +38 -0
- package/dist/commands/plan.js +356 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/quota.d.ts +2 -0
- package/dist/commands/quota.js +77 -0
- package/dist/commands/quota.js.map +1 -0
- package/dist/commands/scenes.js +19 -13
- package/dist/commands/scenes.js.map +1 -1
- package/dist/commands/schema.d.ts +2 -0
- package/dist/commands/schema.js +77 -0
- package/dist/commands/schema.js.map +1 -0
- package/dist/commands/watch.d.ts +2 -0
- package/dist/commands/watch.js +161 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/commands/webhook.js +37 -22
- package/dist/commands/webhook.js.map +1 -1
- package/dist/config.d.ts +11 -0
- package/dist/config.js +32 -6
- package/dist/config.js.map +1 -1
- package/dist/devices/cache.d.ts +50 -0
- package/dist/devices/cache.js +152 -1
- package/dist/devices/cache.js.map +1 -1
- package/dist/devices/catalog.d.ts +49 -0
- package/dist/devices/catalog.js +362 -92
- package/dist/devices/catalog.js.map +1 -1
- package/dist/devices/device-meta.d.ts +15 -0
- package/dist/devices/device-meta.js +52 -0
- package/dist/devices/device-meta.js.map +1 -0
- package/dist/index.js +31 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/devices.d.ts +144 -0
- package/dist/lib/devices.js +329 -0
- package/dist/lib/devices.js.map +1 -0
- package/dist/lib/scenes.d.ts +7 -0
- package/dist/lib/scenes.js +11 -0
- package/dist/lib/scenes.js.map +1 -0
- package/dist/utils/audit.d.ts +13 -0
- package/dist/utils/audit.js +43 -0
- package/dist/utils/audit.js.map +1 -0
- package/dist/utils/filter.d.ts +45 -0
- package/dist/utils/filter.js +96 -0
- package/dist/utils/filter.js.map +1 -0
- package/dist/utils/flags.d.ts +42 -0
- package/dist/utils/flags.js +108 -0
- package/dist/utils/flags.js.map +1 -1
- package/dist/utils/format.d.ts +9 -0
- package/dist/utils/format.js +109 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/name-resolver.d.ts +17 -0
- package/dist/utils/name-resolver.js +78 -0
- package/dist/utils/name-resolver.js.map +1 -0
- package/dist/utils/output.d.ts +18 -0
- package/dist/utils/output.js +66 -6
- package/dist/utils/output.js.map +1 -1
- package/dist/utils/quota.d.ts +48 -0
- package/dist/utils/quota.js +144 -0
- package/dist/utils/quota.js.map +1 -0
- package/dist/utils/retry.d.ts +23 -0
- package/dist/utils/retry.js +60 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/string.d.ts +2 -0
- package/dist/utils/string.js +23 -0
- package/dist/utils/string.js.map +1 -0
- package/package.json +4 -1
package/dist/utils/flags.js
CHANGED
|
@@ -31,4 +31,112 @@ export function getTimeout() {
|
|
|
31
31
|
export function getConfigPath() {
|
|
32
32
|
return getFlagValue('--config');
|
|
33
33
|
}
|
|
34
|
+
/** Named profile → ~/.switchbot/profiles/<name>.json. */
|
|
35
|
+
export function getProfile() {
|
|
36
|
+
return getFlagValue('--profile');
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Audit log path. `--audit-log <path>` enables JSONL append on every mutating
|
|
40
|
+
* command; default path is ~/.switchbot/audit.log when `--audit-log` is given
|
|
41
|
+
* without a value. Returns null when the flag is absent.
|
|
42
|
+
*/
|
|
43
|
+
export function getAuditLog() {
|
|
44
|
+
const idx = process.argv.indexOf('--audit-log');
|
|
45
|
+
if (idx === -1)
|
|
46
|
+
return null;
|
|
47
|
+
const next = process.argv[idx + 1];
|
|
48
|
+
if (!next || next.startsWith('-')) {
|
|
49
|
+
// bare --audit-log → default location
|
|
50
|
+
return `${process.env.HOME ?? process.env.USERPROFILE ?? '.'}/.switchbot/audit.log`;
|
|
51
|
+
}
|
|
52
|
+
return next;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Max 429 retries before surfacing the error. Default 3. `--no-retry`
|
|
56
|
+
* disables retries entirely; `--retry-on-429 <n>` overrides the count.
|
|
57
|
+
*/
|
|
58
|
+
export function getRetryOn429() {
|
|
59
|
+
if (process.argv.includes('--no-retry'))
|
|
60
|
+
return 0;
|
|
61
|
+
const v = getFlagValue('--retry-on-429');
|
|
62
|
+
if (v === undefined)
|
|
63
|
+
return 3;
|
|
64
|
+
const n = Number(v);
|
|
65
|
+
if (!Number.isFinite(n) || n < 0)
|
|
66
|
+
return 3;
|
|
67
|
+
return Math.floor(n);
|
|
68
|
+
}
|
|
69
|
+
/** Backoff strategy for 429 retries. Default 'exponential'. */
|
|
70
|
+
export function getBackoffStrategy() {
|
|
71
|
+
const v = getFlagValue('--backoff');
|
|
72
|
+
if (v === 'linear')
|
|
73
|
+
return 'linear';
|
|
74
|
+
return 'exponential';
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Whether local quota counting is disabled. Quota counting is best-effort
|
|
78
|
+
* (see src/utils/quota.ts) — this lets scripts opt out entirely when even
|
|
79
|
+
* best-effort file I/O is unwelcome.
|
|
80
|
+
*/
|
|
81
|
+
export function isQuotaDisabled() {
|
|
82
|
+
return process.argv.includes('--no-quota');
|
|
83
|
+
}
|
|
84
|
+
const DEFAULT_LIST_TTL_MS = 60 * 60 * 1000;
|
|
85
|
+
function parseDurationToMs(v) {
|
|
86
|
+
const m = /^(\d+)(ms|s|m|h)?$/.exec(v.trim().toLowerCase());
|
|
87
|
+
if (!m)
|
|
88
|
+
return null;
|
|
89
|
+
const n = Number(m[1]);
|
|
90
|
+
if (!Number.isFinite(n) || n < 0)
|
|
91
|
+
return null;
|
|
92
|
+
const unit = m[2] ?? 'ms';
|
|
93
|
+
switch (unit) {
|
|
94
|
+
case 'ms': return n;
|
|
95
|
+
case 's': return n * 1000;
|
|
96
|
+
case 'm': return n * 60 * 1000;
|
|
97
|
+
case 'h': return n * 60 * 60 * 1000;
|
|
98
|
+
default: return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export { parseDurationToMs };
|
|
102
|
+
/** The --format flag value, or undefined when absent. */
|
|
103
|
+
export function getFormat() {
|
|
104
|
+
return getFlagValue('--format');
|
|
105
|
+
}
|
|
106
|
+
/** Comma-separated --fields value, split into an array. */
|
|
107
|
+
export function getFields() {
|
|
108
|
+
const v = getFlagValue('--fields');
|
|
109
|
+
if (!v)
|
|
110
|
+
return undefined;
|
|
111
|
+
return v.split(',').map((f) => f.trim()).filter(Boolean);
|
|
112
|
+
}
|
|
113
|
+
export function getCacheMode() {
|
|
114
|
+
if (process.argv.includes('--no-cache')) {
|
|
115
|
+
return { listTtlMs: 0, statusTtlMs: 0 };
|
|
116
|
+
}
|
|
117
|
+
// Individual TTL overrides take precedence over the combined --cache flag.
|
|
118
|
+
const listFlag = getFlagValue('--cache-list');
|
|
119
|
+
const statusFlag = getFlagValue('--cache-status');
|
|
120
|
+
if (listFlag !== undefined || statusFlag !== undefined) {
|
|
121
|
+
const listTtlMs = listFlag !== undefined
|
|
122
|
+
? (parseDurationToMs(listFlag) ?? DEFAULT_LIST_TTL_MS)
|
|
123
|
+
: DEFAULT_LIST_TTL_MS;
|
|
124
|
+
const statusTtlMs = statusFlag !== undefined
|
|
125
|
+
? (parseDurationToMs(statusFlag) ?? 0)
|
|
126
|
+
: 0;
|
|
127
|
+
return { listTtlMs, statusTtlMs };
|
|
128
|
+
}
|
|
129
|
+
const v = getFlagValue('--cache');
|
|
130
|
+
if (!v || v === 'auto') {
|
|
131
|
+
return { listTtlMs: DEFAULT_LIST_TTL_MS, statusTtlMs: 0 };
|
|
132
|
+
}
|
|
133
|
+
if (v === 'off') {
|
|
134
|
+
return { listTtlMs: 0, statusTtlMs: 0 };
|
|
135
|
+
}
|
|
136
|
+
const ms = parseDurationToMs(v);
|
|
137
|
+
if (ms === null || ms === 0) {
|
|
138
|
+
return { listTtlMs: DEFAULT_LIST_TTL_MS, statusTtlMs: 0 };
|
|
139
|
+
}
|
|
140
|
+
return { listTtlMs: ms, statusTtlMs: ms };
|
|
141
|
+
}
|
|
34
142
|
//# sourceMappingURL=flags.js.map
|
package/dist/utils/flags.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flags.js","sourceRoot":"","sources":["../../src/utils/flags.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,SAAS,YAAY,CAAC,GAAG,SAAmB;IAC1C,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YAChD,OAAO,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,OAAO,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC5C,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,UAAU;IACxB,MAAM,CAAC,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IACpC,IAAI,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC;IACtB,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACpB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC;IACjD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,aAAa;IAC3B,OAAO,YAAY,CAAC,UAAU,CAAC,CAAC;AAClC,CAAC"}
|
|
1
|
+
{"version":3,"file":"flags.js","sourceRoot":"","sources":["../../src/utils/flags.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type OutputFormat = 'table' | 'json' | 'jsonl' | 'tsv' | 'yaml' | 'id';
|
|
2
|
+
export declare function parseFormat(flag: string | undefined): OutputFormat;
|
|
3
|
+
export declare function resolveFormat(): OutputFormat;
|
|
4
|
+
export declare function resolveFields(): string[] | undefined;
|
|
5
|
+
export declare function filterFields(headers: string[], rows: unknown[][], fields: string[] | undefined): {
|
|
6
|
+
headers: string[];
|
|
7
|
+
rows: unknown[][];
|
|
8
|
+
};
|
|
9
|
+
export declare function renderRows(headers: string[], rows: unknown[][], format: OutputFormat, fields?: string[]): void;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { printTable, printJson, isJsonMode, UsageError } from './output.js';
|
|
2
|
+
import { getFormat, getFields } from './flags.js';
|
|
3
|
+
import { dump as yamlDump } from 'js-yaml';
|
|
4
|
+
export function parseFormat(flag) {
|
|
5
|
+
if (!flag)
|
|
6
|
+
return 'table';
|
|
7
|
+
const lower = flag.toLowerCase();
|
|
8
|
+
switch (lower) {
|
|
9
|
+
case 'table': return 'table';
|
|
10
|
+
case 'json': return 'json';
|
|
11
|
+
case 'jsonl': return 'jsonl';
|
|
12
|
+
case 'tsv': return 'tsv';
|
|
13
|
+
case 'yaml': return 'yaml';
|
|
14
|
+
case 'id': return 'id';
|
|
15
|
+
default: {
|
|
16
|
+
const msg = `Unknown --format "${flag}". Expected: table, json, jsonl, tsv, yaml, id.`;
|
|
17
|
+
if (isJsonMode()) {
|
|
18
|
+
console.error(JSON.stringify({ error: { code: 2, kind: 'usage', message: msg } }));
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
console.error(msg);
|
|
22
|
+
}
|
|
23
|
+
process.exit(2);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function resolveFormat() {
|
|
28
|
+
if (process.argv.includes('--json'))
|
|
29
|
+
return 'json';
|
|
30
|
+
return parseFormat(getFormat());
|
|
31
|
+
}
|
|
32
|
+
export function resolveFields() {
|
|
33
|
+
return getFields();
|
|
34
|
+
}
|
|
35
|
+
export function filterFields(headers, rows, fields) {
|
|
36
|
+
if (!fields || fields.length === 0)
|
|
37
|
+
return { headers, rows };
|
|
38
|
+
const unknown = fields.filter((f) => !headers.includes(f));
|
|
39
|
+
if (unknown.length > 0) {
|
|
40
|
+
throw new UsageError(`Unknown field(s): ${unknown.map((f) => `"${f}"`).join(', ')}. ` +
|
|
41
|
+
`Allowed: ${headers.map((f) => `"${f}"`).join(', ')}.`);
|
|
42
|
+
}
|
|
43
|
+
const indices = fields.map((f) => headers.indexOf(f));
|
|
44
|
+
return {
|
|
45
|
+
headers: indices.map((i) => headers[i]),
|
|
46
|
+
rows: rows.map((row) => indices.map((i) => row[i])),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function cellToString(cell) {
|
|
50
|
+
if (cell === null || cell === undefined)
|
|
51
|
+
return '';
|
|
52
|
+
if (typeof cell === 'boolean')
|
|
53
|
+
return cell ? 'true' : 'false';
|
|
54
|
+
if (typeof cell === 'object')
|
|
55
|
+
return JSON.stringify(cell);
|
|
56
|
+
return String(cell);
|
|
57
|
+
}
|
|
58
|
+
function rowToObject(headers, row) {
|
|
59
|
+
const obj = {};
|
|
60
|
+
for (let i = 0; i < headers.length; i++) {
|
|
61
|
+
obj[headers[i]] = row[i] ?? null;
|
|
62
|
+
}
|
|
63
|
+
return obj;
|
|
64
|
+
}
|
|
65
|
+
export function renderRows(headers, rows, format, fields) {
|
|
66
|
+
const filtered = filterFields(headers, rows, fields);
|
|
67
|
+
const h = filtered.headers;
|
|
68
|
+
const r = filtered.rows;
|
|
69
|
+
switch (format) {
|
|
70
|
+
case 'table':
|
|
71
|
+
printTable(h, r);
|
|
72
|
+
break;
|
|
73
|
+
case 'json':
|
|
74
|
+
printJson(r.map((row) => rowToObject(h, row)));
|
|
75
|
+
break;
|
|
76
|
+
case 'jsonl':
|
|
77
|
+
for (const row of r) {
|
|
78
|
+
console.log(JSON.stringify(rowToObject(h, row)));
|
|
79
|
+
}
|
|
80
|
+
break;
|
|
81
|
+
case 'tsv':
|
|
82
|
+
console.log(h.join('\t'));
|
|
83
|
+
for (const row of r) {
|
|
84
|
+
console.log(row.map(cellToString).join('\t'));
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
case 'yaml':
|
|
88
|
+
for (const row of r) {
|
|
89
|
+
const obj = rowToObject(h, row);
|
|
90
|
+
console.log('---');
|
|
91
|
+
console.log(yamlDump(obj, { lineWidth: -1 }).trimEnd());
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
case 'id': {
|
|
95
|
+
const idIdx = h.indexOf('deviceId') !== -1 ? h.indexOf('deviceId')
|
|
96
|
+
: h.indexOf('sceneId') !== -1 ? h.indexOf('sceneId')
|
|
97
|
+
: -1;
|
|
98
|
+
if (idIdx === -1) {
|
|
99
|
+
throw new UsageError(`--format=id requires a "deviceId" or "sceneId" column. ` +
|
|
100
|
+
`This command outputs: ${h.map((c) => `"${c}"`).join(', ')}.`);
|
|
101
|
+
}
|
|
102
|
+
for (const row of r) {
|
|
103
|
+
console.log(cellToString(row[idIdx]));
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface NameMatch {
|
|
2
|
+
deviceId: string;
|
|
3
|
+
name: string;
|
|
4
|
+
score: number;
|
|
5
|
+
}
|
|
6
|
+
export type NameResolveResult = {
|
|
7
|
+
ok: true;
|
|
8
|
+
deviceId: string;
|
|
9
|
+
} | {
|
|
10
|
+
ok: false;
|
|
11
|
+
ambiguous: true;
|
|
12
|
+
candidates: NameMatch[];
|
|
13
|
+
} | {
|
|
14
|
+
ok: false;
|
|
15
|
+
ambiguous: false;
|
|
16
|
+
};
|
|
17
|
+
export declare function resolveDeviceId(deviceId: string | undefined, nameQuery: string | undefined): string;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { loadCache } from '../devices/cache.js';
|
|
2
|
+
import { loadDeviceMeta } from '../devices/device-meta.js';
|
|
3
|
+
import { levenshtein, normalizeDeviceName } from './string.js';
|
|
4
|
+
import { UsageError, StructuredUsageError } from './output.js';
|
|
5
|
+
function resolveDeviceByName(query) {
|
|
6
|
+
const cache = loadCache();
|
|
7
|
+
if (!cache || Object.keys(cache.devices).length === 0) {
|
|
8
|
+
return { ok: false, ambiguous: false };
|
|
9
|
+
}
|
|
10
|
+
const meta = loadDeviceMeta();
|
|
11
|
+
const q = normalizeDeviceName(query);
|
|
12
|
+
const threshold = Math.min(3, Math.floor(q.length * 0.3));
|
|
13
|
+
const candidates = [];
|
|
14
|
+
for (const [deviceId, device] of Object.entries(cache.devices)) {
|
|
15
|
+
// alias exact match (highest priority)
|
|
16
|
+
const alias = meta.devices[deviceId]?.alias;
|
|
17
|
+
if (alias && normalizeDeviceName(alias) === q) {
|
|
18
|
+
return { ok: true, deviceId };
|
|
19
|
+
}
|
|
20
|
+
const rawName = normalizeDeviceName(device.name);
|
|
21
|
+
// exact match
|
|
22
|
+
if (rawName === q)
|
|
23
|
+
return { ok: true, deviceId };
|
|
24
|
+
// alias substring/fuzzy
|
|
25
|
+
if (alias) {
|
|
26
|
+
const normAlias = normalizeDeviceName(alias);
|
|
27
|
+
if (normAlias.includes(q) || q.includes(normAlias)) {
|
|
28
|
+
candidates.push({ deviceId, name: device.name, score: 1 });
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const dist = levenshtein(normAlias, q);
|
|
32
|
+
if (dist <= threshold) {
|
|
33
|
+
candidates.push({ deviceId, name: device.name, score: dist + 1 });
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// name substring
|
|
38
|
+
if (rawName.includes(q) || q.includes(rawName)) {
|
|
39
|
+
candidates.push({ deviceId, name: device.name, score: 1 });
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
// levenshtein
|
|
43
|
+
const dist = levenshtein(rawName, q);
|
|
44
|
+
if (dist <= threshold) {
|
|
45
|
+
candidates.push({ deviceId, name: device.name, score: dist + 1 });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (candidates.length === 0)
|
|
49
|
+
return { ok: false, ambiguous: false };
|
|
50
|
+
candidates.sort((a, b) => a.score - b.score);
|
|
51
|
+
const best = candidates[0].score;
|
|
52
|
+
const top = candidates.filter((c) => c.score <= best + 1);
|
|
53
|
+
if (top.length === 1)
|
|
54
|
+
return { ok: true, deviceId: top[0].deviceId };
|
|
55
|
+
return { ok: false, ambiguous: true, candidates: top.slice(0, 4) };
|
|
56
|
+
}
|
|
57
|
+
export function resolveDeviceId(deviceId, nameQuery) {
|
|
58
|
+
if (deviceId && nameQuery) {
|
|
59
|
+
throw new UsageError('Provide either a deviceId argument or --name, not both.');
|
|
60
|
+
}
|
|
61
|
+
if (deviceId)
|
|
62
|
+
return deviceId;
|
|
63
|
+
if (!nameQuery) {
|
|
64
|
+
throw new UsageError('A deviceId argument or --name flag is required.');
|
|
65
|
+
}
|
|
66
|
+
const cache = loadCache();
|
|
67
|
+
if (!cache) {
|
|
68
|
+
throw new UsageError(`--name requires the device cache. Run 'switchbot devices list' first to populate it.`);
|
|
69
|
+
}
|
|
70
|
+
const result = resolveDeviceByName(nameQuery);
|
|
71
|
+
if (result.ok)
|
|
72
|
+
return result.deviceId;
|
|
73
|
+
if (result.ambiguous) {
|
|
74
|
+
throw new StructuredUsageError(`"${nameQuery}" is ambiguous — be more specific or use the deviceId directly.`, { candidates: result.candidates.map((c) => ({ deviceId: c.deviceId, name: c.name })) });
|
|
75
|
+
}
|
|
76
|
+
throw new UsageError(`No device matches "${nameQuery}". Run 'switchbot devices list' to see device names.`);
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=name-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"name-resolver.js","sourceRoot":"","sources":["../../src/utils/name-resolver.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/output.d.ts
CHANGED
|
@@ -2,4 +2,22 @@ export declare function isJsonMode(): boolean;
|
|
|
2
2
|
export declare function printJson(data: unknown): void;
|
|
3
3
|
export declare function printTable(headers: string[], rows: (string | number | boolean | null | undefined)[][]): void;
|
|
4
4
|
export declare function printKeyValue(data: Record<string, unknown>): void;
|
|
5
|
+
export declare class UsageError extends Error {
|
|
6
|
+
constructor(message: string);
|
|
7
|
+
}
|
|
8
|
+
export type ErrorSubKind = 'device-offline' | 'device-not-found' | 'command-not-supported' | 'auth-failed' | 'quota-exceeded' | 'device-busy' | 'unknown-api-error';
|
|
9
|
+
export interface ErrorPayload {
|
|
10
|
+
code: number;
|
|
11
|
+
kind: 'usage' | 'api' | 'runtime';
|
|
12
|
+
subKind?: ErrorSubKind;
|
|
13
|
+
message: string;
|
|
14
|
+
hint?: string;
|
|
15
|
+
retryable?: boolean;
|
|
16
|
+
context?: Record<string, unknown>;
|
|
17
|
+
}
|
|
18
|
+
export declare class StructuredUsageError extends Error {
|
|
19
|
+
readonly context?: Record<string, unknown> | undefined;
|
|
20
|
+
constructor(message: string, context?: Record<string, unknown> | undefined);
|
|
21
|
+
}
|
|
22
|
+
export declare function buildErrorPayload(error: unknown): ErrorPayload;
|
|
5
23
|
export declare function handleError(error: unknown): never;
|
package/dist/utils/output.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import Table from 'cli-table3';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { ApiError, DryRunSignal } from '../api/client.js';
|
|
4
|
+
import { getFormat } from './flags.js';
|
|
4
5
|
export function isJsonMode() {
|
|
5
|
-
return process.argv.includes('--json');
|
|
6
|
+
return process.argv.includes('--json') || getFormat() === 'json';
|
|
6
7
|
}
|
|
7
8
|
export function printJson(data) {
|
|
8
9
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -37,18 +38,77 @@ export function printKeyValue(data) {
|
|
|
37
38
|
}
|
|
38
39
|
console.log(table.toString());
|
|
39
40
|
}
|
|
41
|
+
export class UsageError extends Error {
|
|
42
|
+
constructor(message) {
|
|
43
|
+
super(message);
|
|
44
|
+
this.name = 'UsageError';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export class StructuredUsageError extends Error {
|
|
48
|
+
context;
|
|
49
|
+
constructor(message, context) {
|
|
50
|
+
super(message);
|
|
51
|
+
this.context = context;
|
|
52
|
+
this.name = 'StructuredUsageError';
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function classifyApiError(code) {
|
|
56
|
+
switch (code) {
|
|
57
|
+
case 151:
|
|
58
|
+
case 160: return 'command-not-supported';
|
|
59
|
+
case 152: return 'device-not-found';
|
|
60
|
+
case 161:
|
|
61
|
+
case 171: return 'device-offline';
|
|
62
|
+
case 190: return 'device-busy';
|
|
63
|
+
case 401: return 'auth-failed';
|
|
64
|
+
case 429: return 'quota-exceeded';
|
|
65
|
+
default: return 'unknown-api-error';
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export function buildErrorPayload(error) {
|
|
69
|
+
if (error instanceof StructuredUsageError) {
|
|
70
|
+
const payload = { code: 2, kind: 'usage', message: error.message };
|
|
71
|
+
if (error.context)
|
|
72
|
+
payload.context = error.context;
|
|
73
|
+
return payload;
|
|
74
|
+
}
|
|
75
|
+
if (error instanceof UsageError) {
|
|
76
|
+
return { code: 2, kind: 'usage', message: error.message };
|
|
77
|
+
}
|
|
78
|
+
const code = error instanceof ApiError ? error.code : 1;
|
|
79
|
+
const kind = error instanceof ApiError ? 'api' : 'runtime';
|
|
80
|
+
const message = error instanceof Error ? error.message : 'An unknown error occurred';
|
|
81
|
+
const hint = error instanceof ApiError ? (error.hint ?? errorHint(error.code)) : null;
|
|
82
|
+
const retryable = error instanceof ApiError ? error.retryable : false;
|
|
83
|
+
const payload = { code, kind, message };
|
|
84
|
+
if (error instanceof ApiError)
|
|
85
|
+
payload.subKind = classifyApiError(error.code);
|
|
86
|
+
if (hint)
|
|
87
|
+
payload.hint = hint;
|
|
88
|
+
if (retryable)
|
|
89
|
+
payload.retryable = true;
|
|
90
|
+
return payload;
|
|
91
|
+
}
|
|
40
92
|
export function handleError(error) {
|
|
41
93
|
if (error instanceof DryRunSignal) {
|
|
42
94
|
process.exit(0);
|
|
43
95
|
}
|
|
96
|
+
const payload = buildErrorPayload(error);
|
|
97
|
+
if (isJsonMode()) {
|
|
98
|
+
console.error(JSON.stringify({ error: payload }));
|
|
99
|
+
process.exit(payload.code === 2 ? 2 : 1);
|
|
100
|
+
}
|
|
101
|
+
if (payload.kind === 'usage') {
|
|
102
|
+
console.error(payload.message);
|
|
103
|
+
process.exit(2);
|
|
104
|
+
}
|
|
44
105
|
if (error instanceof ApiError) {
|
|
45
|
-
console.error(chalk.red(`Error (code ${error.code}): ${
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
console.error(chalk.grey(`Hint: ${hint}`));
|
|
106
|
+
console.error(chalk.red(`Error (code ${error.code}): ${payload.message}`));
|
|
107
|
+
if (payload.hint)
|
|
108
|
+
console.error(chalk.grey(`Hint: ${payload.hint}`));
|
|
49
109
|
}
|
|
50
110
|
else if (error instanceof Error) {
|
|
51
|
-
console.error(chalk.red(`Error: ${
|
|
111
|
+
console.error(chalk.red(`Error: ${payload.message}`));
|
|
52
112
|
}
|
|
53
113
|
else {
|
|
54
114
|
console.error(chalk.red('An unknown error occurred'));
|
package/dist/utils/output.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/utils/output.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAE1D,MAAM,UAAU,UAAU;IACxB,OAAO,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/utils/output.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local quota counter. Tracks the SwitchBot 10k/day request budget so the
|
|
3
|
+
* CLI (and any AI agent) can check "how many calls have I already burned?"
|
|
4
|
+
* without pinging the API.
|
|
5
|
+
*
|
|
6
|
+
* Shape (`~/.switchbot/quota.json`):
|
|
7
|
+
* {
|
|
8
|
+
* "days": {
|
|
9
|
+
* "2026-04-18": {
|
|
10
|
+
* "total": 42,
|
|
11
|
+
* "endpoints": {
|
|
12
|
+
* "GET /v1.1/devices": 3,
|
|
13
|
+
* "GET /v1.1/devices/:id/status": 27,
|
|
14
|
+
* "POST /v1.1/devices/:id/commands": 12
|
|
15
|
+
* }
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* We keep the last 7 days to bound the file size and give a short-term
|
|
21
|
+
* trend. Writes are fire-and-forget — a failed write never breaks the
|
|
22
|
+
* actual API call.
|
|
23
|
+
*/
|
|
24
|
+
export declare const DAILY_QUOTA = 10000;
|
|
25
|
+
export interface DayBucket {
|
|
26
|
+
total: number;
|
|
27
|
+
endpoints: Record<string, number>;
|
|
28
|
+
}
|
|
29
|
+
export interface QuotaFile {
|
|
30
|
+
days: Record<string, DayBucket>;
|
|
31
|
+
}
|
|
32
|
+
export declare function loadQuota(): QuotaFile;
|
|
33
|
+
/**
|
|
34
|
+
* Normalise a full URL into a SwitchBot-style endpoint pattern. The segment
|
|
35
|
+
* immediately after `devices` or `scenes` is collapsed to `:id` so we can
|
|
36
|
+
* bucket by endpoint shape rather than by specific deviceId/sceneId.
|
|
37
|
+
*/
|
|
38
|
+
export declare function normaliseEndpoint(method: string, url: string): string;
|
|
39
|
+
/** Record a single request. Bucketed by local-date + endpoint pattern. */
|
|
40
|
+
export declare function recordRequest(method: string, url: string, now?: Date): void;
|
|
41
|
+
export declare function resetQuota(): void;
|
|
42
|
+
/** Return today's usage (convenience for `quota status`). */
|
|
43
|
+
export declare function todayUsage(now?: Date): {
|
|
44
|
+
date: string;
|
|
45
|
+
total: number;
|
|
46
|
+
remaining: number;
|
|
47
|
+
endpoints: Record<string, number>;
|
|
48
|
+
};
|