aranea-sdk-cli 0.3.2 → 0.3.3

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
@@ -38,6 +38,29 @@ aranea-sdk metatron chat
38
38
  2. **新知見発見時**: `knowledge add` でナレッジベースに追加
39
39
  3. **デバイス登録時**: `register --dry-run` で検証後、実登録
40
40
 
41
+ ### 🔴 特に貴重なナレッジ(必ず追加すべき)
42
+
43
+ 以下の情報は一般ドキュメントでは得られない**実践的知見**です。
44
+ 発見次第、CLIでナレッジベースに追加してください:
45
+
46
+ | カテゴリ | 追加すべき情報 | 例 |
47
+ |---------|--------------|-----|
48
+ | `incident` | ハードウェア固有の問題・解決策 | メモリ不足でクラッシュ、タイムアウトエラー |
49
+ | `tip` | テスト・デバッグで追い込んだパラメータ | HTTPSタイムアウト15秒必要 |
50
+ | `tip` | ESP32メモリ関連設定 | SSL接続に50KB必要 |
51
+ | `tip` | SBC (OrangePi等) のサービス起動・権限問題 | systemd設定、sudoers設定 |
52
+ | `incident` | ハードウェア相性問題 | 特定WiFiモジュールとの非互換 |
53
+
54
+ ```bash
55
+ # 例: インシデント対応で発見した設定値を追加
56
+ aranea-sdk knowledge add \
57
+ --title "ESP32 HTTPSタイムアウト 15秒必要" \
58
+ --category tip \
59
+ --content "ESP32でHTTPS接続する場合、最低15秒のタイムアウトが必要。初回SSL handshakeは特に時間がかかる。-11 READ_TIMEOUTエラーの原因。" \
60
+ --keywords "esp32,https,timeout,ssl,handshake" \
61
+ --device-types "aranea_ar-is04a,aranea_ar-is05a"
62
+ ```
63
+
41
64
  ---
42
65
 
43
66
  ## 概要
@@ -54,10 +54,17 @@ const ora_1 = __importDefault(require("ora"));
54
54
  const axios_1 = __importDefault(require("axios"));
55
55
  const fs = __importStar(require("fs"));
56
56
  const path = __importStar(require("path"));
57
+ const config_1 = require("../config");
57
58
  // ============================================================================
58
59
  // Config
59
60
  // ============================================================================
60
- const KNOWLEDGE_API_BASE = 'https://asia-northeast1-mobesorder.cloudfunctions.net/araneaSDK_knowledgeManagement';
61
+ const KNOWLEDGE_API_ENDPOINTS = {
62
+ production: 'https://asia-northeast1-mobesorder.cloudfunctions.net/araneaKnowledgeManagement',
63
+ staging: 'https://asia-northeast1-mobesorder-staging.cloudfunctions.net/araneaKnowledgeManagement',
64
+ };
65
+ function getKnowledgeApiBase(env) {
66
+ return KNOWLEDGE_API_ENDPOINTS[env];
67
+ }
61
68
  // カテゴリ定義
62
69
  const CATEGORIES = ['api', 'guide', 'code', 'reference', 'incident', 'tip'];
63
70
  // ============================================================================
