aranea-sdk-cli 0.3.13 → 0.3.15

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.
@@ -0,0 +1,15 @@
1
+ /**
2
+ * device コマンド - デバイス直接操作(HTTP経由)
3
+ *
4
+ * MQTTが未設定のデバイスに対して、HTTP経由で直接設定を行う
5
+ *
6
+ * Usage:
7
+ * aranea-sdk device status -i 192.168.3.126
8
+ * aranea-sdk device config get -i 192.168.3.126
9
+ * aranea-sdk device config set -i 192.168.3.126 -k mqtt_broker -v "wss://..."
10
+ * aranea-sdk device reboot -i 192.168.3.126 --force
11
+ * aranea-sdk device scan --subnet 192.168.3
12
+ */
13
+ import { Command } from 'commander';
14
+ export declare const deviceCommand: Command;
15
+ export default deviceCommand;
@@ -0,0 +1,518 @@
1
+ "use strict";
2
+ /**
3
+ * device コマンド - デバイス直接操作(HTTP経由)
4
+ *
5
+ * MQTTが未設定のデバイスに対して、HTTP経由で直接設定を行う
6
+ *
7
+ * Usage:
8
+ * aranea-sdk device status -i 192.168.3.126
9
+ * aranea-sdk device config get -i 192.168.3.126
10
+ * aranea-sdk device config set -i 192.168.3.126 -k mqtt_broker -v "wss://..."
11
+ * aranea-sdk device reboot -i 192.168.3.126 --force
12
+ * aranea-sdk device scan --subnet 192.168.3
13
+ */
14
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ var desc = Object.getOwnPropertyDescriptor(m, k);
17
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
18
+ desc = { enumerable: true, get: function() { return m[k]; } };
19
+ }
20
+ Object.defineProperty(o, k2, desc);
21
+ }) : (function(o, m, k, k2) {
22
+ if (k2 === undefined) k2 = k;
23
+ o[k2] = m[k];
24
+ }));
25
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
26
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
27
+ }) : function(o, v) {
28
+ o["default"] = v;
29
+ });
30
+ var __importStar = (this && this.__importStar) || (function () {
31
+ var ownKeys = function(o) {
32
+ ownKeys = Object.getOwnPropertyNames || function (o) {
33
+ var ar = [];
34
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
35
+ return ar;
36
+ };
37
+ return ownKeys(o);
38
+ };
39
+ return function (mod) {
40
+ if (mod && mod.__esModule) return mod;
41
+ var result = {};
42
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
43
+ __setModuleDefault(result, mod);
44
+ return result;
45
+ };
46
+ })();
47
+ var __importDefault = (this && this.__importDefault) || function (mod) {
48
+ return (mod && mod.__esModule) ? mod : { "default": mod };
49
+ };
50
+ Object.defineProperty(exports, "__esModule", { value: true });
51
+ exports.deviceCommand = void 0;
52
+ const commander_1 = require("commander");
53
+ const chalk_1 = __importDefault(require("chalk"));
54
+ const ora_1 = __importDefault(require("ora"));
55
+ const axios_1 = __importStar(require("axios"));
56
+ // ============================================================================
57
+ // Helper Functions
58
+ // ============================================================================
59
+ /**
60
+ * デバイスのベースURL取得
61
+ */
62
+ function getDeviceBaseUrl(ip, port = 80, https = false) {
63
+ const protocol = https ? 'https' : 'http';
64
+ return `${protocol}://${ip}:${port}`;
65
+ }
66
+ /**
67
+ * HTTP GETリクエスト
68
+ */
69
+ async function httpGet(url, timeout = 5000) {
70
+ const response = await axios_1.default.get(url, {
71
+ timeout,
72
+ headers: {
73
+ Accept: 'application/json',
74
+ },
75
+ });
76
+ return response.data;
77
+ }
78
+ /**
79
+ * HTTP POSTリクエスト
80
+ */
81
+ async function httpPost(url, data, timeout = 5000) {
82
+ const response = await axios_1.default.post(url, data, {
83
+ timeout,
84
+ headers: {
85
+ 'Content-Type': 'application/json',
86
+ Accept: 'application/json',
87
+ },
88
+ });
89
+ return response.data;
90
+ }
91
+ /**
92
+ * エラーメッセージ抽出
93
+ */
94
+ function getErrorMessage(error) {
95
+ if (error instanceof axios_1.AxiosError) {
96
+ if (error.code === 'ECONNREFUSED') {
97
+ return 'Connection refused - デバイスが応答しません';
98
+ }
99
+ if (error.code === 'ETIMEDOUT' || error.code === 'ECONNABORTED') {
100
+ return 'Timeout - デバイスからの応答がありません';
101
+ }
102
+ if (error.response) {
103
+ return `HTTP ${error.response.status}: ${error.response.statusText}`;
104
+ }
105
+ return error.message;
106
+ }
107
+ if (error instanceof Error) {
108
+ return error.message;
109
+ }
110
+ return String(error);
111
+ }
112
+ // ============================================================================
113
+ // Commands
114
+ // ============================================================================
115
+ exports.deviceCommand = new commander_1.Command('device').description('デバイス直接操作(HTTP経由)- MQTT未設定デバイス向け');
116
+ // ----------------------------------------------------------------------------
117
+ // device status
118
+ // ----------------------------------------------------------------------------
119
+ exports.deviceCommand
120
+ .command('status')
121
+ .description('デバイス状態を取得')
122
+ .requiredOption('-i, --ip <ip>', 'デバイスIPアドレス')
123
+ .option('-P, --port <port>', 'HTTPポート', '80')
124
+ .option('--https', 'HTTPSを使用')
125
+ .option('--timeout <ms>', 'タイムアウト(ミリ秒)', '5000')
126
+ .action(async (options) => {
127
+ try {
128
+ console.log(chalk_1.default.bold('\n=== Device Status ===\n'));
129
+ const baseUrl = getDeviceBaseUrl(options.ip, parseInt(options.port), options.https);
130
+ console.log(chalk_1.default.cyan('ターゲット:'));
131
+ console.log(` IP: ${options.ip}`);
132
+ console.log(` Port: ${options.port}`);
133
+ console.log('');
134
+ const spinner = (0, ora_1.default)('ステータス取得中...').start();
135
+ // Try multiple common endpoints
136
+ const endpoints = ['/api/status', '/status', '/api/info', '/info'];
137
+ let status = null;
138
+ let successEndpoint = '';
139
+ for (const endpoint of endpoints) {
140
+ try {
141
+ status = await httpGet(`${baseUrl}${endpoint}`, parseInt(options.timeout));
142
+ successEndpoint = endpoint;
143
+ break;
144
+ }
145
+ catch {
146
+ // Try next endpoint
147
+ }
148
+ }
149
+ if (!status) {
150
+ spinner.fail('デバイスからステータスを取得できませんでした');
151
+ console.log(chalk_1.default.yellow('\n試行したエンドポイント:'));
152
+ endpoints.forEach((e) => console.log(` - ${baseUrl}${e}`));
153
+ process.exit(1);
154
+ }
155
+ spinner.succeed(`ステータス取得成功 (${successEndpoint})`);
156
+ console.log('');
157
+ // Display status
158
+ console.log(chalk_1.default.cyan('デバイス情報:'));
159
+ if (status.lacisId)
160
+ console.log(` LacisID: ${chalk_1.default.green(status.lacisId)}`);
161
+ if (status.cic)
162
+ console.log(` CIC: ${status.cic}`);
163
+ if (status.type)
164
+ console.log(` Type: ${status.type}`);
165
+ if (status.mac)
166
+ console.log(` MAC: ${status.mac}`);
167
+ if (status.ip)
168
+ console.log(` IP: ${status.ip}`);
169
+ if (status.firmwareVersion)
170
+ console.log(` Firmware: ${status.firmwareVersion}`);
171
+ if (status.uptime !== undefined) {
172
+ const hours = Math.floor(status.uptime / 3600);
173
+ const mins = Math.floor((status.uptime % 3600) / 60);
174
+ console.log(` Uptime: ${hours}h ${mins}m`);
175
+ }
176
+ if (status.freeHeap !== undefined)
177
+ console.log(` Free Heap: ${(status.freeHeap / 1024).toFixed(1)} KB`);
178
+ if (status.rssi !== undefined)
179
+ console.log(` WiFi RSSI: ${status.rssi} dBm`);
180
+ if (status.wifiConnected !== undefined) {
181
+ console.log(` WiFi: ${status.wifiConnected ? chalk_1.default.green('Connected') : chalk_1.default.red('Disconnected')}`);
182
+ }
183
+ if (status.mqttConnected !== undefined) {
184
+ console.log(` MQTT: ${status.mqttConnected ? chalk_1.default.green('Connected') : chalk_1.default.yellow('Not connected')}`);
185
+ }
186
+ // Show raw JSON for other fields
187
+ const knownKeys = [
188
+ 'lacisId',
189
+ 'cic',
190
+ 'type',
191
+ 'mac',
192
+ 'ip',
193
+ 'firmwareVersion',
194
+ 'uptime',
195
+ 'freeHeap',
196
+ 'rssi',
197
+ 'wifiConnected',
198
+ 'mqttConnected',
199
+ ];
200
+ const otherKeys = Object.keys(status).filter((k) => !knownKeys.includes(k));
201
+ if (otherKeys.length > 0) {
202
+ console.log('');
203
+ console.log(chalk_1.default.gray('その他のフィールド:'));
204
+ otherKeys.forEach((k) => {
205
+ console.log(` ${k}: ${JSON.stringify(status[k])}`);
206
+ });
207
+ }
208
+ console.log('');
209
+ }
210
+ catch (error) {
211
+ console.error(chalk_1.default.red(`❌ エラー: ${getErrorMessage(error)}`));
212
+ process.exit(1);
213
+ }
214
+ });
215
+ // ----------------------------------------------------------------------------
216
+ // device config (parent)
217
+ // ----------------------------------------------------------------------------
218
+ const configCommand = exports.deviceCommand.command('config').description('デバイス設定の取得・変更');
219
+ // ----------------------------------------------------------------------------
220
+ // device config get
221
+ // ----------------------------------------------------------------------------
222
+ configCommand
223
+ .command('get')
224
+ .description('現在の設定を取得')
225
+ .requiredOption('-i, --ip <ip>', 'デバイスIPアドレス')
226
+ .option('-P, --port <port>', 'HTTPポート', '80')
227
+ .option('--https', 'HTTPSを使用')
228
+ .option('-k, --key <key>', '特定のキーのみ取得')
229
+ .option('--timeout <ms>', 'タイムアウト(ミリ秒)', '5000')
230
+ .action(async (options) => {
231
+ try {
232
+ console.log(chalk_1.default.bold('\n=== Device Config Get ===\n'));
233
+ const baseUrl = getDeviceBaseUrl(options.ip, parseInt(options.port), options.https);
234
+ console.log(chalk_1.default.cyan('ターゲット:'));
235
+ console.log(` IP: ${options.ip}`);
236
+ if (options.key) {
237
+ console.log(` Key: ${options.key}`);
238
+ }
239
+ console.log('');
240
+ const spinner = (0, ora_1.default)('設定取得中...').start();
241
+ const endpoints = ['/api/config', '/config', '/api/settings', '/settings'];
242
+ let config = null;
243
+ let successEndpoint = '';
244
+ for (const endpoint of endpoints) {
245
+ try {
246
+ config = await httpGet(`${baseUrl}${endpoint}`, parseInt(options.timeout));
247
+ successEndpoint = endpoint;
248
+ break;
249
+ }
250
+ catch {
251
+ // Try next endpoint
252
+ }
253
+ }
254
+ if (!config) {
255
+ spinner.fail('デバイスから設定を取得できませんでした');
256
+ process.exit(1);
257
+ }
258
+ spinner.succeed(`設定取得成功 (${successEndpoint})`);
259
+ console.log('');
260
+ if (options.key) {
261
+ // Show specific key
262
+ if (options.key in config) {
263
+ console.log(`${options.key}: ${chalk_1.default.green(String(config[options.key]))}`);
264
+ }
265
+ else {
266
+ console.log(chalk_1.default.yellow(`⚠ キー "${options.key}" が見つかりません`));
267
+ console.log(chalk_1.default.gray('利用可能なキー: ' + Object.keys(config).join(', ')));
268
+ }
269
+ }
270
+ else {
271
+ // Show all config
272
+ console.log(chalk_1.default.cyan('設定一覧:'));
273
+ Object.entries(config).forEach(([key, value]) => {
274
+ const displayValue = typeof value === 'string' && value.length > 50
275
+ ? value.substring(0, 50) + '...'
276
+ : String(value);
277
+ // Highlight MQTT-related keys
278
+ if (key.toLowerCase().includes('mqtt') || key.toLowerCase().includes('broker')) {
279
+ console.log(` ${chalk_1.default.yellow(key)}: ${chalk_1.default.green(displayValue)}`);
280
+ }
281
+ else {
282
+ console.log(` ${key}: ${displayValue}`);
283
+ }
284
+ });
285
+ }
286
+ console.log('');
287
+ }
288
+ catch (error) {
289
+ console.error(chalk_1.default.red(`❌ エラー: ${getErrorMessage(error)}`));
290
+ process.exit(1);
291
+ }
292
+ });
293
+ // ----------------------------------------------------------------------------
294
+ // device config set
295
+ // ----------------------------------------------------------------------------
296
+ configCommand
297
+ .command('set')
298
+ .description('設定値を変更')
299
+ .requiredOption('-i, --ip <ip>', 'デバイスIPアドレス')
300
+ .requiredOption('-k, --key <key>', '設定キー')
301
+ .requiredOption('-v, --value <value>', '設定値')
302
+ .option('-P, --port <port>', 'HTTPポート', '80')
303
+ .option('--https', 'HTTPSを使用')
304
+ .option('--timeout <ms>', 'タイムアウト(ミリ秒)', '5000')
305
+ .option('-d, --dry-run', '実行せずに内容を表示')
306
+ .option('--reboot', '設定変更後にリブート')
307
+ .action(async (options) => {
308
+ try {
309
+ console.log(chalk_1.default.bold('\n=== Device Config Set ===\n'));
310
+ console.log(chalk_1.default.cyan('設定変更:'));
311
+ console.log(` IP: ${options.ip}`);
312
+ console.log(` Key: ${chalk_1.default.yellow(options.key)}`);
313
+ console.log(` Value: ${chalk_1.default.green(options.value)}`);
314
+ console.log('');
315
+ if (options.dryRun) {
316
+ console.log(chalk_1.default.yellow('(dry-run モード: 実際には変更されません)'));
317
+ console.log('');
318
+ return;
319
+ }
320
+ const baseUrl = getDeviceBaseUrl(options.ip, parseInt(options.port), options.https);
321
+ const spinner = (0, ora_1.default)(`${options.key} を設定中...`).start();
322
+ // Try multiple endpoint patterns
323
+ const endpoints = [
324
+ { url: '/api/config', method: 'POST', body: { [options.key]: options.value } },
325
+ { url: '/config', method: 'POST', body: { [options.key]: options.value } },
326
+ { url: '/api/settings', method: 'POST', body: { [options.key]: options.value } },
327
+ { url: `/api/config/${options.key}`, method: 'POST', body: { value: options.value } },
328
+ { url: '/api/nvs', method: 'POST', body: { key: options.key, value: options.value } },
329
+ ];
330
+ let success = false;
331
+ let successEndpoint = '';
332
+ let responseData = null;
333
+ for (const endpoint of endpoints) {
334
+ try {
335
+ responseData = await httpPost(`${baseUrl}${endpoint.url}`, endpoint.body, parseInt(options.timeout));
336
+ success = true;
337
+ successEndpoint = endpoint.url;
338
+ break;
339
+ }
340
+ catch {
341
+ // Try next endpoint
342
+ }
343
+ }
344
+ if (!success) {
345
+ spinner.fail('設定を変更できませんでした');
346
+ console.log(chalk_1.default.yellow('\n⚠ デバイスが設定変更APIをサポートしていない可能性があります'));
347
+ console.log(chalk_1.default.gray('試行したエンドポイント:'));
348
+ endpoints.forEach((e) => console.log(` - ${e.method} ${baseUrl}${e.url}`));
349
+ process.exit(1);
350
+ }
351
+ spinner.succeed(`設定変更成功 (${successEndpoint})`);
352
+ if (responseData) {
353
+ console.log(chalk_1.default.gray('\nレスポンス: ' + JSON.stringify(responseData)));
354
+ }
355
+ // Reboot if requested
356
+ if (options.reboot) {
357
+ console.log('');
358
+ const rebootSpinner = (0, ora_1.default)('デバイスをリブート中...').start();
359
+ try {
360
+ await httpPost(`${baseUrl}/api/reboot`, {}, 3000);
361
+ rebootSpinner.succeed('リブートコマンド送信完了');
362
+ }
363
+ catch {
364
+ // Device might not respond after reboot command
365
+ rebootSpinner.warn('リブートコマンド送信 (デバイスが応答しない場合があります)');
366
+ }
367
+ }
368
+ else {
369
+ console.log(chalk_1.default.yellow('\n⚠ 設定によってはリブートが必要です (--reboot オプション)'));
370
+ }
371
+ console.log('');
372
+ }
373
+ catch (error) {
374
+ console.error(chalk_1.default.red(`❌ エラー: ${getErrorMessage(error)}`));
375
+ process.exit(1);
376
+ }
377
+ });
378
+ // ----------------------------------------------------------------------------
379
+ // device reboot
380
+ // ----------------------------------------------------------------------------
381
+ exports.deviceCommand
382
+ .command('reboot')
383
+ .description('デバイスをリブート')
384
+ .requiredOption('-i, --ip <ip>', 'デバイスIPアドレス')
385
+ .option('-P, --port <port>', 'HTTPポート', '80')
386
+ .option('--https', 'HTTPSを使用')
387
+ .option('--force', '確認なしでリブート')
388
+ .action(async (options) => {
389
+ try {
390
+ console.log(chalk_1.default.bold('\n=== Device Reboot ===\n'));
391
+ console.log(chalk_1.default.cyan('ターゲット:'));
392
+ console.log(` IP: ${options.ip}`);
393
+ console.log('');
394
+ if (!options.force) {
395
+ console.log(chalk_1.default.yellow(`⚠ これにより ${options.ip} がリブートされます。`));
396
+ console.log(chalk_1.default.gray('確認なしで実行するには --force を使用してください。'));
397
+ console.log('');
398
+ process.exit(1);
399
+ }
400
+ const baseUrl = getDeviceBaseUrl(options.ip, parseInt(options.port), options.https);
401
+ const spinner = (0, ora_1.default)(`${options.ip} をリブート中...`).start();
402
+ const endpoints = ['/api/reboot', '/reboot', '/api/restart', '/restart'];
403
+ let sent = false;
404
+ for (const endpoint of endpoints) {
405
+ try {
406
+ await httpPost(`${baseUrl}${endpoint}`, {}, 3000);
407
+ sent = true;
408
+ break;
409
+ }
410
+ catch (error) {
411
+ // Device might close connection immediately after reboot
412
+ if (error instanceof axios_1.AxiosError &&
413
+ (error.code === 'ECONNRESET' || error.code === 'ECONNABORTED')) {
414
+ sent = true;
415
+ break;
416
+ }
417
+ }
418
+ }
419
+ if (sent) {
420
+ spinner.succeed('リブートコマンド送信完了');
421
+ console.log(chalk_1.default.gray('\nデバイスが再起動中です。数秒後にオンラインになります。'));
422
+ }
423
+ else {
424
+ spinner.fail('リブートコマンドを送信できませんでした');
425
+ }
426
+ console.log('');
427
+ }
428
+ catch (error) {
429
+ // Connection reset is expected after reboot
430
+ if (error instanceof axios_1.AxiosError && error.code === 'ECONNRESET') {
431
+ console.log(chalk_1.default.green('✓ リブートコマンド送信完了'));
432
+ }
433
+ else {
434
+ console.error(chalk_1.default.red(`❌ エラー: ${getErrorMessage(error)}`));
435
+ process.exit(1);
436
+ }
437
+ }
438
+ });
439
+ // ----------------------------------------------------------------------------
440
+ // device scan
441
+ // ----------------------------------------------------------------------------
442
+ exports.deviceCommand
443
+ .command('scan')
444
+ .description('ローカルネットワーク上のAraneaデバイスをスキャン')
445
+ .option('-s, --subnet <subnet>', 'スキャン対象サブネット (例: 192.168.3)', '192.168.1')
446
+ .option('--start <num>', '開始IP', '1')
447
+ .option('--end <num>', '終了IP', '254')
448
+ .option('--timeout <ms>', '各IPへのタイムアウト', '500')
449
+ .option('-c, --concurrency <num>', '並列数', '20')
450
+ .action(async (options) => {
451
+ try {
452
+ console.log(chalk_1.default.bold('\n=== Aranea Device Scanner ===\n'));
453
+ const subnet = options.subnet;
454
+ const start = parseInt(options.start);
455
+ const end = parseInt(options.end);
456
+ const timeout = parseInt(options.timeout);
457
+ const concurrency = parseInt(options.concurrency);
458
+ console.log(chalk_1.default.cyan('スキャン設定:'));
459
+ console.log(` Subnet: ${subnet}.${start}-${end}`);
460
+ console.log(` Timeout: ${timeout}ms`);
461
+ console.log(` Concurrency: ${concurrency}`);
462
+ console.log('');
463
+ const spinner = (0, ora_1.default)('スキャン中...').start();
464
+ const foundDevices = [];
465
+ let scanned = 0;
466
+ const total = end - start + 1;
467
+ // Create IP list
468
+ const ips = [];
469
+ for (let i = start; i <= end; i++) {
470
+ ips.push(`${subnet}.${i}`);
471
+ }
472
+ // Scan in batches
473
+ const scanIp = async (ip) => {
474
+ try {
475
+ const status = await httpGet(`http://${ip}/api/status`, timeout);
476
+ if (status &&
477
+ (status.lacisId || status.type?.includes('aranea') || status.type?.includes('ISMS'))) {
478
+ foundDevices.push({ ip, status });
479
+ }
480
+ }
481
+ catch {
482
+ // Not an Aranea device or not responding
483
+ }
484
+ scanned++;
485
+ spinner.text = `スキャン中... ${scanned}/${total} (発見: ${foundDevices.length})`;
486
+ };
487
+ // Process in batches
488
+ for (let i = 0; i < ips.length; i += concurrency) {
489
+ const batch = ips.slice(i, i + concurrency);
490
+ await Promise.all(batch.map(scanIp));
491
+ }
492
+ spinner.succeed(`スキャン完了: ${foundDevices.length} 台のデバイスを発見`);
493
+ if (foundDevices.length > 0) {
494
+ console.log('');
495
+ console.log(chalk_1.default.cyan('発見したデバイス:'));
496
+ console.log('');
497
+ foundDevices.forEach(({ ip, status }) => {
498
+ console.log(` ${chalk_1.default.green('●')} ${chalk_1.default.bold(ip)}`);
499
+ if (status.lacisId)
500
+ console.log(` LacisID: ${chalk_1.default.green(status.lacisId)}`);
501
+ if (status.type)
502
+ console.log(` Type: ${status.type}`);
503
+ if (status.cic)
504
+ console.log(` CIC: ${status.cic}`);
505
+ if (status.mqttConnected !== undefined) {
506
+ console.log(` MQTT: ${status.mqttConnected ? chalk_1.default.green('Connected') : chalk_1.default.yellow('Not connected')}`);
507
+ }
508
+ console.log('');
509
+ });
510
+ }
511
+ console.log('');
512
+ }
513
+ catch (error) {
514
+ console.error(chalk_1.default.red(`❌ エラー: ${getErrorMessage(error)}`));
515
+ process.exit(1);
516
+ }
517
+ });
518
+ exports.default = exports.deviceCommand;
@@ -734,8 +734,8 @@ exports.schemaCommand
734
734
  console.log(chalk_1.default.gray('Remove --dry-run to actually promote'));
