Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

154 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Claude History — VS Code Extension

Overview

Claude History is a VS Code extension that lets you search, browse, and export your Claude Code conversation history — directly inside VS Code.

Claude Code stores all conversations as JSONL files on disk, organized by project. This extension indexes those files using full-text search (FlexSearch), surfaces them in a native VS Code TreeView grouped by project, and renders each conversation in a rich React-powered webview with syntax-highlighted tool cards for every tool Claude used.

Migrated from a standalone Electron desktop app. The core domain logic is 100% platform-agnostic and reusable outside VS Code.


Features

  • Conversation browser — sidebar TreeView groups conversations by project, sorted by recency
  • Full-text searchClaude History: Search QuickPick searches across all conversation content using FlexSearch, with text highlighting in results
  • Sort options — six sort modes: Most Recent, Oldest First, Most Messages, Fewest Messages, Alphabetical, configurable via claudeHistory.sortOrder
  • Date range filter — filter to today, last 7 days, last 30 days, or all time via claudeHistory.dateRange
  • Live file watcher — conversations modified since the panel opened show a live badge; the tree auto-refreshes
  • Rich conversation viewer — React webview renders messages with specialized tool cards:
    • Edit diffs (structured patch hunks with old/new highlighting)
    • Bash terminal output (stdout + stderr, with CollapsibleJson for structured output)
    • Read, Write, Glob, Grep file operations
    • Task agent, TodoWrite, TodoRead task management cards
    • Generic fallback card for unknown tools
  • Export — export any conversation to Markdown, plain text, or JSON via VS Code's native save dialog
  • Copy — copy individual message content to clipboard
  • Multi-profile support — scan conversations across multiple Claude Code config directories (e.g. default + work)
  • Refresh — rebuild the index on demand after new conversations are created
  • Multi-assistant support — Codex CLI sessions appear in a separate tree section alongside Claude sessions; toggle providers via claudeHistory.configureProviders
  • Codex auto-detection — first-time notification when ~/.codex/sessions is detected; one-click to enable
  • Resume sessionsclaudeHistory.resumeProviderSession opens a terminal and runs the correct resume command for any provider (claude --resume <id> or codex resume <id>)

Architecture

The extension is split into two runtimes that cannot share modules directly:

packages/threadbase-core/   ← Private shared package (@threadbase/core)
├── src/session.ts          ← ProviderSession, ProviderMessage interfaces
├── src/provider.ts         ← AssistantProvider interface
├── src/registry.ts         ← ProviderRegistry (Promise.allSettled fan-out + SessionFilter)
└── src/index.ts            ← Re-exports all public symbols

VS Code Extension Host (Node.js)
├── src/core/               ← Platform-agnostic domain logic (no Electron, no VS Code)
│   ├── types.ts            ← All shared domain types
│   ├── scanner.ts          ← JSONL streaming parser with LRU cache
│   ├── indexer.ts          ← FlexSearch full-text index
│   ├── formatters.ts       ← Markdown / plain-text export formatters
│   ├── worktree-parser.ts  ← Git worktree metadata parser
│   ├── execFileNoThrow.ts  ← Safe child_process wrapper
│   ├── profiles.ts         ← Profile config load/save (storageDir-parameterized)
│   ├── filters.ts          ← applyFilters / applySorting with exhaustiveness guard
│   ├── export.ts           ← buildExportContent — format-agnostic export builder
│   └── providers/
│       ├── claude.ts       ← ClaudeProvider — wraps ConversationScanner; resume via `claude --resume <uuid>`
│       └── codex.ts        ← CodexProvider — parses Codex CLI JSONL files; resume via `codex resume <id>`
├── src/services/
│   └── HistoryService.ts   ← Orchestrates scanner + indexer + ProviderRegistry; single VS Code entry point
├── src/providers/
│   └── ConversationTreeProvider.ts  ← vscode.TreeDataProvider; Claude tree + Codex CLI section
├── src/webview/
│   ├── protocol.ts         ← Typed bidirectional message contract (ExtensionMessage / WebviewMessage)
│   └── ConversationPanel.ts ← vscode.WebviewPanel factory; singleton per conversation
└── extension.ts            ← activate() / deactivate(); wires everything together

