yamatovision 1.0.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.

Potentially problematic release.


This version of yamatovision might be problematic. Click here for more details.

Files changed (217) hide show
  1. package/README.md +14 -0
  2. package/bin/bluelamp-vscode-base +325 -0
  3. package/bin/bluelamp1 +2 -0
  4. package/bin/bluelamp10 +2 -0
  5. package/bin/bluelamp100 +2 -0
  6. package/bin/bluelamp11 +2 -0
  7. package/bin/bluelamp12 +2 -0
  8. package/bin/bluelamp13 +2 -0
  9. package/bin/bluelamp14 +2 -0
  10. package/bin/bluelamp15 +2 -0
  11. package/bin/bluelamp16 +2 -0
  12. package/bin/bluelamp17 +2 -0
  13. package/bin/bluelamp18 +2 -0
  14. package/bin/bluelamp19 +2 -0
  15. package/bin/bluelamp2 +2 -0
  16. package/bin/bluelamp20 +2 -0
  17. package/bin/bluelamp21 +2 -0
  18. package/bin/bluelamp22 +2 -0
  19. package/bin/bluelamp23 +2 -0
  20. package/bin/bluelamp24 +2 -0
  21. package/bin/bluelamp25 +2 -0
  22. package/bin/bluelamp26 +2 -0
  23. package/bin/bluelamp27 +2 -0
  24. package/bin/bluelamp28 +2 -0
  25. package/bin/bluelamp29 +2 -0
  26. package/bin/bluelamp3 +2 -0
  27. package/bin/bluelamp30 +2 -0
  28. package/bin/bluelamp31 +2 -0
  29. package/bin/bluelamp32 +2 -0
  30. package/bin/bluelamp33 +2 -0
  31. package/bin/bluelamp34 +2 -0
  32. package/bin/bluelamp35 +2 -0
  33. package/bin/bluelamp36 +2 -0
  34. package/bin/bluelamp37 +2 -0
  35. package/bin/bluelamp38 +2 -0
  36. package/bin/bluelamp39 +2 -0
  37. package/bin/bluelamp4 +2 -0
  38. package/bin/bluelamp40 +2 -0
  39. package/bin/bluelamp41 +2 -0
  40. package/bin/bluelamp42 +2 -0
  41. package/bin/bluelamp43 +2 -0
  42. package/bin/bluelamp44 +2 -0
  43. package/bin/bluelamp45 +2 -0
  44. package/bin/bluelamp46 +2 -0
  45. package/bin/bluelamp47 +2 -0
  46. package/bin/bluelamp48 +2 -0
  47. package/bin/bluelamp49 +2 -0
  48. package/bin/bluelamp5 +2 -0
  49. package/bin/bluelamp50 +2 -0
  50. package/bin/bluelamp51 +2 -0
  51. package/bin/bluelamp52 +2 -0
  52. package/bin/bluelamp53 +2 -0
  53. package/bin/bluelamp54 +2 -0
  54. package/bin/bluelamp55 +2 -0
  55. package/bin/bluelamp56 +2 -0
  56. package/bin/bluelamp57 +2 -0
  57. package/bin/bluelamp58 +2 -0
  58. package/bin/bluelamp59 +2 -0
  59. package/bin/bluelamp6 +2 -0
  60. package/bin/bluelamp60 +2 -0
  61. package/bin/bluelamp61 +2 -0
  62. package/bin/bluelamp62 +2 -0
  63. package/bin/bluelamp63 +2 -0
  64. package/bin/bluelamp64 +2 -0
  65. package/bin/bluelamp65 +2 -0
  66. package/bin/bluelamp66 +2 -0
  67. package/bin/bluelamp67 +2 -0
  68. package/bin/bluelamp68 +2 -0
  69. package/bin/bluelamp69 +2 -0
  70. package/bin/bluelamp7 +2 -0
  71. package/bin/bluelamp70 +2 -0
  72. package/bin/bluelamp71 +2 -0
  73. package/bin/bluelamp72 +2 -0
  74. package/bin/bluelamp73 +2 -0
  75. package/bin/bluelamp74 +2 -0
  76. package/bin/bluelamp75 +2 -0
  77. package/bin/bluelamp76 +2 -0
  78. package/bin/bluelamp77 +2 -0
  79. package/bin/bluelamp78 +2 -0
  80. package/bin/bluelamp79 +2 -0
  81. package/bin/bluelamp8 +2 -0
  82. package/bin/bluelamp80 +2 -0
  83. package/bin/bluelamp81 +2 -0
  84. package/bin/bluelamp82 +2 -0
  85. package/bin/bluelamp83 +2 -0
  86. package/bin/bluelamp84 +2 -0
  87. package/bin/bluelamp85 +2 -0
  88. package/bin/bluelamp86 +2 -0
  89. package/bin/bluelamp87 +2 -0
  90. package/bin/bluelamp88 +2 -0
  91. package/bin/bluelamp89 +2 -0
  92. package/bin/bluelamp9 +2 -0
  93. package/bin/bluelamp90 +2 -0
  94. package/bin/bluelamp91 +2 -0
  95. package/bin/bluelamp92 +2 -0
  96. package/bin/bluelamp93 +2 -0
  97. package/bin/bluelamp94 +2 -0
  98. package/bin/bluelamp95 +2 -0
  99. package/bin/bluelamp96 +2 -0
  100. package/bin/bluelamp97 +2 -0
  101. package/bin/bluelamp98 +2 -0
  102. package/bin/bluelamp99 +2 -0
  103. package/bin/musuhi1 +2 -0
  104. package/bin/musuhi10 +2 -0
  105. package/bin/musuhi100 +2 -0
  106. package/bin/musuhi11 +2 -0
  107. package/bin/musuhi12 +2 -0
  108. package/bin/musuhi13 +2 -0
  109. package/bin/musuhi14 +2 -0
  110. package/bin/musuhi15 +2 -0
  111. package/bin/musuhi16 +2 -0
  112. package/bin/musuhi17 +2 -0
  113. package/bin/musuhi18 +2 -0
  114. package/bin/musuhi19 +2 -0
  115. package/bin/musuhi2 +2 -0
  116. package/bin/musuhi20 +2 -0
  117. package/bin/musuhi21 +2 -0
  118. package/bin/musuhi22 +2 -0
  119. package/bin/musuhi23 +2 -0
  120. package/bin/musuhi24 +2 -0
  121. package/bin/musuhi25 +2 -0
  122. package/bin/musuhi26 +2 -0
  123. package/bin/musuhi27 +2 -0
  124. package/bin/musuhi28 +2 -0
  125. package/bin/musuhi29 +2 -0
  126. package/bin/musuhi3 +2 -0
  127. package/bin/musuhi30 +2 -0
  128. package/bin/musuhi31 +2 -0
  129. package/bin/musuhi32 +2 -0
  130. package/bin/musuhi33 +2 -0
  131. package/bin/musuhi34 +2 -0
  132. package/bin/musuhi35 +2 -0
  133. package/bin/musuhi36 +2 -0
  134. package/bin/musuhi37 +2 -0
  135. package/bin/musuhi38 +2 -0
  136. package/bin/musuhi39 +2 -0
  137. package/bin/musuhi4 +2 -0
  138. package/bin/musuhi40 +2 -0
  139. package/bin/musuhi41 +2 -0
  140. package/bin/musuhi42 +2 -0
  141. package/bin/musuhi43 +2 -0
  142. package/bin/musuhi44 +2 -0
  143. package/bin/musuhi45 +2 -0
  144. package/bin/musuhi46 +2 -0
  145. package/bin/musuhi47 +2 -0
  146. package/bin/musuhi48 +2 -0
  147. package/bin/musuhi49 +2 -0
  148. package/bin/musuhi5 +2 -0
  149. package/bin/musuhi50 +2 -0
  150. package/bin/musuhi51 +2 -0
  151. package/bin/musuhi52 +2 -0
  152. package/bin/musuhi53 +2 -0
  153. package/bin/musuhi54 +2 -0
  154. package/bin/musuhi55 +2 -0
  155. package/bin/musuhi56 +2 -0
  156. package/bin/musuhi57 +2 -0
  157. package/bin/musuhi58 +2 -0
  158. package/bin/musuhi59 +2 -0
  159. package/bin/musuhi6 +2 -0
  160. package/bin/musuhi60 +2 -0
  161. package/bin/musuhi61 +2 -0
  162. package/bin/musuhi62 +2 -0
  163. package/bin/musuhi63 +2 -0
  164. package/bin/musuhi64 +2 -0
  165. package/bin/musuhi65 +2 -0
  166. package/bin/musuhi66 +2 -0
  167. package/bin/musuhi67 +2 -0
  168. package/bin/musuhi68 +2 -0
  169. package/bin/musuhi69 +2 -0
  170. package/bin/musuhi7 +2 -0
  171. package/bin/musuhi70 +2 -0
  172. package/bin/musuhi71 +2 -0
  173. package/bin/musuhi72 +2 -0
  174. package/bin/musuhi73 +2 -0
  175. package/bin/musuhi74 +2 -0
  176. package/bin/musuhi75 +2 -0
  177. package/bin/musuhi76 +2 -0
  178. package/bin/musuhi77 +2 -0
  179. package/bin/musuhi78 +2 -0
  180. package/bin/musuhi79 +2 -0
  181. package/bin/musuhi8 +2 -0
  182. package/bin/musuhi80 +2 -0
  183. package/bin/musuhi81 +2 -0
  184. package/bin/musuhi82 +2 -0
  185. package/bin/musuhi83 +2 -0
  186. package/bin/musuhi84 +2 -0
  187. package/bin/musuhi85 +2 -0
  188. package/bin/musuhi86 +2 -0
  189. package/bin/musuhi87 +2 -0
  190. package/bin/musuhi88 +2 -0
  191. package/bin/musuhi89 +2 -0
  192. package/bin/musuhi9 +2 -0
  193. package/bin/musuhi90 +2 -0
  194. package/bin/musuhi91 +2 -0
  195. package/bin/musuhi92 +2 -0
  196. package/bin/musuhi93 +2 -0
  197. package/bin/musuhi94 +2 -0
  198. package/bin/musuhi95 +2 -0
  199. package/bin/musuhi96 +2 -0
  200. package/bin/musuhi97 +2 -0
  201. package/bin/musuhi98 +2 -0
  202. package/bin/musuhi99 +2 -0
  203. package/lib/agents//343/203/226/343/203/253/343/203/274/343/203/251/343/203/263/343/203/227.md +106 -0
  204. package/lib/auth/InteractiveLogin.js +253 -0
  205. package/lib/auth/PortalAuthClient.js +184 -0
  206. package/lib/auth/TokenManager.js +260 -0
  207. package/lib/i18n/en.json +136 -0
  208. package/lib/i18n/index.js +75 -0
  209. package/lib/i18n/ja.json +136 -0
  210. package/lib/mcp-server/index.cjs +536 -0
  211. package/lib/mcp-server/portal-api-client.cjs +586 -0
  212. package/lib/utils/logger.js +83 -0
  213. package/package.json +155 -0
  214. package/scripts/build.js +348 -0
  215. package/scripts/generate-commands.js +45 -0
  216. package/scripts/playwright-launch.js +141 -0
  217. package/scripts/setup-playwright.js +62 -0
