copilot-lens 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -85
- package/dist/__tests__/cache.test.d.ts +1 -0
- package/dist/__tests__/cache.test.js +60 -0
- package/dist/__tests__/cache.test.js.map +1 -0
- package/dist/__tests__/search.test.d.ts +1 -0
- package/dist/__tests__/search.test.js +203 -0
- package/dist/__tests__/search.test.js.map +1 -0
- package/dist/__tests__/sessions.test.d.ts +1 -0
- package/dist/__tests__/sessions.test.js +273 -0
- package/dist/__tests__/sessions.test.js.map +1 -0
- package/dist/__tests__/vscode-sessions.test.d.ts +1 -0
- package/dist/__tests__/vscode-sessions.test.js +457 -0
- package/dist/__tests__/vscode-sessions.test.js.map +1 -0
- package/dist/cache.d.ts +8 -0
- package/dist/cache.js +23 -0
- package/dist/cache.js.map +1 -0
- package/dist/search.d.ts +28 -0
- package/dist/search.js +176 -0
- package/dist/search.js.map +1 -0
- package/dist/server.js +31 -1
- package/dist/server.js.map +1 -1
- package/dist/sessions.d.ts +7 -1
- package/dist/sessions.js +138 -13
- package/dist/sessions.js.map +1 -1
- package/dist/vscode-sessions.d.ts +61 -0
- package/dist/vscode-sessions.js +469 -0
- package/dist/vscode-sessions.js.map +1 -0
- package/package.json +7 -2
- package/public/app.js +106 -13
- package/public/index.html +9 -1
- package/public/style.css +53 -0
package/README.md
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
# Copilot Lens 👓
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Your Copilot history has answers. Now you can actually find them.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Copilot Lens is a local memory layer for GitHub Copilot — search and browse everything you've ever discussed with Copilot, across both CLI terminal sessions and VS Code Copilot Chat. All on your machine. No cloud. No sign-in.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Why
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- **Understand your usage patterns** — Which repos, branches, and tools do you use most?
|
|
11
|
-
- **Track your productivity** — How much active time are you spending with Copilot?
|
|
9
|
+
Copilot sessions are ephemeral by default. You solve a problem, close the terminal, and it's gone. Days later you need that same approach, that regex, that architecture decision — and you have nothing to reference.
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
Copilot stores all of this locally. Copilot Lens makes it accessible.
|
|
14
12
|
|
|
15
13
|
## Install
|
|
16
14
|
|
|
@@ -18,121 +16,135 @@ Everything runs locally. No data leaves your machine. No cloud. No sign-in.
|
|
|
18
16
|
npm install -g copilot-lens
|
|
19
17
|
```
|
|
20
18
|
|
|
21
|
-
## Usage
|
|
22
|
-
|
|
23
19
|
```bash
|
|
24
|
-
#
|
|
25
|
-
copilot-lens
|
|
20
|
+
# Or without installing
|
|
21
|
+
npx copilot-lens --open
|
|
22
|
+
```
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
copilot-lens --open
|
|
24
|
+
## Usage
|
|
29
25
|
|
|
30
|
-
|
|
26
|
+
```bash
|
|
27
|
+
copilot-lens # Start the dashboard
|
|
28
|
+
copilot-lens --open # Start and open in browser
|
|
31
29
|
copilot-lens --port 8080
|
|
32
|
-
|
|
33
|
-
# Or use npx (no install needed)
|
|
34
|
-
npx copilot-lens --open
|
|
35
30
|
```
|
|
36
31
|
|
|
37
|
-
### CLI Options
|
|
38
|
-
|
|
39
32
|
| Flag | Default | Description |
|
|
40
33
|
|------|---------|-------------|
|
|
41
34
|
| `--port` | `3000` | Port number |
|
|
42
35
|
| `--host` | `localhost` | Host address |
|
|
43
36
|
| `--open` | off | Auto-open browser |
|
|
44
37
|
|
|
38
|
+
---
|
|
39
|
+
|
|
45
40
|
## Features
|
|
46
41
|
|
|
47
|
-
###
|
|
42
|
+
### 🔍 Search — Find anything in your Copilot history
|
|
48
43
|
|
|
49
|
-
|
|
50
|
-
- **Color-coded by directory** — each project gets a unique accent color
|
|
51
|
-
- **Status detection** — see which sessions are Running, Completed, or Error
|
|
52
|
-
- **Three filter dimensions** — filter by time range, status, and directory
|
|
53
|
-
- Click any session to view full details
|
|
44
|
+
Search across every conversation you've ever had with Copilot — CLI and VS Code — in one place.
|
|
54
45
|
|
|
55
|
-
|
|
46
|
+
- Full-text search over all session content
|
|
47
|
+
- Ranked results with inline highlights showing context around each match
|
|
48
|
+
- Filter results by source (CLI vs VS Code), date range, or working directory
|
|
49
|
+
- Results update as you type (debounced)
|
|
50
|
+
- Works offline, entirely on your machine
|
|
56
51
|
|
|
57
|
-
|
|
52
|
+
> **Example**: Search `"redis connection pool"` and instantly find the session from three weeks ago where you worked through that implementation.
|
|
58
53
|
|
|
59
|
-
|
|
60
|
-
- View tool calls made during the session
|
|
61
|
-
- See any errors that occurred
|
|
62
|
-
- Read session plans (if created)
|
|
54
|
+
### 📋 Session Browser — Review your conversations
|
|
63
55
|
|
|
64
|
-
|
|
56
|
+
Browse the full history of your Copilot sessions in a searchable, filterable list.
|
|
65
57
|
|
|
66
|
-
|
|
58
|
+
- **Unified view** — CLI terminal and VS Code Copilot Chat sessions side by side
|
|
59
|
+
- **Source badges** — see at a glance whether a session came from CLI or VS Code
|
|
60
|
+
- **Color-coded by directory** — each project gets a distinct accent color
|
|
61
|
+
- **Status detection** — Running, Completed, or Error
|
|
62
|
+
- **Filter by** time range, status, and working directory
|
|
63
|
+
- Click any session to open the full conversation
|
|
67
64
|
|
|
68
|
-
|
|
65
|
+
**Conversation view:**
|
|
66
|
+
- Chat-style layout — your prompts on the right, Copilot responses on the left
|
|
67
|
+
- Tool calls made during the session
|
|
68
|
+
- Errors that occurred
|
|
69
|
+
- Session plans (if created)
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
|-------|------|---------------|
|
|
72
|
-
| **Sessions Per Day** | Bar (compact) | Daily session activity over time |
|
|
73
|
-
| **Activity by Hour of Day** | Bar (compact) | When during the day you use Copilot most |
|
|
74
|
-
| **Tool Usage** | Doughnut | Most-used tools (grep, edit, powershell, etc.) |
|
|
75
|
-
| **Model Usage** | Doughnut | Which AI models you've used (Claude, GPT, etc.) |
|
|
76
|
-
| **Top Working Directories** | Horizontal bar (full-width) | Which project folders you use Copilot in most |
|
|
77
|
-
| **Time Per Branch** | Horizontal bar | Active Copilot time spent on each git branch |
|
|
78
|
-
| **Time Per Repo** | Horizontal bar | Active Copilot time per repository |
|
|
79
|
-
| **MCP Servers Used** | Doughnut | Which MCP servers are configured across sessions |
|
|
71
|
+

|
|
80
72
|
|
|
81
|
-
|
|
73
|
+
### 📊 Analytics — Understand your usage patterns
|
|
82
74
|
|
|
83
|
-
|
|
75
|
+
Eight interactive charts that show how and when you use Copilot.
|
|
84
76
|
|
|
85
|
-
|
|
77
|
+
| Chart | What It Shows |
|
|
78
|
+
|-------|---------------|
|
|
79
|
+
| Sessions Per Day | Daily activity over time |
|
|
80
|
+
| Activity by Hour | When during the day you use Copilot most |
|
|
81
|
+
| Tool Usage | Most-used tools (grep, edit, glob, etc.) |
|
|
82
|
+
| Model Usage | Which AI models you've used |
|
|
83
|
+
| Top Working Directories | Which projects you use Copilot in most |
|
|
84
|
+
| Time Per Branch | Active Copilot time per git branch |
|
|
85
|
+
| Time Per Repo | Active Copilot time per repository |
|
|
86
|
+
| MCP Servers Used | Which MCP servers appear across sessions |
|
|
86
87
|
|
|
87
|
-
|
|
88
|
+
Dark and light mode. Interactive chart legends. Manual refresh.
|
|
88
89
|
|
|
89
|
-
-
|
|
90
|
-
- **Manual refresh** — refresh button to reload data on demand
|
|
91
|
-
- **Responsive layout** — works on any screen size
|
|
92
|
-
- **2-column grid layout** — compact charts with no wasted space
|
|
90
|
+

|
|
93
91
|
|
|
94
|
-
### 🏆
|
|
92
|
+
### 🏆 Effectiveness Score — See how well you're using Copilot
|
|
95
93
|
|
|
96
|
-
|
|
94
|
+
A 0–100 score per repository (CLI) and globally (VS Code) with actionable improvement tips.
|
|
97
95
|
|
|
98
96
|
| Category | What It Measures |
|
|
99
97
|
|----------|-----------------|
|
|
100
|
-
|
|
|
101
|
-
|
|
|
102
|
-
|
|
|
103
|
-
|
|
|
104
|
-
|
|
|
98
|
+
| Prompt Quality | Average prompt length, clarification rate |
|
|
99
|
+
| Tool Utilization | Diversity of tools used across sessions |
|
|
100
|
+
| Efficiency | Tool success rate, turns per session |
|
|
101
|
+
| MCP Utilization | Configured vs. actually used MCP servers |
|
|
102
|
+
| Engagement | Session duration and usage consistency |
|
|
105
103
|
|
|
106
|
-

|
|
105
|
+
|
|
106
|
+
---
|
|
107
107
|
|
|
108
108
|
## How It Works
|
|
109
109
|
|
|
110
|
-
Copilot Lens reads session data from
|
|
110
|
+
Copilot Lens reads session data from two local sources — no network requests, no external APIs.
|
|
111
111
|
|
|
112
|
-
|
|
113
|
-
-
|
|
114
|
-
-
|
|
112
|
+
### GitHub Copilot CLI Sessions
|
|
113
|
+
- **Location**: `~/.copilot/session-state/`
|
|
114
|
+
- `workspace.yaml` — session metadata (directory, git branch, timestamps)
|
|
115
|
+
- `events.jsonl` — full event log (messages, tool calls, errors)
|
|
116
|
+
- `plan.md` — session plans, if created
|
|
115
117
|
|
|
116
|
-
|
|
118
|
+
### VS Code Copilot Chat Sessions
|
|
119
|
+
- **Index**: `state.vscdb` (SQLite) — session list with titles and timing
|
|
120
|
+
- **Content**: `emptyWindowChatSessions/{id}.json` — full conversation
|
|
117
121
|
|
|
118
|
-
|
|
122
|
+
Supported platforms and paths:
|
|
123
|
+
| Platform | Path |
|
|
124
|
+
|----------|------|
|
|
125
|
+
| macOS | `~/Library/Application Support/Code/` |
|
|
126
|
+
| Windows | `%APPDATA%/Code/` |
|
|
127
|
+
| Linux | `~/.config/Code/` |
|
|
119
128
|
|
|
120
|
-
|
|
129
|
+
VS Code Insiders is also supported. Sessions with pasted images (which can exceed 100MB) are automatically stripped of image data. Files over 200MB are skipped.
|
|
121
130
|
|
|
122
|
-
###
|
|
131
|
+
### Duration Calculation
|
|
123
132
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
| **Completed** | Has an `abort` event with "user initiated" reason, or no recent activity |
|
|
128
|
-
| **Error** | Has an `abort` event with a non-user-initiated reason |
|
|
133
|
+
Durations are calculated from actual event activity, not wall-clock time. Gaps longer than 5 minutes between events are excluded — so a session you paused and resumed doesn't show an inflated duration.
|
|
134
|
+
|
|
135
|
+
---
|
|
129
136
|
|
|
130
137
|
## Tech Stack
|
|
131
138
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
139
|
+
| Layer | Technology |
|
|
140
|
+
|-------|-----------|
|
|
141
|
+
| Backend | Node.js + Express + TypeScript |
|
|
142
|
+
| Frontend | Vanilla HTML/CSS/JavaScript |
|
|
143
|
+
| Charts | Chart.js |
|
|
144
|
+
| Data | YAML, JSONL, SQLite (`better-sqlite3`) |
|
|
145
|
+
| Testing | Vitest (56 tests) |
|
|
146
|
+
|
|
147
|
+
---
|
|
136
148
|
|
|
137
149
|
## Development
|
|
138
150
|
|
|
@@ -140,21 +152,32 @@ Session durations are calculated from **actual event activity**, not wall-clock
|
|
|
140
152
|
git clone https://github.com/pavanvamsi3/copilot-lens.git
|
|
141
153
|
cd copilot-lens
|
|
142
154
|
npm install
|
|
143
|
-
npm run dev # Start with tsx (no build
|
|
155
|
+
npm run dev # Start with tsx (no build step)
|
|
144
156
|
npm run build # Compile TypeScript
|
|
157
|
+
npm test # Run tests
|
|
145
158
|
npm start # Run compiled version
|
|
146
159
|
```
|
|
147
160
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
MIT
|
|
161
|
+
---
|
|
151
162
|
|
|
152
163
|
## Optional: Custom Local Hostname
|
|
153
164
|
|
|
154
|
-
|
|
165
|
+
For a cleaner URL like `http://copilot.lens:3000`:
|
|
166
|
+
|
|
167
|
+
**macOS/Linux:**
|
|
168
|
+
```bash
|
|
169
|
+
echo "127.0.0.1 copilot.lens" | sudo tee -a /etc/hosts
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Windows (run as Admin):**
|
|
173
|
+
```bash
|
|
174
|
+
echo 127.0.0.1 copilot.lens >> C:\Windows\System32\drivers\etc\hosts
|
|
175
|
+
```
|
|
155
176
|
|
|
156
|
-
|
|
157
|
-
- **macOS/Linux**: `echo "127.0.0.1 copilot.lens" | sudo tee -a /etc/hosts`
|
|
177
|
+
Then: `copilot-lens --host copilot.lens`
|
|
158
178
|
|
|
159
|
-
|
|
179
|
+
---
|
|
160
180
|
|
|
181
|
+
## License
|
|
182
|
+
|
|
183
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const cache_1 = require("../cache");
|
|
5
|
+
(0, vitest_1.beforeEach)(() => {
|
|
6
|
+
(0, cache_1.clearCache)();
|
|
7
|
+
});
|
|
8
|
+
(0, vitest_1.describe)("cachedCall", () => {
|
|
9
|
+
(0, vitest_1.it)("returns the computed value on first call", () => {
|
|
10
|
+
const result = (0, cache_1.cachedCall)("test-key", 1000, () => 42);
|
|
11
|
+
(0, vitest_1.expect)(result).toBe(42);
|
|
12
|
+
});
|
|
13
|
+
(0, vitest_1.it)("returns cached value on subsequent calls", () => {
|
|
14
|
+
let callCount = 0;
|
|
15
|
+
const fn = () => ++callCount;
|
|
16
|
+
const first = (0, cache_1.cachedCall)("counter", 1000, fn);
|
|
17
|
+
const second = (0, cache_1.cachedCall)("counter", 1000, fn);
|
|
18
|
+
(0, vitest_1.expect)(first).toBe(1);
|
|
19
|
+
(0, vitest_1.expect)(second).toBe(1); // cached, fn not called again
|
|
20
|
+
(0, vitest_1.expect)(callCount).toBe(1);
|
|
21
|
+
});
|
|
22
|
+
(0, vitest_1.it)("recomputes after TTL expires", () => {
|
|
23
|
+
let callCount = 0;
|
|
24
|
+
const fn = () => ++callCount;
|
|
25
|
+
(0, cache_1.cachedCall)("expire-test", 1000, fn);
|
|
26
|
+
// Manually expire the entry
|
|
27
|
+
const entry = cache_1._cacheInternals.cache.get("expire-test");
|
|
28
|
+
entry.expiresAt = Date.now() - 1;
|
|
29
|
+
const result = (0, cache_1.cachedCall)("expire-test", 1000, fn);
|
|
30
|
+
(0, vitest_1.expect)(result).toBe(2); // fn called again
|
|
31
|
+
(0, vitest_1.expect)(callCount).toBe(2);
|
|
32
|
+
});
|
|
33
|
+
(0, vitest_1.it)("uses separate keys for different caches", () => {
|
|
34
|
+
const a = (0, cache_1.cachedCall)("key-a", 1000, () => "alpha");
|
|
35
|
+
const b = (0, cache_1.cachedCall)("key-b", 1000, () => "beta");
|
|
36
|
+
(0, vitest_1.expect)(a).toBe("alpha");
|
|
37
|
+
(0, vitest_1.expect)(b).toBe("beta");
|
|
38
|
+
});
|
|
39
|
+
(0, vitest_1.it)("caches complex objects", () => {
|
|
40
|
+
const obj = { items: [1, 2, 3], nested: { x: true } };
|
|
41
|
+
const result = (0, cache_1.cachedCall)("obj", 1000, () => obj);
|
|
42
|
+
(0, vitest_1.expect)(result).toEqual(obj);
|
|
43
|
+
(0, vitest_1.expect)(result).toBe(obj); // same reference
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
(0, vitest_1.describe)("clearCache", () => {
|
|
47
|
+
(0, vitest_1.it)("invalidates all cached entries", () => {
|
|
48
|
+
let callCount = 0;
|
|
49
|
+
const fn = () => ++callCount;
|
|
50
|
+
(0, cache_1.cachedCall)("clear-test", 1000, fn);
|
|
51
|
+
(0, vitest_1.expect)(callCount).toBe(1);
|
|
52
|
+
(0, cache_1.clearCache)();
|
|
53
|
+
(0, cache_1.cachedCall)("clear-test", 1000, fn);
|
|
54
|
+
(0, vitest_1.expect)(callCount).toBe(2); // recomputed after clear
|
|
55
|
+
});
|
|
56
|
+
(0, vitest_1.it)("works when cache is empty", () => {
|
|
57
|
+
(0, vitest_1.expect)(() => (0, cache_1.clearCache)()).not.toThrow();
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
//# sourceMappingURL=cache.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.test.js","sourceRoot":"","sources":["../../src/__tests__/cache.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
// Must mock before importing the module under test
|
|
5
|
+
vitest_1.vi.mock("../sessions", async (importOriginal) => {
|
|
6
|
+
const actual = await importOriginal();
|
|
7
|
+
return {
|
|
8
|
+
...actual,
|
|
9
|
+
getSession: vitest_1.vi.fn(),
|
|
10
|
+
listSessions: vitest_1.vi.fn(),
|
|
11
|
+
};
|
|
12
|
+
});
|
|
13
|
+
const search_1 = require("../search");
|
|
14
|
+
const sessions_1 = require("../sessions");
|
|
15
|
+
const mockGetSession = vitest_1.vi.mocked(sessions_1.getSession);
|
|
16
|
+
// Helpers to build minimal SessionMeta and SessionDetail fixtures
|
|
17
|
+
function makeMeta(overrides = {}) {
|
|
18
|
+
return {
|
|
19
|
+
id: "sess-001",
|
|
20
|
+
cwd: "/home/user/project",
|
|
21
|
+
createdAt: "2024-01-15T10:00:00Z",
|
|
22
|
+
updatedAt: "2024-01-15T11:00:00Z",
|
|
23
|
+
status: "completed",
|
|
24
|
+
source: "cli",
|
|
25
|
+
...overrides,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function makeDetail(meta, messages) {
|
|
29
|
+
return {
|
|
30
|
+
...meta,
|
|
31
|
+
events: messages.map((m, i) => ({
|
|
32
|
+
type: m.type,
|
|
33
|
+
id: `event-${i}`,
|
|
34
|
+
timestamp: meta.createdAt,
|
|
35
|
+
data: { content: m.content },
|
|
36
|
+
})),
|
|
37
|
+
hasSnapshots: false,
|
|
38
|
+
eventCounts: {},
|
|
39
|
+
duration: 0,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// ─── Test 1: tokenize ────────────────────────────────────────────────────────
|
|
43
|
+
(0, vitest_1.describe)("tokenize", () => {
|
|
44
|
+
(0, vitest_1.it)("strips punctuation, lowercases, and removes tokens under 2 chars", () => {
|
|
45
|
+
const result = (0, search_1.tokenize)("Hello, World! A 42 foo-bar");
|
|
46
|
+
(0, vitest_1.expect)(result).toContain("hello");
|
|
47
|
+
(0, vitest_1.expect)(result).toContain("world");
|
|
48
|
+
(0, vitest_1.expect)(result).toContain("42");
|
|
49
|
+
(0, vitest_1.expect)(result).toContain("foo");
|
|
50
|
+
(0, vitest_1.expect)(result).toContain("bar");
|
|
51
|
+
// Single char 'a' should be removed
|
|
52
|
+
(0, vitest_1.expect)(result).not.toContain("a");
|
|
53
|
+
// Output should be lowercased
|
|
54
|
+
(0, vitest_1.expect)(result).not.toContain("Hello");
|
|
55
|
+
(0, vitest_1.expect)(result).not.toContain("World");
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
// ─── Tests 2 & 3: Empty / blank query ───────────────────────────────────────
|
|
59
|
+
(0, vitest_1.describe)("SearchIndex.search — empty/blank query", () => {
|
|
60
|
+
let index;
|
|
61
|
+
(0, vitest_1.beforeEach)(() => {
|
|
62
|
+
index = new search_1.SearchIndex();
|
|
63
|
+
const meta = makeMeta();
|
|
64
|
+
mockGetSession.mockReturnValue(makeDetail(meta, [{ type: "user.message", content: "hello world" }]));
|
|
65
|
+
index.buildIndex([meta]);
|
|
66
|
+
});
|
|
67
|
+
(0, vitest_1.it)("returns [] for empty string", () => {
|
|
68
|
+
(0, vitest_1.expect)(index.search("")).toEqual([]);
|
|
69
|
+
});
|
|
70
|
+
(0, vitest_1.it)("returns [] for blank string (spaces only)", () => {
|
|
71
|
+
(0, vitest_1.expect)(index.search(" ")).toEqual([]);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
// ─── Test 4: Title match scores higher than content-only ─────────────────────
|
|
75
|
+
(0, vitest_1.describe)("SearchIndex.search — scoring", () => {
|
|
76
|
+
(0, vitest_1.it)("session with query token in title scores higher than content-only match", () => {
|
|
77
|
+
const index = new search_1.SearchIndex();
|
|
78
|
+
const metaTitle = makeMeta({ id: "title-sess", title: "typescript refactor", cwd: "/a/b" });
|
|
79
|
+
const metaContent = makeMeta({ id: "content-sess", title: "random session", cwd: "/c/d" });
|
|
80
|
+
mockGetSession.mockImplementation((id) => {
|
|
81
|
+
if (id === "title-sess") {
|
|
82
|
+
return makeDetail(metaTitle, [
|
|
83
|
+
{ type: "user.message", content: "please help me with typescript refactor here" },
|
|
84
|
+
]);
|
|
85
|
+
}
|
|
86
|
+
return makeDetail(metaContent, [
|
|
87
|
+
{ type: "user.message", content: "please help me with typescript refactor here" },
|
|
88
|
+
]);
|
|
89
|
+
});
|
|
90
|
+
index.buildIndex([metaTitle, metaContent]);
|
|
91
|
+
const results = index.search("typescript");
|
|
92
|
+
(0, vitest_1.expect)(results.length).toBeGreaterThanOrEqual(2);
|
|
93
|
+
const titleResult = results.find((r) => r.entry.id === "title-sess");
|
|
94
|
+
const contentResult = results.find((r) => r.entry.id === "content-sess");
|
|
95
|
+
(0, vitest_1.expect)(titleResult.score).toBeGreaterThan(contentResult.score);
|
|
96
|
+
});
|
|
97
|
+
// ─── Test 5: cwd match scores higher than content-only ────────────────────
|
|
98
|
+
(0, vitest_1.it)("cwd match scores higher than content-only match", () => {
|
|
99
|
+
const index = new search_1.SearchIndex();
|
|
100
|
+
const metaCwd = makeMeta({ id: "cwd-sess", cwd: "/home/user/typescript-project", title: "sess1" });
|
|
101
|
+
const metaContent = makeMeta({ id: "plain-sess", cwd: "/home/user/other", title: "sess2" });
|
|
102
|
+
mockGetSession.mockImplementation((id) => {
|
|
103
|
+
if (id === "cwd-sess") {
|
|
104
|
+
return makeDetail(metaCwd, [
|
|
105
|
+
{ type: "user.message", content: "help with typescript" },
|
|
106
|
+
]);
|
|
107
|
+
}
|
|
108
|
+
return makeDetail(metaContent, [
|
|
109
|
+
{ type: "user.message", content: "help with typescript" },
|
|
110
|
+
]);
|
|
111
|
+
});
|
|
112
|
+
index.buildIndex([metaCwd, metaContent]);
|
|
113
|
+
const results = index.search("typescript");
|
|
114
|
+
(0, vitest_1.expect)(results.length).toBeGreaterThanOrEqual(2);
|
|
115
|
+
const cwdResult = results.find((r) => r.entry.id === "cwd-sess");
|
|
116
|
+
const plainResult = results.find((r) => r.entry.id === "plain-sess");
|
|
117
|
+
(0, vitest_1.expect)(cwdResult.score).toBeGreaterThan(plainResult.score);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
// ─── Test 6: Highlight extraction ───────────────────────────────────────────
|
|
121
|
+
(0, vitest_1.describe)("SearchIndex.search — highlights", () => {
|
|
122
|
+
(0, vitest_1.it)("highlight snippet is at most 121 chars (±60 around match)", () => {
|
|
123
|
+
const index = new search_1.SearchIndex();
|
|
124
|
+
const meta = makeMeta();
|
|
125
|
+
// Long content with a searchable word in the middle
|
|
126
|
+
const padding = "word ".repeat(20); // 100 chars before and after
|
|
127
|
+
const content = `${padding}targetword ${padding}`;
|
|
128
|
+
mockGetSession.mockReturnValue(makeDetail(meta, [{ type: "user.message", content }]));
|
|
129
|
+
index.buildIndex([meta]);
|
|
130
|
+
const results = index.search("targetword");
|
|
131
|
+
(0, vitest_1.expect)(results.length).toBe(1);
|
|
132
|
+
(0, vitest_1.expect)(results[0].highlights.length).toBeGreaterThan(0);
|
|
133
|
+
for (const snippet of results[0].highlights) {
|
|
134
|
+
// ±60 chars around a 10-char token = max 121 chars before word-boundary trimming
|
|
135
|
+
(0, vitest_1.expect)(snippet.length).toBeLessThanOrEqual(121);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
// ─── Tests 7 & 8: source filter ─────────────────────────────────────────────
|
|
140
|
+
(0, vitest_1.describe)("SearchIndex.search — source filter", () => {
|
|
141
|
+
let index;
|
|
142
|
+
const metaCli = makeMeta({ id: "cli-sess", source: "cli", cwd: "/cli/proj" });
|
|
143
|
+
const metaVscode = makeMeta({ id: "vscode-sess", source: "vscode", cwd: "/vscode/proj" });
|
|
144
|
+
(0, vitest_1.beforeEach)(() => {
|
|
145
|
+
index = new search_1.SearchIndex();
|
|
146
|
+
mockGetSession.mockImplementation((id) => {
|
|
147
|
+
if (id === "cli-sess") {
|
|
148
|
+
return makeDetail(metaCli, [{ type: "user.message", content: "hello from cli session" }]);
|
|
149
|
+
}
|
|
150
|
+
return makeDetail(metaVscode, [{ type: "user.message", content: "hello from vscode session" }]);
|
|
151
|
+
});
|
|
152
|
+
index.buildIndex([metaCli, metaVscode]);
|
|
153
|
+
});
|
|
154
|
+
(0, vitest_1.it)("source:'cli' excludes vscode entries", () => {
|
|
155
|
+
const results = index.search("hello", { source: "cli" });
|
|
156
|
+
(0, vitest_1.expect)(results.every((r) => r.entry.source === "cli")).toBe(true);
|
|
157
|
+
(0, vitest_1.expect)(results.some((r) => r.entry.id === "cli-sess")).toBe(true);
|
|
158
|
+
(0, vitest_1.expect)(results.some((r) => r.entry.id === "vscode-sess")).toBe(false);
|
|
159
|
+
});
|
|
160
|
+
(0, vitest_1.it)("source:'vscode' excludes cli entries", () => {
|
|
161
|
+
const results = index.search("hello", { source: "vscode" });
|
|
162
|
+
(0, vitest_1.expect)(results.every((r) => r.entry.source === "vscode")).toBe(true);
|
|
163
|
+
(0, vitest_1.expect)(results.some((r) => r.entry.id === "vscode-sess")).toBe(true);
|
|
164
|
+
(0, vitest_1.expect)(results.some((r) => r.entry.id === "cli-sess")).toBe(false);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
// ─── Test 9: clear() causes rebuild ─────────────────────────────────────────
|
|
168
|
+
(0, vitest_1.describe)("SearchIndex.clear()", () => {
|
|
169
|
+
(0, vitest_1.it)("causes next search() call to rebuild the index", () => {
|
|
170
|
+
const index = new search_1.SearchIndex();
|
|
171
|
+
const meta = makeMeta({ id: "rebuild-sess" });
|
|
172
|
+
// First build: content has "apple"
|
|
173
|
+
mockGetSession.mockReturnValue(makeDetail(meta, [{ type: "user.message", content: "I love apple pie" }]));
|
|
174
|
+
index.buildIndex([meta]);
|
|
175
|
+
(0, vitest_1.expect)(index.search("apple")).toHaveLength(1);
|
|
176
|
+
(0, vitest_1.expect)(index.search("mango")).toHaveLength(0);
|
|
177
|
+
// Clear and update the mock to return different content
|
|
178
|
+
index.clear();
|
|
179
|
+
mockGetSession.mockReturnValue(makeDetail(meta, [{ type: "user.message", content: "I love mango juice" }]));
|
|
180
|
+
// Next search() should lazy-rebuild from storedSessions
|
|
181
|
+
const afterClear = index.search("mango");
|
|
182
|
+
(0, vitest_1.expect)(afterClear).toHaveLength(1);
|
|
183
|
+
// "apple" no longer in index
|
|
184
|
+
(0, vitest_1.expect)(index.search("apple")).toHaveLength(0);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
// ─── Test 10: limit option ───────────────────────────────────────────────────
|
|
188
|
+
(0, vitest_1.describe)("SearchIndex.search — limit option", () => {
|
|
189
|
+
(0, vitest_1.it)("respects limit option and does not exceed it", () => {
|
|
190
|
+
const index = new search_1.SearchIndex();
|
|
191
|
+
const metas = Array.from({ length: 10 }, (_, i) => makeMeta({ id: `sess-${i}`, cwd: `/proj/${i}`, title: `session ${i}` }));
|
|
192
|
+
mockGetSession.mockImplementation((id) => {
|
|
193
|
+
const meta = metas.find((m) => m.id === id);
|
|
194
|
+
return makeDetail(meta, [
|
|
195
|
+
{ type: "user.message", content: "common keyword everywhere" },
|
|
196
|
+
]);
|
|
197
|
+
});
|
|
198
|
+
index.buildIndex(metas);
|
|
199
|
+
const results = index.search("common", { limit: 3 });
|
|
200
|
+
(0, vitest_1.expect)(results.length).toBeLessThanOrEqual(3);
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
//# sourceMappingURL=search.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.test.js","sourceRoot":"","sources":["../../src/__tests__/search.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|