aranea-sdk-cli 0.1.0 → 0.1.1

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 CHANGED
@@ -1,4 +1,6 @@
1
- # @aranea-sdk/cli
1
+ # aranea-sdk-cli
2
+
3
+ [![npm version](https://badge.fury.io/js/aranea-sdk-cli.svg)](https://www.npmjs.com/package/aranea-sdk-cli)
2
4
 
3
5
  AraneaSDK CLI - ESP32 IoTデバイス開発支援ツール
4
6
 
@@ -9,7 +11,7 @@ AraneaSDK CLIは、AraneaSDK対応ESP32デバイスの開発・テスト・登
9
11
  ## インストール
10
12
 
11
13
  ```bash
12
- npm install -g @aranea-sdk/cli
14
+ npm install -g aranea-sdk-cli
13
15
  ```
14
16
 
15
17
  ## クイックスタート
@@ -1,9 +1,10 @@
1
1
  /**
2
- * schema コマンド
2
+ * schema command
3
3
  *
4
4
  * Usage:
5
5
  * aranea-sdk schema get --type "aranea_ar-is04a"
6
6
  * aranea-sdk schema list
7
+ * aranea-sdk schema validate --type "aranea_ar-is04a" --file state.json
7
8
  */
8
9
  import { Command } from 'commander';
9
10
  export declare const schemaCommand: Command;
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  /**
3
- * schema コマンド
3
+ * schema command
4
4
  *
5
5
  * Usage:
6
6
  * aranea-sdk schema get --type "aranea_ar-is04a"
7
7
  * aranea-sdk schema list
8
+ * aranea-sdk schema validate --type "aranea_ar-is04a" --file state.json
8
9
  */
9
10
  var __importDefault = (this && this.__importDefault) || function (mod) {
10
11
  return (mod && mod.__esModule) ? mod : { "default": mod };
@@ -14,268 +15,336 @@ exports.schemaCommand = void 0;
14
15
  const commander_1 = require("commander");
15
16
  const chalk_1 = __importDefault(require("chalk"));
16
17
  const ora_1 = __importDefault(require("ora"));
17
- // 組み込みスキーマ定義
18
- // 実際の運用ではFirestoreから取得するが、CLIツールでは組み込み版を使用
19
- const BUILTIN_SCHEMAS = {
20
- 'aranea_ar-is01': {
21
- type: 'aranea_ar-is01',
22
- displayName: 'AraneaSDK Basic Sensor',
23
- description: '基本センサーデバイス',
24
- productType: '001',
25
- stateFields: {
26
- Trigger1: { type: 'boolean', description: '汎用トリガー1' },
27
- Trigger2: { type: 'boolean', description: '汎用トリガー2' },
28
- RSSI: { type: 'number', description: 'WiFi信号強度 (dBm)' },
29
- },
30
- commandFields: {},
31
- },
32
- 'aranea_ar-is04a': {
33
- type: 'aranea_ar-is04a',
34
- displayName: 'Network Scanner',
35
- description: 'ネットワークスキャナー (ESP32)',
36
- productType: '004',
37
- stateFields: {
38
- scanMode: { type: 'string', description: 'スキャンモード (arp/ping/passive)' },
39
- discoveredHosts: { type: 'number', description: '発見ホスト数' },
40
- lastScanAt: { type: 'string', description: '最終スキャン時刻 (ISO8601)' },
41
- RSSI: { type: 'number', description: 'WiFi信号強度 (dBm)' },
42
- },
43
- commandFields: {
44
- startScan: { type: 'boolean', description: 'スキャン開始' },
45
- setScanMode: { type: 'string', description: 'スキャンモード設定' },
46
- },
47
- },
48
- 'aranea_ar-is05a': {
49
- type: 'aranea_ar-is05a',
50
- displayName: 'Environment Sensor',
51
- description: '環境センサー (ESP32)',
52
- productType: '005',
53
- stateFields: {
54
- temperature: { type: 'number', description: '温度 (℃)' },
55
- humidity: { type: 'number', description: '湿度 (%)' },
56
- pressure: { type: 'number', description: '気圧 (hPa)' },
57
- co2: { type: 'number', description: 'CO2濃度 (ppm)' },
58
- RSSI: { type: 'number', description: 'WiFi信号強度 (dBm)' },
59
- },
60
- commandFields: {
61
- calibrate: { type: 'boolean', description: 'センサーキャリブレーション' },
62
- },
63
- },
64
- 'aranea_ar-is06a': {
65
- type: 'aranea_ar-is06a',
66
- displayName: 'Power Monitor',
67
- description: '電力モニター (ESP32)',
68
- productType: '006',
69
- stateFields: {
70
- voltage: { type: 'number', description: '電圧 (V)' },
71
- current: { type: 'number', description: '電流 (A)' },
72
- power: { type: 'number', description: '電力 (W)' },
73
- energy: { type: 'number', description: '積算電力量 (Wh)' },
74
- RSSI: { type: 'number', description: 'WiFi信号強度 (dBm)' },
75
- },
76
- commandFields: {
77
- resetEnergy: { type: 'boolean', description: '積算電力量リセット' },
78
- },
79
- },
80
- 'aranea_ar-is10': {
81
- type: 'aranea_ar-is10',
82
- displayName: 'Router Inspector',
83
- description: 'OpenWrt/AsusWRT ルーターインスペクター',
84
- productType: '010',
85
- stateFields: {
86
- routerType: { type: 'string', description: 'ルータータイプ (openwrt/asuswrt)' },
87
- connectedClients: { type: 'number', description: '接続クライアント数' },
88
- wanStatus: { type: 'string', description: 'WAN状態' },
89
- uptime: { type: 'number', description: '稼働時間 (秒)' },
90
- },
91
- commandFields: {
92
- refresh: { type: 'boolean', description: '状態更新' },
93
- },
94
- },
95
- };
18
+ const axios_1 = __importDefault(require("axios"));
19
+ // API Configuration
20
+ const SCHEMA_API_BASE = 'https://asia-northeast1-mobesorder.cloudfunctions.net/araneaSchemaAPI';
21
+ // API Functions
22
+ async function fetchSchemaList() {
23
+ const response = await axios_1.default.get(`${SCHEMA_API_BASE}?action=list`);
24
+ return response.data;
25
+ }
26
+ async function fetchSchema(type) {
27
+ const response = await axios_1.default.get(`${SCHEMA_API_BASE}?action=get&type=${encodeURIComponent(type)}`);
28
+ return response.data;
29
+ }
96
30
  exports.schemaCommand = new commander_1.Command('schema')
97
- .description('Type スキーマの取得・表示');
31
+ .description('Type schema retrieval and validation');
98
32
  // schema list
99
33
  exports.schemaCommand
100
34
  .command('list')
101
- .description('利用可能なTypeスキーマ一覧')
102
- .action(() => {
103
- console.log(chalk_1.default.bold('\n=== AraneaDevice Type スキーマ一覧 ===\n'));
104
- const types = Object.keys(BUILTIN_SCHEMAS).sort();
105
- console.log(chalk_1.default.cyan('登録済みType:'));
106
- console.log('');
107
- types.forEach((type) => {
108
- const schema = BUILTIN_SCHEMAS[type];
109
- console.log(` ${chalk_1.default.green(type)}`);
110
- console.log(` ${schema.displayName} - ${schema.description}`);
111
- console.log(` ProductType: ${schema.productType}`);
35
+ .description('List available Type schemas')
36
+ .action(async () => {
37
+ const spinner = (0, ora_1.default)('Fetching schema list from API...').start();
38
+ try {
39
+ const result = await fetchSchemaList();
40
+ spinner.stop();
41
+ console.log(chalk_1.default.bold('\n=== AraneaDevice Type Schema List ===\n'));
42
+ if (!result.ok || result.count === 0) {
43
+ console.log(chalk_1.default.yellow('No schemas found.'));
44
+ console.log(chalk_1.default.gray('Run schema registration script to initialize schemas.'));
45
+ console.log('');
46
+ return;
47
+ }
48
+ console.log(chalk_1.default.cyan('Registered Types:'));
112
49
  console.log('');
113
- });
114
- console.log(chalk_1.default.gray(`合計: ${types.length} 件`));
115
- console.log('');
50
+ for (const schema of result.schemas) {
51
+ console.log(` ${chalk_1.default.green(schema.type)}`);
52
+ console.log(` ${schema.displayName} - ${schema.description}`);
53
+ console.log(` ProductType: ${schema.productType}`);
54
+ console.log(` Capabilities: ${schema.capabilities.join(', ')}`);
55
+ console.log('');
56
+ }
57
+ console.log(chalk_1.default.gray(`Total: ${result.count} types`));
58
+ console.log('');
59
+ }
60
+ catch (error) {
61
+ spinner.fail('Failed to fetch schema list');
62
+ if (error.response?.status === 404 || error.code === 'ENOTFOUND') {
63
+ console.error(chalk_1.default.red('\nSchema API is not available.'));
64
+ console.error(chalk_1.default.yellow('Please deploy the araneaSchemaAPI function first.'));
65
+ }
66
+ else {
67
+ console.error(chalk_1.default.red(`\nError: ${error.message}`));
68
+ }
69
+ process.exit(1);
70
+ }
116
71
  });
117
72
  // schema get
118
73
  exports.schemaCommand
119
74
  .command('get')
120
- .description('特定Typeのスキーマ詳細を取得')
121
- .requiredOption('-t, --type <type>', '取得するType')
122
- .option('--json', 'JSON形式で出力')
123
- .action((options) => {
124
- const type = options.type;
125
- const schema = BUILTIN_SCHEMAS[type];
126
- if (!schema) {
127
- console.error(chalk_1.default.red(`\nType "${type}" のスキーマが見つかりません`));
75
+ .description('Get detailed schema for a specific Type')
76
+ .requiredOption('-t, --type <type>', 'Type name to retrieve')
77
+ .option('--json', 'Output as JSON')
78
+ .action(async (options) => {
79
+ const spinner = (0, ora_1.default)(`Fetching schema for ${options.type}...`).start();
80
+ try {
81
+ const result = await fetchSchema(options.type);
82
+ spinner.stop();
83
+ if (!result.ok) {
84
+ console.error(chalk_1.default.red(`\nSchema "${options.type}" not found`));
85
+ console.log('');
86
+ if (result.availableTypes && result.availableTypes.length > 0) {
87
+ console.log(chalk_1.default.yellow('Available Types:'));
88
+ result.availableTypes.forEach((t) => {
89
+ console.log(` - ${t}`);
90
+ });
91
+ }
92
+ console.log('');
93
+ process.exit(1);
94
+ }
95
+ const schema = result.schema;
96
+ if (options.json) {
97
+ console.log(JSON.stringify(schema, null, 2));
98
+ return;
99
+ }
100
+ console.log(chalk_1.default.bold(`\n=== ${schema.type} Schema ===\n`));
101
+ console.log(`DisplayName: ${chalk_1.default.cyan(schema.displayName)}`);
102
+ console.log(`Description: ${schema.description}`);
103
+ console.log(`ProductType: ${schema.productType}`);
104
+ console.log(`Capabilities: ${schema.capabilities.join(', ')}`);
105
+ console.log(`Version: ${schema.version}`);
128
106
  console.log('');
129
- console.log(chalk_1.default.yellow('利用可能なType:'));
130
- Object.keys(BUILTIN_SCHEMAS).forEach((t) => {
131
- console.log(` - ${t}`);
132
- });
107
+ // Features
108
+ if (schema.features && schema.features.length > 0) {
109
+ console.log(chalk_1.default.bold('Features:'));
110
+ schema.features.forEach((f) => {
111
+ console.log(` - ${f}`);
112
+ });
113
+ console.log('');
114
+ }
115
+ // State Schema
116
+ console.log(chalk_1.default.bold('State Schema (deviceState fields):'));
117
+ const stateProps = schema.stateSchema?.properties || {};
118
+ const stateRequired = schema.stateSchema?.required || [];
119
+ const stateEntries = Object.entries(stateProps);
120
+ if (stateEntries.length === 0) {
121
+ console.log(chalk_1.default.gray(' (none)'));
122
+ }
123
+ else {
124
+ stateEntries.forEach(([name, def]) => {
125
+ const required = stateRequired.includes(name) ? chalk_1.default.red('*') : '';
126
+ const type = def.type || 'any';
127
+ const desc = def.description || '';
128
+ console.log(` ${chalk_1.default.green(name)}${required}: ${chalk_1.default.yellow(type)}`);
129
+ if (desc) {
130
+ console.log(` ${desc}`);
131
+ }
132
+ });
133
+ }
133
134
  console.log('');
134
- process.exit(1);
135
- }
136
- if (options.json) {
137
- console.log(JSON.stringify(schema, null, 2));
138
- return;
139
- }
140
- console.log(chalk_1.default.bold(`\n=== ${schema.type} スキーマ ===\n`));
141
- console.log(`DisplayName: ${chalk_1.default.cyan(schema.displayName)}`);
142
- console.log(`Description: ${schema.description}`);
143
- console.log(`ProductType: ${schema.productType}`);
144
- console.log('');
145
- // State Fields
146
- console.log(chalk_1.default.bold('State Fields (状態レポート):'));
147
- const stateFields = Object.entries(schema.stateFields);
148
- if (stateFields.length === 0) {
149
- console.log(chalk_1.default.gray(' (なし)'));
150
- }
151
- else {
152
- stateFields.forEach(([name, field]) => {
153
- console.log(` ${chalk_1.default.green(name)}: ${chalk_1.default.yellow(field.type)}`);
154
- console.log(` ${field.description}`);
155
- });
156
- }
157
- console.log('');
158
- // Command Fields
159
- console.log(chalk_1.default.bold('Command Fields (コマンド):'));
160
- const commandFields = Object.entries(schema.commandFields);
161
- if (commandFields.length === 0) {
162
- console.log(chalk_1.default.gray(' (なし)'));
163
- }
164
- else {
165
- commandFields.forEach(([name, field]) => {
166
- console.log(` ${chalk_1.default.green(name)}: ${chalk_1.default.yellow(field.type)}`);
167
- console.log(` ${field.description}`);
135
+ // Command Schema
136
+ if (schema.commandSchema) {
137
+ console.log(chalk_1.default.bold('Command Schema (available commands):'));
138
+ const cmdProps = schema.commandSchema?.properties || {};
139
+ const cmdEntries = Object.entries(cmdProps);
140
+ if (cmdEntries.length === 0) {
141
+ console.log(chalk_1.default.gray(' (none)'));
142
+ }
143
+ else {
144
+ cmdEntries.forEach(([name, def]) => {
145
+ const desc = def.description || '';
146
+ console.log(` ${chalk_1.default.green(name)}`);
147
+ if (desc) {
148
+ console.log(` ${desc}`);
149
+ }
150
+ // Show properties if any
151
+ if (def.properties) {
152
+ Object.entries(def.properties).forEach(([propName, propDef]) => {
153
+ const propType = propDef.type || 'any';
154
+ const propDesc = propDef.description || '';
155
+ console.log(` ${chalk_1.default.cyan(propName)}: ${chalk_1.default.yellow(propType)} ${propDesc}`);
156
+ });
157
+ }
158
+ });
159
+ }
160
+ console.log('');
161
+ }
162
+ // Sample State Report
163
+ console.log(chalk_1.default.bold('Sample State Report Request:'));
164
+ const sampleState = {};
165
+ // Generate sample values from state schema
166
+ Object.entries(stateProps).forEach(([name, def]) => {
167
+ const type = def.type;
168
+ if (type === 'boolean') {
169
+ sampleState[name] = true;
170
+ }
171
+ else if (type === 'number' || type === 'integer') {
172
+ if (name.toLowerCase().includes('rssi')) {
173
+ sampleState[name] = -65;
174
+ }
175
+ else if (def.minimum !== undefined) {
176
+ sampleState[name] = def.minimum;
177
+ }
178
+ else {
179
+ sampleState[name] = 0;
180
+ }
181
+ }
182
+ else if (type === 'string') {
183
+ sampleState[name] = def.format === 'date-time' ? new Date().toISOString() : `sample_${name}`;
184
+ }
185
+ else if (type === 'object') {
186
+ sampleState[name] = {};
187
+ }
188
+ else if (type === 'array') {
189
+ sampleState[name] = [];
190
+ }
168
191
  });
192
+ const sampleRequest = {
193
+ auth: {
194
+ tid: 'T9999999999999999999',
195
+ lacisId: `3${schema.productType.padStart(3, '0')}AABBCCDDEEFF0001`,
196
+ cic: '******',
197
+ },
198
+ report: {
199
+ type: schema.type,
200
+ state: sampleState,
201
+ },
202
+ };
203
+ console.log(chalk_1.default.gray(JSON.stringify(sampleRequest, null, 2)));
204
+ console.log('');
169
205
  }
170
- console.log('');
171
- // サンプルリクエスト生成
172
- console.log(chalk_1.default.bold('サンプル状態レポート:'));
173
- const sampleState = {};
174
- Object.entries(schema.stateFields).forEach(([name, field]) => {
175
- switch (field.type) {
176
- case 'boolean':
177
- sampleState[name] = true;
178
- break;
179
- case 'number':
180
- sampleState[name] = name === 'RSSI' ? -65 : 0;
181
- break;
182
- case 'string':
183
- sampleState[name] = `sample_${name}`;
184
- break;
185
- default:
186
- sampleState[name] = null;
206
+ catch (error) {
207
+ spinner.fail('Failed to fetch schema');
208
+ if (error.response?.status === 404) {
209
+ console.error(chalk_1.default.red(`\nSchema "${options.type}" not found`));
210
+ // Try to show available types
211
+ try {
212
+ const listResult = await fetchSchemaList();
213
+ if (listResult.ok && listResult.count > 0) {
214
+ console.log('');
215
+ console.log(chalk_1.default.yellow('Available Types:'));
216
+ listResult.schemas.forEach((s) => {
217
+ console.log(` - ${s.type}`);
218
+ });
219
+ }
220
+ }
221
+ catch {
222
+ // Ignore
223
+ }
187
224
  }
188
- });
189
- const sampleRequest = {
190
- auth: {
191
- tid: 'T9999999999999999999',
192
- lacisId: '3004AABBCCDDEEFF0001',
193
- cic: '******',
194
- },
195
- report: {
196
- type: schema.type,
197
- state: sampleState,
198
- },
199
- };
200
- console.log(chalk_1.default.gray(JSON.stringify(sampleRequest, null, 2)));
201
- console.log('');
225
+ else {
226
+ console.error(chalk_1.default.red(`\nError: ${error.message}`));
227
+ }
228
+ console.log('');
229
+ process.exit(1);
230
+ }
202
231
  });
203
232
  // schema validate
204
233
  exports.schemaCommand
205
234
  .command('validate')
206
- .description('状態レポートJSONをスキーマに対して検証')
207
- .requiredOption('-t, --type <type>', 'Type')
208
- .requiredOption('-f, --file <path>', 'JSONファイルパス')
209
- .action((options) => {
210
- const spinner = (0, ora_1.default)('検証中...').start();
235
+ .description('Validate a state report JSON against schema')
236
+ .requiredOption('-t, --type <type>', 'Type name')
237
+ .requiredOption('-f, --file <path>', 'JSON file path')
238
+ .action(async (options) => {
239
+ const spinner = (0, ora_1.default)('Validating...').start();
211
240
  try {
212
241
  const fs = require('fs');
213
242
  const path = require('path');
214
- const type = options.type;
215
- const schema = BUILTIN_SCHEMAS[type];
216
- if (!schema) {
217
- spinner.fail(`Type "${type}" のスキーマが見つかりません`);
243
+ // Fetch schema from API
244
+ const schemaResult = await fetchSchema(options.type);
245
+ if (!schemaResult.ok) {
246
+ spinner.fail(`Schema "${options.type}" not found`);
218
247
  process.exit(1);
219
248
  }
249
+ const schema = schemaResult.schema;
250
+ // Read input file
220
251
  const filePath = path.resolve(options.file);
221
252
  if (!fs.existsSync(filePath)) {
222
- spinner.fail(`ファイルが見つかりません: ${filePath}`);
253
+ spinner.fail(`File not found: ${filePath}`);
223
254
  process.exit(1);
224
255
  }
225
256
  const fileContent = fs.readFileSync(filePath, 'utf-8');
226
257
  const data = JSON.parse(fileContent);
227
258
  spinner.stop();
228
- console.log(chalk_1.default.bold(`\n=== スキーマ検証: ${type} ===\n`));
259
+ console.log(chalk_1.default.bold(`\n=== Schema Validation: ${options.type} ===\n`));
229
260
  const issues = [];
230
261
  const warnings = [];
231
- // state フィールドの検証
262
+ // Extract state from input
232
263
  const state = data.report?.state || data.state || data;
233
- Object.entries(schema.stateFields).forEach(([fieldName, fieldDef]) => {
264
+ // Get state schema properties
265
+ const stateProps = schema.stateSchema?.properties || {};
266
+ const stateRequired = schema.stateSchema?.required || [];
267
+ // Check required fields
268
+ stateRequired.forEach((fieldName) => {
234
269
  if (!(fieldName in state)) {
235
- warnings.push(`フィールド "${fieldName}" が存在しません`);
270
+ issues.push(`Required field "${fieldName}" is missing`);
236
271
  }
237
- else {
272
+ });
273
+ // Validate field types
274
+ Object.entries(stateProps).forEach(([fieldName, fieldDef]) => {
275
+ if (fieldName in state) {
238
276
  const value = state[fieldName];
239
- const actualType = typeof value;
277
+ const actualType = Array.isArray(value) ? 'array' : typeof value;
240
278
  const expectedType = fieldDef.type;
241
- if (expectedType === 'number' && actualType !== 'number') {
242
- issues.push(`"${fieldName}": number型が期待されますが ${actualType}型です`);
279
+ if (expectedType === 'number' || expectedType === 'integer') {
280
+ if (actualType !== 'number') {
281
+ issues.push(`"${fieldName}": expected number but got ${actualType}`);
282
+ }
283
+ else {
284
+ // Check range
285
+ if (fieldDef.minimum !== undefined && value < fieldDef.minimum) {
286
+ issues.push(`"${fieldName}": value ${value} is below minimum ${fieldDef.minimum}`);
287
+ }
288
+ if (fieldDef.maximum !== undefined && value > fieldDef.maximum) {
289
+ issues.push(`"${fieldName}": value ${value} is above maximum ${fieldDef.maximum}`);
290
+ }
291
+ }
292
+ }
293
+ else if (expectedType === 'string') {
294
+ if (actualType !== 'string') {
295
+ issues.push(`"${fieldName}": expected string but got ${actualType}`);
296
+ }
243
297
  }
244
- else if (expectedType === 'string' && actualType !== 'string') {
245
- issues.push(`"${fieldName}": string型が期待されますが ${actualType}型です`);
298
+ else if (expectedType === 'boolean') {
299
+ if (actualType !== 'boolean') {
300
+ issues.push(`"${fieldName}": expected boolean but got ${actualType}`);
301
+ }
246
302
  }
247
- else if (expectedType === 'boolean' && actualType !== 'boolean') {
248
- issues.push(`"${fieldName}": boolean型が期待されますが ${actualType}型です`);
303
+ else if (expectedType === 'object') {
304
+ if (actualType !== 'object' || Array.isArray(value)) {
305
+ issues.push(`"${fieldName}": expected object but got ${actualType}`);
306
+ }
249
307
  }
308
+ else if (expectedType === 'array') {
309
+ if (!Array.isArray(value)) {
310
+ issues.push(`"${fieldName}": expected array but got ${actualType}`);
311
+ }
312
+ }
313
+ }
314
+ else if (!stateRequired.includes(fieldName)) {
315
+ warnings.push(`Optional field "${fieldName}" is not present`);
250
316
  }
251
317
  });
252
- // 未定義フィールドのチェック
318
+ // Check for unknown fields
253
319
  Object.keys(state).forEach((key) => {
254
- if (!(key in schema.stateFields)) {
255
- warnings.push(`未定義フィールド "${key}" が含まれています (無視されます)`);
320
+ if (!(key in stateProps)) {
321
+ warnings.push(`Unknown field "${key}" (will be ignored)`);
256
322
  }
257
323
  });
258
- // 結果表示
324
+ // Show results
259
325
  if (issues.length === 0) {
260
- console.log(chalk_1.default.green(' スキーマ検証に成功しました'));
326
+ console.log(chalk_1.default.green('Validation passed'));
261
327
  }
262
328
  else {
263
- console.log(chalk_1.default.red(' スキーマ検証エラー:'));
329
+ console.log(chalk_1.default.red('Validation errors:'));
264
330
  issues.forEach((issue) => {
265
331
  console.log(chalk_1.default.red(` - ${issue}`));
266
332
  });
267
333
  }
268
334
  if (warnings.length > 0) {
269
335
  console.log('');
270
- console.log(chalk_1.default.yellow('警告:'));
336
+ console.log(chalk_1.default.yellow('Warnings:'));
271
337
  warnings.forEach((warning) => {
272
338
  console.log(chalk_1.default.yellow(` - ${warning}`));
273
339
  });
274
340
  }
275
341
  console.log('');
342
+ if (issues.length > 0) {
343
+ process.exit(1);
344
+ }
276
345
  }
277
346
  catch (error) {
278
- spinner.fail(`検証エラー: ${error.message}`);
347
+ spinner.fail(`Validation error: ${error.message}`);
279
348
  process.exit(1);
280
349
  }
281
350
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aranea-sdk-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "AraneaSDK CLI - ESP32 IoTデバイス開発支援ツール",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",