copilot-tracer 1.0.4 → 1.0.6
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 +136 -159
- package/dist/cli.js +95 -76
- package/dist/db.js +166 -3
- package/dist/otlpReceiver.js +222 -15
- package/dist/setup.js +81 -14
- package/dist/webServer.js +39 -8
- package/package.json +2 -2
- package/web/index.html +296 -73
package/README.md
CHANGED
|
@@ -1,246 +1,217 @@
|
|
|
1
1
|
# copilot-tracer
|
|
2
2
|
|
|
3
|
-
Real-time tracing and prompt-refinement
|
|
3
|
+
Real-time tracing and prompt-refinement companion for **GitHub Copilot CLI**, **Claude Code**, and **VS Code Copilot extension**.
|
|
4
4
|
|
|
5
|
-
Captures every prompt, response, token usage, AI credits, tool calls,
|
|
5
|
+
Captures every prompt, response, token usage, AI credits, tool calls, and duration — all in one place. Runs as a background daemon that collects data from all your projects automatically. Includes a web dashboard with project overview and per-project live tracing.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
11
|
+
- **Daemon mode** — install once, run forever. Collects traces from all projects automatically
|
|
12
|
+
- **Auto project detection** — detects project from `github.copilot.git.repository` in OTLP spans
|
|
13
|
+
- **Zero-intrusion capture** — uses Copilot's built-in OTel support. Set env vars, done.
|
|
14
|
+
- **Works everywhere** — captures GitHub Copilot CLI, Claude Code, and VS Code Copilot Chat
|
|
15
|
+
- **Dashboard** — overview of all projects with token usage, credits, and session counts
|
|
16
|
+
- **Live tracer** — real-time trace table per project with detail panel
|
|
17
|
+
- **Prompt refinement** — rewrites prompts with stronger instructions and less noise
|
|
17
18
|
- **AI Credits tracking** — matches exactly what Copilot terminal reports (e.g. `2.59 cr`)
|
|
18
|
-
- **Tool call visibility** — see every tool/skill/MCP invoked during a session
|
|
19
|
-
- **ACP proxy mode** — wrap the Copilot CLI to trace live JSON-RPC traffic when needed
|
|
20
19
|
- **Persistent storage** — SQLite at `~/.copilot-tracer/traces.db`, survives restarts
|
|
21
|
-
- **Console + Web UI** — CLI table view or browser dashboard, your choice
|
|
22
20
|
|
|
23
21
|
---
|
|
24
22
|
|
|
25
|
-
##
|
|
26
|
-
|
|
27
|
-
- Node.js v18+ (tested on v24)
|
|
28
|
-
- GitHub Copilot CLI (`copilot` command available in terminal)
|
|
29
|
-
- VS Code 1.99+ with built-in Copilot (no extension install needed)
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## Install
|
|
23
|
+
## Quick Start (one-time setup)
|
|
34
24
|
|
|
35
25
|
```bash
|
|
36
26
|
npm install -g copilot-tracer
|
|
27
|
+
copilot-tracer --setup --daemon
|
|
37
28
|
```
|
|
38
29
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
> npm link # registers global command from local build
|
|
46
|
-
> ```
|
|
30
|
+
This will:
|
|
31
|
+
1. Detect your Copilot CLI and VS Code installation
|
|
32
|
+
2. Patch `~/.zshrc` with OTEL env vars
|
|
33
|
+
3. Patch VS Code `settings.json` with terminal env vars
|
|
34
|
+
4. Enable Claude Code OTLP logs/events and enhanced beta traces
|
|
35
|
+
5. Start the daemon on port 4747
|
|
47
36
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
## Setup (one-time)
|
|
51
|
-
|
|
52
|
-
Run the auto-setup command. It detects your Copilot CLI and VS Code installation and injects the required config automatically:
|
|
37
|
+
Then apply env vars in your current shell:
|
|
53
38
|
|
|
54
39
|
```bash
|
|
55
|
-
|
|
40
|
+
source ~/.zshrc
|
|
56
41
|
```
|
|
57
42
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
- Patches `~/.zshrc` (or `~/.bashrc`) with OTEL env vars
|
|
62
|
-
- Patches VS Code `settings.json` with `terminal.integrated.env.osx` block
|
|
43
|
+
Restart VS Code once. After that, the daemon collects traces from all your Copilot
|
|
44
|
+
and Claude Code sessions automatically. Claude Code content flags are enabled by
|
|
45
|
+
setup so prompts and responses can be displayed in the local dashboard.
|
|
63
46
|
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
✅ GitHub Copilot CLI detected — /usr/bin/copilot v1.0.77
|
|
67
|
-
✅ Visual Studio Code detected — 1.131.0 (Built-in Copilot)
|
|
68
|
-
✅ Shell profile patched: .zshrc
|
|
69
|
-
✅ VS Code settings patched
|
|
70
|
-
```
|
|
47
|
+
Open **http://localhost:4747** to see the dashboard.
|
|
71
48
|
|
|
72
|
-
|
|
49
|
+
---
|
|
73
50
|
|
|
74
|
-
|
|
75
|
-
source ~/.zshrc
|
|
76
|
-
```
|
|
51
|
+
## How It Works
|
|
77
52
|
|
|
78
|
-
|
|
53
|
+
```
|
|
54
|
+
┌─────────────────────────────────────────────────────────┐
|
|
55
|
+
│ copilot-tracer --daemon (runs once, stays running) │
|
|
56
|
+
│ │
|
|
57
|
+
│ OTLP Receiver ← Copilot CLI + Claude Code + VS Code │
|
|
58
|
+
│ (auto-detects project from github.copilot.git.repository)│
|
|
59
|
+
│ │
|
|
60
|
+
│ SQLite DB → Dashboard + Live Tracer (Socket.io) │
|
|
61
|
+
└─────────────────────────────────────────────────────────┘
|
|
62
|
+
|
|
63
|
+
Copilot CLI / Claude Code / VS Code Copilot Chat
|
|
64
|
+
│
|
|
65
|
+
│ OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4747
|
|
66
|
+
↓
|
|
67
|
+
POST /v1/traces and /v1/logs (OpenTelemetry OTLP JSON)
|
|
68
|
+
│
|
|
69
|
+
↓
|
|
70
|
+
copilot-tracer parses spans and events → tokens, credits, tool calls
|
|
71
|
+
│
|
|
72
|
+
↓
|
|
73
|
+
SQLite DB (~/.copilot-tracer/traces.db)
|
|
74
|
+
│
|
|
75
|
+
├→ Dashboard: all projects overview
|
|
76
|
+
└→ Live Tracer: real-time per-project view
|
|
77
|
+
```
|
|
79
78
|
|
|
80
79
|
---
|
|
81
80
|
|
|
82
|
-
##
|
|
81
|
+
## Usage
|
|
83
82
|
|
|
84
|
-
|
|
83
|
+
### Daemon mode (recommended)
|
|
85
84
|
|
|
86
85
|
```bash
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
export COPILOT_OTEL_ENABLED=true
|
|
90
|
-
```
|
|
86
|
+
# First time: setup + start daemon
|
|
87
|
+
copilot-tracer --setup --daemon
|
|
91
88
|
|
|
92
|
-
|
|
89
|
+
# Subsequent starts
|
|
90
|
+
copilot-tracer --daemon
|
|
93
91
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4747",
|
|
97
|
-
"OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT": "true",
|
|
98
|
-
"COPILOT_OTEL_ENABLED": "true"
|
|
99
|
-
}
|
|
92
|
+
# Custom port
|
|
93
|
+
copilot-tracer --daemon --port 8080
|
|
100
94
|
```
|
|
101
95
|
|
|
102
|
-
|
|
96
|
+
### Normal mode (legacy)
|
|
103
97
|
|
|
104
|
-
|
|
98
|
+
Per-session mode with optional ACP proxy for live CLI tracing:
|
|
105
99
|
|
|
106
100
|
```bash
|
|
107
|
-
|
|
108
|
-
|
|
101
|
+
# Web UI only (read from DB)
|
|
102
|
+
copilot-tracer --ui web --no-proxy
|
|
109
103
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
---
|
|
104
|
+
# With project path
|
|
105
|
+
copilot-tracer --ui web --no-proxy --project-path /path/to/repo
|
|
113
106
|
|
|
114
|
-
|
|
107
|
+
# With ACP proxy (wraps copilot CLI)
|
|
108
|
+
copilot-tracer --ui web
|
|
109
|
+
```
|
|
115
110
|
|
|
116
|
-
|
|
111
|
+
### Setup only
|
|
117
112
|
|
|
118
113
|
```bash
|
|
119
|
-
#
|
|
120
|
-
copilot
|
|
121
|
-
|
|
122
|
-
# Or use Copilot Chat in VS Code
|
|
114
|
+
# Just patch env vars without starting
|
|
115
|
+
copilot-tracer --setup
|
|
123
116
|
```
|
|
124
117
|
|
|
125
|
-
Traces appear instantly in the web UI as each request completes.
|
|
126
|
-
|
|
127
118
|
---
|
|
128
119
|
|
|
129
|
-
##
|
|
120
|
+
## Dashboard
|
|
130
121
|
|
|
131
|
-
|
|
132
|
-
copilot CLI / VS Code Copilot Chat
|
|
133
|
-
|
|
|
134
|
-
| reads OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4747
|
|
135
|
-
|
|
|
136
|
-
↓ POST /v1/traces (OpenTelemetry OTLP JSON)
|
|
137
|
-
copilot-tracer OTLP receiver
|
|
138
|
-
|
|
|
139
|
-
↓
|
|
140
|
-
Parse spans → extract prompt, response, tokens, credits, tool calls
|
|
141
|
-
|
|
|
142
|
-
↓
|
|
143
|
-
SQLite DB (~/.copilot-tracer/traces.db)
|
|
144
|
-
|
|
|
145
|
-
↓
|
|
146
|
-
Web UI (Socket.io real-time) + Console table
|
|
147
|
-
```
|
|
122
|
+
Open http://localhost:4747 after starting the daemon.
|
|
148
123
|
|
|
149
|
-
|
|
124
|
+
- **Summary cards** — total projects, sessions, tokens, credits
|
|
125
|
+
- **Project cards** — each project shows path, session count, tokens, credits, last active
|
|
126
|
+
- **Click a project** → opens live tracer filtered to that project
|
|
127
|
+
<img width="737" height="410" alt="image" src="https://github.com/user-attachments/assets/dc20653b-8774-46b3-9a42-6e7bb934aded" />
|
|
150
128
|
|
|
151
129
|
---
|
|
152
130
|
|
|
153
|
-
##
|
|
131
|
+
## Live Tracer
|
|
154
132
|
|
|
155
|
-
|
|
133
|
+
Real-time trace table for a specific project.
|
|
156
134
|
|
|
157
135
|
**Table columns:**
|
|
158
136
|
| Date/Time | Prompt | AI Credits | Duration | Cached | Written | Reasoning | Skills | Agents | MCPs |
|
|
159
137
|
|
|
160
138
|
**Interactive features:**
|
|
161
|
-
- Click any row → detail panel: full prompt,
|
|
139
|
+
- Click any row → detail panel: full prompt, response, reasoning, call graph
|
|
162
140
|
- Click AI Credits → cost breakdown per token type
|
|
163
|
-
- Click Reasoning
|
|
164
|
-
- Click Skills / Agents / MCPs
|
|
165
|
-
- Real-time updates via Socket.io
|
|
166
|
-
|
|
141
|
+
- Click Reasoning → full reasoning text
|
|
142
|
+
- Click Skills / Agents / MCPs → filtered call list
|
|
143
|
+
- Real-time updates via Socket.io
|
|
144
|
+
|
|
145
|
+
<img width="1504" height="742" alt="image" src="https://github.com/user-attachments/assets/f334108f-c587-4228-8120-7dac2f85f90b" />
|
|
146
|
+
|
|
147
|
+
<img width="1061" height="696" alt="image" src="https://github.com/user-attachments/assets/1555d5a2-dbca-4f1d-b102-3d2865dcee68" />
|
|
167
148
|
|
|
168
149
|
---
|
|
169
150
|
|
|
170
|
-
##
|
|
151
|
+
## Prompt Refinement
|
|
171
152
|
|
|
172
|
-
|
|
173
|
-
copilot-tracer --ui console --no-proxy
|
|
174
|
-
```
|
|
153
|
+
The web UI includes a prompt optimizer. Click "Refine Prompt" in the trace detail panel.
|
|
175
154
|
|
|
176
|
-
|
|
155
|
+
Techniques applied:
|
|
156
|
+
- Role grounding, imperative clarity, output format, chain-of-thought
|
|
157
|
+
- Noise removal, constraint injection, redundancy cleanup
|
|
177
158
|
|
|
178
159
|
---
|
|
179
160
|
|
|
180
|
-
##
|
|
161
|
+
## CLI Flags
|
|
181
162
|
|
|
182
|
-
|
|
163
|
+
| Flag | Description |
|
|
164
|
+
|------|-------------|
|
|
165
|
+
| `--daemon` | Run as background daemon (always-on OTLP receiver) |
|
|
166
|
+
| `--setup` | Auto-detect and configure env vars |
|
|
167
|
+
| `--port <port>` | Web UI port (default: 4747) |
|
|
168
|
+
| `--ui <mode>` | UI mode: console \| web \| both (normal mode only) |
|
|
169
|
+
| `--no-proxy` | Web/console only, no ACP proxy (normal mode only) |
|
|
170
|
+
| `--project-path <path>` | Project source path (normal mode only) |
|
|
171
|
+
| `--session <id>` | Custom session ID (normal mode only) |
|
|
172
|
+
| `--debug` | Verbose logging |
|
|
183
173
|
|
|
184
|
-
|
|
174
|
+
---
|
|
185
175
|
|
|
186
|
-
|
|
187
|
-
- **Imperative clarity** — turns soft phrasing into direct instructions
|
|
188
|
-
- **Output format** — asks for JSON, markdown, bullets, or steps when missing
|
|
189
|
-
- **Reasoning guidance** — adds step-by-step thinking for multi-step tasks
|
|
190
|
-
- **Noise removal** — strips filler like “please”, “could you”, and “I think”
|
|
191
|
-
- **Constraint injection** — adds language, tone, length, and audience constraints
|
|
192
|
-
- **Redundancy cleanup** — removes repeated or conflicting instructions
|
|
176
|
+
## Manual Setup (alternative)
|
|
193
177
|
|
|
194
|
-
|
|
178
|
+
Add to `~/.zshrc`:
|
|
195
179
|
|
|
196
180
|
```bash
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
181
|
+
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4747
|
|
182
|
+
export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true
|
|
183
|
+
export COPILOT_OTEL_ENABLED=true
|
|
184
|
+
|
|
185
|
+
# Claude Code telemetry
|
|
186
|
+
export CLAUDE_CODE_ENABLE_TELEMETRY=1
|
|
187
|
+
export CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1
|
|
188
|
+
export OTEL_LOGS_EXPORTER=otlp
|
|
189
|
+
export OTEL_TRACES_EXPORTER=otlp
|
|
190
|
+
export OTEL_EXPORTER_OTLP_PROTOCOL=http/json
|
|
191
|
+
export OTEL_LOG_USER_PROMPTS=1
|
|
192
|
+
export OTEL_LOG_ASSISTANT_RESPONSES=1
|
|
200
193
|
```
|
|
201
194
|
|
|
202
|
-
|
|
195
|
+
Claude Code exports standard OTLP logs/events and optional beta traces. See
|
|
196
|
+
[Anthropic's monitoring documentation](https://code.claude.com/docs/en/monitoring-usage)
|
|
197
|
+
for protocol and content controls.
|
|
198
|
+
|
|
199
|
+
For VS Code, add to `~/Library/Application Support/Code/User/settings.json`:
|
|
203
200
|
|
|
204
201
|
```json
|
|
205
|
-
{
|
|
206
|
-
"
|
|
207
|
-
"
|
|
208
|
-
"
|
|
209
|
-
"techniques": [],
|
|
210
|
-
"origTok": 10,
|
|
211
|
-
"newTok": 22,
|
|
212
|
-
"inputSavingPct": 0
|
|
202
|
+
"terminal.integrated.env.osx": {
|
|
203
|
+
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4747",
|
|
204
|
+
"OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT": "true",
|
|
205
|
+
"COPILOT_OTEL_ENABLED": "true"
|
|
213
206
|
}
|
|
214
207
|
```
|
|
215
208
|
|
|
216
209
|
---
|
|
217
210
|
|
|
218
|
-
## CLI Flags
|
|
219
|
-
|
|
220
|
-
| Flag | Description |
|
|
221
|
-
|------|-------------|
|
|
222
|
-
| `--ui web` | Start web UI (default) |
|
|
223
|
-
| `--ui console` | Start console table UI |
|
|
224
|
-
| `--ui both` | Both web + console |
|
|
225
|
-
| `--port 4747` | Web UI port (default: 4747) |
|
|
226
|
-
| `--no-proxy` | Web/console only, no ACP proxy |
|
|
227
|
-
| `--session <id>` | Custom session ID |
|
|
228
|
-
| `--setup` | Auto-detect and configure env vars |
|
|
229
|
-
| `--debug` | Verbose logging |
|
|
230
|
-
|
|
231
|
-
---
|
|
232
|
-
|
|
233
211
|
## Storage
|
|
234
212
|
|
|
235
213
|
Traces persist to `~/.copilot-tracer/traces.db` (SQLite). Safe to keep across sessions.
|
|
236
214
|
|
|
237
|
-
To test the web UI without running a live Copilot session:
|
|
238
|
-
|
|
239
|
-
```bash
|
|
240
|
-
node test-seed.mjs # seeds 4 sample traces (source build only)
|
|
241
|
-
copilot-tracer --ui web --no-proxy --session test-session-001
|
|
242
|
-
```
|
|
243
|
-
|
|
244
215
|
---
|
|
245
216
|
|
|
246
217
|
## Build & Publish
|
|
@@ -253,18 +224,24 @@ npx tsc # compile to dist/
|
|
|
253
224
|
To publish a new release to npm:
|
|
254
225
|
|
|
255
226
|
```bash
|
|
256
|
-
#
|
|
227
|
+
# Login first
|
|
228
|
+
npm login
|
|
229
|
+
|
|
230
|
+
# Patch version (1.0.4 → 1.0.5)
|
|
257
231
|
bash scripts/publish.sh
|
|
258
232
|
|
|
259
|
-
#
|
|
233
|
+
# Minor version
|
|
260
234
|
bash scripts/publish.sh minor
|
|
261
235
|
|
|
262
|
-
#
|
|
236
|
+
# Major version
|
|
237
|
+
bash scripts/publish.sh major
|
|
238
|
+
|
|
239
|
+
# Beta pre-release
|
|
263
240
|
bash scripts/publish.sh --tag beta --pre beta
|
|
264
241
|
```
|
|
265
242
|
|
|
266
243
|
The script will:
|
|
267
|
-
1. Check npm authentication
|
|
244
|
+
1. Check npm authentication
|
|
268
245
|
2. Verify git working tree is clean
|
|
269
246
|
3. Type-check + build
|
|
270
247
|
4. Verify `better-sqlite3` native module loads
|
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,8 @@ import { spawn } from 'child_process';
|
|
|
4
4
|
import { randomUUID } from 'crypto';
|
|
5
5
|
import readline from 'readline';
|
|
6
6
|
import fs from 'fs';
|
|
7
|
-
import
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { createSession, getTraces, getSessionSummary, ensureProject } from './db.js';
|
|
8
9
|
import { handleAcpMessage, traceEvents } from './proxy.js';
|
|
9
10
|
import { renderConsoleTable } from './consoleUi.js';
|
|
10
11
|
import { startWebServer } from './webServer.js';
|
|
@@ -20,91 +21,109 @@ program
|
|
|
20
21
|
.option('--session <id>', 'Filter by session ID')
|
|
21
22
|
.option('--debug', 'Dump ALL raw ACP messages to stderr (use to discover real method names)')
|
|
22
23
|
.option('--setup', 'Auto-detect copilot CLI + VS Code and configure OTLP env vars')
|
|
24
|
+
.option('--project-path <path>', 'Project source path (defaults to cwd)')
|
|
25
|
+
.option('--daemon', 'Run as background daemon — collects all OTLP data, no ACP proxy')
|
|
23
26
|
.allowUnknownOption()
|
|
24
27
|
.parse();
|
|
25
28
|
const opts = program.opts();
|
|
26
29
|
const port = parseInt(opts.port);
|
|
27
30
|
// Handle --setup: patch env files, apply to current process, then fall through to start web UI
|
|
28
31
|
if (opts.setup) {
|
|
29
|
-
runSetup(port);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
const sessionId = opts.session || randomUUID();
|
|
35
|
-
createSession(sessionId);
|
|
36
|
-
console.log(`\n 🤖 Copilot Tracer | Session: ${sessionId}\n`);
|
|
37
|
-
// Start Web UI
|
|
38
|
-
if (opts.ui === 'web' || opts.ui === 'both') {
|
|
39
|
-
startWebServer(port, sessionId);
|
|
40
|
-
setTimeout(() => open(`http://localhost:${port}/`), 1500);
|
|
32
|
+
runSetup(port, opts.daemon);
|
|
33
|
+
if (!opts.daemon) {
|
|
34
|
+
opts.proxy = false;
|
|
35
|
+
opts.ui = 'web';
|
|
36
|
+
}
|
|
41
37
|
}
|
|
42
|
-
//
|
|
43
|
-
if (opts.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
refreshConsole();
|
|
38
|
+
// ── Daemon mode: run as always-on OTLP receiver ───────────────────────────
|
|
39
|
+
if (opts.daemon) {
|
|
40
|
+
console.log(`\n 🤖 Copilot Tracer — Daemon Mode`);
|
|
41
|
+
console.log(` 📡 Listening for OTLP traces on port ${port}`);
|
|
42
|
+
console.log(` 🌐 Dashboard: http://localhost:${port}/`);
|
|
43
|
+
console.log(` Press Ctrl+C to stop\n`);
|
|
44
|
+
startWebServer(port);
|
|
45
|
+
process.on('SIGINT', () => { process.exit(0); });
|
|
46
|
+
process.on('SIGTERM', () => { process.exit(0); });
|
|
52
47
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
48
|
+
else {
|
|
49
|
+
// ── Normal mode: per-session with optional ACP proxy ─────────────────────
|
|
50
|
+
const sessionId = opts.session || randomUUID();
|
|
51
|
+
// Resolve project path and create project record
|
|
52
|
+
const projectPath = opts.projectPath
|
|
53
|
+
? path.resolve(opts.projectPath)
|
|
54
|
+
: process.cwd();
|
|
55
|
+
const projectId = ensureProject(projectPath);
|
|
56
|
+
createSession(sessionId, projectId);
|
|
57
|
+
console.log(`\n 🤖 Copilot Tracer | Session: ${sessionId}`);
|
|
58
|
+
console.log(` 📁 Project: ${projectPath}\n`);
|
|
59
|
+
// Start Web UI
|
|
60
|
+
if (opts.ui === 'web' || opts.ui === 'both') {
|
|
61
|
+
startWebServer(port, sessionId, projectId);
|
|
62
|
+
setTimeout(() => open(`http://localhost:${port}/`), 1500);
|
|
63
63
|
}
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
logFile?.write(entry + '\n');
|
|
64
|
+
// Start Console UI refresh loop
|
|
65
|
+
if (opts.ui === 'console' || opts.ui === 'both') {
|
|
66
|
+
const refreshConsole = () => {
|
|
67
|
+
const entries = getTraces(sessionId, 50);
|
|
68
|
+
const summary = getSessionSummary(sessionId);
|
|
69
|
+
renderConsoleTable(entries, summary ?? undefined);
|
|
70
|
+
};
|
|
71
|
+
traceEvents.on('trace:update', refreshConsole);
|
|
72
|
+
traceEvents.on('trace:done', refreshConsole);
|
|
73
|
+
refreshConsole();
|
|
75
74
|
}
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
process.stderr.write(`[TRACER] stdin non-JSON: ${line}\n`);
|
|
75
|
+
// ACP Proxy — wrap copilot CLI
|
|
76
|
+
if (opts.proxy !== false) {
|
|
77
|
+
const copilotArgs = ['--acp', '--stdio', ...program.args];
|
|
78
|
+
const child = spawn(opts.cmd, copilotArgs, {
|
|
79
|
+
stdio: ['pipe', 'pipe', 'inherit'],
|
|
80
|
+
});
|
|
81
|
+
if (!child.pid) {
|
|
82
|
+
console.error(`\n ❌ Failed to start: ${opts.cmd} ${copilotArgs.join(' ')}`);
|
|
83
|
+
console.error(' Make sure GitHub Copilot CLI is installed: npm install -g @github/copilot-cli\n');
|
|
84
|
+
process.exit(1);
|
|
87
85
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
86
|
+
const stdinRl = readline.createInterface({ input: process.stdin });
|
|
87
|
+
const stdoutRl = readline.createInterface({ input: child.stdout });
|
|
88
|
+
const debug = opts.debug === true;
|
|
89
|
+
const logFile = debug ? fs.createWriteStream(`/tmp/copilot-tracer-${sessionId.slice(0, 8)}.ndjson`, { flags: 'a' }) : null;
|
|
90
|
+
function debugLog(direction, raw, parsed) {
|
|
91
|
+
if (!debug)
|
|
92
|
+
return;
|
|
93
|
+
const entry = JSON.stringify({ ts: new Date().toISOString(), dir: direction, raw, parsed });
|
|
94
|
+
process.stderr.write('[TRACER] ' + entry + '\n');
|
|
95
|
+
logFile?.write(entry + '\n');
|
|
97
96
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
97
|
+
stdinRl.on('line', (line) => {
|
|
98
|
+
let parsed;
|
|
99
|
+
try {
|
|
100
|
+
parsed = JSON.parse(line);
|
|
101
|
+
handleAcpMessage(sessionId, parsed, 'out');
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
if (debug)
|
|
105
|
+
process.stderr.write(`[TRACER] stdin non-JSON: ${line}\n`);
|
|
106
|
+
}
|
|
107
|
+
debugLog('→ copilot', line, parsed);
|
|
108
|
+
child.stdin.write(line + '\n');
|
|
109
|
+
});
|
|
110
|
+
stdoutRl.on('line', (line) => {
|
|
111
|
+
let parsed;
|
|
112
|
+
try {
|
|
113
|
+
parsed = JSON.parse(line);
|
|
114
|
+
handleAcpMessage(sessionId, parsed, 'in');
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
if (debug)
|
|
118
|
+
process.stderr.write(`[TRACER] stdout non-JSON: ${line}\n`);
|
|
119
|
+
}
|
|
120
|
+
debugLog('← copilot', line, parsed);
|
|
121
|
+
process.stdout.write(line + '\n');
|
|
122
|
+
});
|
|
123
|
+
child.on('exit', (code) => {
|
|
124
|
+
console.log(`\n Copilot CLI exited (code ${code})\n`);
|
|
125
|
+
process.exit(code ?? 0);
|
|
126
|
+
});
|
|
127
|
+
process.on('SIGINT', () => { child.kill(); process.exit(0); });
|
|
128
|
+
}
|
|
110
129
|
}
|