@@ -72,8 +79,9 @@ function getAuthToken() {
72
79
  /**
73
80
  * API呼び出し(Callable形式)
74
81
  */
75
- async function callKnowledgeAPI(action, params, token) {
76
- const response = await axios_1.default.post(KNOWLEDGE_API_BASE, { data: { action, ...params } }, {
82
+ async function callKnowledgeAPI(action, params, token, env) {
83
+ const apiBase = getKnowledgeApiBase(env);
84
+ const response = await axios_1.default.post(apiBase, { data: { action, ...params } }, {
77
85
  headers: {
78
86
  'Content-Type': 'application/json',
79
87
  Authorization: `Bearer ${token}`,
@@ -131,9 +139,12 @@ exports.knowledgeCommand
131
139
  .option('--device-types <types>', '関連デバイスタイプ (カンマ区切り)')
132
140
  .option('--status <status>', 'ステータス (draft|published)', 'draft')
133
141
  .option('--token <token>', '認証トークン')
142
+ .option('-e, --endpoint <env>', '環境 (staging|production)', 'production')
134
143
  .action(async (options) => {
135
144
  try {
136
- console.log(chalk_1.default.bold('\n=== Knowledge Add ===\n'));
145
+ const env = (0, config_1.resolveEnvironment)(options.endpoint);
146
+ (0, config_1.warnIfProduction)(env, 'knowledge add');
147
+ console.log(chalk_1.default.bold(`\n=== Knowledge Add (${env}) ===\n`));
137
148
  // 認証トークン
138
149
  const token = options.token || getAuthToken();
139
150
  if (!token) {
@@ -186,7 +197,7 @@ exports.knowledgeCommand
186
197
  relatedDeviceTypes: deviceTypes,
187
198
  status: options.status,
188
199
  },
189
- }, token);
200
+ }, token, env);
190
201
  spinner.stop();
191
202
  if (result.success) {
192
203
  console.log(chalk_1.default.green('✓ ナレッジエントリを追加しました'));
@@ -194,6 +205,7 @@ exports.knowledgeCommand
194
205
  console.log(` Title: ${options.title}`);
195
206
  console.log(` Category: ${options.category}`);
196
207
  console.log(` Status: ${options.status}`);
208
+ console.log(` Environment: ${env}`);
197
209
  }
198
210
  else {
199
211
  console.log(chalk_1.default.red(`✗ 追加失敗: ${result.error}`));
@@ -212,9 +224,11 @@ exports.knowledgeCommand
212
224
  .option('-c, --category <category>', 'カテゴリフィルタ')
213
225
  .option('-l, --limit <limit>', '結果数', '10')
214
226
  .option('--token <token>', '認証トークン')
227
+ .option('-e, --endpoint <env>', '環境 (staging|production)', 'production')
215
228
  .action(async (options) => {
216
229
  try {
217
- console.log(chalk_1.default.bold('\n=== Knowledge Search ===\n'));
230
+ const env = (0, config_1.resolveEnvironment)(options.endpoint);
231
+ console.log(chalk_1.default.bold(`\n=== Knowledge Search (${env}) ===\n`));
218
232
  const token = options.token || getAuthToken();
219
233
  if (!token) {
220
234
  console.error(chalk_1.default.red('❌ 認証トークンが必要です'));
@@ -225,7 +239,7 @@ exports.knowledgeCommand
225
239
  query: options.query,
226
240
  category: options.category,
227
241
  limit: parseInt(options.limit, 10),
228
- }, token);
242
+ }, token, env);
229
243
  spinner.stop();
230
244
  if (result.success && result.data) {
231
245
  const entries = Array.isArray(result.data) ? result.data : [];
@@ -254,9 +268,11 @@ exports.knowledgeCommand
254
268
  .option('-s, --status <status>', 'ステータスフィルタ (draft|published|archived)')
255
269
  .option('-l, --limit <limit>', '表示数', '20')
256
270
  .option('--token <token>', '認証トークン')
271
+ .option('-e, --endpoint <env>', '環境 (staging|production)', 'production')
257
272
  .action(async (options) => {
258
273
  try {
259
- console.log(chalk_1.default.bold('\n=== Knowledge List ===\n'));
274
+ const env = (0, config_1.resolveEnvironment)(options.endpoint);
275
+ console.log(chalk_1.default.bold(`\n=== Knowledge List (${env}) ===\n`));
260
276
  const token = options.token || getAuthToken();
261
277
  if (!token) {
262
278
  console.error(chalk_1.default.red('❌ 認証トークンが必要です'));
@@ -267,7 +283,7 @@ exports.knowledgeCommand
267
283
  category: options.category,
268
284
  status: options.status,
269
285
  limit: parseInt(options.limit, 10),
270
- }, token);
286
+ }, token, env);
271
287
  spinner.stop();
272
288
  if (result.success && result.data) {
273
289
  const entries = Array.isArray(result.data) ? result.data : [];
@@ -294,16 +310,18 @@ exports.knowledgeCommand
294
310
  .description('ナレッジエントリを取得')
295
311
  .requiredOption('-i, --id <id>', 'エントリID')
296
312
  .option('--token <token>', '認証トークン')
313
+ .option('-e, --endpoint <env>', '環境 (staging|production)', 'production')
297
314
  .action(async (options) => {
298
315
  try {
299
- console.log(chalk_1.default.bold('\n=== Knowledge Get ===\n'));
316
+ const env = (0, config_1.resolveEnvironment)(options.endpoint);
317
+ console.log(chalk_1.default.bold(`\n=== Knowledge Get (${env}) ===\n`));
300
318
  const token = options.token || getAuthToken();
301
319
  if (!token) {
302
320
  console.error(chalk_1.default.red('❌ 認証トークンが必要です'));
303
321
  process.exit(1);
304
322
  }
305
323
  const spinner = (0, ora_1.default)('ナレッジを取得中...').start();
306
- const result = await callKnowledgeAPI('get', { id: options.id }, token);
324
+ const result = await callKnowledgeAPI('get', { id: options.id }, token, env);
307
325
  spinner.stop();
308
326
  if (result.success && result.data) {
309
327
  formatEntry(result.data, true);
@@ -323,10 +341,13 @@ exports.knowledgeCommand
323
341
  .description('ナレッジエントリを削除 (アーカイブ)')
324
342
  .requiredOption('-i, --id <id>', 'エントリID')
325
343
  .option('--token <token>', '認証トークン')
344
+ .option('-e, --endpoint <env>', '環境 (staging|production)', 'production')
326
345
  .option('-y, --yes', '確認をスキップ')
327
346
  .action(async (options) => {
328
347
  try {
329
- console.log(chalk_1.default.bold('\n=== Knowledge Delete ===\n'));
348
+ const env = (0, config_1.resolveEnvironment)(options.endpoint);
349
+ (0, config_1.warnIfProduction)(env, 'knowledge delete');
350
+ console.log(chalk_1.default.bold(`\n=== Knowledge Delete (${env}) ===\n`));
330
351
  const token = options.token || getAuthToken();
331
352
  if (!token) {
332
353
  console.error(chalk_1.default.red('❌ 認証トークンが必要です'));
@@ -338,7 +359,7 @@ exports.knowledgeCommand
338
359
  // Note: In a real CLI, would use inquirer for confirmation
339
360
  }
340
361
  const spinner = (0, ora_1.default)('削除中...').start();
341
- const result = await callKnowledgeAPI('delete', { id: options.id }, token);
362
+ const result = await callKnowledgeAPI('delete', { id: options.id }, token, env);
342
363
  spinner.stop();
343
364
  if (result.success) {
344
365
  console.log(chalk_1.default.green('✓ ナレッジエントリをアーカイブしました'));
@@ -355,20 +376,74 @@ exports.knowledgeCommand
355
376
  // knowledge categories
356
377
  exports.knowledgeCommand
357
378
  .command('categories')
358
- .description('利用可能なカテゴリ一覧')
379
+ .description('利用可能なカテゴリ一覧と追加すべきナレッジの例')
359
380
  .action(() => {
360
381
  console.log(chalk_1.default.bold('\n=== Knowledge Categories ===\n'));
361
- const categoryDescriptions = {
362
- api: 'API仕様・エンドポイント',
363
- guide: '実装ガイド・チュートリアル',
364
- code: 'コードサンプル・スニペット',
365
- reference: 'リファレンス・仕様書',
366
- incident: 'インシデント・トラブルシューティング',
367
- tip: 'Tips・ノウハウ',
382
+ const categoryInfo = {
383
+ api: {
384
+ desc: 'API仕様・エンドポイント',
385
+ examples: [
386
+ 'State Report API の仕様変更',
387
+ 'エンドポイントURL・認証方式',
388
+ ],
389
+ },
390
+ guide: {
391
+ desc: '実装ガイド・チュートリアル',
392
+ examples: [
393
+ 'ESP32 State Report実装手順',
394
+ 'OrangePi サービス設定ガイド',
395
+ ],
396
+ },
397
+ code: {
398
+ desc: 'コードサンプル・スニペット',
399
+ examples: [
400
+ 'Arduino HTTPS接続コード',
401
+ 'Python MQTT受信サンプル',
402
+ ],
403
+ },
404
+ reference: {
405
+ desc: 'リファレンス・仕様書',
406
+ examples: [
407
+ 'スキーマ定義一覧',
408
+ 'エラーコード一覧',
409
+ ],
410
+ },
411
+ incident: {
412
+ desc: 'インシデント・トラブルシューティング',
413
+ examples: [
414
+ '⚠️ ハードウェア固有の問題・解決策',
415
+ '⚠️ メモリ不足・タイムアウト事例',
416
+ '⚠️ 相性問題・回避策',
417
+ ],
418
+ },
419
+ tip: {
420
+ desc: 'Tips・ノウハウ(一般情報では得られない実践知見)',
421
+ examples: [
422
+ '⚠️ ESP32 HTTPSタイムアウト 15秒必要',
423
+ '⚠️ OrangePi サービス起動順序',
424
+ '⚠️ メモリ設定・バッファサイズの追い込み値',
425
+ '⚠️ ハードウェア相性・非互換情報',
426
+ ],
427
+ },
368
428
  };
369
429
  for (const cat of CATEGORIES) {
370
- console.log(` ${chalk_1.default.cyan(cat.padEnd(12))} ${categoryDescriptions[cat]}`);
430
+ const info = categoryInfo[cat];
431
+ console.log(` ${chalk_1.default.cyan(cat.padEnd(12))} ${info.desc}`);
432
+ for (const ex of info.examples) {
433
+ if (ex.startsWith('⚠️')) {
434
+ console.log(` ${chalk_1.default.yellow(ex)}`);
435
+ }
436
+ else {
437
+ console.log(` ${chalk_1.default.gray('- ' + ex)}`);
438
+ }
439
+ }
440
+ console.log('');
371
441
  }
372
- console.log('');
442
+ console.log(chalk_1.default.bold('📝 AIエージェント向け: 以下のナレッジは特に貴重です\n'));
443
+ console.log(chalk_1.default.yellow(' • インシデント対応で発見したハードウェア固有の設定値'));
444
+ console.log(chalk_1.default.yellow(' • テスト・デバッグで追い込んだパラメータ(タイムアウト、バッファサイズ等)'));
445
+ console.log(chalk_1.default.yellow(' • ESP32のメモリ関連、SBCのサービス起動・権限問題'));
446
+ console.log(chalk_1.default.yellow(' • ハードウェア相性問題と回避策'));
447
+ console.log(chalk_1.default.yellow(' • 一般的なドキュメントには載っていない実践的知見\n'));
373
448
  });
374
449
  exports.default = exports.knowledgeCommand;
@@ -51,10 +51,17 @@ const chalk_1 = __importDefault(require("chalk"));
51
51
  const ora_1 = __importDefault(require("ora"));
52
52
  const axios_1 = __importDefault(require("axios"));
53
53
  const readline = __importStar(require("readline"));
54
+ const config_1 = require("../config");
54
55
  // ============================================================================
55
56
  // Config
56
57
  // ============================================================================
57
- const METATRON_API_BASE = 'https://asia-northeast1-mobesorder.cloudfunctions.net/araneaSDK_metatronQuery';
58
+ const METATRON_API_ENDPOINTS = {
59
+ production: 'https://asia-northeast1-mobesorder.cloudfunctions.net/araneaMetatronQuery',
60
+ staging: 'https://asia-northeast1-mobesorder-staging.cloudfunctions.net/araneaMetatronQuery',
61
+ };
62
+ function getMetatronApiBase(env) {
63
+ return METATRON_API_ENDPOINTS[env];
64
+ }
58
65
  // ============================================================================
59
66
  // Helper Functions
60
67
  // ============================================================================
@@ -67,8 +74,9 @@ function getAuthToken() {
67
74
  /**
68
75
  * Metatron API呼び出し
69
76
  */
70
- async function queryMetatron(query, context, token) {
71
- const response = await axios_1.default.post(METATRON_API_BASE, { data: { query, context } }, {
77
+ async function queryMetatron(query, context, token, env) {
78
+ const apiBase = getMetatronApiBase(env);
79
+ const response = await axios_1.default.post(apiBase, { data: { query, context } }, {
72
80
  headers: {
73
81
  'Content-Type': 'application/json',
74
82
  Authorization: `Bearer ${token}`,
@@ -110,11 +118,13 @@ exports.metatronCommand
110
118
  .description('単発質問')
111
119
  .option('--context <context>', 'コンテキスト', 'aranea_sdk_cli')
112
120
  .option('--token <token>', '認証トークン')
121
+ .option('-e, --endpoint <env>', '環境 (staging|production)', 'production')
113
122
  .option('--raw', 'JSON出力')
114
123
  .action(async (question, options) => {
115
124
  try {
125
+ const env = (0, config_1.resolveEnvironment)(options.endpoint);
116
126
  if (!options.raw) {
117
- console.log(chalk_1.default.bold('\n=== AraneaMetatron ===\n'));
127
+ console.log(chalk_1.default.bold(`\n=== AraneaMetatron (${env}) ===\n`));
118
128
  console.log(chalk_1.default.gray(`Q: ${question}`));
119
129
  }
120
130
  const token = options.token || getAuthToken();
@@ -123,7 +133,7 @@ exports.metatronCommand
123
133
  process.exit(1);
124
134
  }
125
135
  const spinner = options.raw ? null : (0, ora_1.default)('回答生成中...').start();
126
- const result = await queryMetatron(question, options.context, token);
136
+ const result = await queryMetatron(question, options.context, token, env);
127
137
  spinner?.stop();
128
138
  if (options.raw) {
129
139
  console.log(JSON.stringify(result, null, 2));
@@ -143,8 +153,10 @@ exports.metatronCommand
143
153
  .description('対話モード (REPL)')
144
154
  .option('--context <context>', 'コンテキスト', 'aranea_sdk_cli')
145
155
  .option('--token <token>', '認証トークン')
156
+ .option('-e, --endpoint <env>', '環境 (staging|production)', 'production')
146
157
  .action(async (options) => {
147
- console.log(chalk_1.default.bold('\n=== AraneaMetatron Chat ===\n'));
158
+ const env = (0, config_1.resolveEnvironment)(options.endpoint);
159
+ console.log(chalk_1.default.bold(`\n=== AraneaMetatron Chat (${env}) ===\n`));
148
160
  console.log(chalk_1.default.gray('AraneaSDKについて質問してください。'));
149
161
  console.log(chalk_1.default.gray('終了するには "exit" または Ctrl+C を入力\n'));
150
162
  const token = options.token || getAuthToken();
@@ -171,7 +183,7 @@ exports.metatronCommand
171
183
  const spinner = (0, ora_1.default)('').start();
172
184
  spinner.text = '';
173
185
  try {
174
- const result = await queryMetatron(query, options.context, token);
186
+ const result = await queryMetatron(query, options.context, token, env);
175
187
  spinner.stop();
176
188
  console.log('');
177
189
  console.log(chalk_1.default.green('Metatron:'), result.answer);
package/dist/index.js CHANGED
@@ -28,7 +28,7 @@ const program = new commander_1.Command();
28
28
  program
29
29
  .name('aranea-sdk')
30
30
  .description('AraneaSDK CLI - デバイス開発支援ツール')
31
- .version('0.3.2');
31
+ .version('0.3.3');
32
32
  // test コマンド
33
33
  program.addCommand(test_1.testCommand);
34
34
  // simulate コマンド
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aranea-sdk-cli",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "AraneaSDK CLI - ESP32 IoTデバイス開発支援ツール",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",