VS Code Webview (sandboxed iframe — no Node.js access)
└── src/webview-ui/
    ├── index.html          ← CSP nonce placeholder
    ├── main.tsx            ← React 18 createRoot entry point
    ├── App.tsx             ← Conversation viewer root; handles all webview ↔ extension messages
    ├── vscodeApi.ts        ← Singleton wrapper for acquireVsCodeApi()
    ├── types.ts            ← Re-exports from src/core/types (type-only, no runtime coupling)
    └── components/
        ├── MessageContent.tsx        ← Renders message text with react-markdown + remark-gfm
        ├── ToolInvocationBadge.tsx   ← Inline badge showing tool name + input summary
        ├── MessageNavigation.tsx     ← Prev/Next navigator for jumping between messages
        ├── ToolResultCard.tsx        ← Dispatcher — routes to the correct tool card
        └── tool-cards/
            ├── EditDiffCard.tsx      ← Structured patch diff viewer
            ├── BashTerminalCard.tsx  ← stdout/stderr terminal output with CollapsibleJson
            ├── GrepResultCard.tsx    ← Grep match results with file/line context
            ├── GlobResultCard.tsx    ← File glob match list
            ├── ReadFileCard.tsx      ← File read operation card
            ├── WriteFileCard.tsx     ← File write operation card
            ├── TaskToolCard.tsx      ← Task agent / TodoWrite / TodoRead cards
            ├── CollapsibleJson.tsx   ← Expandable JSON viewer (used by BashTerminalCard)
            └── GenericToolCard.tsx   ← Fallback for unknown tool types

Extension Host ↔ Webview Message Protocol

Communication between the two runtimes uses a typed, discriminated-union message protocol defined in src/webview/protocol.ts:

// Extension Host → Webview
type ExtensionMessage =
  | { type: 'loadConversation'; conversation: Conversation }
  | { type: 'highlightQuery'; query: string }

// Webview → Extension Host
type WebviewMessage =
  | { type: 'ready' }
  | { type: 'copyMessage'; content: string }
  | { type: 'exportConversation'; format: ExportFormat }
  | { type: 'openExternal'; url: string }

The webview sends ready on mount; the extension host replays the last loaded conversation on reconnect (e.g. when the panel regains focus after being hidden).


Design Decisions

Platform-agnostic core (src/core/)

All domain logic lives in src/core/ with zero Electron and zero VS Code imports. This was a deliberate architectural boundary: core modules can be tested with plain Vitest (no VS Code test runner needed), ported to other editors, or used in CLI tools without modification.

HistoryService as the single orchestrator

HistoryService is the only class in the extension host that directly uses ConversationScanner and SearchIndexer. All VS Code commands and providers talk to HistoryService, never to the core modules directly. This keeps the VS Code surface area isolated and makes the domain logic independently testable.

esbuild over webpack

Two separate esbuild invocations produce two bundles:

  • Extension hostplatform: 'node', format: 'cjs', external: ['vscode'] (VS Code API injected at runtime)
  • Webview bundleplatform: 'browser', format: 'esm', bundles React + all dependencies into a single out/webview/main.js

esbuild was chosen over webpack for its simplicity and zero-config approach. No loader configuration, no plugin ecosystem to manage.

Two tsconfig.json files

The extension host and webview have fundamentally different compilation targets:

