copilot-lens 1.0.0 → 1.0.2
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 +100 -12
- package/dist/sessions.d.ts +11 -1
- package/dist/sessions.js +118 -18
- package/dist/sessions.js.map +1 -1
- package/package.json +14 -3
- package/public/app.js +90 -8
- package/public/index.html +19 -2
- package/public/style.css +60 -14
package/README.md
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
# Copilot Lens 👓
|
|
2
2
|
|
|
3
|
-
A local dashboard to visualize and analyze your GitHub Copilot CLI sessions.
|
|
3
|
+
A local web dashboard to visualize, explore, and analyze your **GitHub Copilot CLI** terminal sessions. See your full conversation history, tool usage patterns, and usage analytics — all without leaving your machine.
|
|
4
|
+
|
|
5
|
+
## Why Copilot Lens?
|
|
6
|
+
|
|
7
|
+
GitHub Copilot CLI stores session data locally, but there's no built-in way to browse or analyze it. Copilot Lens gives you a clean, interactive dashboard to:
|
|
8
|
+
|
|
9
|
+
- **Review past sessions** — What did you ask? What did Copilot do?
|
|
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?
|
|
12
|
+
|
|
13
|
+
Everything runs locally. No data leaves your machine. No cloud. No sign-in.
|
|
4
14
|
|
|
5
15
|
## Install
|
|
6
16
|
|
|
@@ -14,14 +24,17 @@ npm install -g copilot-lens
|
|
|
14
24
|
# Start the dashboard
|
|
15
25
|
copilot-lens
|
|
16
26
|
|
|
17
|
-
#
|
|
18
|
-
copilot-lens --
|
|
27
|
+
# Auto-open in browser
|
|
28
|
+
copilot-lens --open
|
|
29
|
+
|
|
30
|
+
# Custom port
|
|
31
|
+
copilot-lens --port 8080
|
|
19
32
|
|
|
20
33
|
# Or use npx (no install needed)
|
|
21
|
-
npx copilot-lens
|
|
34
|
+
npx copilot-lens --open
|
|
22
35
|
```
|
|
23
36
|
|
|
24
|
-
### Options
|
|
37
|
+
### CLI Options
|
|
25
38
|
|
|
26
39
|
| Flag | Default | Description |
|
|
27
40
|
|------|---------|-------------|
|
|
@@ -31,15 +44,89 @@ npx copilot-lens
|
|
|
31
44
|
|
|
32
45
|
## Features
|
|
33
46
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
-
|
|
37
|
-
- **
|
|
38
|
-
- **
|
|
47
|
+
### 📋 Session Browser
|
|
48
|
+
|
|
49
|
+
- Browse all your Copilot CLI sessions in a searchable, filterable list
|
|
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
|
|
54
|
+
|
|
55
|
+
### 💬 Conversation View
|
|
56
|
+
|
|
57
|
+
- Chat-style layout with your prompts on the right and Copilot responses on the left
|
|
58
|
+
- View tool calls made during the session
|
|
59
|
+
- See any errors that occurred
|
|
60
|
+
- Read session plans (if created)
|
|
61
|
+
|
|
62
|
+
### 📊 Analytics Dashboard
|
|
63
|
+
|
|
64
|
+
Eight interactive charts powered by Chart.js, arranged in a 2-column grid:
|
|
65
|
+
|
|
66
|
+
| Chart | Type | What It Shows |
|
|
67
|
+
|-------|------|---------------|
|
|
68
|
+
| **Sessions Per Day** | Bar (compact) | Daily session activity over time |
|
|
69
|
+
| **Activity by Hour of Day** | Bar (compact) | When during the day you use Copilot most |
|
|
70
|
+
| **Tool Usage** | Doughnut | Most-used tools (grep, edit, powershell, etc.) |
|
|
71
|
+
| **Model Usage** | Doughnut | Which AI models you've used (Claude, GPT, etc.) |
|
|
72
|
+
| **Top Working Directories** | Horizontal bar (full-width) | Which project folders you use Copilot in most |
|
|
73
|
+
| **Time Per Branch** | Horizontal bar | Active Copilot time spent on each git branch |
|
|
74
|
+
| **Time Per Repo** | Horizontal bar | Active Copilot time per repository |
|
|
75
|
+
| **MCP Servers Used** | Doughnut | Which MCP servers are configured across sessions |
|
|
76
|
+
|
|
77
|
+
Doughnut chart legends are interactive — click a label to toggle that segment's visibility.
|
|
78
|
+
|
|
79
|
+
#### Glimpse of Analytics Dashboard
|
|
80
|
+
|
|
81
|
+
<img width="1184" height="1011" alt="image" src="https://github.com/user-attachments/assets/136205ca-f206-4fb1-88a7-71640314a9b5" />
|
|
82
|
+
|
|
39
83
|
|
|
40
|
-
|
|
84
|
+
### 🎨 UI Features
|
|
41
85
|
|
|
42
|
-
|
|
86
|
+
- **Dark & Light mode** — toggle with one click, preference is saved
|
|
87
|
+
- **Manual refresh** — refresh button to reload data on demand
|
|
88
|
+
- **Responsive layout** — works on any screen size
|
|
89
|
+
- **2-column grid layout** — compact charts with no wasted space
|
|
90
|
+
|
|
91
|
+
## How It Works
|
|
92
|
+
|
|
93
|
+
Copilot Lens reads session data from `~/.copilot/session-state/`, where GitHub Copilot CLI stores:
|
|
94
|
+
|
|
95
|
+
- **`workspace.yaml`** — Session metadata (directory, git branch, timestamps)
|
|
96
|
+
- **`events.jsonl`** — Full event log (messages, tool calls, errors)
|
|
97
|
+
- **`plan.md`** — Session plans (if created)
|
|
98
|
+
|
|
99
|
+
A local Express server parses these files and serves a static frontend dashboard.
|
|
100
|
+
|
|
101
|
+
### Duration Calculation
|
|
102
|
+
|
|
103
|
+
Session durations are calculated from **actual event activity**, not wall-clock time. Gaps longer than 5 minutes between events are excluded, so resumed sessions don't show inflated durations.
|
|
104
|
+
|
|
105
|
+
### Status Detection
|
|
106
|
+
|
|
107
|
+
| Status | How It's Detected |
|
|
108
|
+
|--------|-------------------|
|
|
109
|
+
| **Running** | `session.db` exists and was modified within 10 min, or `events.jsonl` modified within 5 min |
|
|
110
|
+
| **Completed** | Has an `abort` event with "user initiated" reason, or no recent activity |
|
|
111
|
+
| **Error** | Has an `abort` event with a non-user-initiated reason |
|
|
112
|
+
|
|
113
|
+
## Tech Stack
|
|
114
|
+
|
|
115
|
+
- **Backend**: Node.js + Express + TypeScript
|
|
116
|
+
- **Frontend**: Vanilla HTML/CSS/JavaScript
|
|
117
|
+
- **Charts**: Chart.js
|
|
118
|
+
- **Data**: YAML + JSONL parsing (no database required)
|
|
119
|
+
|
|
120
|
+
## Development
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
git clone https://github.com/pavanvamsi3/copilot-lens.git
|
|
124
|
+
cd copilot-lens
|
|
125
|
+
npm install
|
|
126
|
+
npm run dev # Start with tsx (no build needed)
|
|
127
|
+
npm run build # Compile TypeScript
|
|
128
|
+
npm start # Run compiled version
|
|
129
|
+
```
|
|
43
130
|
|
|
44
131
|
## License
|
|
45
132
|
|
|
@@ -53,3 +140,4 @@ If you'd like a prettier URL like `http://copilot.lens:3000`, add this to your h
|
|
|
53
140
|
- **macOS/Linux**: `echo "127.0.0.1 copilot.lens" | sudo tee -a /etc/hosts`
|
|
54
141
|
|
|
55
142
|
Then run: `copilot-lens --host copilot.lens`
|
|
143
|
+
|
package/dist/sessions.d.ts
CHANGED
|
@@ -33,7 +33,17 @@ export interface AnalyticsData {
|
|
|
33
33
|
totalDuration: number;
|
|
34
34
|
toolUsage: Record<string, number>;
|
|
35
35
|
topDirectories: Record<string, number>;
|
|
36
|
-
|
|
36
|
+
branchTime: Record<string, number>;
|
|
37
|
+
repoTime: Record<string, number>;
|
|
38
|
+
modelUsage: Record<string, number>;
|
|
39
|
+
mcpServers: Record<string, number>;
|
|
40
|
+
toolSuccessRate: Record<string, {
|
|
41
|
+
success: number;
|
|
42
|
+
failure: number;
|
|
43
|
+
}>;
|
|
44
|
+
turnsPerSession: number[];
|
|
45
|
+
hourOfDay: Record<string, number>;
|
|
46
|
+
errorTypes: Record<string, number>;
|
|
37
47
|
}
|
|
38
48
|
export declare function listSessions(): SessionMeta[];
|
|
39
49
|
export declare function getSession(sessionId: string): SessionDetail | null;
|
package/dist/sessions.js
CHANGED
|
@@ -45,12 +45,19 @@ function getSessionDir() {
|
|
|
45
45
|
}
|
|
46
46
|
function detectStatus(sessionDir, _updatedAt) {
|
|
47
47
|
try {
|
|
48
|
-
// session.db only exists for actively running sessions — strongest signal
|
|
49
|
-
if (fs.existsSync(path.join(sessionDir, "session.db")))
|
|
50
|
-
return "running";
|
|
51
48
|
const eventsPath = path.join(sessionDir, "events.jsonl");
|
|
52
|
-
|
|
49
|
+
// Check session.db + recent activity (session.db can be stale if not cleaned up)
|
|
50
|
+
const dbPath = path.join(sessionDir, "session.db");
|
|
51
|
+
if (fs.existsSync(dbPath)) {
|
|
52
|
+
const dbAge = Date.now() - fs.statSync(dbPath).mtimeMs;
|
|
53
|
+
if (dbAge < 600000)
|
|
54
|
+
return "running"; // session.db modified within 10 min
|
|
55
|
+
}
|
|
56
|
+
if (!fs.existsSync(eventsPath)) {
|
|
57
|
+
// No events yet — only "running" if session.db exists (checked above)
|
|
58
|
+
// A workspace.yaml alone with no events means the session was never active
|
|
53
59
|
return "completed";
|
|
60
|
+
}
|
|
54
61
|
// Only read the last 2KB to check for abort events (avoid reading huge files)
|
|
55
62
|
const stat = fs.statSync(eventsPath);
|
|
56
63
|
const readSize = Math.min(stat.size, 2048);
|
|
@@ -70,7 +77,7 @@ function detectStatus(sessionDir, _updatedAt) {
|
|
|
70
77
|
}
|
|
71
78
|
catch { }
|
|
72
79
|
}
|
|
73
|
-
// No abort — check if recently modified
|
|
80
|
+
// No abort — check if events.jsonl recently modified
|
|
74
81
|
const age = Date.now() - stat.mtimeMs;
|
|
75
82
|
if (age < 300000)
|
|
76
83
|
return "running";
|
|
@@ -165,10 +172,18 @@ function getSession(sessionId) {
|
|
|
165
172
|
for (const e of events) {
|
|
166
173
|
eventCounts[e.type] = (eventCounts[e.type] || 0) + 1;
|
|
167
174
|
}
|
|
168
|
-
// Calculate duration
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
|
|
175
|
+
// Calculate active duration from event timestamps (cap gaps at 5 min)
|
|
176
|
+
let duration = 0;
|
|
177
|
+
const timestamps = events
|
|
178
|
+
.map((e) => new Date(e.timestamp).getTime())
|
|
179
|
+
.filter((t) => t > 0)
|
|
180
|
+
.sort((a, b) => a - b);
|
|
181
|
+
if (timestamps.length >= 2) {
|
|
182
|
+
const MAX_GAP = 300000;
|
|
183
|
+
for (let i = 1; i < timestamps.length; i++) {
|
|
184
|
+
duration += Math.min(timestamps[i] - timestamps[i - 1], MAX_GAP);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
172
187
|
return {
|
|
173
188
|
id: ws.id || sessionId,
|
|
174
189
|
cwd: ws.cwd || "",
|
|
@@ -191,7 +206,14 @@ function getAnalytics() {
|
|
|
191
206
|
const sessionsPerDay = {};
|
|
192
207
|
const toolUsage = {};
|
|
193
208
|
const topDirectories = {};
|
|
194
|
-
const
|
|
209
|
+
const branchTime = {};
|
|
210
|
+
const repoTime = {};
|
|
211
|
+
const modelUsage = {};
|
|
212
|
+
const mcpServers = {};
|
|
213
|
+
const toolSuccessRate = {};
|
|
214
|
+
const turnsPerSession = [];
|
|
215
|
+
const hourOfDay = {};
|
|
216
|
+
const errorTypes = {};
|
|
195
217
|
const durations = [];
|
|
196
218
|
const sessionDir = getSessionDir();
|
|
197
219
|
for (const s of sessions) {
|
|
@@ -199,33 +221,104 @@ function getAnalytics() {
|
|
|
199
221
|
const day = s.createdAt.slice(0, 10);
|
|
200
222
|
if (day)
|
|
201
223
|
sessionsPerDay[day] = (sessionsPerDay[day] || 0) + 1;
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
224
|
+
// Hour of day
|
|
225
|
+
try {
|
|
226
|
+
const hour = new Date(s.createdAt).getHours().toString().padStart(2, "0") + ":00";
|
|
227
|
+
hourOfDay[hour] = (hourOfDay[hour] || 0) + 1;
|
|
228
|
+
}
|
|
229
|
+
catch { }
|
|
230
|
+
// Duration — calculated from actual event activity, not updated_at - created_at
|
|
231
|
+
// (sessions can be resumed days later, inflating the duration)
|
|
232
|
+
// Computed below after scanning events.jsonl
|
|
206
233
|
// Top directories
|
|
207
234
|
const dirName = s.cwd || "unknown";
|
|
208
235
|
topDirectories[dirName] = (topDirectories[dirName] || 0) + 1;
|
|
209
236
|
// Branch activity
|
|
210
237
|
const branch = s.branch || "unknown";
|
|
211
|
-
|
|
212
|
-
// Tool usage — scan events.jsonl line by line without loading full detail
|
|
238
|
+
// Scan events.jsonl for all metrics
|
|
213
239
|
try {
|
|
214
240
|
const eventsPath = path.join(sessionDir, s.id, "events.jsonl");
|
|
215
241
|
if (fs.existsSync(eventsPath)) {
|
|
216
242
|
const content = fs.readFileSync(eventsPath, "utf-8");
|
|
243
|
+
let turnCount = 0;
|
|
244
|
+
const timestamps = [];
|
|
217
245
|
for (const line of content.split("\n")) {
|
|
218
|
-
if (!line.
|
|
246
|
+
if (!line.trim())
|
|
219
247
|
continue;
|
|
220
248
|
try {
|
|
221
249
|
const event = JSON.parse(line);
|
|
250
|
+
// Collect timestamps for active duration
|
|
251
|
+
if (event.timestamp) {
|
|
252
|
+
const t = new Date(event.timestamp).getTime();
|
|
253
|
+
if (t > 0)
|
|
254
|
+
timestamps.push(t);
|
|
255
|
+
}
|
|
256
|
+
// Tool usage
|
|
222
257
|
if (event.type === "tool.execution_start") {
|
|
223
258
|
const tool = event.data?.tool || event.data?.toolName || "unknown";
|
|
224
259
|
toolUsage[tool] = (toolUsage[tool] || 0) + 1;
|
|
225
260
|
}
|
|
261
|
+
// Tool success rate
|
|
262
|
+
if (event.type === "tool.execution_complete") {
|
|
263
|
+
const tool = event.data?.tool || event.data?.toolName || "unknown";
|
|
264
|
+
if (!toolSuccessRate[tool])
|
|
265
|
+
toolSuccessRate[tool] = { success: 0, failure: 0 };
|
|
266
|
+
if (event.data?.success)
|
|
267
|
+
toolSuccessRate[tool].success++;
|
|
268
|
+
else
|
|
269
|
+
toolSuccessRate[tool].failure++;
|
|
270
|
+
}
|
|
271
|
+
// MCP servers
|
|
272
|
+
if (event.type === "session.info" && event.data?.infoType === "mcp") {
|
|
273
|
+
const msg = event.data?.message || "";
|
|
274
|
+
const match = msg.match(/Configured MCP servers?:\s*(.+)/i);
|
|
275
|
+
if (match) {
|
|
276
|
+
for (const server of match[1].split(",").map((s) => s.trim())) {
|
|
277
|
+
if (server)
|
|
278
|
+
mcpServers[server] = (mcpServers[server] || 0) + 1;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
// Model usage
|
|
283
|
+
if (event.type === "session.info" && event.data?.infoType === "model") {
|
|
284
|
+
const msg = event.data?.message || "";
|
|
285
|
+
const match = msg.match(/Model changed to:\s*([^\s.]+(?:[-.][^\s.]+)*)/i);
|
|
286
|
+
if (match)
|
|
287
|
+
modelUsage[match[1]] = (modelUsage[match[1]] || 0) + 1;
|
|
288
|
+
}
|
|
289
|
+
if (event.type === "session.start" && event.data?.model) {
|
|
290
|
+
const model = event.data.model;
|
|
291
|
+
modelUsage[model] = (modelUsage[model] || 0) + 1;
|
|
292
|
+
}
|
|
293
|
+
// Turn counting
|
|
294
|
+
if (event.type === "assistant.turn_start")
|
|
295
|
+
turnCount++;
|
|
296
|
+
// Errors
|
|
297
|
+
if (event.type === "session.error") {
|
|
298
|
+
const errType = event.data?.errorType || "unknown";
|
|
299
|
+
errorTypes[errType] = (errorTypes[errType] || 0) + 1;
|
|
300
|
+
}
|
|
226
301
|
}
|
|
227
302
|
catch { }
|
|
228
303
|
}
|
|
304
|
+
if (turnCount > 0)
|
|
305
|
+
turnsPerSession.push(turnCount);
|
|
306
|
+
// Calculate active duration: sum gaps between events, cap each gap at 5 min
|
|
307
|
+
if (timestamps.length >= 2) {
|
|
308
|
+
timestamps.sort((a, b) => a - b);
|
|
309
|
+
let activeDur = 0;
|
|
310
|
+
const MAX_GAP = 300000; // 5 minutes
|
|
311
|
+
for (let i = 1; i < timestamps.length; i++) {
|
|
312
|
+
const gap = timestamps[i] - timestamps[i - 1];
|
|
313
|
+
activeDur += Math.min(gap, MAX_GAP);
|
|
314
|
+
}
|
|
315
|
+
if (activeDur > 0) {
|
|
316
|
+
durations.push(activeDur);
|
|
317
|
+
branchTime[branch] = (branchTime[branch] || 0) + activeDur;
|
|
318
|
+
const repo = s.gitRoot || s.cwd || "unknown";
|
|
319
|
+
repoTime[repo] = (repoTime[repo] || 0) + activeDur;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
229
322
|
}
|
|
230
323
|
}
|
|
231
324
|
catch { }
|
|
@@ -240,7 +333,14 @@ function getAnalytics() {
|
|
|
240
333
|
totalDuration,
|
|
241
334
|
toolUsage,
|
|
242
335
|
topDirectories,
|
|
243
|
-
|
|
336
|
+
branchTime,
|
|
337
|
+
repoTime,
|
|
338
|
+
modelUsage,
|
|
339
|
+
mcpServers,
|
|
340
|
+
toolSuccessRate,
|
|
341
|
+
turnsPerSession,
|
|
342
|
+
hourOfDay,
|
|
343
|
+
errorTypes,
|
|
244
344
|
};
|
|
245
345
|
}
|
|
246
346
|
//# sourceMappingURL=sessions.js.map
|
package/dist/sessions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../src/sessions.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../src/sessions.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwGA,oCAoCC;AAED,gCAqFC;AAED,oCAgJC;AArXD,uCAAyB;AACzB,2CAA6B;AAC7B,uCAAyB;AACzB,+BAA0C;AAmD1C,SAAS,aAAa;IACpB,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,YAAY,CAAC,UAAkB,EAAE,UAAkB;IAC1D,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;QAEzD,iFAAiF;QACjF,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;QACnD,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACvD,IAAI,KAAK,GAAG,MAAO;gBAAE,OAAO,SAAS,CAAC,CAAC,oCAAoC;QAC7E,CAAC;QAED,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/B,sEAAsE;YACtE,2EAA2E;YAC3E,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,8EAA8E;QAC9E,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC3C,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QACxC,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC;QACrE,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAEjB,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEzD,yCAAyC;QACzC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC/B,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBAC3B,OAAO,KAAK,CAAC,IAAI,EAAE,MAAM,KAAK,gBAAgB,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC;gBACzE,CAAC;YACH,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACZ,CAAC;QAED,qDAAqD;QACrD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QACtC,IAAI,GAAG,GAAG,MAAO;YAAE,OAAO,SAAS,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,SAAgB,YAAY;IAC1B,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAEnC,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAkB,EAAE,CAAC;IAEnC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;YAAE,SAAS;QACnC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;QAC5D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,SAAS;QAErC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC7C,MAAM,EAAE,GAAG,IAAA,YAAS,EAAC,GAAG,CAAC,CAAC;YAC1B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAC/C,MAAM,SAAS,GAAG,EAAE,CAAC,UAAU,IAAI,EAAE,CAAC;YACtC,QAAQ,CAAC,IAAI,CAAC;gBACZ,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,KAAK,CAAC,IAAI;gBACvB,GAAG,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE;gBACjB,OAAO,EAAE,EAAE,CAAC,QAAQ;gBACpB,MAAM,EAAE,EAAE,CAAC,MAAM;gBACjB,SAAS,EAAE,EAAE,CAAC,UAAU,IAAI,EAAE;gBAC9B,SAAS;gBACT,YAAY,EAAE,EAAE,CAAC,aAAa;gBAC9B,MAAM,EAAE,YAAY,CAAC,WAAW,EAAE,SAAS,CAAC;aAC7C,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,uBAAuB;QACzB,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,IAAI,CACX,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAC5E,CAAC;IACF,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAgB,UAAU,CAAC,SAAiB;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,SAAS,CAAC,CAAC;IAClD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAErC,uBAAuB;IACvB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;IAChD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAExC,IAAI,EAAO,CAAC;IACZ,IAAI,CAAC;QACH,EAAE,GAAG,IAAA,YAAS,EAAC,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,qBAAqB;IACrB,MAAM,MAAM,GAAmB,EAAE,CAAC;IAClC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAClD,IAAI,CAAC;QACH,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC/D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;oBAAE,SAAS;gBAC3B,IAAI,CAAC;oBACH,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;gBAChC,CAAC;gBAAC,MAAM,CAAC;oBACP,uBAAuB;gBACzB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,uCAAuC;IACzC,CAAC;IAED,eAAe;IACf,IAAI,WAA+B,CAAC;IACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAC3C,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,WAAW,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACnD,CAAC;IAED,kBAAkB;IAClB,MAAM,YAAY,GAAG,EAAE,CAAC,UAAU,CAChC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAkB,EAAE,YAAY,CAAC,CACjD,CAAC;IAEF,mDAAmD;IACnD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC;IAClE,MAAM,cAAc,GAAG,UAAU,EAAE,IAAI,EAAE,cAAc,CAAC;IAExD,uBAAuB;IACvB,MAAM,WAAW,GAA2B,EAAE,CAAC;IAC/C,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IACvD,CAAC;IAED,sEAAsE;IACtE,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,MAAM,UAAU,GAAG,MAAM;SACtB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;SAC3C,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;SACpB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACzB,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,MAAO,CAAC;QACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3C,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAED,OAAO;QACL,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,SAAS;QACtB,GAAG,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE;QACjB,OAAO,EAAE,EAAE,CAAC,QAAQ;QACpB,MAAM,EAAE,EAAE,CAAC,MAAM;QACjB,SAAS,EAAE,EAAE,CAAC,UAAU,IAAI,EAAE;QAC9B,SAAS,EAAE,EAAE,CAAC,UAAU,IAAI,EAAE;QAC9B,YAAY,EAAE,EAAE,CAAC,aAAa;QAC9B,MAAM;QACN,WAAW;QACX,YAAY;QACZ,cAAc;QACd,WAAW;QACX,QAAQ;QACR,MAAM,EAAE,YAAY,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,IAAI,EAAE,CAAC;KAC/C,CAAC;AACJ,CAAC;AAED,SAAgB,YAAY;IAC1B,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAChC,MAAM,cAAc,GAA2B,EAAE,CAAC;IAClD,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,MAAM,cAAc,GAA2B,EAAE,CAAC;IAClD,MAAM,UAAU,GAA2B,EAAE,CAAC;IAC9C,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAC5C,MAAM,UAAU,GAA2B,EAAE,CAAC;IAC9C,MAAM,UAAU,GAA2B,EAAE,CAAC;IAC9C,MAAM,eAAe,GAAyD,EAAE,CAAC;IACjF,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,MAAM,UAAU,GAA2B,EAAE,CAAC;IAC9C,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IAEnC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,mBAAmB;QACnB,MAAM,GAAG,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrC,IAAI,GAAG;YAAE,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAE9D,cAAc;QACd,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC;YAClF,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QAEV,gFAAgF;QAChF,+DAA+D;QAC/D,6CAA6C;QAE7C,kBAAkB;QAClB,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,IAAI,SAAS,CAAC;QACnC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAE7D,kBAAkB;QAClB,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,IAAI,SAAS,CAAC;QAErC,oCAAoC;QACpC,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,cAAc,CAAC,CAAC;YAC/D,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC9B,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;gBACrD,IAAI,SAAS,GAAG,CAAC,CAAC;gBAClB,MAAM,UAAU,GAAa,EAAE,CAAC;gBAChC,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;oBACvC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;wBAAE,SAAS;oBAC3B,IAAI,CAAC;wBACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;wBAE/B,yCAAyC;wBACzC,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;4BACpB,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;4BAC9C,IAAI,CAAC,GAAG,CAAC;gCAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;wBAChC,CAAC;wBAED,aAAa;wBACb,IAAI,KAAK,CAAC,IAAI,KAAK,sBAAsB,EAAE,CAAC;4BAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,QAAQ,IAAI,SAAS,CAAC;4BACnE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;wBAC/C,CAAC;wBAED,oBAAoB;wBACpB,IAAI,KAAK,CAAC,IAAI,KAAK,yBAAyB,EAAE,CAAC;4BAC7C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,QAAQ,IAAI,SAAS,CAAC;4BACnE,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;gCAAE,eAAe,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;4BAC/E,IAAI,KAAK,CAAC,IAAI,EAAE,OAAO;gCAAE,eAAe,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;;gCACpD,eAAe,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;wBACvC,CAAC;wBAED,cAAc;wBACd,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,KAAK,CAAC,IAAI,EAAE,QAAQ,KAAK,KAAK,EAAE,CAAC;4BACpE,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC;4BACtC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;4BAC5D,IAAI,KAAK,EAAE,CAAC;gCACV,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;oCACtE,IAAI,MAAM;wCAAE,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;gCACjE,CAAC;4BACH,CAAC;wBACH,CAAC;wBAED,cAAc;wBACd,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,KAAK,CAAC,IAAI,EAAE,QAAQ,KAAK,OAAO,EAAE,CAAC;4BACtE,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC;4BACtC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;4BAC1E,IAAI,KAAK;gCAAE,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;wBACpE,CAAC;wBACD,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;4BACxD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;4BAC/B,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;wBACnD,CAAC;wBAED,gBAAgB;wBAChB,IAAI,KAAK,CAAC,IAAI,KAAK,sBAAsB;4BAAE,SAAS,EAAE,CAAC;wBAEvD,SAAS;wBACT,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;4BACnC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,SAAS,IAAI,SAAS,CAAC;4BACnD,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;wBACvD,CAAC;oBACH,CAAC;oBAAC,MAAM,CAAC,CAAA,CAAC;gBACZ,CAAC;gBACD,IAAI,SAAS,GAAG,CAAC;oBAAE,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAEnD,4EAA4E;gBAC5E,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;oBAC3B,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;oBACjC,IAAI,SAAS,GAAG,CAAC,CAAC;oBAClB,MAAM,OAAO,GAAG,MAAO,CAAC,CAAC,YAAY;oBACrC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;wBAC3C,MAAM,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;wBAC9C,SAAS,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;oBACtC,CAAC;oBACD,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;wBAClB,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;wBAC1B,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;wBAC3D,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,IAAI,SAAS,CAAC;wBAC7C,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;oBACrD,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IAED,MAAM,aAAa,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAE3D,OAAO;QACL,aAAa,EAAE,QAAQ,CAAC,MAAM;QAC9B,cAAc;QACd,WAAW,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACpE,WAAW,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1D,WAAW,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1D,aAAa;QACb,SAAS;QACT,cAAc;QACd,UAAU;QACV,QAAQ;QACR,UAAU;QACV,UAAU;QACV,eAAe;QACf,eAAe;QACf,SAAS;QACT,UAAU;KACX,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "copilot-lens",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "A local dashboard to visualize and analyze your GitHub Copilot CLI sessions",
|
|
5
5
|
"main": "dist/server.js",
|
|
6
6
|
"bin": {
|
|
@@ -12,14 +12,25 @@
|
|
|
12
12
|
"start": "node dist/cli.js",
|
|
13
13
|
"prepublishOnly": "npm run build"
|
|
14
14
|
},
|
|
15
|
-
"keywords": [
|
|
15
|
+
"keywords": [
|
|
16
|
+
"copilot",
|
|
17
|
+
"github",
|
|
18
|
+
"cli",
|
|
19
|
+
"dashboard",
|
|
20
|
+
"sessions",
|
|
21
|
+
"analytics"
|
|
22
|
+
],
|
|
16
23
|
"author": "pavanvamsi3",
|
|
17
24
|
"license": "MIT",
|
|
18
25
|
"repository": {
|
|
19
26
|
"type": "git",
|
|
20
27
|
"url": "https://github.com/pavanvamsi3/copilot-lens"
|
|
21
28
|
},
|
|
22
|
-
"files": [
|
|
29
|
+
"files": [
|
|
30
|
+
"dist/",
|
|
31
|
+
"public/",
|
|
32
|
+
"README.md"
|
|
33
|
+
],
|
|
23
34
|
"dependencies": {
|
|
24
35
|
"cors": "^2.8.6",
|
|
25
36
|
"express": "^5.2.1",
|
package/public/app.js
CHANGED
|
@@ -39,6 +39,7 @@ const detailModal = document.getElementById("detailModal");
|
|
|
39
39
|
const detailContent = document.getElementById("detailContent");
|
|
40
40
|
const modalClose = document.getElementById("modalClose");
|
|
41
41
|
const refreshBtn = document.getElementById("refreshBtn");
|
|
42
|
+
const statsCards = document.getElementById("statsCards");
|
|
42
43
|
|
|
43
44
|
// Navigation
|
|
44
45
|
document.querySelectorAll(".nav-btn").forEach((btn) => {
|
|
@@ -181,7 +182,7 @@ function renderDetail(s) {
|
|
|
181
182
|
|
|
182
183
|
// Interleave conversation messages in order
|
|
183
184
|
const conversation = s.events
|
|
184
|
-
.filter((e) => e.type === "user.message" || e.type === "assistant.message")
|
|
185
|
+
.filter((e) => (e.type === "user.message" || e.type === "assistant.message") && (e.data?.content || "").trim())
|
|
185
186
|
.map((e) => {
|
|
186
187
|
const isUser = e.type === "user.message";
|
|
187
188
|
const content = e.data?.content || "";
|
|
@@ -222,7 +223,9 @@ function renderDetail(s) {
|
|
|
222
223
|
</div>
|
|
223
224
|
|
|
224
225
|
<div class="detail-panel active" id="panel-conversation">
|
|
226
|
+
<div class="conversation-list">
|
|
225
227
|
${conversation || '<div style="color:var(--text-dim)">No messages in this session</div>'}
|
|
228
|
+
</div>
|
|
226
229
|
</div>
|
|
227
230
|
|
|
228
231
|
<div class="detail-panel" id="panel-tools">
|
|
@@ -299,6 +302,9 @@ function renderCharts() {
|
|
|
299
302
|
charts = {};
|
|
300
303
|
|
|
301
304
|
const chartColors = ["#58a6ff", "#3fb950", "#d29922", "#f85149", "#bc8cff", "#f0883e", "#56d4dd", "#db61a2"];
|
|
305
|
+
const isLight = document.documentElement.getAttribute("data-theme") === "light";
|
|
306
|
+
const tickColor = isLight ? "#656d76" : "#8b949e";
|
|
307
|
+
const legendColor = isLight ? "#1f2328" : "#e6edf3";
|
|
302
308
|
|
|
303
309
|
// Sessions per day
|
|
304
310
|
const days = Object.keys(analytics.sessionsPerDay).sort();
|
|
@@ -308,7 +314,7 @@ function renderCharts() {
|
|
|
308
314
|
labels: days.map((d) => d.slice(5)), // MM-DD
|
|
309
315
|
datasets: [{ label: "Sessions", data: days.map((d) => analytics.sessionsPerDay[d]), backgroundColor: "#58a6ff88", borderColor: "#58a6ff", borderWidth: 1 }],
|
|
310
316
|
},
|
|
311
|
-
options: { responsive: true, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, ticks: { color:
|
|
317
|
+
options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, ticks: { color: tickColor } }, x: { ticks: { color: tickColor } } } },
|
|
312
318
|
});
|
|
313
319
|
|
|
314
320
|
// Tool usage (top 10)
|
|
@@ -322,7 +328,7 @@ function renderCharts() {
|
|
|
322
328
|
labels: tools.map((t) => t[0]),
|
|
323
329
|
datasets: [{ data: tools.map((t) => t[1]), backgroundColor: chartColors }],
|
|
324
330
|
},
|
|
325
|
-
options: { responsive: true, plugins: { legend: { position: "
|
|
331
|
+
options: { responsive: true, plugins: { legend: { position: "bottom", labels: { color: legendColor, font: { size: 13 }, padding: 14, boxWidth: 14 } } } },
|
|
326
332
|
});
|
|
327
333
|
}
|
|
328
334
|
|
|
@@ -337,12 +343,12 @@ function renderCharts() {
|
|
|
337
343
|
labels: dirs.map((d) => shortDir(d[0])),
|
|
338
344
|
datasets: [{ label: "Sessions", data: dirs.map((d) => d[1]), backgroundColor: "#3fb95088", borderColor: "#3fb950", borderWidth: 1 }],
|
|
339
345
|
},
|
|
340
|
-
options: { indexAxis: "y", responsive: true, plugins: { legend: { display: false } }, scales: { x: { beginAtZero: true, ticks: { color:
|
|
346
|
+
options: { indexAxis: "y", responsive: true, plugins: { legend: { display: false } }, scales: { x: { beginAtZero: true, ticks: { color: tickColor } }, y: { ticks: { color: tickColor, font: { size: 12 } } } } },
|
|
341
347
|
});
|
|
342
348
|
}
|
|
343
349
|
|
|
344
|
-
// Branch
|
|
345
|
-
const branches = Object.entries(analytics.
|
|
350
|
+
// Branch time (top 8)
|
|
351
|
+
const branches = Object.entries(analytics.branchTime || {})
|
|
346
352
|
.sort((a, b) => b[1] - a[1])
|
|
347
353
|
.slice(0, 8);
|
|
348
354
|
if (branches.length) {
|
|
@@ -350,11 +356,68 @@ function renderCharts() {
|
|
|
350
356
|
type: "bar",
|
|
351
357
|
data: {
|
|
352
358
|
labels: branches.map((b) => b[0]),
|
|
353
|
-
datasets: [{ label: "
|
|
359
|
+
datasets: [{ label: "Time", data: branches.map((b) => Math.round(b[1] / 60000)), backgroundColor: "#d2992288", borderColor: "#d29922", borderWidth: 1 }],
|
|
360
|
+
},
|
|
361
|
+
options: { indexAxis: "y", responsive: true, plugins: { legend: { display: false }, tooltip: { callbacks: { label: (ctx) => formatDuration(ctx.raw * 60000) } } }, scales: { x: { beginAtZero: true, title: { display: true, text: "minutes", color: tickColor }, ticks: { color: tickColor } }, y: { ticks: { color: tickColor, font: { size: 12 } } } } },
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Time per repo (top 8)
|
|
366
|
+
const repos = Object.entries(analytics.repoTime || {})
|
|
367
|
+
.sort((a, b) => b[1] - a[1])
|
|
368
|
+
.slice(0, 8);
|
|
369
|
+
if (repos.length) {
|
|
370
|
+
charts.repoTime = new Chart(document.getElementById("repoTimeChart"), {
|
|
371
|
+
type: "bar",
|
|
372
|
+
data: {
|
|
373
|
+
labels: repos.map((r) => shortDir(r[0])),
|
|
374
|
+
datasets: [{ label: "Time", data: repos.map((r) => Math.round(r[1] / 60000)), backgroundColor: "#3fb95088", borderColor: "#3fb950", borderWidth: 1 }],
|
|
375
|
+
},
|
|
376
|
+
options: { indexAxis: "y", responsive: true, plugins: { legend: { display: false }, tooltip: { callbacks: { label: (ctx) => formatDuration(ctx.raw * 60000) } } }, scales: { x: { beginAtZero: true, title: { display: true, text: "minutes", color: tickColor }, ticks: { color: tickColor } }, y: { ticks: { color: tickColor, font: { size: 12 } } } } },
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// MCP Servers
|
|
381
|
+
const mcpEntries = Object.entries(analytics.mcpServers || {}).sort((a, b) => b[1] - a[1]);
|
|
382
|
+
if (mcpEntries.length) {
|
|
383
|
+
charts.mcp = new Chart(document.getElementById("mcpChart"), {
|
|
384
|
+
type: "doughnut",
|
|
385
|
+
data: {
|
|
386
|
+
labels: mcpEntries.map((m) => m[0]),
|
|
387
|
+
datasets: [{ data: mcpEntries.map((m) => m[1]), backgroundColor: chartColors }],
|
|
354
388
|
},
|
|
355
|
-
options: {
|
|
389
|
+
options: { responsive: true, plugins: { legend: { position: "bottom", labels: { color: legendColor, font: { size: 13 }, padding: 14, boxWidth: 14 } } } },
|
|
356
390
|
});
|
|
391
|
+
} else {
|
|
392
|
+
document.getElementById("mcpChart").parentElement.innerHTML = '<h3>MCP Servers Used</h3><div style="color:var(--text-dim);padding:40px;text-align:center">No MCP servers detected</div>';
|
|
357
393
|
}
|
|
394
|
+
|
|
395
|
+
// Model Usage
|
|
396
|
+
const models = Object.entries(analytics.modelUsage || {}).sort((a, b) => b[1] - a[1]);
|
|
397
|
+
if (models.length) {
|
|
398
|
+
charts.model = new Chart(document.getElementById("modelChart"), {
|
|
399
|
+
type: "doughnut",
|
|
400
|
+
data: {
|
|
401
|
+
labels: models.map((m) => m[0]),
|
|
402
|
+
datasets: [{ data: models.map((m) => m[1]), backgroundColor: chartColors }],
|
|
403
|
+
},
|
|
404
|
+
options: { responsive: true, plugins: { legend: { position: "bottom", labels: { color: legendColor, font: { size: 13 }, padding: 14, boxWidth: 14 } } } },
|
|
405
|
+
});
|
|
406
|
+
} else {
|
|
407
|
+
document.getElementById("modelChart").parentElement.innerHTML = '<h3>Model Usage</h3><div style="color:var(--text-dim);padding:40px;text-align:center">No model data detected</div>';
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Activity by Hour of Day
|
|
411
|
+
const hours = analytics.hourOfDay || {};
|
|
412
|
+
const allHours = Array.from({ length: 24 }, (_, i) => i.toString().padStart(2, "0") + ":00");
|
|
413
|
+
charts.hour = new Chart(document.getElementById("hourChart"), {
|
|
414
|
+
type: "bar",
|
|
415
|
+
data: {
|
|
416
|
+
labels: allHours.map((h) => h.slice(0, 2)),
|
|
417
|
+
datasets: [{ label: "Sessions", data: allHours.map((h) => hours[h] || 0), backgroundColor: "#56d4dd88", borderColor: "#56d4dd", borderWidth: 1 }],
|
|
418
|
+
},
|
|
419
|
+
options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, ticks: { color: tickColor } }, x: { ticks: { color: tickColor } } } },
|
|
420
|
+
});
|
|
358
421
|
}
|
|
359
422
|
|
|
360
423
|
// Data loading
|
|
@@ -394,5 +457,24 @@ refreshBtn.addEventListener("click", () => {
|
|
|
394
457
|
setTimeout(() => refreshBtn.classList.remove("spinning"), 600);
|
|
395
458
|
});
|
|
396
459
|
|
|
460
|
+
// Theme toggle
|
|
461
|
+
const themeToggle = document.getElementById("themeToggle");
|
|
462
|
+
const savedTheme = localStorage.getItem("copilot-lens-theme");
|
|
463
|
+
if (savedTheme === "light") document.documentElement.setAttribute("data-theme", "light");
|
|
464
|
+
themeToggle.textContent = document.documentElement.getAttribute("data-theme") === "light" ? "🌙" : "☀️";
|
|
465
|
+
|
|
466
|
+
themeToggle.addEventListener("click", () => {
|
|
467
|
+
const isLight = document.documentElement.getAttribute("data-theme") === "light";
|
|
468
|
+
if (isLight) {
|
|
469
|
+
document.documentElement.removeAttribute("data-theme");
|
|
470
|
+
localStorage.setItem("copilot-lens-theme", "dark");
|
|
471
|
+
themeToggle.textContent = "☀️";
|
|
472
|
+
} else {
|
|
473
|
+
document.documentElement.setAttribute("data-theme", "light");
|
|
474
|
+
localStorage.setItem("copilot-lens-theme", "light");
|
|
475
|
+
themeToggle.textContent = "🌙";
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
|
|
397
479
|
// Init
|
|
398
480
|
loadSessions();
|
package/public/index.html
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
<button class="nav-btn" data-page="analytics">Analytics</button>
|
|
16
16
|
</nav>
|
|
17
17
|
<button class="refresh-btn" id="refreshBtn" title="Refresh data">⟳ Refresh</button>
|
|
18
|
+
<button class="refresh-btn" id="themeToggle" title="Toggle light/dark mode">☀️</button>
|
|
18
19
|
</header>
|
|
19
20
|
|
|
20
21
|
<main>
|
|
@@ -46,22 +47,38 @@
|
|
|
46
47
|
<section id="analyticsPage" class="page">
|
|
47
48
|
<div class="stats-cards" id="statsCards"></div>
|
|
48
49
|
<div class="charts-grid">
|
|
49
|
-
<div class="chart-card">
|
|
50
|
+
<div class="chart-card compact">
|
|
50
51
|
<h3>Sessions Per Day</h3>
|
|
51
52
|
<canvas id="sessionsPerDayChart"></canvas>
|
|
52
53
|
</div>
|
|
54
|
+
<div class="chart-card compact">
|
|
55
|
+
<h3>Activity by Hour of Day</h3>
|
|
56
|
+
<canvas id="hourChart"></canvas>
|
|
57
|
+
</div>
|
|
53
58
|
<div class="chart-card">
|
|
54
59
|
<h3>Tool Usage</h3>
|
|
55
60
|
<canvas id="toolUsageChart"></canvas>
|
|
56
61
|
</div>
|
|
57
62
|
<div class="chart-card">
|
|
63
|
+
<h3>Model Usage</h3>
|
|
64
|
+
<canvas id="modelChart"></canvas>
|
|
65
|
+
</div>
|
|
66
|
+
<div class="chart-card full-width">
|
|
58
67
|
<h3>Top Working Directories</h3>
|
|
59
68
|
<canvas id="topDirsChart"></canvas>
|
|
60
69
|
</div>
|
|
61
70
|
<div class="chart-card">
|
|
62
|
-
<h3>Branch
|
|
71
|
+
<h3>Time Per Branch</h3>
|
|
63
72
|
<canvas id="branchChart"></canvas>
|
|
64
73
|
</div>
|
|
74
|
+
<div class="chart-card">
|
|
75
|
+
<h3>Time Per Repo</h3>
|
|
76
|
+
<canvas id="repoTimeChart"></canvas>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="chart-card">
|
|
79
|
+
<h3>MCP Servers Used</h3>
|
|
80
|
+
<canvas id="mcpChart"></canvas>
|
|
81
|
+
</div>
|
|
65
82
|
</div>
|
|
66
83
|
</section>
|
|
67
84
|
|
package/public/style.css
CHANGED
|
@@ -14,6 +14,19 @@
|
|
|
14
14
|
--radius: 8px;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
[data-theme="light"] {
|
|
18
|
+
--bg: #ffffff;
|
|
19
|
+
--surface: #f6f8fa;
|
|
20
|
+
--surface2: #eaeef2;
|
|
21
|
+
--border: #d0d7de;
|
|
22
|
+
--text: #1f2328;
|
|
23
|
+
--text-dim: #656d76;
|
|
24
|
+
--accent: #0969da;
|
|
25
|
+
--accent2: #1a7f37;
|
|
26
|
+
--danger: #cf222e;
|
|
27
|
+
--warning: #9a6700;
|
|
28
|
+
}
|
|
29
|
+
|
|
17
30
|
body {
|
|
18
31
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
19
32
|
background: var(--bg);
|
|
@@ -153,10 +166,10 @@ main { max-width: 1200px; margin: 0 auto; padding: 24px; }
|
|
|
153
166
|
font-weight: 600;
|
|
154
167
|
}
|
|
155
168
|
|
|
156
|
-
.badge-branch { background:
|
|
157
|
-
.badge-running { background:
|
|
158
|
-
.badge-completed { background:
|
|
159
|
-
.badge-error { background:
|
|
169
|
+
.badge-branch { background: color-mix(in srgb, var(--accent) 15%, var(--surface)); color: var(--accent); }
|
|
170
|
+
.badge-running { background: color-mix(in srgb, var(--accent2) 15%, var(--surface)); color: var(--accent2); }
|
|
171
|
+
.badge-completed { background: var(--surface2); color: var(--text-dim); }
|
|
172
|
+
.badge-error { background: color-mix(in srgb, var(--danger) 15%, var(--surface)); color: var(--danger); }
|
|
160
173
|
|
|
161
174
|
/* Stats Cards */
|
|
162
175
|
.stats-cards {
|
|
@@ -189,7 +202,7 @@ main { max-width: 1200px; margin: 0 auto; padding: 24px; }
|
|
|
189
202
|
/* Charts */
|
|
190
203
|
.charts-grid {
|
|
191
204
|
display: grid;
|
|
192
|
-
grid-template-columns: repeat(
|
|
205
|
+
grid-template-columns: repeat(2, 1fr);
|
|
193
206
|
gap: 16px;
|
|
194
207
|
}
|
|
195
208
|
|
|
@@ -198,6 +211,29 @@ main { max-width: 1200px; margin: 0 auto; padding: 24px; }
|
|
|
198
211
|
border: 1px solid var(--border);
|
|
199
212
|
border-radius: var(--radius);
|
|
200
213
|
padding: 20px;
|
|
214
|
+
min-height: 280px;
|
|
215
|
+
display: flex;
|
|
216
|
+
flex-direction: column;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.chart-card canvas {
|
|
220
|
+
flex: 1;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.chart-card.compact {
|
|
224
|
+
min-height: 200px;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.chart-card.compact canvas {
|
|
228
|
+
max-height: 150px;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.chart-card.full-width {
|
|
232
|
+
grid-column: 1 / -1;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
@media (max-width: 768px) {
|
|
236
|
+
.charts-grid { grid-template-columns: 1fr; }
|
|
201
237
|
}
|
|
202
238
|
|
|
203
239
|
.chart-card h3 {
|
|
@@ -293,30 +329,40 @@ main { max-width: 1200px; margin: 0 auto; padding: 24px; }
|
|
|
293
329
|
.detail-panel.active { display: block; }
|
|
294
330
|
|
|
295
331
|
/* Conversation */
|
|
332
|
+
.conversation-list {
|
|
333
|
+
display: flex;
|
|
334
|
+
flex-direction: column;
|
|
335
|
+
gap: 16px;
|
|
336
|
+
padding: 8px 0;
|
|
337
|
+
}
|
|
338
|
+
|
|
296
339
|
.message {
|
|
297
|
-
|
|
298
|
-
padding: 12px;
|
|
299
|
-
border-radius:
|
|
340
|
+
max-width: 75%;
|
|
341
|
+
padding: 12px 16px;
|
|
342
|
+
border-radius: 12px;
|
|
300
343
|
font-size: 0.85rem;
|
|
301
|
-
line-height: 1.
|
|
344
|
+
line-height: 1.6;
|
|
302
345
|
white-space: pre-wrap;
|
|
303
346
|
word-break: break-word;
|
|
304
347
|
}
|
|
305
348
|
|
|
306
349
|
.message-user {
|
|
307
|
-
|
|
308
|
-
|
|
350
|
+
align-self: flex-end;
|
|
351
|
+
background: color-mix(in srgb, var(--accent) 15%, var(--surface));
|
|
352
|
+
border-bottom-right-radius: 4px;
|
|
309
353
|
}
|
|
310
354
|
|
|
311
355
|
.message-assistant {
|
|
312
|
-
|
|
313
|
-
|
|
356
|
+
align-self: flex-start;
|
|
357
|
+
background: var(--surface2);
|
|
358
|
+
border-bottom-left-radius: 4px;
|
|
314
359
|
}
|
|
315
360
|
|
|
316
361
|
.message-label {
|
|
317
|
-
font-size: 0.
|
|
362
|
+
font-size: 0.7rem;
|
|
318
363
|
font-weight: 700;
|
|
319
364
|
text-transform: uppercase;
|
|
365
|
+
letter-spacing: 0.5px;
|
|
320
366
|
margin-bottom: 6px;
|
|
321
367
|
color: var(--text-dim);
|
|
322
368
|
}
|