Add VSCode extension for MariaDB Profiler Viewer#16
Conversation
Detailed plan for a VSCode extension equivalent to the existing JetBrains plugin (jetbrains-plugin/). Covers feature mapping, tech stack, directory structure, data models, services, UI layout, communication protocol, implementation phases, and risk analysis. https://claude.ai/code/session_01EabgSSMXSA25Pjf1aTEmB2
Replace all Webview-based UI with VSCode native APIs: - QueryLogTable (Webview) -> QueryTreeProvider (TreeView with expandable details) - StatisticsView (Webview) -> StatisticsTreeProvider (TreeView with Unicode bar charts) - SQL detail (Webview) -> QueryDocumentProvider (Virtual Document .sql with syntax highlighting) - LiveTailView (Webview) -> OutputChannel - FilterBar (Webview) -> QuickPick commands + toolbar buttons Benefits: zero dependencies, no HTML/CSS/JS build pipeline, lighter memory footprint, full theme integration, better Remote SSH/WSL stability. https://claude.ai/code/session_01EabgSSMXSA25Pjf1aTEmB2
All UI uses VSCode native APIs only - no Webview, no HTML/CSS/JS: - TreeView for jobs list, query log (expandable details), and statistics - Virtual Document (.sql) for full SQL display with syntax highlighting - OutputChannel for live tail streaming - QuickPick for filter/search interactions Structure: - src/model/: QueryEntry, JobInfo (matching PHP JSONL/JSON formats) - src/service/: LogParser, JobManager, Statistics, FileWatcher, FrameResolver - src/provider/: JobTree, QueryTree, StatisticsTree, QueryDocument - src/command/: startJob, stopJob, openLog, filter, search, liveTail - test/unit/: 56 tests passing (QueryEntry, JobInfo, Statistics, LogParser) TypeScript compiles cleanly, esbuild production bundle works. https://claude.ai/code/session_01EabgSSMXSA25Pjf1aTEmB2
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. WalkthroughMariaDB Profiler Viewer の VSCode 拡張を追加します。設計仕様書、ビルド/テスト設定、拡張エントリポイント、ジョブ/クエリ用データモデル、ログ解析・ジョブ管理・ファイル監視・フレーム解決・統計の各サービス、ツリービュー・ドキュメントプロバイダ、フィルタ/Search/ライブテイル等のコマンド、ユーティリティ、ユニットテストを導入します。 Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant VSCode as "VSCode Extension"
participant JobMgr as "JobManagerService"
participant LogParser as "LogParserService"
participant QueryTree as "QueryTreeProvider"
participant Stats as "StatisticsService"
User->>VSCode: ジョブ読み込み/リフレッシュ要求
VSCode->>JobMgr: loadJobs()
JobMgr-->>VSCode: JobInfo[]
VSCode->>QueryTree: refresh(entries)
VSCode->>Stats: computeStats(entries)
Stats-->>VSCode: QueryStats
QueryTree-->>User: ツリービュー表示
sequenceDiagram
actor User
participant VSCode as "VSCode Extension"
participant LiveTail as "LiveTailManager"
participant FileWatch as "FileWatcherService"
participant LogParser as "LogParserService"
participant Output as "OutputChannel"
User->>VSCode: ライブテイル開始(jobKey)
VSCode->>LiveTail: start(jobKey)
LiveTail->>LogParser: parseJsonlFile(path)
LogParser-->>LiveTail: 既存エントリ
LiveTail->>FileWatch: watchFile(jsonlPath)
FileWatch-->>LiveTail: onChange()
LiveTail->>LogParser: parseJsonlFileFromOffset(path, offset)
LogParser-->>LiveTail: 新規エントリ
LiveTail->>Output: フォーマットして出力
Output-->>User: 表示
sequenceDiagram
actor User
participant VSCode as "VSCode Extension"
participant Quick as "QuickPick"
participant QueryTree as "QueryTreeProvider"
participant Context as "VSCode Context"
User->>VSCode: 型でフィルタ選択
VSCode->>QueryTree: getAllTypes()
QueryTree-->>VSCode: タイプ一覧+件数
VSCode->>Quick: Show QuickPick
Quick-->>User: 選択表示
User->>Quick: 選択
Quick->>VSCode: 選択結果
VSCode->>QueryTree: setFilter(type)
QueryTree->>Context: setContext(hasFilter)
QueryTree-->>User: ツリー更新
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Runs on pushes/PRs that touch vscode-extension/: - TypeScript type check (tsc --noEmit) - Unit tests (vitest) - Production build (esbuild) Mirrors the existing plugin-build.yml pattern for JetBrains plugin. https://claude.ai/code/session_01EabgSSMXSA25Pjf1aTEmB2
- New build-vscode job: npm ci, tsc, vitest, esbuild, vsce package - Produces .vsix artifact included in GitHub Release assets - Release job now depends on build-vscode alongside existing jobs https://claude.ai/code/session_01EabgSSMXSA25Pjf1aTEmB2
There was a problem hiding this comment.
Actionable comments posted: 20
🧹 Nitpick comments (16)
vscode-extension/src/command/filterQueries.ts (1)
5-8: 3関数すべてでcontext: vscode.ExtensionContextパラメータが未使用
registerFilterByTypeCommand・registerFilterByTagCommand・registerClearFilterCommandの引数contextはどの関数本体でも参照されていません。Disposableを返す設計なので呼び出し側でライフサイクル管理を行うべきですが、そうであればcontextを受け取る必要はありません。パラメータを削除するか、関数内でcontext.subscriptions.push(...)を行うかに統一することを推奨します。♻️ リファクタ案(パラメータ削除)
export function registerFilterByTypeCommand( - context: vscode.ExtensionContext, queryTreeProvider: QueryTreeProvider, ): vscode.Disposable { export function registerFilterByTagCommand( - context: vscode.ExtensionContext, queryTreeProvider: QueryTreeProvider, ): vscode.Disposable { export function registerClearFilterCommand( - context: vscode.ExtensionContext, queryTreeProvider: QueryTreeProvider, ): vscode.Disposable {Also applies to: 43-46, 83-85
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@vscode-extension/src/command/filterQueries.ts` around lines 5 - 8, The three exported functions registerFilterByTypeCommand, registerFilterByTagCommand, and registerClearFilterCommand take an unused context: vscode.ExtensionContext parameter; remove that parameter from each function signature and any internal references, update any call sites to stop passing context, and keep each function returning a vscode.Disposable as before; alternatively, if you prefer lifecycle registration inside these functions, instead accept context and call context.subscriptions.push(theDisposable) inside each function—pick one approach and apply it consistently across the three functions and their callers.vscode-extension/test/unit/QueryEntry.test.ts (1)
81-146: シングルクォートを含むパラメータ値のテストケース追加を推奨
getBoundQueryのテスト群は充実していますが、パラメータ値にシングルクォートが含まれる場合(例:"O'Brien")のテストが不足しています。これはsrc/model/QueryEntry.tsの実装上の問題(後述)と対になるケースです。➕ 追加テスト案
+ it('should escape single quotes in parameter values', () => { + const entry: QueryEntry = { + jobKey: '', query: 'SELECT * FROM users WHERE name = ?', timestamp: 0, + params: ["O'Brien"], + }; + expect(getBoundQuery(entry)).toBe("SELECT * FROM users WHERE name = 'O''Brien'"); + });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@vscode-extension/test/unit/QueryEntry.test.ts` around lines 81 - 146, Add a unit test to cover parameters containing single quotes (e.g., "O'Brien") to ensure getBoundQuery properly escapes or formats such values; update vscode-extension/test/unit/QueryEntry.test.ts by adding a case that uses getBoundQuery with a query containing a ? and a param value with a single quote, then assert the returned SQL contains the parameter safely quoted/escaped (and mirror the expected escaping behavior implemented in src/model/QueryEntry.ts) so this edge case is validated.vscode-extension/src/command/startJob.ts (1)
4-8:contextパラメーターが未使用
context: vscode.ExtensionContextを受け取っていますが、関数内で一切使用されていません。戻り値のDisposableを呼び出し元がcontext.subscriptions.push(...)で管理する設計なら、このパラメーターは削除するか、内部でcontext.subscriptions.pushするかを統一した方がすっきりします。♻️ パラメーター削除案
export function registerStartJobCommand( - context: vscode.ExtensionContext, jobManager: JobManagerService, onJobsChanged: () => void, ): vscode.Disposable {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@vscode-extension/src/command/startJob.ts` around lines 4 - 8, The function registerStartJobCommand currently accepts an unused context: vscode.ExtensionContext; either remove that parameter from the signature and all call sites, or use it to register the returned Disposable into context.subscriptions (call context.subscriptions.push(...) inside registerStartJobCommand) so ownership is consistent; update the function signature and any callers if removing the parameter, or keep the signature and add context.subscriptions.push(disposable) before returning to ensure the parameter is used (refer to registerStartJobCommand and any call sites that pass context).vscode-extension/tsconfig.json (1)
13-14: バンドル型 VSCode 拡張ではdeclaration/declarationMapは不要esbuild で
dist/extension.jsに単一バンドルするため、.d.tsファイルは VSCode ランタイムに消費されません。これらを有効にしておくとビルドで不要な成果物が生成されます。♻️ 修正提案
- "declaration": true, - "declarationMap": true, "sourceMap": true🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@vscode-extension/tsconfig.json` around lines 13 - 14, tsconfig の "declaration" と "declarationMap" が有効になっているためビルドで不要な .d.ts が生成されていますので、VSCode 拡張を esbuild で単一バンドルする前提なら tsconfig.json の "declaration" と "declarationMap" を削除するか false に設定してください(対象の設定キー: "declaration", "declarationMap" を編集、ファイル: tsconfig.json を更新)。vscode-extension/src/service/LogParserService.ts (1)
42-48:readRawLogTailがファイル全体をメモリに読み込むファイル全体を読んでから末尾 N 行を切り出しています。大きなログファイルでは不要なメモリを消費します。ファイル末尾から逆方向に読む方式か、
tail相当のオフセット計算を使うことで改善できます。- readRawLogTail(filePath: string, maxLines: number = 500): string { - if (!fs.existsSync(filePath)) { return ''; } - - const content = fs.readFileSync(filePath, 'utf-8'); - const lines = content.split('\n'); - const tail = lines.slice(-maxLines); - return tail.join('\n'); - } + readRawLogTail(filePath: string, maxLines: number = 500): string { + if (!fs.existsSync(filePath)) { return ''; } + + const fd = fs.openSync(filePath, 'r'); + try { + const stat = fs.fstatSync(fd); + // 末尾から最大 maxLines * 平均行長(256バイト)分だけ読む + const chunkSize = Math.min(stat.size, maxLines * 256); + const buffer = Buffer.alloc(chunkSize); + const bytesRead = fs.readSync(fd, buffer, 0, chunkSize, stat.size - chunkSize); + const lines = buffer.slice(0, bytesRead).toString('utf-8').split('\n'); + return lines.slice(-maxLines).join('\n'); + } finally { + fs.closeSync(fd); + } + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@vscode-extension/src/service/LogParserService.ts` around lines 42 - 48, readRawLogTail currently reads the whole file into memory; change it to read only the tail by opening the file (fs.openSync), using fs.statSync to get file size, and reading backwards in fixed-size chunks with fs.readSync until you have collected maxLines (or hit file start), then extract and return the last N lines—this avoids loading the entire file for large logs; update the implementation in readRawLogTail to perform chunked backward reads (or compute an appropriate start offset and createReadStream from that offset) and ensure proper fd closing and error handling.vscode-extension/test/unit/JobInfo.test.ts (1)
94-106: LGTM —formatDurationの分単位での小数秒ケースを追加すると更に堅牢現在のテストは整数秒のケース (
225-100=125s → 2m5s) のみカバーしています。secs % 60が小数になるケース(例:formatDuration(100, 161.5)→secs=1.5, toFixed(0)="2"→"1m2s")を追加するとtoFixed(0)の丸め挙動を確認できます。任意の改善です。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@vscode-extension/test/unit/JobInfo.test.ts` around lines 94 - 106, Add a unit test to JobInfo.test.ts inside the describe('formatDuration') block that covers fractional seconds: call formatDuration(100, 161.5) and assert the expected string for fractional-second output (so the test will catch rounding issues in formatDuration); this ensures formatDuration (the function under test) correctly handles secs%60 being a non-integer and will surface any toFixed/rounding bugs.vscode-extension/src/extension.ts (1)
176-183: インラインimport()型の使用Line 178 でインラインの
import('./model/QueryEntry').QueryEntryを使用しています。ファイル先頭でQueryEntryは既にモデルとして利用可能なはずなので、通常のインポートに統一した方が可読性が向上します。♻️ 修正案
ファイル先頭に追加(Line 22 付近の
JobInfoインポートの近くに):import { JobInfo } from './model/JobInfo'; +import { QueryEntry } from './model/QueryEntry';そしてLine 178を:
- (item: { entry?: import('./model/QueryEntry').QueryEntry; entryIndex?: number }) => { + (item: { entry?: QueryEntry; entryIndex?: number }) => {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@vscode-extension/src/extension.ts` around lines 176 - 183, ファイル先頭の既存インポート群(JobInfo の近く)に QueryEntry 型を通常の import 文で追加し、registerCommand のコールバック引数で使っているインライン型 import('./model/QueryEntry').QueryEntry を置き換えてください。具体的には showSqlCmd を定義している箇所のシグネチャを QueryEntry を参照する形に変更し、既存の queryDocumentProvider.showQueryDetail(item.entry, item.entryIndex ?? 0) 呼び出しはそのまま動作するように型だけ修正してください。vscode-extension/src/service/FileWatcherService.ts (2)
19-25: 同一パスへのwatchFile再呼び出しで既存のウォッチャーが上書きされる同じ
filePathでwatchFileを複数回呼ぶと、前のコールバックが警告なくサイレントに破棄されます。これが意図的であれば問題ありませんが、呼び出し元がこの動作を認識していない場合にバグの原因になり得ます。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@vscode-extension/src/service/FileWatcherService.ts` around lines 19 - 25, watchFile currently overwrites an existing watcher entry for the same filePath (this.watchers.set) which silently drops the previous callback; modify watchFile to detect an existing watcher via this.watchers.has(filePath) and handle it explicitly: either (a) reject/throw or return an error when duplicate registrations occur, or (b) change the watcher value shape to hold an array of callbacks and push the new onChange into that array (and update any code that invokes callback to iterate the array), or (c) log a clear warning before overwriting; update the watcher structure and any usages of the callback (and related fields lastSize/lastMtime) accordingly so duplicate registrations are handled deterministically.
39-54: ポーリングごとにfs.statSyncが2回呼ばれている
getFileSizeとgetFileMtimeがそれぞれ個別にfs.statSyncを呼び出しており、ウォッチ対象ファイルごとにポーリングサイクルあたり2回のシステムコールが発生しています。1回のstatSyncで両方の値を取得できます。♻️ 修正案
private poll(): void { for (const [filePath, entry] of this.watchers) { - const size = this.getFileSize(filePath); - const mtime = this.getFileMtime(filePath); + const stat = this.getFileStat(filePath); + const size = stat?.size ?? -1; + const mtime = stat?.mtimeMs ?? -1; if (size !== entry.lastSize || mtime !== entry.lastMtime) { entry.lastSize = size; entry.lastMtime = mtime; try { entry.callback(); } catch (e) { // Ignore callback errors } } } } - private getFileSize(filePath: string): number { - try { - return fs.statSync(filePath).size; - } catch { - return -1; - } - } - - private getFileMtime(filePath: string): number { - try { - return fs.statSync(filePath).mtimeMs; - } catch { - return -1; - } - } + private getFileStat(filePath: string): fs.Stats | null { + try { + return fs.statSync(filePath); + } catch { + return null; + } + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@vscode-extension/src/service/FileWatcherService.ts` around lines 39 - 54, poll() currently calls getFileSize(filePath) and getFileMtime(filePath) which each call fs.statSync, causing two stat syscalls per file per poll; change poll() to call fs.statSync once (or a single helper that returns both size and mtime) for each filePath, extract size and mtime from that single stat result, compare with entry.lastSize and entry.lastMtime, update both, and invoke entry.callback() as before (ensure to keep the try/catch around entry.callback); update or remove getFileSize/getFileMtime accordingly so they no longer perform duplicate stat calls.vscode-extension/src/command/openLog.ts (1)
6-7: 未使用のcontextパラメータ
contextは関数本体で使用されていません。他のコマンド登録関数との署名の一貫性のためと思われますが、将来的に不要であれば削除も検討してください。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@vscode-extension/src/command/openLog.ts` around lines 6 - 7, The parameter `context` in the function `registerOpenLogCommand` is unused; either remove it from the function signature and update any callers to match, or mark it as intentionally unused (rename to `_context` or add an ESLint ignore for unused vars) to keep the signature consistent with other command registration functions; update `registerOpenLogCommand` accordingly and ensure exported signature and all imports/call sites remain consistent.vscode-extension/package.json (1)
226-229:lintとtypecheckスクリプトが重複両方とも
tsc --noEmitを実行しています。片方を削除するか、lintで ESLint 等のリンターを実行することを検討してください。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@vscode-extension/package.json` around lines 226 - 229, The package.json defines duplicate scripts: "typecheck" and "lint" both run "tsc --noEmit"; update package.json scripts to remove the duplication by either deleting the "lint" script or changing "lint" to run a real linter (e.g., ESLint) instead of "tsc --noEmit"; edit the "lint" entry so it invokes your linter command (for example eslint with your project file extensions and config) or remove "lint" so only "typecheck" remains.vscode-extension/src/util/queryUtils.ts (1)
12-15:shortKeyで切り詰め表示であることが分からない切り詰められたキーに省略記号がないため、ユーザーが完全なキーだと誤解する可能性があります。
♻️ 提案
export function shortKey(key: string, maxLen: number = 12): string { if (key.length <= maxLen) { return key; } - return key.substring(0, maxLen); + return key.substring(0, maxLen - 1) + '…'; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@vscode-extension/src/util/queryUtils.ts` around lines 12 - 15, shortKey currently returns a truncated substring without indicating truncation; update the shortKey function so that when key.length > maxLen it returns a visible truncated form (e.g., include an ellipsis "…" or "..." ) and ensure the total returned length respects maxLen (adjust substring length to maxLen minus the ellipsis length); handle small maxLen values gracefully (if maxLen is too small to include an ellipsis, fall back to the raw substring).vscode-extension/src/provider/StatisticsTreeProvider.ts (1)
7-21:EventEmitterのdisposeが実装されていません。
_onDidChangeTreeDataのEventEmitterはDisposableを実装しており、TreeProvider が不要になった際にdispose()を呼ぶべきです。TreeProviderがextension全体のライフサイクルで存在する場合は問題になりにくいですが、ベストプラクティスとしてDisposableの実装を検討してください。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@vscode-extension/src/provider/StatisticsTreeProvider.ts` around lines 7 - 21, StatisticsTreeProvider currently creates an EventEmitter (_onDidChangeTreeData) but doesn't dispose it; implement Disposable by adding a dispose() method on StatisticsTreeProvider that calls this._onDidChangeTreeData.dispose() (and any other cleanup if added), and ensure the provider's consumer (where it's registered) calls provider.dispose() when tearing down; reference the class StatisticsTreeProvider and its _onDidChangeTreeData, updateStats, clear methods to locate where to add the dispose implementation.vscode-extension/src/provider/QueryTreeProvider.ts (1)
95-102:allEntries.indexOf(entry)が O(n) のため、大量エントリ時にパフォーマンスが劣化します。
filteredEntriesの各要素に対してallEntries.indexOf(entry)を実行すると、最大maxQueries(デフォルト10,000)×allEntries.lengthの計算量になります。フィルタ適用時にインデックスを保持することで解消できます。♻️ 修正案: フィルタリング時にインデックスを保持
- private allEntries: QueryEntry[] = []; - private filteredEntries: QueryEntry[] = []; + private allEntries: QueryEntry[] = []; + private filteredEntries: { entry: QueryEntry; globalIndex: number }[] = [];
applyFiltersとgetChildrenを対応させ、filteredEntriesにglobalIndexを持たせることでindexOfを回避します。変更範囲が広いため、別のアプローチとしてMap<QueryEntry, number>をallEntries更新時に構築する方法もあります。+ private entryIndexMap = new Map<QueryEntry, number>(); + loadEntries(entries: QueryEntry[]): void { this.allEntries = entries; + this.entryIndexMap = new Map(entries.map((e, i) => [e, i])); this.applyFilters(); } appendEntries(entries: QueryEntry[]): void { + const startIdx = this.allEntries.length; this.allEntries.push(...entries); + entries.forEach((e, i) => this.entryIndexMap.set(e, startIdx + i)); this.applyFilters(); }getChildren(element?: QueryTreeItem): QueryTreeItem[] { if (!element) { return this.filteredEntries.map((entry, index) => { - const globalIndex = this.allEntries.indexOf(entry); + const globalIndex = this.entryIndexMap.get(entry) ?? -1; return new QueryEntryItem(entry, globalIndex); }); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@vscode-extension/src/provider/QueryTreeProvider.ts` around lines 95 - 102, getChildren currently calls this.allEntries.indexOf(entry) for each filtered entry which is O(n); avoid this by preserving the global index during filtering or by building a Map from entry->index when allEntries changes. Modify applyFilters (or the allEntries update path) to produce filteredEntries entries that include a globalIndex (or construct a Map<QueryEntry, number> once), then update getChildren to read that precomputed globalIndex and pass it into new QueryEntryItem(entry, globalIndex) instead of calling indexOf; update types for filteredEntries as needed (or keep a parallel array of indices) and ensure QueryEntryItem construction uses the stored index.vscode-extension/src/service/JobManagerService.ts (1)
28-34:getActiveJobs()とgetCompletedJobs()がそれぞれloadJobs()を呼び出し、ファイルを二重に読み込みます。両方のメソッドが連続して呼ばれる場合、
jobs.jsonの読み込みとパースが2回実行されます。現時点で大きな問題ではありませんが、呼び出し側でキャッシュする設計も検討に値します。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@vscode-extension/src/service/JobManagerService.ts` around lines 28 - 34, Both getActiveJobs and getCompletedJobs call loadJobs separately causing jobs.json to be read/parsing twice; change loadJobs to return a cached in-memory array (e.g., add a private cachedJobs: JobInfo[] | null) and have loadJobs populate cachedJobs on first call and return it on subsequent calls, and ensure any mutating methods (those that add/update/delete jobs) clear or refresh cachedJobs so callers get fresh data; update references to loadJobs, getActiveJobs, and getCompletedJobs accordingly.vscode-extension/src/command/liveTail.ts (1)
110-150:contextパラメータが未使用です。
registerLiveTailCommandsのcontext: vscode.ExtensionContextパラメータが関数内で使用されていません。不要であれば削除、将来的に使用する予定であれば_contextにリネームしてください。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@vscode-extension/src/command/liveTail.ts` around lines 110 - 150, The context parameter of registerLiveTailCommands is unused; either remove it from the function signature and all its call sites, or rename it to _context to indicate intentional unused status. Update the declaration of registerLiveTailCommands and any places that call it (e.g., where it's passed an ExtensionContext) to match your chosen change, keeping the other parameters (liveTailManager, jobManager) and preserved behavior of start/stop command registration.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@PLAN_VSCODE_EXTENSION.md`:
- Around line 410-426: The design doc types/interfaces are out of sync with the
implementation: update the doc so JobInfo.startedAt uses number (not string),
JobsFile uses active_jobs and completed_jobs (not active/completed), and
BacktraceFrame uses class_name (optional) instead of class; locate the
interfaces named JobInfo, JobsFile and BacktraceFrame in the doc and change the
field names and types to match the implementation precisely (startedAt: number,
active_jobs/completed_jobs, class_name?) so the document reflects the actual
code.
- Around line 382-408: Update the documented QueryEntry interface to match the
implementation: change timestamp from string to number and change params from
string[] to (string | null)[] (keep it optional), e.g. adjust the QueryEntry
declaration so timestamp: number and params?: (string | null)[]; leave other
fields and the helper function signatures as-is (referencing the QueryEntry and
params/timestamp symbols to locate the code).
In `@vscode-extension/package.json`:
- Around line 232-239: Update the devDependencies in package.json: bump
"esbuild" from "^0.19.0" to "^0.27.3" and "vitest" from "^1.2.0" to "^4.0.18"
(entries inside the "devDependencies" object), then run your package manager to
refresh lockfile and verify by running the build/test scripts to ensure
compatibility with the new versions.
In `@vscode-extension/src/command/liveTail.ts`:
- Around line 85-106: You compute qtype via getQueryType(entry) but never print
it and you use entry.trace.indexOf(frame) which can give wrong indices for
duplicate frames; update the output in the loop that calls
this.outputChannel.appendLine(`[${time}] ... ${shortSql}`) to include qtype
(e.g., after status or before shortSql) and change the trace printing loop to
use an indexed loop (for (let i = 0; i < entry.trace.slice(0,3).length; i++) or
for (const [i, frame] of entry.trace.slice(0,3).entries())) so you can print the
correct frame index instead of entry.trace.indexOf(frame); keep the existing use
of getShortSql, formatTimestamp and the trailing "... (n more frames)" behavior.
In `@vscode-extension/src/command/openLog.ts`:
- Around line 22-27: The code in openLog.ts should (1) guard against
parseJsonlFile throwing by wrapping the call to
logParser.parseJsonlFile(filePath) in a try/catch and displaying a
vscode.window.showErrorMessage with the error if it fails (and aborting further
steps), and (2) after successfully calling
queryTreeProvider.loadEntries(entries) call
updateFilterContext(queryTreeProvider) and statisticsService.computeStats() (the
same functions used in loadJobQueries) so the filter context and statistics are
refreshed; ensure the needed symbols (updateFilterContext, statisticsService)
are imported or otherwise available before calling them and only show the
success vscode.window.showInformationMessage when all steps complete.
In `@vscode-extension/src/extension.ts`:
- Around line 96-100: Replace the inline require and unsafe statSync call by
importing fs at the top (add "import * as fs from 'fs'") and change the
jsonlOffset computation around queryTreeProvider.loadEntries(entries) to safely
handle missing files: check existence with fs.existsSync(jsonlPath) or wrap
fs.statSync in a try/catch, and set jsonlOffset = 0 when the file does not exist
or stat fails; reference symbols: queryTreeProvider.loadEntries, jsonlOffset,
jsonlPath.
- Around line 207-211: jobsJsonPath is computed once at activation via
jobManager.getJobsJsonPath() so when mariadbProfiler.logDirectory changes the
watcher keeps watching the old path; change jobsJsonPath from const to let,
compute it with jobManager.getJobsJsonPath(), then in the existing
settings-change handler (the handler that reacts to mariadbProfiler changes)
detect when logDirectory changes, unwatch the old path (e.g.
fileWatcher.unwatchFile(jobsJsonPath) or dispose the previous watcher) and
reassign jobsJsonPath = jobManager.getJobsJsonPath() and call
fileWatcher.watchFile(jobsJsonPath, () => refreshJobs()) to start watching the
updated file path.
In `@vscode-extension/src/model/JobInfo.ts`:
- Around line 75-81: formatDuration currently computes secs as a floating-point
remainder which can round to 60 ("1m60s"); change formatDuration to first treat
an active job (endedAt undefined) by returning "running...", then compute
totalSeconds = Math.round(end - startedAt) (or Math.floor if you prefer
truncation), derive minutes = Math.floor(totalSeconds / 60) and secs =
totalSeconds % 60 to avoid "60" seconds, and for durations under 1s return
milliseconds (e.g., `${Math.round(seconds*1000)} ms`) so the function
(formatDuration) matches JetBrains behavior and never yields "1m60s".
In `@vscode-extension/src/model/QueryEntry.ts`:
- Around line 131-137: TABLE_PATTERNS currently uses (\w+) which fails to
capture schema-qualified names like database.table; update TABLE_PATTERNS in
QueryEntry.ts to allow dot-separated identifiers (for example replace \w+ with a
pattern that permits dots in addition to word chars, and also handle backticked
qualifiers such as `db`.`table`) so schema.table and backticked variants are
captured correctly by the existing extraction logic in QueryEntry (ensure all
entries in TABLE_PATTERNS are changed consistently).
- Around line 117-123: q, params, paramIndex, result
のプレースホルダ置換でシングルクォートを含む文字列パラメータが適切にエスケープされていません。params[paramIndex] をそのまま
`'${param}'` で包むのではなく、param が null の場合は 'NULL'、文字列の場合は内部のシングルクォートを SQL
標準の2重シングルクォートに置換してから `'...`で囲むように置換処理を修正してください(例: param.replace(/'/g, "''")
を適用)。これにより result に挿入される表示用 SQL が安全にエスケープされます。
In `@vscode-extension/src/provider/JobTreeProvider.ts`:
- Around line 39-44: The ThemeColor used for non-active jobs is invalid: replace
the unsupported 'charts.gray' with a standard UI color (e.g.,
'descriptionForeground' or 'disabledForeground') when constructing this.iconPath
based on job.isActive; update the conditional that sets new
vscode.ThemeColor(...) so non-active branches use one of those valid color IDs
to ensure the gray/disabled appearance renders correctly.
In `@vscode-extension/src/provider/QueryDocumentProvider.ts`:
- Line 10: The documents Map (private documents: Map<string, QueryEntry>) grows
unbounded because showQueryDetail adds entries but never evicts them; add a
simple FIFO cap to prevent memory leaks by tracking insertion order (or using an
array/queue of keys) and, when adding in showQueryDetail, if size >=
MAX_DOCUMENTS remove the oldest key and its QueryEntry from documents before
inserting the new one; choose a sensible MAX_DOCUMENTS constant, update any
tests/uses of QueryEntry if needed, and ensure eviction logic runs atomically
with insertion to avoid races.
- Around line 19-20: In showQueryDetail remove the unused local variable qtype
(the declaration "const qtype = getQueryType(entry);") since getQueryType is
called again inside formatQueryDocument; either delete that line or pass qtype
into formatQueryDocument and use it there—locate the showQueryDetail method and
the formatQueryDocument/getQueryType usages to make the change.
In `@vscode-extension/src/service/FrameResolverService.ts`:
- Around line 41-43: FrameResolverService currently accepts any numeric result
(variable result) including floating-point values, which can later be used as an
invalid index into entry.trace; update the validation to only allow integers by
replacing the typeof check with an integer check (e.g., use
Number.isInteger(result)) and keep the bounds checks (result >= 0 && result <
entry.trace.length) so only whole-number indices are returned; modify the code
around the result validation in FrameResolverService (the branch that returns
result based on entry.trace.length) to enforce integer-only indices.
- Around line 38-39: このコードは vm.createContext / script.runInContext で外部提供の
frameResolverScript を直接実行して RCE リスクがあるため、実行前に VS Code の Workspace Trust API
を使ってワークスペースが信頼済みかを確認し、信頼されていない場合は実行を中止してエラーを返すように修正してください(該当箇所:
FrameResolverService.ts の vm.createContext と script.runInContext を呼び出している箇所、及び
frameResolverScript を受け取るロジック)。併せて package.json の contributes に
capabilities.untrustedWorkspaces.supported を false
に設定して拡張機能のワークスペーストラスト要件を宣言する変更を追加してください。
- Around line 57-71: getScript currently sets cachedScript = null and
cachedScriptText = scriptText on compile error, which makes the first condition
(this.cachedScriptText === scriptText && this.cachedScript) false and causes
repeated re-compilation attempts; fix by recording failed compilations and
short-circuiting: add a new member (e.g., failedScriptText or failedScripts:
Set<string>) and in getScript first check if the scriptText is in the failure
marker and return null immediately, and in the catch block add the scriptText to
that failure marker instead of relying on cachedScriptText alone; keep
references to getScript, cachedScript, cachedScriptText and update their logic
accordingly.
In `@vscode-extension/src/service/JobManagerService.ts`:
- Around line 36-47: startJob may return raw stdout on fallback which can
contain unexpected chars; update startJob (which calls runCli) so that when
output.match(/Job '([^']+)' started/) fails and jobKey is undefined you sanitize
and validate the output before returning: trim it, then extract a safe job
identifier using a strict regex (e.g. allow only [A-Za-z0-9_-]+) and return that
if present, otherwise throw or return a clear error/empty value instead of the
raw stdout to avoid leaking arbitrary strings into callers.
In `@vscode-extension/src/service/LogParserService.ts`:
- Around line 24-36: The code has a TOCTOU race: statSync is called before
openSync and readSync's return value is ignored, which can cause zero-padded
buffers and JSON parse errors when files rotate or shrink; fix
parseJsonlFileFromOffset and tailRawLog by opening the file first (openSync),
calling fs.fstatSync(fd) to get the current size, allocate/read only the needed
bytes, and check the bytesRead returned by fs.readSync—use bytesRead to slice
the buffer/string before passing to parseJsonlContent and compute the newOffset
based on the fstat size (or handle truncation appropriately).
In `@vscode-extension/src/util/pathMapping.ts`:
- Line 9: The current use of containerPath.replace(from, to) treats the
replacement string `to` as a replacement pattern (so `$&`, `$'`, etc. are
processed); change the logic in the path-mapping function that uses
containerPath.replace(from, to) to perform a safe prefix swap instead: check if
containerPath.startsWith(from) and if so return to +
containerPath.slice(from.length), otherwise return containerPath unchanged;
update the function that references containerPath.replace (the mapping routine
in pathMapping.ts) to use this startsWith + slice approach to avoid
special-character interpretation.
In `@vscode-extension/src/util/queryUtils.ts`:
- Around line 1-5: The generateBar function can throw a RangeError when value >
max because filled can exceed barWidth, making barWidth - filled negative; clamp
the computed filled value to the range [0, barWidth] after computing filled
(using value, max, barWidth) so the repeats never receive a negative count—keep
the existing max === 0 guard and then use the clamped filled when building the
string.
---
Nitpick comments:
In `@vscode-extension/package.json`:
- Around line 226-229: The package.json defines duplicate scripts: "typecheck"
and "lint" both run "tsc --noEmit"; update package.json scripts to remove the
duplication by either deleting the "lint" script or changing "lint" to run a
real linter (e.g., ESLint) instead of "tsc --noEmit"; edit the "lint" entry so
it invokes your linter command (for example eslint with your project file
extensions and config) or remove "lint" so only "typecheck" remains.
In `@vscode-extension/src/command/filterQueries.ts`:
- Around line 5-8: The three exported functions registerFilterByTypeCommand,
registerFilterByTagCommand, and registerClearFilterCommand take an unused
context: vscode.ExtensionContext parameter; remove that parameter from each
function signature and any internal references, update any call sites to stop
passing context, and keep each function returning a vscode.Disposable as before;
alternatively, if you prefer lifecycle registration inside these functions,
instead accept context and call context.subscriptions.push(theDisposable) inside
each function—pick one approach and apply it consistently across the three
functions and their callers.
In `@vscode-extension/src/command/liveTail.ts`:
- Around line 110-150: The context parameter of registerLiveTailCommands is
unused; either remove it from the function signature and all its call sites, or
rename it to _context to indicate intentional unused status. Update the
declaration of registerLiveTailCommands and any places that call it (e.g., where
it's passed an ExtensionContext) to match your chosen change, keeping the other
parameters (liveTailManager, jobManager) and preserved behavior of start/stop
command registration.
In `@vscode-extension/src/command/openLog.ts`:
- Around line 6-7: The parameter `context` in the function
`registerOpenLogCommand` is unused; either remove it from the function signature
and update any callers to match, or mark it as intentionally unused (rename to
`_context` or add an ESLint ignore for unused vars) to keep the signature
consistent with other command registration functions; update
`registerOpenLogCommand` accordingly and ensure exported signature and all
imports/call sites remain consistent.
In `@vscode-extension/src/command/startJob.ts`:
- Around line 4-8: The function registerStartJobCommand currently accepts an
unused context: vscode.ExtensionContext; either remove that parameter from the
signature and all call sites, or use it to register the returned Disposable into
context.subscriptions (call context.subscriptions.push(...) inside
registerStartJobCommand) so ownership is consistent; update the function
signature and any callers if removing the parameter, or keep the signature and
add context.subscriptions.push(disposable) before returning to ensure the
parameter is used (refer to registerStartJobCommand and any call sites that pass
context).
In `@vscode-extension/src/extension.ts`:
- Around line 176-183: ファイル先頭の既存インポート群(JobInfo の近く)に QueryEntry 型を通常の import
文で追加し、registerCommand のコールバック引数で使っているインライン型
import('./model/QueryEntry').QueryEntry を置き換えてください。具体的には showSqlCmd
を定義している箇所のシグネチャを QueryEntry を参照する形に変更し、既存の
queryDocumentProvider.showQueryDetail(item.entry, item.entryIndex ?? 0)
呼び出しはそのまま動作するように型だけ修正してください。
In `@vscode-extension/src/provider/QueryTreeProvider.ts`:
- Around line 95-102: getChildren currently calls this.allEntries.indexOf(entry)
for each filtered entry which is O(n); avoid this by preserving the global index
during filtering or by building a Map from entry->index when allEntries changes.
Modify applyFilters (or the allEntries update path) to produce filteredEntries
entries that include a globalIndex (or construct a Map<QueryEntry, number>
once), then update getChildren to read that precomputed globalIndex and pass it
into new QueryEntryItem(entry, globalIndex) instead of calling indexOf; update
types for filteredEntries as needed (or keep a parallel array of indices) and
ensure QueryEntryItem construction uses the stored index.
In `@vscode-extension/src/provider/StatisticsTreeProvider.ts`:
- Around line 7-21: StatisticsTreeProvider currently creates an EventEmitter
(_onDidChangeTreeData) but doesn't dispose it; implement Disposable by adding a
dispose() method on StatisticsTreeProvider that calls
this._onDidChangeTreeData.dispose() (and any other cleanup if added), and ensure
the provider's consumer (where it's registered) calls provider.dispose() when
tearing down; reference the class StatisticsTreeProvider and its
_onDidChangeTreeData, updateStats, clear methods to locate where to add the
dispose implementation.
In `@vscode-extension/src/service/FileWatcherService.ts`:
- Around line 19-25: watchFile currently overwrites an existing watcher entry
for the same filePath (this.watchers.set) which silently drops the previous
callback; modify watchFile to detect an existing watcher via
this.watchers.has(filePath) and handle it explicitly: either (a) reject/throw or
return an error when duplicate registrations occur, or (b) change the watcher
value shape to hold an array of callbacks and push the new onChange into that
array (and update any code that invokes callback to iterate the array), or (c)
log a clear warning before overwriting; update the watcher structure and any
usages of the callback (and related fields lastSize/lastMtime) accordingly so
duplicate registrations are handled deterministically.
- Around line 39-54: poll() currently calls getFileSize(filePath) and
getFileMtime(filePath) which each call fs.statSync, causing two stat syscalls
per file per poll; change poll() to call fs.statSync once (or a single helper
that returns both size and mtime) for each filePath, extract size and mtime from
that single stat result, compare with entry.lastSize and entry.lastMtime, update
both, and invoke entry.callback() as before (ensure to keep the try/catch around
entry.callback); update or remove getFileSize/getFileMtime accordingly so they
no longer perform duplicate stat calls.
In `@vscode-extension/src/service/JobManagerService.ts`:
- Around line 28-34: Both getActiveJobs and getCompletedJobs call loadJobs
separately causing jobs.json to be read/parsing twice; change loadJobs to return
a cached in-memory array (e.g., add a private cachedJobs: JobInfo[] | null) and
have loadJobs populate cachedJobs on first call and return it on subsequent
calls, and ensure any mutating methods (those that add/update/delete jobs) clear
or refresh cachedJobs so callers get fresh data; update references to loadJobs,
getActiveJobs, and getCompletedJobs accordingly.
In `@vscode-extension/src/service/LogParserService.ts`:
- Around line 42-48: readRawLogTail currently reads the whole file into memory;
change it to read only the tail by opening the file (fs.openSync), using
fs.statSync to get file size, and reading backwards in fixed-size chunks with
fs.readSync until you have collected maxLines (or hit file start), then extract
and return the last N lines—this avoids loading the entire file for large logs;
update the implementation in readRawLogTail to perform chunked backward reads
(or compute an appropriate start offset and createReadStream from that offset)
and ensure proper fd closing and error handling.
In `@vscode-extension/src/util/queryUtils.ts`:
- Around line 12-15: shortKey currently returns a truncated substring without
indicating truncation; update the shortKey function so that when key.length >
maxLen it returns a visible truncated form (e.g., include an ellipsis "…" or
"..." ) and ensure the total returned length respects maxLen (adjust substring
length to maxLen minus the ellipsis length); handle small maxLen values
gracefully (if maxLen is too small to include an ellipsis, fall back to the raw
substring).
In `@vscode-extension/test/unit/JobInfo.test.ts`:
- Around line 94-106: Add a unit test to JobInfo.test.ts inside the
describe('formatDuration') block that covers fractional seconds: call
formatDuration(100, 161.5) and assert the expected string for fractional-second
output (so the test will catch rounding issues in formatDuration); this ensures
formatDuration (the function under test) correctly handles secs%60 being a
non-integer and will surface any toFixed/rounding bugs.
In `@vscode-extension/test/unit/QueryEntry.test.ts`:
- Around line 81-146: Add a unit test to cover parameters containing single
quotes (e.g., "O'Brien") to ensure getBoundQuery properly escapes or formats
such values; update vscode-extension/test/unit/QueryEntry.test.ts by adding a
case that uses getBoundQuery with a query containing a ? and a param value with
a single quote, then assert the returned SQL contains the parameter safely
quoted/escaped (and mirror the expected escaping behavior implemented in
src/model/QueryEntry.ts) so this edge case is validated.
In `@vscode-extension/tsconfig.json`:
- Around line 13-14: tsconfig の "declaration" と "declarationMap"
が有効になっているためビルドで不要な .d.ts が生成されていますので、VSCode 拡張を esbuild で単一バンドルする前提なら
tsconfig.json の "declaration" と "declarationMap" を削除するか false に設定してください(対象の設定キー:
"declaration", "declarationMap" を編集、ファイル: tsconfig.json を更新)。
Package and upload .vsix on every push/PR, matching plugin-build.yml which uploads the JetBrains plugin .zip. https://claude.ai/code/session_01EabgSSMXSA25Pjf1aTEmB2
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
.github/workflows/release.yml (1)
196-238: ジョブにタイムアウトを設定することを推奨します
timeout-minutesが指定されていないため、vitest や esbuild がハングした場合にジョブが GitHub のデフォルト上限(6時間)まで実行され続けます。⚙️ タイムアウト設定の提案
build-vscode: name: VSCode Extension runs-on: ubuntu-latest + timeout-minutes: 15🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/release.yml around lines 196 - 238, The build-vscode job lacks a timeout and can hang indefinitely; add a timeout-minutes entry (e.g., timeout-minutes: 30) to the build-vscode job definition so the whole job (including steps running npx vitest run, node esbuild.mjs, and the packaging step using npx `@vscode/vsce`) is automatically cancelled after the configured time; place the timeout-minutes field alongside name: and runs-on: under the build-vscode job..github/workflows/vscode-build.yml (2)
19-23:permissionsブロックの明示的な宣言を推奨します。ワークフローおよびジョブレベルに
permissionsが宣言されていないため、GITHUB_TOKENはリポジトリのデフォルト権限(多くの場合contents: write等)を持ちます。このワークフローはアーティファクトのアップロードのみ行うため、最小権限原則に従い権限を明示することが望ましいです。♻️ 修正案: 最小権限の明示
+permissions: + contents: read + jobs: build: if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'no_run') name: Build & Test Extension runs-on: ubuntu-latest🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/vscode-build.yml around lines 19 - 23, Add an explicit permissions block to the workflow to scope GITHUB_TOKEN to the minimum needed (e.g., artifacts: write and id-token if used), by adding a top-level "permissions" entry and/or a job-level "permissions" under the "build" job; ensure the "GITHUB_TOKEN" permission does not default to broad scopes like contents: write and instead lists only the required permissions for artifact upload (reference the workflow's top-level permissions key and the build job's permissions override if present).
3-13: 内部PRで重複CIランが発生します。同一リポジトリの内部PRでは、ブランチへの
pushイベントとpull_requestイベントが同時に発火します。両者のgithub.refは異なる(例:refs/heads/featurevsrefs/pull/16/merge)ため、concurrency グループが別々になり、同じコミットに対して2回ビルドが走ります。
pushトリガーを保護ブランチのみに限定するか、PRが存在しない場合のみ push ビルドを実行する条件を追加することを推奨します。♻️ 修正案: pushトリガーをメインブランチのみに限定する
on: push: - branches: ['**'] + branches: + - 'main' paths: - 'vscode-extension/**' - '.github/workflows/vscode-build.yml' pull_request: branches: ['**'] paths: - 'vscode-extension/**' - '.github/workflows/vscode-build.yml'または、
pushイベント時にPRが存在しない場合のみ実行する条件をbuildジョブに追加することもできます。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/vscode-build.yml around lines 3 - 13, 同一コミットで push と pull_request の両イベントが発火して重複CIが走っているので、.github/workflows/vscode-build.yml の on: push と on: pull_request トリガーを調整してください。簡単な修正は on.push.branches を保護ブランチ(例: main, release/*)のみに限定すること、あるいは build ジョブ(ジョブ名 build)に実行条件を追加して push イベント時は PR が存在しない場合のみ実行するようにすること(結果的に pull_request と重複しないようにする)。該当箇所はファイル内の on.push / on.pull_request セクションと build ジョブの if 条件を編集してください。
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/vscode-build.yml:
- Around line 51-53: パッケージングで npx を使っているためロックされたバージョンが使われず再現性が失われています;
ワークフローステップ "Package .vsix" (working-directory: vscode-extension) の run コマンドで現在の
"npx `@vscode/vsce` package --no-dependencies -o mariadb-profiler-viewer.vsix"
を、ロックされた devDependency を確実に使うために "npm exec `@vscode/vsce` -- package
--no-dependencies -o mariadb-profiler-viewer.vsix" に置き換えるか、あるいは既存の npm
スクリプトを利用する場合は "npm run package" を使うように修正してください.
---
Nitpick comments:
In @.github/workflows/release.yml:
- Around line 196-238: The build-vscode job lacks a timeout and can hang
indefinitely; add a timeout-minutes entry (e.g., timeout-minutes: 30) to the
build-vscode job definition so the whole job (including steps running npx vitest
run, node esbuild.mjs, and the packaging step using npx `@vscode/vsce`) is
automatically cancelled after the configured time; place the timeout-minutes
field alongside name: and runs-on: under the build-vscode job.
In @.github/workflows/vscode-build.yml:
- Around line 19-23: Add an explicit permissions block to the workflow to scope
GITHUB_TOKEN to the minimum needed (e.g., artifacts: write and id-token if
used), by adding a top-level "permissions" entry and/or a job-level
"permissions" under the "build" job; ensure the "GITHUB_TOKEN" permission does
not default to broad scopes like contents: write and instead lists only the
required permissions for artifact upload (reference the workflow's top-level
permissions key and the build job's permissions override if present).
- Around line 3-13: 同一コミットで push と pull_request
の両イベントが発火して重複CIが走っているので、.github/workflows/vscode-build.yml の on: push と on:
pull_request トリガーを調整してください。簡単な修正は on.push.branches を保護ブランチ(例: main,
release/*)のみに限定すること、あるいは build ジョブ(ジョブ名 build)に実行条件を追加して push イベント時は PR
が存在しない場合のみ実行するようにすること(結果的に pull_request と重複しないようにする)。該当箇所はファイル内の on.push /
on.pull_request セクションと build ジョブの if 条件を編集してください。
- liveTail.ts: include qtype in output, fix trace frame indexing for duplicates
- package.json: bump esbuild ^0.27.3 / vitest ^4.0.18, add untrustedWorkspaces capability
- openLog.ts: add try/catch for parseJsonlFile, refresh filter context and statistics
- extension.ts: replace require('fs') with proper import, safe statSync, re-watch jobsJsonPath on logDirectory change
- JobInfo.ts: fix formatDuration "1m60s" rounding bug, show "running..." for active jobs, ms for <1s
- QueryEntry.ts: escape single quotes in bound params, support schema.table in TABLE_PATTERNS
- JobTreeProvider.ts: replace unsupported 'charts.gray' ThemeColor with 'disabledForeground'
- QueryDocumentProvider.ts: add FIFO cap (50) to documents Map, remove unused qtype variable
- FrameResolverService.ts: add Workspace Trust guard, enforce integer-only indices, cache failed compilations
- JobManagerService.ts: sanitize fallback startJob output with strict regex
- LogParserService.ts: fix TOCTOU race by using fstatSync on opened fd, use bytesRead from readSync
- pathMapping.ts: use startsWith+slice instead of replace to avoid replacement pattern injection
- queryUtils.ts: clamp generateBar filled value to prevent RangeError
- vscode-build.yml: use npm exec instead of npx for reproducible packaging
https://claude.ai/code/session_01EabgSSMXSA25Pjf1aTEmB2
Use getBoundQuery() instead of raw SQL for the tree view label and
live tail output so users see actual parameter values (e.g.
'SELECT * FROM users WHERE id = 42') instead of placeholders
('SELECT * FROM users WHERE id = ?').
https://claude.ai/code/session_01EabgSSMXSA25Pjf1aTEmB2
Summary
This PR introduces a complete VSCode extension implementation for visualizing and analyzing MariaDB/MySQL query profiling data generated by
php-ext-mariadb-salvage. The extension provides feature parity with the existing JetBrains plugin but uses VSCode's native API exclusively (no Webview) for a lightweight, fast, and theme-integrated experience.Key Changes
Extension Architecture: Complete TypeScript-based VSCode extension with modular service and provider layers
LogParserService: JSONL parser with offset-based incremental reading for efficient log handlingJobManagerService: Job lifecycle management and CLI integrationStatisticsService: Query statistics computation (by type, table, tag)FileWatcherService: Polling-based file monitoring (Docker-compatible)FrameResolverService: JavaScript-based backtrace frame resolutionUI Components: Three native TreeView providers (no Webview)
JobTreeProvider: Job list with active/completed statusQueryTreeProvider: Hierarchical query display with expandable details (tables, tags, backtrace)StatisticsTreeProvider: Unicode bar chart statistics dashboardQueryDocumentProvider: Virtual SQL documents with syntax highlightingCommands & Interactions: 11 registered commands via command palette and TreeView menus
Configuration: VSCode Settings integration for
Testing: Comprehensive unit test suite using Vitest
Build & Packaging
Implementation Details
https://claude.ai/code/session_01EabgSSMXSA25Pjf1aTEmB2
Summary by CodeRabbit
新機能
テスト
ドキュメント
Chores