bluelamp-vscode 2.0.2 → 2.0.5

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,426 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * BlueLamp VSCode Extension - Release Build Script with Advanced Obfuscation
4
+ *
5
+ * 高度難読化を適用したリリースビルドを生成
6
+ *
7
+ * 主要機能:
8
+ * - JavaScript Obfuscatorによる高度難読化
9
+ * - クリーンな出力ディレクトリ構造の維持
10
+ * - 配布用package.jsonの最適化
11
+ * - エラーハンドリングと進行状況表示
12
+ */
13
+
14
+ const fs = require('fs').promises;
15
+ const path = require('path');
16
+
17
+ // 設定定数
18
+ const PROJECT_ROOT = path.dirname(__dirname);
19
+ const VERSION = '2.0.4';
20
+ const RELEASE_DIR = path.join(PROJECT_ROOT, 'release');
21
+ const OUTPUT_DIR = path.join(RELEASE_DIR, `bluelamp-vscode-v${VERSION}`);
22
+
23
+ // 高度難読化設定(全ファイル用 - ログ出力保護)
24
+ const HIGH_OBFUSCATION_OPTIONS = {
25
+ compact: true,
26
+ controlFlowFlattening: true,
27
+ controlFlowFlatteningThreshold: 0.75,
28
+ deadCodeInjection: true,
29
+ deadCodeInjectionThreshold: 0.4,
30
+ debugProtection: true,
31
+ debugProtectionInterval: 4000,
32
+ disableConsoleOutput: false, // ログ出力を保護
33
+ identifierNamesGenerator: 'hexadecimal',
34
+ log: false,
35
+ numbersToExpressions: true,
36
+ renameGlobals: true,
37
+ selfDefending: true,
38
+ simplify: true,
39
+ splitStrings: true,
40
+ splitStringsChunkLength: 5,
41
+ stringArray: true,
42
+ stringArrayCallsTransform: true,
43
+ stringArrayCallsTransformThreshold: 0.8,
44
+ stringArrayEncoding: ['base64'],
45
+ stringArrayIndexShift: true,
46
+ stringArrayRotate: true,
47
+ stringArrayShuffle: true,
48
+ stringArrayWrappersCount: 2,
49
+ stringArrayWrappersChainedCalls: true,
50
+ stringArrayWrappersParametersMaxCount: 4,
51
+ stringArrayWrappersType: 'function',
52
+ stringArrayThreshold: 0.8,
53
+ transformObjectKeys: true,
54
+ unicodeEscapeSequence: false
55
+ };
56
+
57
+ // 軽度難読化設定(現在未使用 - 全て高度難読化に変更済み)
58
+ const LIGHT_OBFUSCATION_OPTIONS = {
59
+ compact: true,
60
+ controlFlowFlattening: false,
61
+ deadCodeInjection: false,
62
+ debugProtection: false,
63
+ disableConsoleOutput: false, // console.logを保護
64
+ identifierNamesGenerator: 'mangled',
65
+ log: false,
66
+ renameGlobals: false,
67
+ selfDefending: false,
68
+ simplify: true,
69
+ stringArray: false, // 文字列配列を無効化(日本語保護)
70
+ stringArrayEncoding: [],
71
+ stringArrayThreshold: 0, // 文字列変換を完全に無効化
72
+ transformObjectKeys: false,
73
+ unicodeEscapeSequence: false
74
+ };
75
+
76
+ // 対象ファイルパターン
77
+ const TARGET_PATTERNS = {
78
+ lib: {
79
+ auth: ['*.js'],
80
+ 'mcp-server': ['*.cjs', '*.js']
81
+ },
82
+ bin: ['bluelamp-vscode-base'],
83
+ scripts: ['*.js']
84
+ };
85
+
86
+ /**
87
+ * コンソール出力ユーティリティ
88
+ */
89
+ class Logger {
90
+ static info(message) {
91
+ console.log(`\x1b[36m[INFO]\x1b[0m ${message}`);
92
+ }
93
+
94
+ static success(message) {
95
+ console.log(`\x1b[32m[SUCCESS]\x1b[0m ${message}`);
96
+ }
97
+
98
+ static warn(message) {
99
+ console.log(`\x1b[33m[WARN]\x1b[0m ${message}`);
100
+ }
101
+
102
+ static error(message) {
103
+ console.log(`\x1b[31m[ERROR]\x1b[0m ${message}`);
104
+ }
105
+
106
+ static step(step, total, message) {
107
+ console.log(`\x1b[34m[${step}/${total}]\x1b[0m ${message}`);
108
+ }
109
+ }
110
+
111
+ /**
112
+ * ディレクトリの作成
113
+ */
114
+ async function ensureDirectory(dirPath) {
115
+ try {
116
+ await fs.access(dirPath);
117
+ } catch {
118
+ await fs.mkdir(dirPath, { recursive: true });
119
+ }
120
+ }
121
+
122
+ /**
123
+ * ディレクトリの完全削除
124
+ */
125
+ async function removeDirectory(dirPath) {
126
+ try {
127
+ await fs.access(dirPath);
128
+ await fs.rm(dirPath, { recursive: true, force: true });
129
+ } catch {
130
+ // ディレクトリが存在しない場合は無視
131
+ }
132
+ }
133
+
134
+ /**
135
+ * JavaScript Obfuscatorのロード
136
+ */
137
+ function loadObfuscator() {
138
+ try {
139
+ return require('javascript-obfuscator');
140
+ } catch (error) {
141
+ Logger.error('javascript-obfuscator package not found. Installing...');
142
+ console.log('Run: npm install javascript-obfuscator --save-dev');
143
+ process.exit(1);
144
+ }
145
+ }
146
+
147
+ /**
148
+ * ファイルの難読化
149
+ */
150
+ async function obfuscateFile(inputPath, outputPath, obfuscationType = 'high') {
151
+ const JavaScriptObfuscator = loadObfuscator();
152
+ try {
153
+ const sourceCode = await fs.readFile(inputPath, 'utf8');
154
+
155
+ // shebang行を保持
156
+ let shebang = '';
157
+ let codeToObfuscate = sourceCode;
158
+
159
+ if (sourceCode.startsWith('#!')) {
160
+ const firstNewline = sourceCode.indexOf('\n');
161
+ shebang = sourceCode.substring(0, firstNewline + 1);
162
+ codeToObfuscate = sourceCode.substring(firstNewline + 1);
163
+ }
164
+
165
+ // 難読化オプションを選択
166
+ const obfuscationOptions = obfuscationType === 'light'
167
+ ? LIGHT_OBFUSCATION_OPTIONS
168
+ : HIGH_OBFUSCATION_OPTIONS;
169
+
170
+ // 難読化実行
171
+ const obfuscatedCode = JavaScriptObfuscator.obfuscate(codeToObfuscate, obfuscationOptions);
172
+
173
+ // shebang + 難読化コードを結合
174
+ const finalCode = shebang + obfuscatedCode.getObfuscatedCode();
175
+
176
+ // 出力ディレクトリを確保
177
+ await ensureDirectory(path.dirname(outputPath));
178
+
179
+ // ファイル書き込み
180
+ await fs.writeFile(outputPath, finalCode, 'utf8');
181
+
182
+ // 実行権限の復元(binファイルの場合)
183
+ if (outputPath.includes('/bin/')) {
184
+ await fs.chmod(outputPath, 0o755);
185
+ }
186
+
187
+ return true;
188
+ } catch (error) {
189
+ Logger.error(`Failed to obfuscate ${inputPath}: ${error.message}`);
190
+ return false;
191
+ }
192
+ }
193
+
194
+ /**
195
+ * ファイルの単純コピー
196
+ */
197
+ async function copyFile(inputPath, outputPath) {
198
+ try {
199
+ await ensureDirectory(path.dirname(outputPath));
200
+ await fs.copyFile(inputPath, outputPath);
201
+ return true;
202
+ } catch (error) {
203
+ Logger.error(`Failed to copy ${inputPath}: ${error.message}`);
204
+ return false;
205
+ }
206
+ }
207
+
208
+ /**
209
+ * 対象ファイルの収集
210
+ */
211
+ async function collectTargetFiles() {
212
+ const files = [];
213
+
214
+ // lib/auth/*.js
215
+ const authDir = path.join(PROJECT_ROOT, 'lib', 'auth');
216
+ try {
217
+ const authFiles = await fs.readdir(authDir);
218
+ for (const file of authFiles) {
219
+ if (file.endsWith('.js')) {
220
+ files.push({
221
+ input: path.join(authDir, file),
222
+ output: path.join(OUTPUT_DIR, 'lib', 'auth', file),
223
+ type: 'obfuscate',
224
+ obfuscationType: 'high' // 認証モジュールも高度難読化
225
+ });
226
+ }
227
+ }
228
+ } catch (error) {
229
+ Logger.warn(`lib/auth directory not found: ${error.message}`);
230
+ }
231
+
232
+ // lib/mcp-server/*.{cjs,js}
233
+ const mcpDir = path.join(PROJECT_ROOT, 'lib', 'mcp-server');
234
+ try {
235
+ const mcpFiles = await fs.readdir(mcpDir);
236
+ for (const file of mcpFiles) {
237
+ if (file.endsWith('.cjs') || file.endsWith('.js')) {
238
+ files.push({
239
+ input: path.join(mcpDir, file),
240
+ output: path.join(OUTPUT_DIR, 'lib', 'mcp-server', file),
241
+ type: 'obfuscate',
242
+ obfuscationType: 'high'
243
+ });
244
+ }
245
+ }
246
+ } catch (error) {
247
+ Logger.warn(`lib/mcp-server directory not found: ${error.message}`);
248
+ }
249
+
250
+ // bin/bluelamp-vscode-base
251
+ const baseScript = path.join(PROJECT_ROOT, 'bin', 'bluelamp-vscode-base');
252
+ try {
253
+ await fs.access(baseScript);
254
+ files.push({
255
+ input: baseScript,
256
+ output: path.join(OUTPUT_DIR, 'bin', 'bluelamp-vscode-base'),
257
+ type: 'obfuscate', // 高度難読化を適用
258
+ obfuscationType: 'high'
259
+ });
260
+ } catch (error) {
261
+ Logger.warn(`bin/bluelamp-vscode-base not found: ${error.message}`);
262
+ }
263
+
264
+ // 他のbinファイル(高度難読化)
265
+ const binDir = path.join(PROJECT_ROOT, 'bin');
266
+ try {
267
+ const binFiles = await fs.readdir(binDir);
268
+ for (const file of binFiles) {
269
+ if (file !== 'bluelamp-vscode-base' && file.startsWith('bluelamp-vscode')) {
270
+ files.push({
271
+ input: path.join(binDir, file),
272
+ output: path.join(OUTPUT_DIR, 'bin', file),
273
+ type: 'obfuscate',
274
+ obfuscationType: 'high'
275
+ });
276
+ }
277
+ }
278
+ } catch (error) {
279
+ Logger.warn(`bin directory not found: ${error.message}`);
280
+ }
281
+
282
+ return files;
283
+ }
284
+
285
+ /**
286
+ * 配布用package.jsonの生成
287
+ */
288
+ async function generateReleasePackageJson() {
289
+ try {
290
+ const packageJsonPath = path.join(PROJECT_ROOT, 'package.json');
291
+ const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
292
+
293
+ // 配布用に最適化
294
+ const releasePackageJson = {
295
+ name: packageJson.name,
296
+ version: VERSION,
297
+ description: packageJson.description + ' (Obfuscated Release)',
298
+ main: packageJson.main,
299
+ bin: packageJson.bin,
300
+ keywords: packageJson.keywords,
301
+ author: packageJson.author,
302
+ license: packageJson.license,
303
+ dependencies: packageJson.dependencies,
304
+ engines: packageJson.engines,
305
+ files: packageJson.files,
306
+ preferGlobal: packageJson.preferGlobal,
307
+ repository: packageJson.repository
308
+ };
309
+
310
+ const outputPath = path.join(OUTPUT_DIR, 'package.json');
311
+ await fs.writeFile(outputPath, JSON.stringify(releasePackageJson, null, 2), 'utf8');
312
+
313
+ Logger.success('Generated release package.json');
314
+ return true;
315
+ } catch (error) {
316
+ Logger.error(`Failed to generate package.json: ${error.message}`);
317
+ return false;
318
+ }
319
+ }
320
+
321
+ /**
322
+ * READMEのコピー
323
+ */
324
+ async function copyReadme() {
325
+ try {
326
+ const readmePath = path.join(PROJECT_ROOT, 'README.md');
327
+ const outputPath = path.join(OUTPUT_DIR, 'README.md');
328
+ await copyFile(readmePath, outputPath);
329
+ Logger.success('Copied README.md');
330
+ return true;
331
+ } catch (error) {
332
+ Logger.error(`Failed to copy README.md: ${error.message}`);
333
+ return false;
334
+ }
335
+ }
336
+
337
+ /**
338
+ * メイン処理
339
+ */
340
+ async function main() {
341
+ const startTime = Date.now();
342
+
343
+ Logger.info('🚀 Starting BlueLamp VSCode Release Build with Advanced Obfuscation');
344
+ Logger.info(`📂 Output directory: ${OUTPUT_DIR}`);
345
+
346
+ try {
347
+ // Step 1: クリーンアップ
348
+ Logger.step(1, 6, 'Cleaning release directory...');
349
+ await removeDirectory(RELEASE_DIR);
350
+ await ensureDirectory(OUTPUT_DIR);
351
+
352
+ // Step 2: 対象ファイルの収集
353
+ Logger.step(2, 6, 'Collecting target files...');
354
+ const targetFiles = await collectTargetFiles();
355
+ Logger.info(`📄 Found ${targetFiles.length} files to process`);
356
+
357
+ // Step 3: ファイル処理
358
+ Logger.step(3, 6, 'Processing files with obfuscation...');
359
+ let processedCount = 0;
360
+ let errorCount = 0;
361
+
362
+ for (const file of targetFiles) {
363
+ const fileName = path.basename(file.input);
364
+
365
+ if (file.type === 'obfuscate') {
366
+ const obfType = file.obfuscationType || 'high';
367
+ Logger.info(`🔒 Obfuscating (${obfType}): ${fileName}`);
368
+ const success = await obfuscateFile(file.input, file.output, obfType);
369
+ if (success) {
370
+ processedCount++;
371
+ } else {
372
+ errorCount++;
373
+ }
374
+ } else {
375
+ Logger.info(`📋 Copying: ${fileName}`);
376
+ const success = await copyFile(file.input, file.output);
377
+ if (success) {
378
+ processedCount++;
379
+ } else {
380
+ errorCount++;
381
+ }
382
+ }
383
+ }
384
+
385
+ // Step 4: package.json生成
386
+ Logger.step(4, 6, 'Generating release package.json...');
387
+ await generateReleasePackageJson();
388
+
389
+ // Step 5: README.mdコピー
390
+ Logger.step(5, 6, 'Copying documentation...');
391
+ await copyReadme();
392
+
393
+ // Step 6: 完了報告
394
+ Logger.step(6, 6, 'Build completed!');
395
+
396
+ const endTime = Date.now();
397
+ const duration = ((endTime - startTime) / 1000).toFixed(2);
398
+
399
+ Logger.success('✅ Release build completed successfully!');
400
+ Logger.info(`📊 Processed: ${processedCount} files, Errors: ${errorCount}`);
401
+ Logger.info(`⏱️ Build time: ${duration} seconds`);
402
+ Logger.info(`📦 Release package: ${OUTPUT_DIR}`);
403
+
404
+ if (errorCount > 0) {
405
+ Logger.warn('⚠️ Some files could not be processed. Check the logs above.');
406
+ process.exit(1);
407
+ }
408
+
409
+ } catch (error) {
410
+ Logger.error(`❌ Build failed: ${error.message}`);
411
+ Logger.error(error.stack);
412
+ process.exit(1);
413
+ }
414
+ }
415
+
416
+ // スクリプトを実行
417
+ if (require.main === module) {
418
+ main();
419
+ }
420
+
421
+ module.exports = {
422
+ main,
423
+ HIGH_OBFUSCATION_OPTIONS,
424
+ LIGHT_OBFUSCATION_OPTIONS,
425
+ obfuscateFile
426
+ };
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * BlueLamp VSCode コマンド生成スクリプト
5
+ * 16個のコマンドファイルを自動生成
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+
11
+ const binDir = path.join(__dirname, '..', 'bin');
12
+ const baseScript = path.join(binDir, 'bluelamp-vscode-base');
13
+
14
+ // 16個のコマンドを生成
15
+ for (let i = 1; i <= 16; i++) {
16
+ const commandName = `bluelamp-vscode${i}`;
17
+ const commandPath = path.join(binDir, commandName);
18
+
19
+ // シンボリックリンクまたはラッパースクリプトを作成
20
+ const content = `#!/usr/bin/env node
21
+ require('./bluelamp-vscode-base');
22
+ `;
23
+
24
+ fs.writeFileSync(commandPath, content);
25
+ fs.chmodSync(commandPath, '755');
26
+
27
+ console.log(`✅ Created: ${commandName}`);
28
+ }
29
+
30
+ // ベーススクリプトにも実行権限を付与
31
+ if (fs.existsSync(baseScript)) {
32
+ fs.chmodSync(baseScript, '755');
33
+ }
34
+
35
+ console.log('\n✨ 16個のコマンドファイルを生成しました');