@switchbot/openapi-cli 3.1.0 → 3.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 (113) hide show
  1. package/README.md +34 -42
  2. package/dist/index.js +56945 -169
  3. package/dist/policy/schema/v0.2.json +1 -1
  4. package/package.json +3 -2
  5. package/dist/api/client.js +0 -235
  6. package/dist/auth.js +0 -20
  7. package/dist/commands/agent-bootstrap.js +0 -182
  8. package/dist/commands/auth.js +0 -354
  9. package/dist/commands/batch.js +0 -413
  10. package/dist/commands/cache.js +0 -126
  11. package/dist/commands/capabilities.js +0 -385
  12. package/dist/commands/catalog.js +0 -359
  13. package/dist/commands/completion.js +0 -385
  14. package/dist/commands/config.js +0 -376
  15. package/dist/commands/daemon.js +0 -367
  16. package/dist/commands/device-meta.js +0 -159
  17. package/dist/commands/devices.js +0 -948
  18. package/dist/commands/doctor.js +0 -1015
  19. package/dist/commands/events.js +0 -563
  20. package/dist/commands/expand.js +0 -130
  21. package/dist/commands/explain.js +0 -139
  22. package/dist/commands/health.js +0 -113
  23. package/dist/commands/history.js +0 -320
  24. package/dist/commands/identity.js +0 -59
  25. package/dist/commands/install.js +0 -246
  26. package/dist/commands/mcp.js +0 -2017
  27. package/dist/commands/plan.js +0 -653
  28. package/dist/commands/policy.js +0 -586
  29. package/dist/commands/quota.js +0 -78
  30. package/dist/commands/rules.js +0 -875
  31. package/dist/commands/scenes.js +0 -264
  32. package/dist/commands/schema.js +0 -177
  33. package/dist/commands/status-sync.js +0 -131
  34. package/dist/commands/uninstall.js +0 -237
  35. package/dist/commands/upgrade-check.js +0 -88
  36. package/dist/commands/watch.js +0 -194
  37. package/dist/commands/webhook.js +0 -182
  38. package/dist/config.js +0 -258
  39. package/dist/credentials/backends/file.js +0 -101
  40. package/dist/credentials/backends/linux.js +0 -129
  41. package/dist/credentials/backends/macos.js +0 -129
  42. package/dist/credentials/backends/windows.js +0 -215
  43. package/dist/credentials/keychain.js +0 -88
  44. package/dist/credentials/prime.js +0 -52
  45. package/dist/devices/cache.js +0 -293
  46. package/dist/devices/catalog.js +0 -767
  47. package/dist/devices/device-meta.js +0 -56
  48. package/dist/devices/history-agg.js +0 -138
  49. package/dist/devices/history-query.js +0 -181
  50. package/dist/devices/param-validator.js +0 -433
  51. package/dist/devices/resources.js +0 -270
  52. package/dist/install/default-steps.js +0 -257
  53. package/dist/install/preflight.js +0 -212
  54. package/dist/install/steps.js +0 -67
  55. package/dist/lib/command-keywords.js +0 -17
  56. package/dist/lib/daemon-state.js +0 -46
  57. package/dist/lib/destructive-mode.js +0 -12
  58. package/dist/lib/devices.js +0 -382
  59. package/dist/lib/idempotency.js +0 -106
  60. package/dist/lib/plan-store.js +0 -68
  61. package/dist/lib/request-context.js +0 -12
  62. package/dist/lib/scenes.js +0 -10
  63. package/dist/logger.js +0 -16
  64. package/dist/mcp/device-history.js +0 -145
  65. package/dist/mcp/events-subscription.js +0 -213
  66. package/dist/mqtt/client.js +0 -180
  67. package/dist/mqtt/credential.js +0 -30
  68. package/dist/policy/add-rule.js +0 -124
  69. package/dist/policy/diff.js +0 -91
  70. package/dist/policy/format.js +0 -57
  71. package/dist/policy/load.js +0 -61
  72. package/dist/policy/migrate.js +0 -67
  73. package/dist/policy/schema.js +0 -18
  74. package/dist/policy/validate.js +0 -262
  75. package/dist/rules/action.js +0 -205
  76. package/dist/rules/audit-query.js +0 -89
  77. package/dist/rules/conflict-analyzer.js +0 -203
  78. package/dist/rules/cron-scheduler.js +0 -186
  79. package/dist/rules/destructive.js +0 -52
  80. package/dist/rules/engine.js +0 -757
  81. package/dist/rules/matcher.js +0 -230
  82. package/dist/rules/pid-file.js +0 -95
  83. package/dist/rules/quiet-hours.js +0 -45
  84. package/dist/rules/suggest.js +0 -95
  85. package/dist/rules/throttle.js +0 -116
  86. package/dist/rules/types.js +0 -34
  87. package/dist/rules/webhook-listener.js +0 -223
  88. package/dist/rules/webhook-token.js +0 -90
  89. package/dist/schema/field-aliases.js +0 -131
  90. package/dist/sinks/dispatcher.js +0 -12
  91. package/dist/sinks/file.js +0 -19
  92. package/dist/sinks/format.js +0 -56
  93. package/dist/sinks/homeassistant.js +0 -44
  94. package/dist/sinks/openclaw.js +0 -33
  95. package/dist/sinks/stdout.js +0 -5
  96. package/dist/sinks/telegram.js +0 -28
  97. package/dist/sinks/types.js +0 -1
  98. package/dist/sinks/webhook.js +0 -22
  99. package/dist/status-sync/manager.js +0 -268
  100. package/dist/utils/arg-parsers.js +0 -66
  101. package/dist/utils/audit.js +0 -117
  102. package/dist/utils/filter.js +0 -189
  103. package/dist/utils/flags.js +0 -186
  104. package/dist/utils/format.js +0 -117
  105. package/dist/utils/health.js +0 -101
  106. package/dist/utils/help-json.js +0 -54
  107. package/dist/utils/name-resolver.js +0 -137
  108. package/dist/utils/output.js +0 -404
  109. package/dist/utils/quota.js +0 -227
  110. package/dist/utils/redact.js +0 -68
  111. package/dist/utils/retry.js +0 -140
  112. package/dist/utils/string.js +0 -22
  113. package/dist/version.js +0 -4