@@ -0,0 +1,586 @@
1
+ /**
2
+ * Portal API Client for BlueLamp VSCode
3
+ * 認証付きでPortal APIからプロンプトを取得
4
+ */
5
+
6
+ const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
7
+ const https = require('https');
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const os = require('os');
11
+ const { logger } = require('../utils/logger');
12
+ const { t } = require('../i18n');
13
+
14
+ // HTTPS検証設定(本番環境では有効化、開発環境のみ自己署名証明書を許可)
15
+ const isDevEnvironment = process.env.NODE_ENV === 'development' ||
16
+ (process.env.PORTAL_URL && process.env.PORTAL_URL.includes('localhost'));
17
+ const httpsAgent = new https.Agent({
18
+ rejectUnauthorized: !isDevEnvironment
19
+ });
20
+
21
+ const PORTAL_URL = process.env.PORTAL_URL || 'https://musuhi-portal-235426778039.asia-northeast1.run.app';
22
+
23
+ // ログファイル(index.cjsと同じファイルに書き込む)
24
+ const LOG_DIR = path.join(os.homedir(), '.bluelamp-vscode', 'logs');
25
+ const LOG_FILE = path.join(LOG_DIR, 'mcp.log');
26
+
27
+ // ログディレクトリが存在しない場合は作成
28
+ if (!fs.existsSync(LOG_DIR)) {
29
+ fs.mkdirSync(LOG_DIR, { recursive: true });
30
+ }
31
+
32
+ /**
33
+ * ファイルとコンソールにログを出力
34
+ * @param {string} message - ログメッセージ
35
+ */
36
+ function log(message) {
37
+ const timestamp = new Date().toISOString();
38
+ const logMessage = `[${timestamp}] ${message}\n`;
39
+ fs.appendFileSync(LOG_FILE, logMessage);
40
+ logger.debug(message);
41
+ }
42
+
43
+ /**
44
+ * Portal APIから認証付きでプロンプトを取得
45
+ * @param {string} keyword - 検索キーワード(例: "@要件定義")
46
+ * @param {string} token - CLI認証トークン
47
+ * @param {string} [language='ja'] - 言語コード('ja' or 'en')
48
+ * @returns {Promise<{success: boolean, knowledge?: string, title?: string, tags?: string[], error?: string}>}
49
+ */
50
+ async function getPromptFromPortal(keyword, token, language = 'ja') {
51
+ try {
52
+ log(`[portal-api-client] getPromptFromPortal called with keyword: ${keyword}, lang: ${language}, token: ${token ? 'present' : 'missing'}`);
53
+
54
+ if (!token) {
55
+ log('[portal-api-client] No authentication token provided');
56
+ return { success: false, error: t('mcp.noAuthToken') };
57
+ }
58
+
59
+ // キーワードをそのまま使用 + 言語パラメータ追加
60
+ const encodedKeyword = encodeURIComponent(keyword);
61
+ const url = `${PORTAL_URL}/api/cli/prompts/knowledge-injection/${encodedKeyword}?lang=${language}`;
62
+ log(`[portal-api-client] Direct keyword search: ${url}`);
63
+ log(`[portal-api-client] Token (first 30 chars): ${token.substring(0, 30)}...`);
64
+
65
+ log(`[portal-api-client] About to call fetch...`);
66
+ const response = await fetch(url, {
67
+ method: 'GET',
68
+ headers: {
69
+ 'X-CLI-Token': token,
70
+ 'Content-Type': 'application/json',
71
+ 'User-Agent': 'BlueLamp-VSCode-MCP/1.0'
72
+ },
73
+ agent: url.startsWith('https') ? httpsAgent : undefined
74
+ });
75
+ log(`[portal-api-client] Fetch completed`);
76
+
77
+ log(`[portal-api-client] Response status: ${response.status}`);
78
+ log(`[portal-api-client] Response headers: ${JSON.stringify(Object.fromEntries(response.headers.entries()))}`);
79
+
80
+ if (!response.ok) {
81
+ log(`[portal-api-client] Portal API error: ${response.status}`);
82
+ const errorText = await response.text();
83
+ log(`[portal-api-client] Error response: ${errorText}`);
84
+ let errorMessage = t('mcp.portalApiError', { status: response.status });
85
+ try {
86
+ const errorData = JSON.parse(errorText);
87
+ if (errorData.message) {
88
+ errorMessage = errorData.message;
89
+ }
90
+ } catch (e) {
91
+ // JSONパースエラーは無視
92
+ }
93
+ return { success: false, error: errorMessage };
94
+ }
95
+
96
+ const data = await response.json();
97
+ log(`[portal-api-client] Direct keyword search completed successfully`);
98
+
99
+ if (!data.success) {
100
+ log(`[portal-api-client] API returned success: false`);
101
+ return { success: false, error: data.message || t('mcp.apiReturnedError') };
102
+ }
103
+
104
+ // 直接プロンプトデータを取得(検索不要)
105
+ const prompt = data.data;
106
+
107
+ if (!prompt) {
108
+ log(`[portal-api-client] No prompt found for keyword: ${keyword}`);
109
+ return { success: false, error: t('mcp.promptNotFoundForKeyword', { keyword }) };
110
+ }
111
+
112
+ log(`[portal-api-client] Found prompt: ${prompt.title}`);
113
+
114
+ // プロンプトの詳細情報が既に含まれているかチェック
115
+ if (prompt.content || prompt.text) {
116
+ // 詳細情報が含まれている場合はそのまま返す
117
+ return {
118
+ success: true,
119
+ knowledge: prompt.content || prompt.text,
120
+ title: prompt.title,
121
+ tags: prompt.tags || []
122
+ };
123
+ }
124
+
125
+ // 個別のプロンプト詳細を取得
126
+ try {
127
+ const detailUrl = `${PORTAL_URL}/api/cli/prompts/${prompt.id}`;
128
+ log(`[portal-api-client] Fetching prompt details from: ${detailUrl}`);
129
+
130
+ const detailResponse = await fetch(detailUrl, {
131
+ method: 'GET',
132
+ headers: {
133
+ 'X-CLI-Token': token,
134
+ 'Content-Type': 'application/json',
135
+ 'User-Agent': 'BlueLamp-VSCode-MCP/1.0'
136
+ },
137
+ agent: httpsAgent
138
+ });
139
+
140
+ if (detailResponse.ok) {
141
+ const detailData = await detailResponse.json();
142
+ if (detailData.success && detailData.data?.prompt?.content) {
143
+ log(`[portal-api-client] Successfully fetched prompt content`);
144
+
145
+ return {
146
+ success: true,
147
+ knowledge: detailData.data.prompt.content,
148
+ title: prompt.title || prompt.name,
149
+ tags: prompt.tags
150
+ };
151
+ }
152
+ }
153
+ } catch (error) {
154
+ log(`[portal-api-client] Error fetching prompt details: ${error.message}`);
155
+ }
156
+
157
+ // フォールバック: リスト情報のみ返す
158
+ return {
159
+ success: true,
160
+ knowledge: prompt.description || `# ${prompt.title}\n\n${t('mcp.knowledgeLoadError', { error: 'detail fetch failed' })}`,
161
+ title: prompt.title || prompt.name,
162
+ tags: prompt.tags
163
+ };
164
+
165
+ } catch (error) {
166
+ log(`[portal-api-client] FATAL ERROR in getPromptFromPortal: ${error.message}`);
167
+ log(`[portal-api-client] Error stack: ${error.stack}`);
168
+ logger.error(`Failed to get prompt from Portal: ${error.message}`);
169
+ return { success: false, error: t('mcp.portalCommunicationError', { error: error.message }) };
170
+ }
171
+ }
172
+
173
+ /**
174
+ * スロット設定を取得
175
+ * bluelamp1〜18の起動時キーワードをユーザーごとにカスタマイズ
176
+ *
177
+ * @param {number} slotNumber - スロット番号(1〜18)
178
+ * @param {string} token - CLI認証トークン
179
+ * @returns {Promise<string|null>} カスタムキーワードまたはnull(デフォルト使用)
180
+ */
181
+ async function getSlotConfig(slotNumber, token) {
182
+ try {
183
+ if (!token) {
184
+ log('[portal-api-client] getSlotConfig: No token, returning null');
185
+ return null;
186
+ }
187
+
188
+ const url = `${PORTAL_URL}/api/cli/slot-config/${slotNumber}`;
189
+ log(`[portal-api-client] Fetching slot config: ${url}`);
190
+
191
+ const response = await fetch(url, {
192
+ method: 'GET',
193
+ headers: {
194
+ 'X-CLI-Token': token,
195
+ 'Content-Type': 'application/json',
196
+ 'User-Agent': 'BlueLamp-VSCode-MCP/1.0'
197
+ },
198
+ agent: url.startsWith('https') ? httpsAgent : undefined
199
+ });
200
+
201
+ if (!response.ok) {
202
+ log(`[portal-api-client] Slot config API error: ${response.status}, using default`);
203
+ return null;
204
+ }
205
+
206
+ const data = await response.json();
207
+
208
+ if (data.success && data.data?.keyword) {
209
+ log(`[portal-api-client] Slot ${slotNumber}: custom keyword "${data.data.keyword}"`);
210
+ return data.data.keyword;
211
+ }
212
+
213
+ log(`[portal-api-client] Slot ${slotNumber}: no custom config, using default`);
214
+ return null;
215
+
216
+ } catch (error) {
217
+ log(`[portal-api-client] getSlotConfig error: ${error.message}, using default`);
218
+ return null;
219
+ }
220
+ }
221
+
222
+ /**
223
+ * 違反報告をPortal APIに送信
224
+ * @param {string} reason - 違反理由
225
+ * @param {'warning'|'serious'|'critical'} severity - 重大度
226
+ * @param {string} token - CLI認証トークン
227
+ * @param {string} [userMessage] - ユーザーが実際に送信した抽出試行メッセージ
228
+ * @returns {Promise<{success: boolean, action?: string, violationCount?: number, message?: string, error?: string}>}
229
+ */
230
+ async function reportViolation(reason, severity, token, userMessage) {
231
+ try {
232
+ log(`[portal-api-client] reportViolation called: severity=${severity}`);
233
+
234
+ if (!token) {
235
+ return { success: false, error: t('mcp.violationNoToken') };
236
+ }
237
+
238
+ const url = `${PORTAL_URL}/api/cli/report-violation`;
239
+ const body = { reason, severity };
240
+ if (userMessage) {
241
+ body.userMessage = userMessage;
242
+ }
243
+
244
+ const response = await fetch(url, {
245
+ method: 'POST',
246
+ headers: {
247
+ 'X-CLI-Token': token,
248
+ 'Content-Type': 'application/json',
249
+ 'User-Agent': 'BlueLamp-VSCode-MCP/1.0'
250
+ },
251
+ agent: url.startsWith('https') ? httpsAgent : undefined,
252
+ body: JSON.stringify(body)
253
+ });
254
+
255
+ if (!response.ok) {
256
+ const errorText = await response.text();
257
+ log(`[portal-api-client] reportViolation error: ${response.status} ${errorText}`);
258
+ return { success: false, error: t('mcp.violationApiError', { status: response.status }) };
259
+ }
260
+
261
+ const data = await response.json();
262
+ log(`[portal-api-client] reportViolation result: action=${data.action}, count=${data.violationCount}`);
263
+ return data;
264
+
265
+ } catch (error) {
266
+ log(`[portal-api-client] reportViolation FATAL: ${error.message}`);
267
+ return { success: false, error: t('mcp.violationCommunicationError', { error: error.message }) };
268
+ }
269
+ }
270
+
271
+ /**
272
+ * 利用可能なMCPカタログ一覧を取得
273
+ * @param {Object} options - { category, search, limit }
274
+ * @param {string} token - CLI認証トークン
275
+ * @param {string} language - 言語コード
276
+ * @returns {Promise<{success: boolean, data?: Array, error?: string}>}
277
+ */
278
+ async function listAvailableMcps(options = {}, token, language = 'ja') {
279
+ try {
280
+ log(`[portal-api-client] listAvailableMcps called: ${JSON.stringify(options)}`);
281
+
282
+ if (!token) {
283
+ return { success: false, error: t('mcp.noAuthToken') };
284
+ }
285
+
286
+ const params = new URLSearchParams();
287
+ if (options.category) params.set('category', options.category);
288
+ if (options.search) params.set('search', options.search);
289
+ if (options.limit) params.set('limit', String(options.limit));
290
+ params.set('lang', language);
291
+
292
+ const url = `${PORTAL_URL}/api/mcp/catalog?${params.toString()}`;
293
+ log(`[portal-api-client] Fetching MCP catalog: ${url}`);
294
+
295
+ const response = await fetch(url, {
296
+ method: 'GET',
297
+ headers: {
298
+ 'X-CLI-Token': token,
299
+ 'Content-Type': 'application/json',
300
+ 'User-Agent': 'BlueLamp-VSCode-MCP/1.0'
301
+ },
302
+ agent: url.startsWith('https') ? httpsAgent : undefined
303
+ });
304
+
305
+ if (!response.ok) {
306
+ const errorText = await response.text();
307
+ log(`[portal-api-client] listAvailableMcps error: ${response.status} ${errorText}`);
308
+ let errorMessage = t('mcp.listMcpsFailed', { error: `HTTP ${response.status}` });
309
+ try {
310
+ const errorData = JSON.parse(errorText);
311
+ if (errorData.message) errorMessage = errorData.message;
312
+ } catch (e) {
313
+ // JSONパースエラーは無視
314
+ }
315
+ return { success: false, error: errorMessage };
316
+ }
317
+
318
+ const data = await response.json();
319
+ log(`[portal-api-client] listAvailableMcps: ${data.data?.length || 0} MCPs found`);
320
+ return { success: true, data: data.data || [] };
321
+
322
+ } catch (error) {
323
+ log(`[portal-api-client] listAvailableMcps FATAL: ${error.message}`);
324
+ return { success: false, error: t('mcp.portalCommunicationError', { error: error.message }) };
325
+ }
326
+ }
327
+
328
+ /**
329
+ * 特定MCPの詳細情報を取得
330
+ * @param {string} mcpId - MCP ID
331
+ * @param {string} token - CLI認証トークン
332
+ * @param {string} language - 言語コード
333
+ * @returns {Promise<{success: boolean, data?: Object, error?: string}>}
334
+ */
335
+ async function getMcpInfo(mcpId, token, language = 'ja') {
336
+ try {
337
+ log(`[portal-api-client] getMcpInfo called: mcpId=${mcpId}`);
338
+
339
+ if (!token) {
340
+ return { success: false, error: t('mcp.noAuthToken') };
341
+ }
342
+
343
+ const url = `${PORTAL_URL}/api/mcp/${encodeURIComponent(mcpId)}/details?lang=${language}`;
344
+ log(`[portal-api-client] Fetching MCP info: ${url}`);
345
+
346
+ const response = await fetch(url, {
347
+ method: 'GET',
348
+ headers: {
349
+ 'X-CLI-Token': token,
350
+ 'Content-Type': 'application/json',
351
+ 'User-Agent': 'BlueLamp-VSCode-MCP/1.0'
352
+ },
353
+ agent: url.startsWith('https') ? httpsAgent : undefined
354
+ });
355
+
356
+ if (!response.ok) {
357
+ const errorText = await response.text();
358
+ log(`[portal-api-client] getMcpInfo error: ${response.status} ${errorText}`);
359
+ let errorMessage = t('mcp.getMcpInfoFailed', { error: `HTTP ${response.status}` });
360
+ try {
361
+ const errorData = JSON.parse(errorText);
362
+ if (errorData.message) errorMessage = errorData.message;
363
+ } catch (e) {
364
+ // JSONパースエラーは無視
365
+ }
366
+ return { success: false, error: errorMessage };
367
+ }
368
+
369
+ const data = await response.json();
370
+ log(`[portal-api-client] getMcpInfo: found ${data.data?.name || mcpId}`);
371
+ return { success: true, data: data.data };
372
+
373
+ } catch (error) {
374
+ log(`[portal-api-client] getMcpInfo FATAL: ${error.message}`);
375
+ return { success: false, error: t('mcp.portalCommunicationError', { error: error.message }) };
376
+ }
377
+ }
378
+
379
+ /**
380
+ * MCPツールをプロキシ経由で実行
381
+ * @param {string} mcpId - MCP ID
382
+ * @param {string} toolName - ツール名
383
+ * @param {Object} args - ツール引数
384
+ * @param {string} token - CLI認証トークン
385
+ * @returns {Promise<{success: boolean, data?: any, error?: string}>}
386
+ */
387
+ async function callMcpTool(mcpId, toolName, args, token) {
388
+ try {
389
+ log(`[portal-api-client] callMcpTool called: mcpId=${mcpId}, tool=${toolName}`);
390
+
391
+ if (!token) {
392
+ return { success: false, error: t('mcp.noAuthToken') };
393
+ }
394
+
395
+ const url = `${PORTAL_URL}/api/mcp/${encodeURIComponent(mcpId)}/call`;
396
+ const body = { tool_name: toolName, arguments: args };
397
+
398
+ log(`[portal-api-client] Calling MCP tool: ${url}`);
399
+
400
+ const response = await fetch(url, {
401
+ method: 'POST',
402
+ headers: {
403
+ 'X-CLI-Token': token,
404
+ 'Content-Type': 'application/json',
405
+ 'User-Agent': 'BlueLamp-VSCode-MCP/1.0'
406
+ },
407
+ agent: url.startsWith('https') ? httpsAgent : undefined,
408
+ body: JSON.stringify(body)
409
+ });
410
+
411
+ if (!response.ok) {
412
+ const errorText = await response.text();
413
+ log(`[portal-api-client] callMcpTool error: ${response.status} ${errorText}`);
414
+ let errorMessage = t('mcp.callToolFailed', { error: `HTTP ${response.status}` });
415
+ try {
416
+ const errorData = JSON.parse(errorText);
417
+ if (errorData.message) errorMessage = errorData.message;
418
+ } catch (e) {
419
+ // JSONパースエラーは無視
420
+ }
421
+ return { success: false, error: errorMessage };
422
+ }
423
+
424
+ const data = await response.json();
425
+ log(`[portal-api-client] callMcpTool: success`);
426
+ return { success: true, data: data.data };
427
+
428
+ } catch (error) {
429
+ log(`[portal-api-client] callMcpTool FATAL: ${error.message}`);
430
+ return { success: false, error: t('mcp.portalCommunicationError', { error: error.message }) };
431
+ }
432
+ }
433
+
434
+ /**
435
+ * MCPコードのセキュリティスキャン
436
+ * @param {string} code - スキャン対象コード
437
+ * @param {string} token - CLI認証トークン
438
+ */
439
+ async function scanMcpCode(code, token) {
440
+ try {
441
+ log(`[portal-api-client] scanMcpCode called`);
442
+ if (!token) return { success: false, error: t('mcp.noAuthToken') };
443
+
444
+ const url = `${PORTAL_URL}/api/mcp/scan`;
445
+ const response = await fetch(url, {
446
+ method: 'POST',
447
+ headers: {
448
+ 'X-CLI-Token': token,
449
+ 'Content-Type': 'application/json',
450
+ 'User-Agent': 'BlueLamp-VSCode-MCP/1.0'
451
+ },
452
+ agent: url.startsWith('https') ? httpsAgent : undefined,
453
+ body: JSON.stringify({ code })
454
+ });
455
+
456
+ if (!response.ok) {
457
+ const errorText = await response.text();
458
+ log(`[portal-api-client] scanMcpCode error: ${response.status} ${errorText}`);
459
+ return { success: false, error: `HTTP ${response.status}` };
460
+ }
461
+
462
+ const data = await response.json();
463
+ return { success: true, data: data.data };
464
+ } catch (error) {
465
+ log(`[portal-api-client] scanMcpCode FATAL: ${error.message}`);
466
+ return { success: false, error: t('mcp.portalCommunicationError', { error: error.message }) };
467
+ }
468
+ }
469
+
470
+ /**
471
+ * ユーザーMCPをデプロイ
472
+ * @param {Object} deployData - { code, name, description, tools, category, envVars }
473
+ * @param {string} token - CLI認証トークン
474
+ */
475
+ async function deployUserMcp(deployData, token) {
476
+ try {
477
+ log(`[portal-api-client] deployUserMcp called: name=${deployData.name}`);
478
+ if (!token) return { success: false, error: t('mcp.noAuthToken') };
479
+
480
+ const url = `${PORTAL_URL}/api/mcp/deploy`;
481
+ const response = await fetch(url, {
482
+ method: 'POST',
483
+ headers: {
484
+ 'X-CLI-Token': token,
485
+ 'Content-Type': 'application/json',
486
+ 'User-Agent': 'BlueLamp-VSCode-MCP/1.0'
487
+ },
488
+ agent: url.startsWith('https') ? httpsAgent : undefined,
489
+ body: JSON.stringify(deployData)
490
+ });
491
+
492
+ if (!response.ok) {
493
+ const errorText = await response.text();
494
+ log(`[portal-api-client] deployUserMcp error: ${response.status} ${errorText}`);
495
+ let errorMessage = `HTTP ${response.status}`;
496
+ try {
497
+ const errorData = JSON.parse(errorText);
498
+ if (errorData.error) errorMessage = errorData.error;
499
+ if (errorData.details) return { success: false, error: errorMessage, details: errorData.details };
500
+ } catch (e) { /* ignore */ }
501
+ return { success: false, error: errorMessage };
502
+ }
503
+
504
+ const data = await response.json();
505
+ return { success: true, data: data.data };
506
+ } catch (error) {
507
+ log(`[portal-api-client] deployUserMcp FATAL: ${error.message}`);
508
+ return { success: false, error: t('mcp.portalCommunicationError', { error: error.message }) };
509
+ }
510
+ }
511
+
512
+ /**
513
+ * 自作MCP一覧取得
514
+ * @param {string} token - CLI認証トークン
515
+ */
516
+ async function listUserCreatedMcps(token) {
517
+ try {
518
+ log(`[portal-api-client] listUserCreatedMcps called`);
519
+ if (!token) return { success: false, error: t('mcp.noAuthToken') };
520
+
521
+ const url = `${PORTAL_URL}/api/mcp/user/me/created`;
522
+ const response = await fetch(url, {
523
+ method: 'GET',
524
+ headers: {
525
+ 'X-CLI-Token': token,
526
+ 'Content-Type': 'application/json',
527
+ 'User-Agent': 'BlueLamp-VSCode-MCP/1.0'
528
+ },
529
+ agent: url.startsWith('https') ? httpsAgent : undefined
530
+ });
531
+
532
+ if (!response.ok) {
533
+ const errorText = await response.text();
534
+ log(`[portal-api-client] listUserCreatedMcps error: ${response.status}`);
535
+ return { success: false, error: `HTTP ${response.status}` };
536
+ }
537
+
538
+ const data = await response.json();
539
+ return { success: true, data: data.data };
540
+ } catch (error) {
541
+ log(`[portal-api-client] listUserCreatedMcps FATAL: ${error.message}`);
542
+ return { success: false, error: t('mcp.portalCommunicationError', { error: error.message }) };
543
+ }
544
+ }
545
+
546
+ /**
547
+ * ユーザーMCP削除
548
+ * @param {string} mcpId - MCP ID
549
+ * @param {string} token - CLI認証トークン
550
+ */
551
+ async function deleteUserMcp(mcpId, token) {
552
+ try {
553
+ log(`[portal-api-client] deleteUserMcp called: mcpId=${mcpId}`);
554
+ if (!token) return { success: false, error: t('mcp.noAuthToken') };
555
+
556
+ const url = `${PORTAL_URL}/api/mcp/${encodeURIComponent(mcpId)}`;
557
+ const response = await fetch(url, {
558
+ method: 'DELETE',
559
+ headers: {
560
+ 'X-CLI-Token': token,
561
+ 'Content-Type': 'application/json',
562
+ 'User-Agent': 'BlueLamp-VSCode-MCP/1.0'
563
+ },
564
+ agent: url.startsWith('https') ? httpsAgent : undefined
565
+ });
566
+
567
+ if (!response.ok) {
568
+ const errorText = await response.text();
569
+ log(`[portal-api-client] deleteUserMcp error: ${response.status}`);
570
+ let errorMessage = `HTTP ${response.status}`;
571
+ try {
572
+ const errorData = JSON.parse(errorText);
573
+ if (errorData.error) errorMessage = errorData.error;
574
+ } catch (e) { /* ignore */ }
575
+ return { success: false, error: errorMessage };
576
+ }
577
+
578
+ const data = await response.json();
579
+ return { success: true, data: data.data };
580
+ } catch (error) {
581
+ log(`[portal-api-client] deleteUserMcp FATAL: ${error.message}`);
582
+ return { success: false, error: t('mcp.portalCommunicationError', { error: error.message }) };
583
+ }
584
+ }
585
+
586
+ module.exports = { getPromptFromPortal, getSlotConfig, reportViolation, listAvailableMcps, getMcpInfo, callMcpTool, scanMcpCode, deployUserMcp, listUserCreatedMcps, deleteUserMcp };
@@ -0,0 +1,83 @@
1
+ /**
2
+ * むすひ VSCode Logger
3
+ * 環境変数ベースのログレベル制御
4
+ *
5
+ * @module logger
6
+ */
7
+
8
+ const LOG_LEVELS = {
9
+ debug: 0,
10
+ info: 1,
11
+ warn: 2,
12
+ error: 3,
13
+ silent: 4
14
+ };
15
+
16
+ const LOG_LEVEL = process.env.MUSUHI_LOG_LEVEL || 'info';
17
+ const currentLevel = LOG_LEVELS[LOG_LEVEL] ?? LOG_LEVELS.info;
18
+
19
+ /**
20
+ * タイムスタンプ付きログメッセージを生成
21
+ * @param {string} level - ログレベル
22
+ * @param {string} message - メッセージ
23
+ * @returns {string} フォーマット済みメッセージ
24
+ */
25
+ function formatMessage(level, message) {
26
+ const timestamp = new Date().toISOString();
27
+ return `[${timestamp}] [${level.toUpperCase()}] ${message}`;
28
+ }
29
+
30
+ /**
31
+ * ログ出力関数
32
+ */
33
+ const logger = {
34
+ /**
35
+ * デバッグログ
36
+ * @param {string} message - メッセージ
37
+ */
38
+ debug(message) {
39
+ if (currentLevel <= LOG_LEVELS.debug) {
40
+ console.error(formatMessage('debug', message));
41
+ }
42
+ },
43
+
44
+ /**
45
+ * 情報ログ
46
+ * @param {string} message - メッセージ
47
+ */
48
+ info(message) {
49
+ if (currentLevel <= LOG_LEVELS.info) {
50
+ console.error(formatMessage('info', message));
51
+ }
52
+ },
53
+
54
+ /**
55
+ * 警告ログ
56
+ * @param {string} message - メッセージ
57
+ */
58
+ warn(message) {
59
+ if (currentLevel <= LOG_LEVELS.warn) {
60
+ console.warn(formatMessage('warn', message));
61
+ }
62
+ },
63
+
64
+ /**
65
+ * エラーログ
66
+ * @param {string} message - メッセージ
67
+ */
68
+ error(message) {
69
+ if (currentLevel <= LOG_LEVELS.error) {
70
+ console.error(formatMessage('error', message));
71
+ }
72
+ },
73
+
74
+ /**
75
+ * ログレベルを取得
76
+ * @returns {string} 現在のログレベル
77
+ */
78
+ getLevel() {
79
+ return LOG_LEVEL;
80
+ }
81
+ };
82
+
83
+ module.exports = { logger, LOG_LEVELS };