Sidebar & Custom Panels
The Interactive Sidebar & Custom Panels integrate four custom views directly into the VS Code Explorer sidebar. These panels provide an interactive, real-time interface for browsing tags, managing backlinks, chat-based querying, and discovering related notes.
1. Overview
The sidebar consolidates four core productivity components:
- AI Notes by Tag: A collapsible tree of tags populated by parsing note frontmatter. Supports filtering, multi-selecting notes, bulk reclassification, and note merging.
- AI Notes Backlinks: Real-time display of incoming markdown links referencing the active document.
- AI Notes Related: A hybrid, real-time list of notes relevant to the active document. Matches using tag overlap, then ranks using LLM summaries.
- AI Notes Chat: An interactive chat interface that uses the note vault's summaries as a knowledge base to answer questions. Includes clickable links to open matching notes directly.
2. Real-time Links Indexing & Watcher
The backlinks panel parses markdown links using a robust regular expression: \[([^\]]*)\]\(([^)]+\.md)\).
It keeps an in-memory index (linkIndex: Map<string, BacklinkEntry[]>) and updates it automatically using a workspace-wide filesystem watcher:
async function initialize(): Promise<void> {
await this.buildIndex();
// Listen for vault modifications in real-time
const watcher = vscode.workspace.createFileSystemWatcher('**/*.md');
watcher.onDidChange(() => this.rebuildIndex());
watcher.onDidCreate(() => this.rebuildIndex());
watcher.onDidDelete(() => this.rebuildIndex());
this.disposables.push(watcher);
vscode.window.onDidChangeActiveTextEditor(() => this.refresh(), null, this.disposables);
}
3. Hybrid AI Related Notes Ranking
Searching notes for related content using only the LLM can be slow and expensive. To make this performant and real-time, the extension uses a hybrid two-phase approach:
- Phase A (High-pass Filter): Quickly scans the workspace to find notes sharing at least one tag with the open document. Scores candidates based on tag overlap.
- Phase B (AI Ranker): If the notes have summaries, it sends the top 10 candidates to the LLM. The LLM evaluates note summaries against the current note's summary and returns a prioritized list of the top 5 most relevant notes.
private async aiRank(currentSummary: string, candidates: RelatedNote[]): Promise<RelatedNote[]> {
const candidateList = candidates.map((c, i) => {
const desc = c.summary || path.basename(c.filePath);
return `${i + 1}. "${desc}"`;
}).join('\n');
const prompt = `Given this note summary: "${currentSummary}"
Rank these candidate notes by relevance (most related first). Return ONLY a JSON array of numbers, e.g. [2, 5, 1].
${candidateList}`;
try {
const response = await chatCompletionWithRetry(prompt);
const match = response.match(/\[[\d,\s]+\]/);
if (match) {
const indices: number[] = JSON.parse(match[0]);
const ranked: RelatedNote[] = [];
for (const idx of indices) {
if (idx >= 1 && idx <= candidates.length && ranked.length < 5) {
ranked.push(candidates[idx - 1]);
}
}
return ranked;
}
} catch {}
return candidates.slice(0, 5);
}