bluelamp 4.0.5 → 4.0.6
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/bin/bluelamp-vscode-base +258 -0
- package/bin/bluelamp-vscode1 +2 -0
- package/bin/bluelamp-vscode10 +2 -0
- package/bin/bluelamp-vscode11 +2 -0
- package/bin/bluelamp-vscode12 +2 -0
- package/bin/bluelamp-vscode13 +2 -0
- package/bin/bluelamp-vscode14 +2 -0
- package/bin/bluelamp-vscode15 +2 -0
- package/bin/bluelamp-vscode16 +2 -0
- package/bin/bluelamp-vscode17 +2 -0
- package/bin/bluelamp-vscode18 +2 -0
- package/bin/bluelamp-vscode2 +2 -0
- package/bin/bluelamp-vscode3 +2 -0
- package/bin/bluelamp-vscode4 +2 -0
- package/bin/bluelamp-vscode5 +2 -0
- package/bin/bluelamp-vscode6 +2 -0
- package/bin/bluelamp-vscode7 +2 -0
- package/bin/bluelamp-vscode8 +2 -0
- package/bin/bluelamp-vscode9 +2 -0
- package/lib/auth/PortalAuthClient.js +1 -1
- package/lib/mcp-server/index.cjs +57 -25
- package/lib/mcp-server/portal-api-client.cjs +37 -10
- package/lib/utils/logger.js +83 -0
- package/package.json +33 -25
- package/scripts/generate-commands.js +10 -15
- package/bin/bluelamp-base +0 -200
- package/bin/bluelamp-hook +0 -49
- package/bin/bluelamp1 +0 -2
- package/bin/bluelamp10 +0 -2
- package/bin/bluelamp11 +0 -2
- package/bin/bluelamp12 +0 -2
- package/bin/bluelamp13 +0 -2
- package/bin/bluelamp14 +0 -2
- package/bin/bluelamp15 +0 -2
- package/bin/bluelamp16 +0 -2
- package/bin/bluelamp17 +0 -2
- package/bin/bluelamp18 +0 -2
- package/bin/bluelamp2 +0 -2
- package/bin/bluelamp3 +0 -2
- package/bin/bluelamp4 +0 -2
- package/bin/bluelamp5 +0 -2
- package/bin/bluelamp6 +0 -2
- package/bin/bluelamp7 +0 -2
- package/bin/bluelamp8 +0 -2
- package/bin/bluelamp9 +0 -2
- package/lib/mcp-server/fetch-prompt.js +0 -61
- package/scripts/setup-hook.js +0 -98
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* BlueLamp VSCode MCP Integration
|
|
5
|
+
* Base script for VSCode extension prompt injection
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { spawn } = require('child_process');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const os = require('os');
|
|
12
|
+
|
|
13
|
+
// パッケージのルートディレクトリを取得
|
|
14
|
+
const packageRoot = path.dirname(__dirname);
|
|
15
|
+
|
|
16
|
+
// .envファイルを読み込み(.env.localを優先)
|
|
17
|
+
const dotenvLocalPath = path.join(packageRoot, '.env.local');
|
|
18
|
+
const dotenvPath = path.join(packageRoot, '.env');
|
|
19
|
+
|
|
20
|
+
if (fs.existsSync(dotenvLocalPath)) {
|
|
21
|
+
require('dotenv').config({ path: dotenvLocalPath });
|
|
22
|
+
console.log('📁 Loaded .env.local');
|
|
23
|
+
} else if (fs.existsSync(dotenvPath)) {
|
|
24
|
+
require('dotenv').config({ path: dotenvPath });
|
|
25
|
+
console.log('📁 Loaded .env');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// コマンドマッピング(18個のプロンプト - 新BlueLamp 18エージェント体制)
|
|
29
|
+
const PROMPT_MAPPING = {
|
|
30
|
+
'bluelamp-vscode1': '@要件定義', // Phase @1: 要件定義エンジニア
|
|
31
|
+
'bluelamp-vscode2': '@Git管理', // Phase @2: Git/GitHub管理
|
|
32
|
+
'bluelamp-vscode3': '@フロントエンド基盤', // Phase @3: フロントエンド基盤オーケストレーター
|
|
33
|
+
'bluelamp-vscode4': '@ページ実装オーケストレーター', // Phase @4: ページ実装統括
|
|
34
|
+
'bluelamp-vscode5': '@環境構築オーケストレーター', // Phase @5: 環境構築
|
|
35
|
+
'bluelamp-vscode6': '@バックエンド計画オーケストレーター', // Phase @6: バックエンド実装計画
|
|
36
|
+
'bluelamp-vscode7': '@バックエンド実装オーケストレーター', // Phase @7: バックエンド実装統括
|
|
37
|
+
'bluelamp-vscode8': '@フロントエンド実装オーケストレーター', // Phase @8: API統合統括
|
|
38
|
+
'bluelamp-vscode9': '@E2Eテストオーケストレーター', // Phase @9: E2Eテスト統括
|
|
39
|
+
'bluelamp-vscode10': '@本番運用診断オーケストレーター', // Phase @10: CVSS 3.1準拠本番運用診断
|
|
40
|
+
'bluelamp-vscode11': '@デプロイオーケストレーター', // Phase @11: デプロイメント統括
|
|
41
|
+
'bluelamp-vscode12': '@拡張要件定義', // Tools @12: 拡張要件定義オーケストレーター
|
|
42
|
+
'bluelamp-vscode13': '@拡張機能実装', // Tools @13: 拡張機能実装オーケストレーター
|
|
43
|
+
'bluelamp-vscode14': '@デバッグ技術', // Tools @14: 自己完結型デバッグマスター
|
|
44
|
+
'bluelamp-vscode15': '@リファクタリング', // Tools @15: 超並列リファクタリング
|
|
45
|
+
'bluelamp-vscode16': '@ドキュメント生成', // Tools @16: ドキュメント生成統括
|
|
46
|
+
'bluelamp-vscode17': '@相談', // Tools @17: 相談対応
|
|
47
|
+
'bluelamp-vscode18': '@MCP追加' // Tools @18: MCP追加エージェント
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* コマンド名から対応するキーワードを取得
|
|
52
|
+
*/
|
|
53
|
+
function getKeywordFromCommand() {
|
|
54
|
+
const commandPath = process.argv[1];
|
|
55
|
+
const commandName = path.basename(commandPath);
|
|
56
|
+
|
|
57
|
+
if (!PROMPT_MAPPING[commandName]) {
|
|
58
|
+
console.error(`❌ 未定義のコマンド: ${commandName}`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return PROMPT_MAPPING[commandName];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* MCPサーバー設定を作成
|
|
67
|
+
*/
|
|
68
|
+
function createMCPConfig(keyword, cliToken) {
|
|
69
|
+
const mcpServerPath = path.join(packageRoot, 'lib/mcp-server/index.cjs');
|
|
70
|
+
const tempConfigPath = path.join(os.tmpdir(), `bluelamp-vscode-${Date.now()}.json`);
|
|
71
|
+
|
|
72
|
+
// .env.localからPORTAL_URLを取得(デフォルトは本番)
|
|
73
|
+
const portalUrl = process.env.PORTAL_URL || "https://bluelamp-6clpzmy5pa-an.a.run.app";
|
|
74
|
+
|
|
75
|
+
const config = {
|
|
76
|
+
mcpServers: {
|
|
77
|
+
"bluelamp-vscode": {
|
|
78
|
+
command: "node",
|
|
79
|
+
args: [mcpServerPath],
|
|
80
|
+
env: {
|
|
81
|
+
BLUELAMP_KEYWORD: keyword,
|
|
82
|
+
BLUELAMP_TOKEN: cliToken,
|
|
83
|
+
PORTAL_URL: portalUrl
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
fs.writeFileSync(tempConfigPath, JSON.stringify(config, null, 2));
|
|
90
|
+
return tempConfigPath;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Portal認証の実行(BlueLamp VSCode独自の認証システム)
|
|
95
|
+
*/
|
|
96
|
+
async function performPortalAuth() {
|
|
97
|
+
try {
|
|
98
|
+
// BlueLamp VSCode用の認証モジュールを使用
|
|
99
|
+
const { InteractiveLogin } = require('../lib/auth/InteractiveLogin');
|
|
100
|
+
|
|
101
|
+
const authResult = await InteractiveLogin.performLogin();
|
|
102
|
+
|
|
103
|
+
InteractiveLogin.displayLoginSuccess(authResult);
|
|
104
|
+
|
|
105
|
+
return authResult.token;
|
|
106
|
+
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error('❌ Portal認証エラー:', error.message);
|
|
109
|
+
console.error('');
|
|
110
|
+
console.error('解決方法:');
|
|
111
|
+
console.error('1. インターネット接続を確認してください');
|
|
112
|
+
console.error('2. Portal認証情報が正しいか確認してください');
|
|
113
|
+
console.error('3. https://bluelamp-6clpzmy5pa-an.a.run.app にアクセスできるか確認してください');
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* メイン処理
|
|
120
|
+
*/
|
|
121
|
+
async function main() {
|
|
122
|
+
const keyword = getKeywordFromCommand();
|
|
123
|
+
|
|
124
|
+
// --debugフラグの確認
|
|
125
|
+
const isDebugMode = process.argv.includes('--debug');
|
|
126
|
+
|
|
127
|
+
console.log('🔵 BlueLamp VSCode MCP Integration');
|
|
128
|
+
console.log(`📚 プロンプト: ${keyword}`);
|
|
129
|
+
if (isDebugMode) {
|
|
130
|
+
console.log('🐛 デバッグモード: 有効');
|
|
131
|
+
console.log(` ログファイル: ${path.join(os.tmpdir(), 'bluelamp-vscode-mcp-latest.log')}`);
|
|
132
|
+
}
|
|
133
|
+
console.log('');
|
|
134
|
+
|
|
135
|
+
// Portal認証の実行
|
|
136
|
+
const cliToken = await performPortalAuth();
|
|
137
|
+
|
|
138
|
+
// MCP設定ファイルを作成(認証トークンを含む)
|
|
139
|
+
const configPath = createMCPConfig(keyword, cliToken);
|
|
140
|
+
|
|
141
|
+
// 初期プロンプトメッセージ
|
|
142
|
+
const initialPrompt = `> 拡張モードで起動
|
|
143
|
+
|
|
144
|
+
🔵 BlueLamp 統合認証システム が有効化されました
|
|
145
|
+
|
|
146
|
+
\x1b[34m╭─────────────────────────────────────────────────────────────────╮\x1b[0m
|
|
147
|
+
\x1b[34m│ │\x1b[0m
|
|
148
|
+
\x1b[34m│ B l u e L a m p │\x1b[0m
|
|
149
|
+
\x1b[34m│ ───────────────── │\x1b[0m
|
|
150
|
+
\x1b[34m│ さあ始めましょう │\x1b[0m
|
|
151
|
+
\x1b[34m│ │\x1b[0m
|
|
152
|
+
\x1b[34m╰─────────────────────────────────────────────────────────────────╯\x1b[0m
|
|
153
|
+
|
|
154
|
+
**最初に必ず専門知識を注入してください**
|
|
155
|
+
inject_knowledge ツールで keyword: "${keyword}" を実行してから開始してください。(初回必須)
|
|
156
|
+
|
|
157
|
+
重要:キーワードは "${keyword}" をそのまま使用してください。変換や推測は不要です。
|
|
158
|
+
|
|
159
|
+
準備完了です。まず知識注入を実行してから、タスクを開始してください。`;
|
|
160
|
+
|
|
161
|
+
// Claude を起動
|
|
162
|
+
console.log('🚀 Claude 起動中...');
|
|
163
|
+
console.log(' - MCP Server: BlueLamp VSCode');
|
|
164
|
+
console.log(` - Knowledge: ${keyword}`);
|
|
165
|
+
console.log('');
|
|
166
|
+
|
|
167
|
+
// Windows対応: PowerShell経由でclaude.ps1を実行
|
|
168
|
+
const isWindows = process.platform === 'win32';
|
|
169
|
+
let claudeCommand, claudeArgs;
|
|
170
|
+
|
|
171
|
+
if (isWindows) {
|
|
172
|
+
// Windows: PowerShell経由でclaude.ps1を実行
|
|
173
|
+
claudeCommand = 'powershell.exe';
|
|
174
|
+
claudeArgs = [
|
|
175
|
+
'-NoProfile',
|
|
176
|
+
'-Command',
|
|
177
|
+
'claude',
|
|
178
|
+
initialPrompt,
|
|
179
|
+
'--dangerously-skip-permissions',
|
|
180
|
+
'--mcp-config', configPath
|
|
181
|
+
];
|
|
182
|
+
} else {
|
|
183
|
+
// Mac/Linux: 直接実行
|
|
184
|
+
claudeCommand = 'claude';
|
|
185
|
+
claudeArgs = [
|
|
186
|
+
initialPrompt,
|
|
187
|
+
'--dangerously-skip-permissions',
|
|
188
|
+
'--mcp-config', configPath
|
|
189
|
+
];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// デバッグモードの場合、詳細情報を表示
|
|
193
|
+
if (isDebugMode) {
|
|
194
|
+
console.log('🐛 デバッグ情報:');
|
|
195
|
+
console.log(` コマンド: ${claudeCommand}`);
|
|
196
|
+
console.log(` 引数: ${JSON.stringify(claudeArgs, null, 2)}`);
|
|
197
|
+
console.log(` MCP設定ファイル: ${configPath}`);
|
|
198
|
+
console.log(` 環境変数 BLUELAMP_KEYWORD: ${keyword}`);
|
|
199
|
+
console.log(` 環境変数 BLUELAMP_TOKEN: ${cliToken.substring(0, 20)}...`);
|
|
200
|
+
console.log(` 環境変数 PORTAL_URL: ${process.env.PORTAL_URL || 'https://bluelamp-6clpzmy5pa-an.a.run.app'}`);
|
|
201
|
+
console.log('');
|
|
202
|
+
|
|
203
|
+
// MCP設定ファイルの内容を表示
|
|
204
|
+
const configContent = fs.readFileSync(configPath, 'utf-8');
|
|
205
|
+
console.log('📄 MCP設定ファイル内容:');
|
|
206
|
+
console.log(configContent);
|
|
207
|
+
console.log('');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const child = spawn(claudeCommand, claudeArgs, {
|
|
211
|
+
stdio: 'inherit',
|
|
212
|
+
env: {
|
|
213
|
+
...process.env,
|
|
214
|
+
BLUELAMP_VSCODE_KEYWORD: keyword
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// エラーハンドリング
|
|
219
|
+
child.on('error', (error) => {
|
|
220
|
+
console.error('❌ Claude 起動エラー:', error.message);
|
|
221
|
+
|
|
222
|
+
// 一時ファイルをクリーンアップ
|
|
223
|
+
try {
|
|
224
|
+
fs.unlinkSync(configPath);
|
|
225
|
+
} catch (e) {
|
|
226
|
+
// ignore
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
process.exit(1);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// 終了時のクリーンアップ
|
|
233
|
+
child.on('exit', (code) => {
|
|
234
|
+
console.log('');
|
|
235
|
+
console.log('🔵 BlueLamp VSCode セッション終了');
|
|
236
|
+
|
|
237
|
+
// 一時ファイルをクリーンアップ
|
|
238
|
+
try {
|
|
239
|
+
fs.unlinkSync(configPath);
|
|
240
|
+
} catch (e) {
|
|
241
|
+
// ignore
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
process.exit(code || 0);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// SIGINT (Ctrl+C) ハンドリング
|
|
248
|
+
process.on('SIGINT', () => {
|
|
249
|
+
console.log('\n🔵 BlueLamp VSCode を終了しています...');
|
|
250
|
+
child.kill('SIGINT');
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// メイン処理の実行
|
|
255
|
+
main().catch((error) => {
|
|
256
|
+
console.error('❌ 予期しないエラー:', error.message);
|
|
257
|
+
process.exit(1);
|
|
258
|
+
});
|
|
@@ -113,7 +113,7 @@ class PortalAuthClient {
|
|
|
113
113
|
'Accept': 'application/json'
|
|
114
114
|
},
|
|
115
115
|
timeout: this.REQUEST_TIMEOUT,
|
|
116
|
-
rejectUnauthorized:
|
|
116
|
+
rejectUnauthorized: !this.isLocalDev() // 開発環境のみ自己署名証明書を許可
|
|
117
117
|
};
|
|
118
118
|
|
|
119
119
|
const client = url.protocol === 'https:' ? https : http;
|
package/lib/mcp-server/index.cjs
CHANGED
|
@@ -12,6 +12,7 @@ const {
|
|
|
12
12
|
ListToolsRequestSchema,
|
|
13
13
|
} = require('@modelcontextprotocol/sdk/types.js');
|
|
14
14
|
const { getPromptFromPortal } = require('./portal-api-client.cjs');
|
|
15
|
+
const { logger } = require('../utils/logger');
|
|
15
16
|
const path = require('path');
|
|
16
17
|
const fs = require('fs');
|
|
17
18
|
const os = require('os');
|
|
@@ -22,10 +23,10 @@ const dotenvPath = path.join(__dirname, '../../.env');
|
|
|
22
23
|
|
|
23
24
|
if (fs.existsSync(dotenvLocalPath)) {
|
|
24
25
|
require('dotenv').config({ path: dotenvLocalPath });
|
|
25
|
-
|
|
26
|
+
logger.debug('[MCP Server] Loaded .env.local');
|
|
26
27
|
} else if (fs.existsSync(dotenvPath)) {
|
|
27
28
|
require('dotenv').config({ path: dotenvPath });
|
|
28
|
-
|
|
29
|
+
logger.debug('[MCP Server] Loaded .env');
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
// 環境変数から取得
|
|
@@ -33,14 +34,24 @@ const KEYWORD = process.env.BLUELAMP_KEYWORD || 'BL-要件定義';
|
|
|
33
34
|
const TOKEN = process.env.BLUELAMP_TOKEN;
|
|
34
35
|
const PORTAL_URL = process.env.PORTAL_URL || 'https://bluelamp-6clpzmy5pa-an.a.run.app';
|
|
35
36
|
|
|
36
|
-
//
|
|
37
|
-
const
|
|
37
|
+
// ログファイル設定(ユーザーホームディレクトリに保存)
|
|
38
|
+
const LOG_DIR = path.join(os.homedir(), '.bluelamp-vscode', 'logs');
|
|
39
|
+
const LOG_FILE = path.join(LOG_DIR, 'mcp.log');
|
|
38
40
|
|
|
41
|
+
// ログディレクトリが存在しない場合は作成
|
|
42
|
+
if (!fs.existsSync(LOG_DIR)) {
|
|
43
|
+
fs.mkdirSync(LOG_DIR, { recursive: true });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* ファイルとコンソールにログを出力
|
|
48
|
+
* @param {string} message - ログメッセージ
|
|
49
|
+
*/
|
|
39
50
|
function log(message) {
|
|
40
51
|
const timestamp = new Date().toISOString();
|
|
41
52
|
const logMessage = `[${timestamp}] ${message}\n`;
|
|
42
53
|
fs.appendFileSync(LOG_FILE, logMessage);
|
|
43
|
-
|
|
54
|
+
logger.info(`[MCP Server] ${message}`);
|
|
44
55
|
}
|
|
45
56
|
|
|
46
57
|
log(`MCP Server started - Log file: ${LOG_FILE}`);
|
|
@@ -50,6 +61,10 @@ log(` TOKEN: ${TOKEN ? TOKEN.substring(0, 20) + '...' : 'NOT SET'}`);
|
|
|
50
61
|
log(` PORTAL_URL: ${PORTAL_URL}`);
|
|
51
62
|
log(` .env file exists: ${fs.existsSync(dotenvPath)}`);
|
|
52
63
|
|
|
64
|
+
/**
|
|
65
|
+
* BlueLamp VSCode MCPサーバークラス
|
|
66
|
+
* @class BlueLampVSCodeServer
|
|
67
|
+
*/
|
|
53
68
|
class BlueLampVSCodeServer {
|
|
54
69
|
constructor() {
|
|
55
70
|
this.server = new Server(
|
|
@@ -100,34 +115,50 @@ class BlueLampVSCodeServer {
|
|
|
100
115
|
log(`[MCP Server] TOKEN: ${TOKEN ? TOKEN.substring(0, 20) + '...' : 'missing'}`);
|
|
101
116
|
log(`[MCP Server] PORTAL_URL: ${PORTAL_URL}`);
|
|
102
117
|
|
|
103
|
-
|
|
104
|
-
|
|
118
|
+
try {
|
|
119
|
+
// Portal APIから認証付きで知識を取得
|
|
120
|
+
const result = await getPromptFromPortal(keyword, TOKEN);
|
|
121
|
+
|
|
122
|
+
if (!result || !result.success) {
|
|
123
|
+
const errorMessage = result?.error || `キーワード "${keyword}" に対応する知識が見つかりませんでした`;
|
|
124
|
+
log(`[MCP Server] Knowledge injection failed: ${errorMessage}`);
|
|
125
|
+
return {
|
|
126
|
+
content: [
|
|
127
|
+
{
|
|
128
|
+
type: 'text',
|
|
129
|
+
text: `❌ Portal APIから知識を取得できませんでした: ${errorMessage}`,
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
isError: true,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
105
135
|
|
|
106
|
-
|
|
136
|
+
// 知識注入メッセージを返す
|
|
107
137
|
return {
|
|
108
138
|
content: [
|
|
109
139
|
{
|
|
110
140
|
type: 'text',
|
|
111
|
-
text:
|
|
112
|
-
},
|
|
113
|
-
],
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// 知識注入メッセージを返す
|
|
118
|
-
return {
|
|
119
|
-
content: [
|
|
120
|
-
{
|
|
121
|
-
type: 'text',
|
|
122
|
-
text: `✅ BlueLamp VSCode 知識注入完了
|
|
141
|
+
text: `✅ BlueLamp VSCode 知識注入完了
|
|
123
142
|
|
|
124
143
|
${result.knowledge}
|
|
125
144
|
|
|
126
145
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
127
146
|
専門知識が注入されました。このロールで支援を開始します。`,
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
};
|
|
150
|
+
} catch (error) {
|
|
151
|
+
log(`[MCP Server] Exception in inject_knowledge: ${error.message}`);
|
|
152
|
+
return {
|
|
153
|
+
content: [
|
|
154
|
+
{
|
|
155
|
+
type: 'text',
|
|
156
|
+
text: `❌ 知識注入中にエラーが発生しました: ${error.message}`,
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
isError: true,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
131
162
|
}
|
|
132
163
|
|
|
133
164
|
return {
|
|
@@ -137,6 +168,7 @@ ${result.knowledge}
|
|
|
137
168
|
text: `Unknown tool: ${request.params.name}`,
|
|
138
169
|
},
|
|
139
170
|
],
|
|
171
|
+
isError: true,
|
|
140
172
|
};
|
|
141
173
|
});
|
|
142
174
|
}
|
|
@@ -144,7 +176,7 @@ ${result.knowledge}
|
|
|
144
176
|
async run() {
|
|
145
177
|
const transport = new StdioServerTransport();
|
|
146
178
|
await this.server.connect(transport);
|
|
147
|
-
|
|
179
|
+
logger.info('BlueLamp VSCode MCP server started');
|
|
148
180
|
|
|
149
181
|
// 起動時に自動的に知識を注入(環境変数で指定されたキーワード)
|
|
150
182
|
if (KEYWORD && TOKEN) {
|
|
@@ -161,4 +193,4 @@ ${result.knowledge}
|
|
|
161
193
|
|
|
162
194
|
// サーバー起動
|
|
163
195
|
const server = new BlueLampVSCodeServer();
|
|
164
|
-
server.run().catch(
|
|
196
|
+
server.run().catch((err) => logger.error(err.message));
|
|
@@ -8,31 +8,46 @@ const https = require('https');
|
|
|
8
8
|
const fs = require('fs');
|
|
9
9
|
const path = require('path');
|
|
10
10
|
const os = require('os');
|
|
11
|
+
const { logger } = require('../utils/logger');
|
|
11
12
|
|
|
12
|
-
//
|
|
13
|
+
// HTTPS検証設定(本番環境では有効化、開発環境のみ自己署名証明書を許可)
|
|
14
|
+
const isDevEnvironment = process.env.NODE_ENV === 'development' ||
|
|
15
|
+
(process.env.PORTAL_URL && process.env.PORTAL_URL.includes('localhost'));
|
|
13
16
|
const httpsAgent = new https.Agent({
|
|
14
|
-
rejectUnauthorized:
|
|
17
|
+
rejectUnauthorized: !isDevEnvironment
|
|
15
18
|
});
|
|
16
19
|
|
|
17
20
|
const PORTAL_URL = process.env.PORTAL_URL || 'https://bluelamp-6clpzmy5pa-an.a.run.app';
|
|
18
21
|
|
|
19
22
|
// ログファイル(index.cjsと同じファイルに書き込む)
|
|
20
|
-
const
|
|
23
|
+
const LOG_DIR = path.join(os.homedir(), '.bluelamp-vscode', 'logs');
|
|
24
|
+
const LOG_FILE = path.join(LOG_DIR, 'mcp.log');
|
|
25
|
+
|
|
26
|
+
// ログディレクトリが存在しない場合は作成
|
|
27
|
+
if (!fs.existsSync(LOG_DIR)) {
|
|
28
|
+
fs.mkdirSync(LOG_DIR, { recursive: true });
|
|
29
|
+
}
|
|
21
30
|
|
|
22
31
|
// 共通設定のキャッシュ(5分間有効)
|
|
23
32
|
let globalConfigCache = null;
|
|
24
33
|
let cacheExpiry = 0;
|
|
25
34
|
|
|
35
|
+
/**
|
|
36
|
+
* ファイルとコンソールにログを出力
|
|
37
|
+
* @param {string} message - ログメッセージ
|
|
38
|
+
*/
|
|
26
39
|
function log(message) {
|
|
27
40
|
const timestamp = new Date().toISOString();
|
|
28
41
|
const logMessage = `[${timestamp}] ${message}\n`;
|
|
29
42
|
fs.appendFileSync(LOG_FILE, logMessage);
|
|
30
|
-
|
|
43
|
+
logger.debug(message);
|
|
31
44
|
}
|
|
32
45
|
|
|
33
46
|
/**
|
|
34
47
|
* 共通CLAUDE.MD設定を取得(オプショナル)
|
|
35
48
|
* エラーが発生してもnullを返して処理を継続
|
|
49
|
+
* @param {string} token - CLI認証トークン
|
|
50
|
+
* @returns {Promise<string|null>} 共通設定文字列またはnull
|
|
36
51
|
*/
|
|
37
52
|
async function getGlobalConfig(token) {
|
|
38
53
|
try {
|
|
@@ -82,6 +97,9 @@ async function getGlobalConfig(token) {
|
|
|
82
97
|
|
|
83
98
|
/**
|
|
84
99
|
* Portal APIから認証付きでプロンプトを取得
|
|
100
|
+
* @param {string} keyword - 検索キーワード(例: "@要件定義")
|
|
101
|
+
* @param {string} token - CLI認証トークン
|
|
102
|
+
* @returns {Promise<{success: boolean, knowledge?: string, title?: string, tags?: string[], error?: string}>}
|
|
85
103
|
*/
|
|
86
104
|
async function getPromptFromPortal(keyword, token) {
|
|
87
105
|
try {
|
|
@@ -89,7 +107,7 @@ async function getPromptFromPortal(keyword, token) {
|
|
|
89
107
|
|
|
90
108
|
if (!token) {
|
|
91
109
|
log('[portal-api-client] No authentication token provided');
|
|
92
|
-
return
|
|
110
|
+
return { success: false, error: '認証トークンが設定されていません。bluelamp login コマンドでログインしてください。' };
|
|
93
111
|
}
|
|
94
112
|
|
|
95
113
|
// キーワードをそのまま使用
|
|
@@ -117,7 +135,16 @@ async function getPromptFromPortal(keyword, token) {
|
|
|
117
135
|
log(`[portal-api-client] Portal API error: ${response.status}`);
|
|
118
136
|
const errorText = await response.text();
|
|
119
137
|
log(`[portal-api-client] Error response: ${errorText}`);
|
|
120
|
-
|
|
138
|
+
let errorMessage = `Portal APIエラー (HTTP ${response.status})`;
|
|
139
|
+
try {
|
|
140
|
+
const errorData = JSON.parse(errorText);
|
|
141
|
+
if (errorData.message) {
|
|
142
|
+
errorMessage = errorData.message;
|
|
143
|
+
}
|
|
144
|
+
} catch (e) {
|
|
145
|
+
// JSONパースエラーは無視
|
|
146
|
+
}
|
|
147
|
+
return { success: false, error: errorMessage };
|
|
121
148
|
}
|
|
122
149
|
|
|
123
150
|
const data = await response.json();
|
|
@@ -125,7 +152,7 @@ async function getPromptFromPortal(keyword, token) {
|
|
|
125
152
|
|
|
126
153
|
if (!data.success) {
|
|
127
154
|
log(`[portal-api-client] API returned success: false`);
|
|
128
|
-
return
|
|
155
|
+
return { success: false, error: data.message || 'APIがエラーを返しました' };
|
|
129
156
|
}
|
|
130
157
|
|
|
131
158
|
// 直接プロンプトデータを取得(検索不要)
|
|
@@ -133,7 +160,7 @@ async function getPromptFromPortal(keyword, token) {
|
|
|
133
160
|
|
|
134
161
|
if (!prompt) {
|
|
135
162
|
log(`[portal-api-client] No prompt found for keyword: ${keyword}`);
|
|
136
|
-
return
|
|
163
|
+
return { success: false, error: `キーワード "${keyword}" に対応するプロンプトが見つかりませんでした` };
|
|
137
164
|
}
|
|
138
165
|
|
|
139
166
|
log(`[portal-api-client] Found prompt: ${prompt.title}`);
|
|
@@ -202,8 +229,8 @@ async function getPromptFromPortal(keyword, token) {
|
|
|
202
229
|
} catch (error) {
|
|
203
230
|
log(`[portal-api-client] FATAL ERROR in getPromptFromPortal: ${error.message}`);
|
|
204
231
|
log(`[portal-api-client] Error stack: ${error.stack}`);
|
|
205
|
-
|
|
206
|
-
return
|
|
232
|
+
logger.error(`Failed to get prompt from Portal: ${error.message}`);
|
|
233
|
+
return { success: false, error: `Portal API通信エラー: ${error.message}` };
|
|
207
234
|
}
|
|
208
235
|
}
|
|
209
236
|
|