Skip to content

Commit 15ad870

Browse files
committed
More file updates
1 parent 0d5ae69 commit 15ad870

File tree

19 files changed

+498
-217
lines changed

19 files changed

+498
-217
lines changed

.github/copilot-instructions.md

Lines changed: 50 additions & 176 deletions
Large diffs are not rendered by default.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
applyTo: "cli/**"
3+
---
4+
5+
# CLI — Architecture & Integration Guide
6+
7+
The CLI (`cli/`) is a standalone command-line tool that **shares the session discovery and data access classes** from `vscode-extension/src/` but has its own aggregation pipeline. It is built with TypeScript and bundled via `cli/esbuild.js` into `cli/dist/cli.js`.
8+
9+
## Key Files
10+
11+
- **`cli/src/helpers.ts`**: Shared helper functions — session discovery, file processing, stats aggregation. Imports all data access classes from `vscode-extension/src/`.
12+
- **`cli/src/commands/`**: One file per sub-command (`stats`, `usage`, `environmental`, `fluency`, `diagnostics`).
13+
- **`cli/esbuild.js`**: Build script. Copies JSON data files from `vscode-extension/src/` to a temp location before bundling, then removes them.
14+
- **`cli/tsconfig.json`**: `paths` alias points to `../vscode-extension/src/*`.
15+
16+
## Developer Workflow
17+
18+
```bash
19+
cd cli
20+
npm install
21+
npm run build # development build
22+
npm run build:production # minified release build
23+
```
24+
25+
Or from the repo root:
26+
```powershell
27+
./build.ps1 -Project cli
28+
```
29+
30+
## Adding a New Editor / Data Source
31+
32+
When adding support for a new editor or data source, wire it into **both** `vscode-extension/src/` (see `.github/instructions/vscode-extension.instructions.md`) **and** this CLI.
33+
34+
### CLI Files to Update
35+
36+
| File | What to add |
37+
|---|---|
38+
| `cli/src/helpers.ts` | Import, factory function, singleton, detection, stat routing, `processSessionFile()` branch, `calculateUsageAnalysisStats()` deps |
39+
| `cli/src/commands/stats.ts` | Add entry to `getEditorDisplayName()` |
40+
| `cli/src/commands/usage.ts` | No change needed — uses shared helpers |
41+
| `cli/README.md` | Add the new editor to the "Data Sources" section |
42+
43+
### Integration Points in `cli/src/helpers.ts`
44+
45+
1. **Import**`import { NewEditorDataAccess } from '../../vscode-extension/src/neweditor';`
46+
2. **Factory function**`function createNewEditor(): NewEditorDataAccess { return new NewEditorDataAccess(); }`
47+
3. **Singleton**`const _newEditorInstance = createNewEditor();`
48+
4. **`createSessionDiscovery()`** — pass `newEditor: _newEditorInstance` in the deps object
49+
5. **`statSessionFile()`** — add guard routing virtual paths to the real DB file (before the generic `fs.promises.stat()` fallthrough)
50+
6. **`getEditorSourceFromPath()`** — add a path pattern check *before* the generic `'/code/'` or `'vscode'` fallthrough, returning a stable lowercase identifier (e.g. `'neweditor'`)
51+
7. **`processSessionFile()`** — add a guard block calling `getTokens()`, `countInteractions()`, `getModelUsage()` from the data access class and returning a `SessionData` object
52+
8. **`calculateUsageAnalysisStats()` deps** — pass `newEditor: _newEditorInstance` so `analyzeSessionUsage()` can route to it
53+
54+
### Checklist
55+
56+
- [ ] `cli/src/helpers.ts` — import, factory, singleton, detection, stat routing, processSessionFile block, usageAnalysis deps
57+
- [ ] `cli/src/commands/stats.ts``getEditorDisplayName()` entry
58+
- [ ] `cli/README.md` — "Data Sources" section updated
59+
- [ ] `npm run build` passes (from `cli/`)
60+
- [ ] CLI `stats` command shows the new editor in the session list
61+
- [ ] Token counts are non-zero and plausible
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
applyTo: "visualstudio-extension/**"
3+
---
4+
5+
# Visual Studio Extension — Architecture & Development Guide
6+
7+
The `visualstudio-extension/` folder contains a C# Visual Studio extension (`.vsix`) that replicates the core views of the VS Code extension for users of Visual Studio IDE.
8+
9+
## Planned Approach (Option C — WebView2 + existing webviews)
10+
11+
The extension hosts a **WebView2** control inside a Visual Studio Tool Window (C# `AsyncPackage`). The existing compiled webview bundles from `vscode-extension/dist/webview/` run inside WebView2 — avoiding a full UI rewrite. A thin C# bridge handles file I/O and passes JSON to the webview via `PostWebMessageAsJson`.
12+
13+
### Key design decisions
14+
15+
- **Data layer**: The `VisualStudioDataAccess` class in `vscode-extension/src/visualstudio.ts` already handles all session discovery and parsing for Visual Studio Copilot Chat binary session files (MessagePack format). The C# host reads session metadata and delegates token estimation to this layer by shelling out to the CLI, or by re-implementing only the discovery logic in C#.
16+
- **UI**: WebView2 renders the existing `details`, `chart`, `usage`, and `diagnostics` webview bundles. The VS Code CSS theme tokens (`--vscode-*`) will need a compatibility shim mapping to Visual Studio theme tokens.
17+
- **No cloud storage**: Azure Storage integration is out of scope for the initial version.
18+
19+
## Developer Workflow
20+
21+
```bash
22+
# Prerequisites: Visual Studio 2022, .NET SDK, VSIX workload
23+
cd visualstudio-extension
24+
dotnet build --configuration Release
25+
```
26+
27+
Or from the repo root:
28+
```powershell
29+
./build.ps1 -Project visualstudio
30+
```
31+
32+
## Session File Discovery
33+
34+
Visual Studio Copilot Chat stores sessions as MessagePack-encoded binary files:
35+
```
36+
<project>\.vs\<solution>.<ext>\copilot-chat\<hash>\sessions\<uuid>
37+
```
38+
39+
Discovery is already implemented — see `vscode-extension/src/visualstudio.ts` for `VisualStudioDataAccess.discoverSessions()`.
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
---
2+
applyTo: "vscode-extension/**"
3+
---
4+
5+
# VS Code Extension — Architecture & Development Guide
6+
7+
## Architecture Overview
8+
9+
The entire extension's logic is contained within the `CopilotTokenTracker` class in `vscode-extension/src/extension.ts`. Its primary function is to track GitHub Copilot token usage by reading and parsing session log files.
10+
11+
- **Activation**: The extension activates on VS Code startup via the `onStartupFinished` event in `vscode-extension/package.json`. The `activate` function in `vscode-extension/src/extension.ts` instantiates `CopilotTokenTracker`.
12+
13+
- **Data Source**: The core data comes from `.json` log files generated by the GitHub Copilot Chat extension. The `getCopilotSessionFiles` method locates these files in the user's OS-specific AppData directory for VS Code (e.g., `.../Code/User/workspaceStorage/.../chatSessions` and `.../Code/User/globalStorage/emptyWindowChatSessions`).
14+
15+
- **Data Flow**:
16+
1. A timer in the `constructor` calls `updateTokenStats()` every 5 minutes.
17+
2. `updateTokenStats()` calls `calculateDetailedStats()` to aggregate data.
18+
3. `calculateDetailedStats()` reads all session files found by `getCopilotSessionFiles()`.
19+
4. For each file, it calculates token counts (`estimateTokensFromSession`), interactions (`countInteractionsInSession`), and per-model usage (`getModelUsageFromSession`).
20+
5. Token counts are *estimated* using character-to-token ratios defined in the `tokenEstimators` class property. This is a key convention.
21+
22+
- **Thinking Token Tracking**: Models that use extended thinking (e.g., Claude) produce `kind: "thinking"` response items in session logs. These are tracked separately:
23+
- `estimateTokensFromSession` and `estimateTokensFromJsonlSession` return `{ tokens, thinkingTokens }`. The `tokens` field is the **grand total** (input + output + thinking). The `thinkingTokens` field is a **breakdown** showing what portion of the total was thinking — it is NOT subtracted from `tokens`.
24+
- `SessionFileCache` stores `thinkingTokens` alongside `tokens`.
25+
- `extractResponseData` separates `responseText` and `thinkingText` so the logviewer can display them independently per turn.
26+
- `getModelUsageFromSession` does NOT separate thinking — thinking tokens are counted as `outputTokens` in the per-model breakdown. This is intentional since it keeps cost estimation simple.
27+
- **Critical invariant**: When computing token totals for display (per-turn, per-session, per-period), always include thinking tokens. In the logviewer, `totalTokens = input + output + thinking`. In stats aggregation, `sessionData.tokens` already includes thinking. Never subtract thinking from a total.
28+
- `CACHE_VERSION` must be bumped when changing how tokens are counted so stale caches are invalidated.
29+
30+
- **OpenCode Support**: The extension also reads session data from [OpenCode](https://opencode.ai), a terminal-based coding agent. OpenCode stores its data in `~/.local/share/opencode/` (Linux/macOS) or the equivalent XDG data directory.
31+
32+
- **Dual storage backends**: OpenCode originally stored sessions as individual JSON files under `storage/session/`, `storage/message/`, and `storage/part/`. It later migrated to a SQLite database (`opencode.db`) in the same data directory. The extension supports **both** backends — it tries the SQLite DB first and falls back to JSON files.
33+
- **SQLite reading**: The extension uses `sql.js` (a pure JS/WASM SQLite reader, no native dependencies) to read `opencode.db`. The WASM binary (`sql-wasm.wasm`) is copied to `dist/` during the esbuild step. The sql.js module is lazy-loaded and cached in `_sqlJsModule`.
34+
- **DB schema**: The `opencode.db` database has tables `session` (id, slug, title, directory, time_created, time_updated), `message` (id, session_id, time_created, data JSON), and `part` (id, message_id, session_id, time_created, data JSON). The `data` column in `message` contains JSON with `{role, model: {providerID, modelID}, tokens: {total, input, output, reasoning, cache: {read, write}}}`.
35+
- **Virtual path scheme**: Since the existing architecture is file-path-based, DB-stored sessions use virtual paths of the form `<opencode_dir>/opencode.db#ses_<id>`. Detection helpers: `isOpenCodeDbSession()` checks for the `opencode.db#ses_` pattern, `getOpenCodeSessionId()` parses both virtual paths and `ses_<id>.json` filenames.
36+
- **Async methods**: `getOpenCodeMessagesForSession(filePath)` and `getOpenCodePartsForMessage(messageId)` are the primary data access methods — they try DB first, fall back to JSON. The OpenCode token/interaction/model methods (`getTokensFromOpenCodeSession`, `countOpenCodeInteractions`, `getOpenCodeModelUsage`) are all async.
37+
- **`statSessionFile()`**: A helper that resolves DB virtual paths to `fs.promises.stat()` on the `opencode.db` file itself. **All `fs.promises.stat(sessionFile)` calls in loops that process session files must use `this.statSessionFile()` instead**, to avoid failures on DB virtual paths.
38+
- **Key invariant**: When adding new code that processes session file paths (stat calls, path splitting, folder grouping), always check `isOpenCodeDbSession()` first and handle the virtual path appropriately (use `statSessionFile()` for stats, use `getOpenCodeDataDir()` for folder grouping).
39+
40+
- **UI Components**:
41+
1. **Status Bar**: A `vscode.StatusBarItem` (`statusBarItem`) shows a brief summary. Its tooltip provides more detail.
42+
2. **Details Panel**: The `copilot-token-tracker.showDetails` command opens a `vscode.WebviewPanel`. The content for this panel is generated dynamically as an HTML string by the `getDetailsHtml` method.
43+
44+
## Developer Workflow
45+
46+
- **Setup**: Run `npm install` inside `vscode-extension/` to install dependencies.
47+
- **Build**: Run `npm run compile` from `vscode-extension/` to lint and build the extension using `esbuild`. The output is a single file: `vscode-extension/dist/extension.js`.
48+
- **Watch Mode**: For active development, use `npm run watch` from `vscode-extension/`. This will automatically recompile the extension on file changes.
49+
- **Testing/Debugging**: Press `F5` in VS Code to open the Extension Development Host. This will launch a new VS Code window with the extension running. `console.log` statements from `vscode-extension/src/extension.ts` will appear in the Developer Tools console of this new window (Help > Toggle Developer Tools).
50+
51+
**Important build guidance:** After making changes to source code or related files (TypeScript, JavaScript, JSON, or other code files used by the extension), always run `npm run compile` from `vscode-extension/` to validate that the project still builds and lints cleanly before opening a pull request or releasing. You do not need to run the full compile step for documentation-only changes (Markdown files), but you should run it after any edits that touch source, configuration, or JSON data files.
52+
53+
## Development Guidelines
54+
55+
- **Minimal Changes**: Only modify files that are directly needed for the actual changes being implemented. Avoid touching unrelated files, configuration files, or dependencies unless absolutely necessary for the feature or fix.
56+
- **Focused Modifications**: Make surgical, precise changes that address the specific requirements without affecting other functionality.
57+
- **Preserve Existing Structure**: Maintain the existing code organization and file structure. Don't refactor or reorganize code unless it's essential for the task.
58+
59+
## Logging Best Practices
60+
61+
**CRITICAL**: Do NOT add debug logging statements like `this.log('[DEBUG] message')` or `console.log('[DEBUG] ...')` for troubleshooting during development. This approach has been found to flood the output channel and cause messages to disappear.
62+
63+
### Why DEBUG Logs Are Problematic
64+
65+
**Extension Host Flooding**: When DEBUG log statements are added to frequently-called methods in `extension.ts` (e.g., cache lookups, file processing loops, webview message handlers), they can generate hundreds of log entries per operation. VS Code's OutputChannel has a buffer limit, and excessive logging causes older messages to be pushed out and lost. This was observed when:
66+
- Cache hit/miss logging was added to session file processing
67+
- JSONL content reference counting was logged for each file
68+
- Webview message handlers logged every incoming message with full JSON payloads
69+
- Session data was logged with repository counts on each webview update
70+
71+
**Symptom**: After operations like clearing the cache, expected log messages would disappear from the Output panel because they were pushed out of the buffer by DEBUG logs.
72+
73+
### Extension vs Webview Logging
74+
75+
These are two completely separate logging systems:
76+
77+
| Context | Method | Destination | Visibility |
78+
|---------|--------|-------------|------------|
79+
| Extension (`vscode-extension/src/extension.ts`) | `this.log()`, `this.warn()`, `this.error()` | VS Code Output Channel | Output panel → "Copilot Token Tracker" |
80+
| Webview (`vscode-extension/src/webview/*/main.ts`) | `console.log()` | Browser DevTools | Help → Toggle Developer Tools in webview |
81+
82+
- Clearing the output channel (`outputChannel.clear()`) does NOT affect webview console logs
83+
- Webview console.log statements do NOT appear in the Output panel
84+
- DEBUG prefixes in webviews were removed to maintain consistency with extension guidelines
85+
86+
### Best Practices
87+
88+
- **Use Existing Logs**: The extension already has comprehensive logging. Review existing log statements before adding new ones.
89+
- **Minimal Logging**: Only add logging if absolutely necessary for a new feature. Keep messages concise.
90+
- **Remove Debug Logs**: Any temporary debug logging added during development MUST be removed before committing.
91+
- **Log Methods**: Use appropriate severity:
92+
- `log(message)` - Standard informational messages
93+
- `warn(message)` - Warnings or recoverable errors
94+
- `error(message)` - Critical errors
95+
- **No Debug Prefixes**: Avoid `[DEBUG]` markers. The log output is already timestamped.
96+
- **Avoid High-Frequency Logging**: Never log inside loops that process many items (files, sessions, cache entries).
97+
98+
### Debugging Without Logs
99+
100+
Prefer VS Code's debugger with breakpoints rather than adding log statements:
101+
1. Press `F5` to launch Extension Development Host
102+
2. Set breakpoints in `vscode-extension/src/extension.ts`
103+
3. Use the Debug Console to inspect variables
104+
105+
## Key Files & Conventions
106+
107+
- **`vscode-extension/src/extension.ts`**: The single source file containing all logic.
108+
- `CopilotTokenTracker`: The main class.
109+
- `calculateDetailedStats()`: The primary data aggregation method.
110+
- `getDetailsHtml()`: The method responsible for rendering the webview's HTML content. All styling is inlined within this method's template string.
111+
- **`vscode-extension/src/README.md`**: **IMPORTANT**: Contains detailed instructions for updating the JSON data files. Always consult this file when updating tokenEstimators.json or modelPricing.json. It includes structure definitions, update procedures, and current pricing information.
112+
- **`vscode-extension/src/tokenEstimators.json`**: Character-to-token ratio estimators for different AI models. See `vscode-extension/src/README.md` for update instructions.
113+
- **`vscode-extension/src/modelPricing.json`**: Model pricing data with input/output costs per million tokens. Includes metadata about pricing sources and last update date. See `vscode-extension/src/README.md` for detailed update instructions and current pricing sources.
114+
- **`docs/FLUENCY-LEVELS.md`**: Documents the scoring rules for the Copilot Fluency Score dashboard (4 stages, 6 categories, thresholds, and boosters). **Keep this file up to date** when changing the `calculateMaturityScores()` method in `vscode-extension/src/extension.ts`.
115+
- **`vscode-extension/package.json`**: Defines activation events, commands, and build scripts.
116+
- **`vscode-extension/esbuild.js`**: The build script that bundles the TypeScript source and JSON data files. Also copies `sql-wasm.wasm` from `node_modules/sql.js/dist/` to `dist/` for OpenCode SQLite support.
117+
- **`vscode-extension/src/types/json.d.ts`**: Type declarations for JSON module imports and the `sql.js` module.
118+
119+
## Webview Navigation Buttons
120+
121+
To maintain a consistent, VS Code-native look across all webview panels (Details, Chart, Usage Analysis, Diagnostics), use the VS Code Webview UI Toolkit for top-level navigation buttons.
122+
123+
- **Use `vscode-button`**: Prefer the toolkit button component for header navigation controls instead of custom `<button>` elements. Example usage in a webview script:
124+
125+
```ts
126+
const { provideVSCodeDesignSystem, vsCodeButton } = await import('@vscode/webview-ui-toolkit');
127+
provideVSCodeDesignSystem().register(vsCodeButton());
128+
129+
// then create buttons in the DOM:
130+
const btn = document.createElement('vscode-button');
131+
btn.id = 'btn-details';
132+
btn.textContent = '🤖 Details';
133+
btn.setAttribute('appearance', 'primary');
134+
```
135+
136+
- **Register the toolkit in each webview**: Each webview that uses `vscode-button` should import and register the toolkit in its `bootstrap()` or initialization function before rendering the layout.
137+
138+
- **Wire messages unchanged**: Buttons should `postMessage` the same navigation commands (`showDetails`, `showChart`, `showUsageAnalysis`, `showDiagnostics`, `refresh`) so the extension can reuse existing panels. Do not change the command names.
139+
140+
- **Checklist for PRs touching webviews**:
141+
- Ensure the toolkit is registered before creating `vscode-button` elements.
142+
- Keep navigation command names unchanged so `extension.ts` handlers continue to work.
143+
- Run `npm run compile` and verify TypeScript and ESLint pass.
144+
- Visually compare the header with the Details and other panels to confirm parity.
145+
146+
## Adding a New Editor / Data Source
147+
148+
When adding support for a new editor or data source, you must wire it into **both** this extension (`vscode-extension/src/`) **and** the CLI (`cli/src/`). See `.github/instructions/cli.instructions.md` for the CLI integration checklist.

0 commit comments

Comments
 (0)