UI Layer

Sidebar & Custom Panels

Source Files: notesByTagWebview.ts, backlinksWebview.ts, relatedNotesWebview.ts, chatWebview.ts Complexity: High

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:

  1. 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.
  2. 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);
}