@@ -1,212 +0,0 @@
1
- /**
2
- * Install-orchestrator pre-flight (Phase 3A · F5).
3
- *
4
- * Pure library — no CLI entry. Consumers (e.g. a future
5
- * `openclaw plugins install` command) call `runPreflight()` and decide
6
- * whether to proceed based on the returned result. Nothing here mutates
7
- * user state: every check is read-only.
8
- *
9
- * The check list mirrors `docs/design/phase3-install.md` step 1 minus
10
- * the bits that require external services (npm registry / SwitchBot API
11
- * reachability are left for the installer itself to probe when it has
12
- * a plan to retry, since they are the flakiest of the lot).
13
- */
14
- import fs from 'node:fs';
15
- import path from 'node:path';
16
- import os from 'node:os';
17
- import { resolvePolicyPath, loadPolicyFile, PolicyFileNotFoundError } from '../policy/load.js';
18
- import { validateLoadedPolicy } from '../policy/validate.js';
19
- import { selectCredentialStore } from '../credentials/keychain.js';
20
- function parseMajor(version) {
21
- const m = /^v?(\d+)\./.exec(version);
22
- if (!m)
23
- return null;
24
- const n = Number(m[1]);
25
- return Number.isFinite(n) ? n : null;
26
- }
27
- function checkNodeVersion(opts) {
28
- const required = opts.minNodeMajor ?? 18;
29
- const version = opts.nodeVersion ?? process.version;
30
- const major = parseMajor(version);
31
- if (major === null) {
32
- return {
33
- name: 'node',
34
- status: 'fail',
35
- message: `unrecognised Node.js version string: ${version}`,
36
- hint: 'reinstall Node.js from https://nodejs.org',
37
- };
38
- }
39
- if (major < required) {
40
- return {
41
- name: 'node',
42
- status: 'fail',
43
- message: `Node.js ${version} < required v${required}`,
44
- hint: `upgrade Node.js to v${required} or later`,
45
- };
46
- }
47
- return { name: 'node', status: 'ok', message: `Node.js ${version}` };
48
- }
49
- function checkPolicy() {
50
- const policyPath = resolvePolicyPath();
51
- try {
52
- const loaded = loadPolicyFile(policyPath);
53
- const result = validateLoadedPolicy(loaded);
54
- if (result.valid) {
55
- return {
56
- name: 'policy',
57
- status: 'ok',
58
- message: `policy at ${policyPath} validates (v${result.schemaVersion ?? '?'})`,
59
- };
60
- }
61
- return {
62
- name: 'policy',
63
- status: 'warn',
64
- message: `policy at ${policyPath} has ${result.errors.length} validation error(s)`,
65
- hint: 'run "switchbot policy validate" to see details before installing',
66
- };
67
- }
68
- catch (err) {
69
- if (err instanceof PolicyFileNotFoundError) {
70
- return {
71
- name: 'policy',
72
- status: 'ok',
73
- message: `no policy at ${policyPath} (installer will scaffold one)`,
74
- };
75
- }
76
- return {
77
- name: 'policy',
78
- status: 'warn',
79
- message: `policy at ${policyPath} is unreadable: ${err instanceof Error ? err.message : String(err)}`,
80
- hint: 'move the file aside, then re-run — the installer will scaffold a fresh copy',
81
- };
82
- }
83
- }
84
- async function checkKeychain() {
85
- try {
86
- const store = await selectCredentialStore();
87
- const desc = store.describe();
88
- if (desc.writable) {
89
- return {
90
- name: 'keychain',
91
- status: 'ok',
92
- message: `credential backend: ${desc.backend}`,
93
- };
94
- }
95
- return {
96
- name: 'keychain',
97
- status: 'warn',
98
- message: `credential backend ${desc.backend} is not writable — will fall back to file`,
99
- hint: desc.notes ?? 'install the OS keychain helper to get native credential storage',
100
- };
101
- }
102
- catch (err) {
103
- return {
104
- name: 'keychain',
105
- status: 'warn',
106
- message: `keychain probe failed: ${err instanceof Error ? err.message : String(err)}`,
107
- hint: 'the installer will fall back to the file backend',
108
- };
109
- }
110
- }
111
- function checkHomeDirWritable() {
112
- const home = os.homedir();
113
- const switchbotDir = path.join(home, '.switchbot');
114
- try {
115
- const homeStat = fs.statSync(home);
116
- if (!homeStat.isDirectory()) {
117
- return {
118
- name: 'home',
119
- status: 'fail',
120
- message: `home path is not a directory: ${home}`,
121
- hint: 'check your HOME/USERPROFILE environment configuration',
122
- };
123
- }
124
- if (fs.existsSync(switchbotDir)) {
125
- const sbStat = fs.statSync(switchbotDir);
126
- if (!sbStat.isDirectory()) {
127
- return {
128
- name: 'home',
129
- status: 'fail',
130
- message: `${switchbotDir} exists but is not a directory`,
131
- hint: 'move the file aside and re-run install',
132
- };
133
- }
134
- fs.accessSync(switchbotDir, fs.constants.W_OK);
135
- return { name: 'home', status: 'ok', message: `writable: ${switchbotDir}` };
136
- }
137
- fs.accessSync(home, fs.constants.W_OK);
138
- return { name: 'home', status: 'ok', message: `writable: ${home}` };
139
- }
140
- catch (err) {
141
- return {
142
- name: 'home',
143
- status: 'fail',
144
- message: `cannot write under ${home}: ${err instanceof Error ? err.message : String(err)}`,
145
- hint: 'check ownership and permissions on your home directory',
146
- };
147
- }
148
- }
149
- function nearestExistingPath(target) {
150
- let cur = target;
151
- while (true) {
152
- if (fs.existsSync(cur))
153
- return cur;
154
- const parent = path.dirname(cur);
155
- if (parent === cur)
156
- return null;
157
- cur = parent;
158
- }
159
- }
160
- function checkAgentSkillDirWritable(opts) {
161
- const shouldCheck = opts.agent === 'claude-code' && (opts.expectSkillLink ?? true);
162
- if (!shouldCheck)
163
- return null;
164
- const home = os.homedir();
165
- const target = path.join(home, '.claude', 'skills');
166
- try {
167
- const existing = nearestExistingPath(target);
168
- if (!existing) {
169
- return {
170
- name: 'agent-skills-dir',
171
- status: 'fail',
172
- message: `cannot resolve an existing parent for ${target}`,
173
- hint: 'check your home directory path and permissions',
174
- };
175
- }
176
- const stat = fs.statSync(existing);
177
- if (!stat.isDirectory()) {
178
- return {
179
- name: 'agent-skills-dir',
180
- status: 'fail',
181
- message: `path component is not a directory: ${existing}`,
182
- hint: 'move the blocking file aside and re-run install',
183
- };
184
- }
185
- fs.accessSync(existing, fs.constants.W_OK);
186
- return { name: 'agent-skills-dir', status: 'ok', message: `writable: ${target}` };
187
- }
188
- catch (err) {
189
- return {
190
- name: 'agent-skills-dir',
191
- status: 'fail',
192
- message: `cannot write to ${target}: ${err instanceof Error ? err.message : String(err)}`,
193
- hint: 'open Claude Code once (it will create ~/.claude) or create the directory manually',
194
- };
195
- }
196
- }
197
- /**
198
- * Run every pre-flight check and return a combined result. Safe to
199
- * call multiple times; no state is cached.
200
- */
201
- export async function runPreflight(options = {}) {
202
- const checks = [];
203
- checks.push(checkNodeVersion(options));
204
- checks.push(checkPolicy());
205
- checks.push(await checkKeychain());
206
- checks.push(checkHomeDirWritable());
207
- const agentCheck = checkAgentSkillDirWritable(options);
208
- if (agentCheck)
209
- checks.push(agentCheck);
210
- const ok = checks.every((c) => c.status !== 'fail');
211
- return { checks, ok };
212
- }
@@ -1,67 +0,0 @@
1
- /**
2
- * Install-orchestrator step runner (Phase 3A · F5).
3
- *
4
- * Each step has a deterministic `execute` and a matching `undo`. The
5
- * runner executes steps in order; on any failure it walks the
6
- * already-completed steps in reverse and invokes their `undo`. If an
7
- * `undo` itself fails, the error is captured and surfaced — the
8
- * runner does NOT abort the rollback. The caller gets a full report
9
- * and can decide how to surface partial cleanup failures.
10
- *
11
- * The module is intentionally agnostic of what steps do; consumers
12
- * (future `openclaw plugins install`) plug in concrete steps like
13
- * "npm i -g the CLI" or "write the credential to the keychain".
14
- */
15
- /**
16
- * Run the given steps in order. On the first failure, the runner
17
- * walks already-executed steps in reverse and invokes each step's
18
- * undo. Returns a report describing every step's fate.
19
- */
20
- export async function runInstall(steps, options = {}) {
21
- const ctx = (options.context ?? {});
22
- const outcomes = [];
23
- const executed = [];
24
- let failedAt;
25
- for (const step of steps) {
26
- try {
27
- await step.execute(ctx);
28
- outcomes.push({ step: step.name, status: 'succeeded' });
29
- executed.push(step);
30
- }
31
- catch (err) {
32
- outcomes.push({
33
- step: step.name,
34
- status: 'failed',
35
- error: err instanceof Error ? err.message : String(err),
36
- });
37
- failedAt = step.name;
38
- break;
39
- }
40
- if (options.stopAfter === step.name)
41
- break;
42
- }
43
- if (failedAt !== undefined) {
44
- // Roll back completed steps in reverse. Undo failures are captured
45
- // but do not abort further rollback attempts — the goal is to
46
- // leave as little residue as possible.
47
- for (let i = executed.length - 1; i >= 0; i--) {
48
- const step = executed[i];
49
- try {
50
- await step.undo(ctx);
51
- outcomes.push({ step: step.name, status: 'rolled-back' });
52
- }
53
- catch (err) {
54
- outcomes.push({
55
- step: step.name,
56
- status: 'rollback-failed',
57
- error: err instanceof Error ? err.message : String(err),
58
- });
59
- }
60
- }
61
- }
62
- return {
63
- ok: failedAt === undefined,
64
- outcomes,
65
- ...(failedAt !== undefined ? { failedAt } : {}),
66
- };
67
- }
@@ -1,17 +0,0 @@
1
- export const COMMAND_KEYWORDS = [
2
- { pattern: /\boff\b|\bturn.?off\b|\bstop\b/i, command: 'turnOff' },
3
- { pattern: /\bon\b|\bturn.?on\b|\bstart\b/i, command: 'turnOn' },
4
- { pattern: /\bpress\b|\bclick\b|\btap\b/i, command: 'press' },
5
- { pattern: /\block\b/i, command: 'lock' },
6
- { pattern: /\bunlock\b/i, command: 'unlock' },
7
- { pattern: /\bopen\b|\braise\b|\bup\b/i, command: 'open' },
8
- { pattern: /\bclose\b|\blower\b|\bdown\b/i, command: 'close' },
9
- { pattern: /\bpause\b/i, command: 'pause' },
10
- ];
11
- export function inferCommandFromIntent(intent) {
12
- for (const k of COMMAND_KEYWORDS) {
13
- if (k.pattern.test(intent))
14
- return k.command;
15
- }
16
- return undefined;
17
- }
@@ -1,46 +0,0 @@
1
- import fs from 'node:fs';
2
- import os from 'node:os';
3
- import path from 'node:path';
4
- function getStateDir() {
5
- return path.join(os.homedir(), '.switchbot');
6
- }
7
- function getDaemonPidFile() {
8
- return path.join(getStateDir(), 'daemon.pid');
9
- }
10
- function getDaemonLogFile() {
11
- return path.join(getStateDir(), 'daemon.log');
12
- }
13
- function getDaemonStateFile() {
14
- return path.join(getStateDir(), 'daemon.state.json');
15
- }
16
- function getHealthzPidFile() {
17
- return path.join(getStateDir(), 'healthz.pid');
18
- }
19
- export const DAEMON_PID_FILE = getDaemonPidFile();
20
- export const DAEMON_LOG_FILE = getDaemonLogFile();
21
- export const DAEMON_STATE_FILE = getDaemonStateFile();
22
- export const HEALTHZ_PID_FILE = getHealthzPidFile();
23
- function ensureStateDir() {
24
- fs.mkdirSync(getStateDir(), { recursive: true, mode: 0o700 });
25
- }
26
- export function writeDaemonState(state) {
27
- ensureStateDir();
28
- fs.writeFileSync(getDaemonStateFile(), JSON.stringify(state, null, 2), { mode: 0o600 });
29
- }
30
- export function readDaemonState() {
31
- try {
32
- const raw = fs.readFileSync(getDaemonStateFile(), 'utf-8');
33
- return JSON.parse(raw);
34
- }
35
- catch {
36
- return null;
37
- }
38
- }
39
- export function removeDaemonState() {
40
- try {
41
- fs.unlinkSync(getDaemonStateFile());
42
- }
43
- catch {
44
- // best effort
45
- }
46
- }
@@ -1,12 +0,0 @@
1
- import { getActiveProfile } from './request-context.js';
2
- const DIRECT_DESTRUCTIVE_PROFILES = new Set(['dev', 'development']);
3
- export function allowsDirectDestructiveExecution(profile = getActiveProfile()) {
4
- if (process.env.SWITCHBOT_ALLOW_DIRECT_DESTRUCTIVE === '1')
5
- return true;
6
- if (!profile)
7
- return false;
8
- return DIRECT_DESTRUCTIVE_PROFILES.has(profile.toLowerCase());
9
- }
10
- export function destructiveExecutionHint() {
11
- return "Use 'switchbot plan save <file>' -> 'switchbot plan review <planId>' -> 'switchbot plan approve <planId>' -> 'switchbot plan execute <planId>' instead.";
12
- }