735
735
  return;
736
736
  }
737
- // Confirmation step
738
- if (!options.confirm) {
737
+ // Confirmation step (skip if --confirm or --force)
738
+ if (!options.confirm && !options.force) {
739
739
  console.log(chalk_1.default.red('This will promote the schema to PRODUCTION state.'));
740
740
  console.log(chalk_1.default.red('Existing devices using this schema type will be affected.'));
741
741
  console.log('');
@@ -1031,8 +1031,8 @@ exports.schemaCommand
1031
1031
  console.log(chalk_1.default.gray('Remove --dry-run to actually rollback'));
1032
1032
  return;
1033
1033
  }
1034
- // Confirmation step
1035
- if (!options.confirm) {
1034
+ // Confirmation step (skip if --confirm or --force)
1035
+ if (!options.confirm && !options.force) {
1036
1036
  console.log(chalk_1.default.red('This will rollback the schema to a previous version.'));
1037
1037
  console.log(chalk_1.default.red('The current version will be saved in history.'));
1038
1038
  console.log('');
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ const validate_1 = require("./commands/validate");
21
21
  const schema_1 = require("./commands/schema");
22
22
  const register_1 = require("./commands/register");
23
23
  const mqtt_1 = require("./commands/mqtt");
24
+ const device_1 = require("./commands/device");
24
25
  const knowledge_1 = require("./commands/knowledge");
25
26
  const metatron_1 = require("./commands/metatron");
26
27
  const auth_1 = require("./commands/auth");
@@ -28,7 +29,7 @@ const program = new commander_1.Command();
28
29
  program
29
30
  .name('aranea-sdk')
30
31
  .description('AraneaSDK CLI - デバイス開発支援ツール')
31
- .version('0.3.13');
32
+ .version('0.3.15');
32
33
  // test コマンド
33
34
  program.addCommand(test_1.testCommand);
34
35
  // simulate コマンド
@@ -41,6 +42,8 @@ program.addCommand(schema_1.schemaCommand);
41
42
  program.addCommand(register_1.registerCommand);
42
43
  // mqtt コマンド (v0.2.0 P0)
43
44
  program.addCommand(mqtt_1.mqttCommand);
45
+ // device コマンド (v0.3.15) - HTTP直接操作
46
+ program.addCommand(device_1.deviceCommand);
44
47
  // knowledge コマンド (v0.2.1)
45
48
  program.addCommand(knowledge_1.knowledgeCommand);
46
49
  // metatron コマンド (v0.2.1)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aranea-sdk-cli",
3
- "version": "0.3.13",
3
+ "version": "0.3.15",
4
4
  "description": "AraneaSDK CLI - ESP32 IoTデバイス開発支援ツール",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",