Extension host Webview
Config tsconfig.json tsconfig.webview.json
Module CommonJS ESNext
Lib ES2020 ES2020 + DOM
JSX react-jsx
Excludes src/webview-ui/** everything except src/webview-ui/**

A single tsconfig.json cannot correctly typecheck both because DOM types (e.g. window, document) conflict with Node.js globals.

CSP nonce-based webview security

The webview HTML uses a cryptographically random nonce on every load:

<script nonce="${nonce}" src="${scriptUri}"></script>

The Content Security Policy restricts scripts to only those carrying the correct nonce, preventing XSS from injected content in conversation messages.

retainContextWhenHidden: true

ConversationPanel sets retainContextWhenHidden: true on the WebviewPanel. This preserves the React component tree and scroll position when the user switches tabs and returns, avoiding a full re-render and re-fetch of the conversation data.

Singleton acquireVsCodeApi()

acquireVsCodeApi() may only be called once per webview lifetime. src/webview-ui/vscodeApi.ts wraps it in a module-level singleton and exports a typed postMessage function. All components call this module — never acquireVsCodeApi() directly.

FlexSearch Document index

SearchIndexer uses FlexSearch's Document index (not the simpler Index) to support field-level indexing across sessionName, projectName, and preview. This allows searches to be scoped or ranked by field. The index is rebuilt from scratch on each rebuild() call; there is no persistence to disk (index rebuild from JSONL files is fast enough at typical conversation counts).

Provider abstraction (packages/threadbase-core)

The AssistantProvider interface decouples the extension from any specific AI tool. Each provider implements scanSessions(), loadSession(), and resumeCommand(). ProviderRegistry fans out getSessions() to all registered providers using Promise.allSettled — a failing provider (disk error, missing directory) is silently skipped rather than aborting the whole scan.

threadbase-core is a private npm package ("private": true) with no VS Code dependency. It is linked via file: in package.json and resolved by both tsc (via paths alias) and Vitest (via resolve.alias) without a build step.

Claude sessions continue to flow through the existing ConversationScanner/SearchIndexer pipeline unchanged. The ClaudeProvider registered in ProviderRegistry is used only for the resumeCommand path; getProviderSessions() is for non-Claude providers (Codex, and future additions).

Profiles

Claude Code supports multiple config directories via CLAUDE_CONFIG_DIR. src/core/profiles.ts manages a profiles.json file in VS Code's globalStorageUri directory. On first run, a default profile pointing to ~/.claude is created automatically. Additional profiles (e.g. for work accounts) can be added by editing profiles.json directly (UI is planned for a future stage).


Getting Started

Prerequisites

  • VS Code 1.85.0 or later
  • Node.js 18.x or later
  • npm 9.x or later

Install Dependencies

git clone https://github.com/RonenMars/vscode-claude-code-manager
cd vscode-claude-code-manager
npm install

Build

npm run build

This runs node esbuild.js and produces:

  • out/extension.js — extension host bundle (~72 kb)
  • out/webview/main.js — React webview bundle (~1.5 mb, includes React + all deps)

Development Mode (Watch)

npm run watch

Rebuilds both bundles on file changes. In VS Code, press F5 to launch the extension in a new Extension Development Host window. After making changes, press Ctrl+Shift+F5 (macOS: Shift+Cmd+F5) to reload.

Running Tests

npm test

Runs all Vitest unit tests (core modules only — no VS Code runtime required):

npm run test:watch   # watch mode

TypeScript Type Check (no emit)

npx tsc --noEmit                                  # extension host
npx tsc --noEmit --project tsconfig.webview.json  # webview

Commands

Command Title Description
claudeHistory.search Claude History: Search Opens a QuickPick to full-text search all conversations
claudeHistory.refresh Claude History: Refresh Index Rescans JSONL files and rebuilds the search index
claudeHistory.openConversation Claude History: Open Conversation Opens a conversation in the webview panel
claudeHistory.openWorkspace Claude History: Open Workspace Conversations Filters the tree to the current workspace's conversations
claudeHistory.setSortOrder Claude History: Set Sort Order QuickPick to change the tree sort order
claudeHistory.setDateRange Claude History: Set Date Range QuickPick to change the date range filter
claudeHistory.resumeProviderSession Claude History: Resume Provider Session Opens a terminal and runs the resume command for a session (claude --resume or codex resume)
claudeHistory.configureProviders Claude History: Configure Providers Multi-select QuickPick to toggle which session providers are shown in the tree

All commands are also accessible from the activity bar sidebar panel's toolbar.


Configuration

Setting Type Default Description
claudeHistory.defaultProfileId string "default" Profile ID used for scanning when no explicit profile is selected
claudeHistory.sortOrder string "recent" Conversation sort order: recent, oldest, messages-desc, messages-asc, alpha
claudeHistory.dateRange string "all" Date range filter: all, today, week, month, year
claudeHistory.enabledProviders string[] ["claude"] Active session providers shown in the tree. Add "codex" to enable Codex CLI sessions
claudeHistory.codexSessionsPath string "" Override path to the Codex CLI sessions directory. Leave empty to use the default (~/.codex/sessions/)

Profiles are managed via profiles.json in VS Code's global storage directory. To find this directory, run Developer: Open Extension Storage from the command palette after the extension has activated.


Project Structure

vscode-claude-code-manager/
├── packages/
│   └── threadbase-core/    ← Private shared package (@threadbase/core)
│       └── src/            ← ProviderSession, AssistantProvider, ProviderRegistry
├── src/
│   ├── core/               ← Platform-agnostic domain logic + tests
│   │   └── providers/      ← ClaudeProvider, CodexProvider
│   ├── services/           ← VS Code orchestration layer
│   ├── providers/          ← VS Code TreeDataProvider
│   ├── webview/            ← Panel factory + typed message protocol
│   ├── webview-ui/         ← React conversation viewer (browser bundle)
│   └── extension.ts        ← Extension entry point
├── src/test/
│   └── fixtures/           ← Real JSONL conversation files used in tests
├── out/                    ← Build output (git-ignored)
│   ├── extension.js        ← Extension host bundle
│   └── webview/
│       └── main.js         ← Webview React bundle
├── docs/
│   ├── stage0-architecture.md    ← Target architecture spec
│   └── stage0-feature-parity.md ← Feature parity matrix vs. original Electron app
├── esbuild.js              ← Build script (extension host + webview)
├── tsconfig.json           ← Extension host TypeScript config
├── tsconfig.webview.json   ← Webview TypeScript config
└── vitest.config.ts        ← Test runner config (core only)

Tech Stack

Layer Technology
Extension host TypeScript 5.3, Node.js, VS Code API ^1.85.0
Full-text search FlexSearch 0.7
Webview UI React 18, TypeScript
Markdown rendering react-markdown + remark-gfm
Build esbuild
Tests Vitest

Relation to the Electron App

This extension is a migration of claude-code-search-history, a standalone Electron desktop app. The VS Code extension covers Stages 0–5 of that migration:

Stage Scope Status
0 Analysis + project bootstrap ✅ Complete
1 Core module extraction (types, scanner, indexer, formatters, profiles, filters, export) ✅ Complete
2 Extension scaffold (package.json, tsconfigs, esbuild, entry point) ✅ Complete
3 HistoryService + ConversationTreeProvider ✅ Complete
4 Webview infrastructure (ConversationPanel + message protocol) ✅ Complete
5 React conversation viewer (all tool cards + message navigation) ✅ Complete
6 Sort options, date filter, text highlighting, live file watcher, task tool cards ✅ Complete
7+ Chat terminal (node-pty), worktrees panel, profiles UI Planned

Dropped from extension scope (Electron-only):

  • ChatTerminal — xterm.js + node-pty interactive terminal
  • ActiveChatList — live chat session management
  • WorktreesPanel — git worktree creation UI
  • ProfilesPanel — profile management UI

Redesigned for VS Code:

Electron VS Code
ResultsList + SearchBar VS Code QuickPick
FilterPanel QuickPick filter step
Electron IPC (ipcMain / ipcRenderer) Typed postMessage protocol
app.getPath('userData') context.globalStorageUri.fsPath
dialog.showSaveDialog vscode.window.showSaveDialog
electron-store context.globalState / vscode.workspace.getConfiguration
scan-progress IPC push event vscode.window.withProgress

License

MIT

About

Threadbase VS Code extension — search and browse Claude Code conversation history inside the editor.

Topics

Resources

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages