copilot-tracer 1.0.3 → 1.0.5
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 +119 -123
- package/dist/cli.js +95 -76
- package/dist/db.js +166 -3
- package/dist/otlpReceiver.js +34 -16
- package/dist/setup.js +35 -12
- package/dist/webServer.js +86 -8
- package/package.json +2 -2
- package/web/index.html +438 -69
- package/web/index.html.patch +0 -0
package/README.md
CHANGED
|
@@ -1,177 +1,152 @@
|
|
|
1
1
|
# copilot-tracer
|
|
2
2
|
|
|
3
|
-
Real-time tracing and
|
|
3
|
+
Real-time tracing and prompt-refinement companion for **GitHub Copilot CLI** 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
|
-
- **
|
|
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 both Copilot CLI 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
|
|
16
18
|
- **AI Credits tracking** — matches exactly what Copilot terminal reports (e.g. `2.59 cr`)
|
|
17
|
-
- **Tool call visibility** — see every tool/skill/MCP invoked during a session
|
|
18
19
|
- **Persistent storage** — SQLite at `~/.copilot-tracer/traces.db`, survives restarts
|
|
19
|
-
- **Console + Web UI** — CLI table view or browser dashboard, your choice
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
##
|
|
24
|
-
|
|
25
|
-
- Node.js v18+ (tested on v24)
|
|
26
|
-
- GitHub Copilot CLI (`copilot` command available in terminal)
|
|
27
|
-
- VS Code 1.99+ with built-in Copilot (no extension install needed)
|
|
28
|
-
|
|
29
|
-
---
|
|
30
|
-
|
|
31
|
-
## Install
|
|
23
|
+
## Quick Start (one-time setup)
|
|
32
24
|
|
|
33
25
|
```bash
|
|
34
26
|
npm install -g copilot-tracer
|
|
27
|
+
copilot-tracer --setup --daemon
|
|
35
28
|
```
|
|
36
29
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
> cd copilot-tracer && npm install && npx tsc
|
|
43
|
-
> npm link # registers global command from local build
|
|
44
|
-
> ```
|
|
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. Start the daemon on port 4747
|
|
45
35
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
## Setup (one-time)
|
|
49
|
-
|
|
50
|
-
Run the auto-setup command. It detects your Copilot CLI and VS Code installation and injects the required config automatically:
|
|
36
|
+
Then apply env vars in your current shell:
|
|
51
37
|
|
|
52
38
|
```bash
|
|
53
|
-
|
|
39
|
+
source ~/.zshrc
|
|
54
40
|
```
|
|
55
41
|
|
|
56
|
-
|
|
57
|
-
- Detects `copilot` CLI path and version
|
|
58
|
-
- Detects VS Code version and confirms built-in Copilot
|
|
59
|
-
- Patches `~/.zshrc` (or `~/.bashrc`) with OTEL env vars
|
|
60
|
-
- Patches VS Code `settings.json` with `terminal.integrated.env.osx` block
|
|
42
|
+
Restart VS Code once. After that, the daemon collects traces from all your Copilot sessions automatically.
|
|
61
43
|
|
|
62
|
-
|
|
63
|
-
```
|
|
64
|
-
✅ GitHub Copilot CLI detected — /usr/bin/copilot v1.0.77
|
|
65
|
-
✅ Visual Studio Code detected — 1.131.0 (Built-in Copilot)
|
|
66
|
-
✅ Shell profile patched: .zshrc
|
|
67
|
-
✅ VS Code settings patched
|
|
68
|
-
```
|
|
44
|
+
Open **http://localhost:4747** to see the dashboard.
|
|
69
45
|
|
|
70
|
-
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## How It Works
|
|
71
49
|
|
|
72
|
-
```bash
|
|
73
|
-
source ~/.zshrc
|
|
74
50
|
```
|
|
51
|
+
┌─────────────────────────────────────────────────────────┐
|
|
52
|
+
│ copilot-tracer --daemon (runs once, stays running) │
|
|
53
|
+
│ │
|
|
54
|
+
│ OTLP Receiver ← Copilot CLI + VS Code │
|
|
55
|
+
│ (auto-detects project from github.copilot.git.repository)│
|
|
56
|
+
│ │
|
|
57
|
+
│ SQLite DB → Dashboard + Live Tracer (Socket.io) │
|
|
58
|
+
└─────────────────────────────────────────────────────────┘
|
|
75
59
|
|
|
76
|
-
|
|
60
|
+
Copilot CLI / VS Code Copilot Chat
|
|
61
|
+
│
|
|
62
|
+
│ OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4747
|
|
63
|
+
↓
|
|
64
|
+
POST /v1/traces (OpenTelemetry OTLP JSON)
|
|
65
|
+
│
|
|
66
|
+
↓
|
|
67
|
+
copilot-tracer parses spans → tokens, credits, tool calls
|
|
68
|
+
│
|
|
69
|
+
↓
|
|
70
|
+
SQLite DB (~/.copilot-tracer/traces.db)
|
|
71
|
+
│
|
|
72
|
+
├→ Dashboard: all projects overview
|
|
73
|
+
└→ Live Tracer: real-time per-project view
|
|
74
|
+
```
|
|
77
75
|
|
|
78
76
|
---
|
|
79
77
|
|
|
80
|
-
##
|
|
78
|
+
## Usage
|
|
81
79
|
|
|
82
|
-
|
|
80
|
+
### Daemon mode (recommended)
|
|
83
81
|
|
|
84
82
|
```bash
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
export COPILOT_OTEL_ENABLED=true
|
|
88
|
-
```
|
|
83
|
+
# First time: setup + start daemon
|
|
84
|
+
copilot-tracer --setup --daemon
|
|
89
85
|
|
|
90
|
-
|
|
86
|
+
# Subsequent starts
|
|
87
|
+
copilot-tracer --daemon
|
|
91
88
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4747",
|
|
95
|
-
"OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT": "true",
|
|
96
|
-
"COPILOT_OTEL_ENABLED": "true"
|
|
97
|
-
}
|
|
89
|
+
# Custom port
|
|
90
|
+
copilot-tracer --daemon --port 8080
|
|
98
91
|
```
|
|
99
92
|
|
|
100
|
-
|
|
93
|
+
### Normal mode (legacy)
|
|
101
94
|
|
|
102
|
-
|
|
95
|
+
Per-session mode with optional ACP proxy for live CLI tracing:
|
|
103
96
|
|
|
104
97
|
```bash
|
|
105
|
-
|
|
106
|
-
|
|
98
|
+
# Web UI only (read from DB)
|
|
99
|
+
copilot-tracer --ui web --no-proxy
|
|
107
100
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
---
|
|
101
|
+
# With project path
|
|
102
|
+
copilot-tracer --ui web --no-proxy --project-path /path/to/repo
|
|
111
103
|
|
|
112
|
-
|
|
104
|
+
# With ACP proxy (wraps copilot CLI)
|
|
105
|
+
copilot-tracer --ui web
|
|
106
|
+
```
|
|
113
107
|
|
|
114
|
-
|
|
108
|
+
### Setup only
|
|
115
109
|
|
|
116
110
|
```bash
|
|
117
|
-
#
|
|
118
|
-
copilot
|
|
119
|
-
|
|
120
|
-
# Or use Copilot Chat in VS Code
|
|
111
|
+
# Just patch env vars without starting
|
|
112
|
+
copilot-tracer --setup
|
|
121
113
|
```
|
|
122
114
|
|
|
123
|
-
Traces appear instantly in the web UI as each request completes.
|
|
124
|
-
|
|
125
115
|
---
|
|
126
116
|
|
|
127
|
-
##
|
|
117
|
+
## Dashboard
|
|
128
118
|
|
|
129
|
-
|
|
130
|
-
copilot CLI / VS Code Copilot Chat
|
|
131
|
-
|
|
|
132
|
-
| reads OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4747
|
|
133
|
-
|
|
|
134
|
-
↓ POST /v1/traces (OpenTelemetry OTLP JSON)
|
|
135
|
-
copilot-tracer OTLP receiver
|
|
136
|
-
|
|
|
137
|
-
↓
|
|
138
|
-
Parse spans → extract prompt, response, tokens, credits, tool calls
|
|
139
|
-
|
|
|
140
|
-
↓
|
|
141
|
-
SQLite DB (~/.copilot-tracer/traces.db)
|
|
142
|
-
|
|
|
143
|
-
↓
|
|
144
|
-
Web UI (Socket.io real-time) + Console table
|
|
145
|
-
```
|
|
119
|
+
Open http://localhost:4747 after starting the daemon.
|
|
146
120
|
|
|
147
|
-
|
|
121
|
+
- **Summary cards** — total projects, sessions, tokens, credits
|
|
122
|
+
- **Project cards** — each project shows path, session count, tokens, credits, last active
|
|
123
|
+
- **Click a project** → opens live tracer filtered to that project
|
|
148
124
|
|
|
149
125
|
---
|
|
150
126
|
|
|
151
|
-
##
|
|
127
|
+
## Live Tracer
|
|
152
128
|
|
|
153
|
-
|
|
129
|
+
Real-time trace table for a specific project.
|
|
154
130
|
|
|
155
131
|
**Table columns:**
|
|
156
132
|
| Date/Time | Prompt | AI Credits | Duration | Cached | Written | Reasoning | Skills | Agents | MCPs |
|
|
157
133
|
|
|
158
134
|
**Interactive features:**
|
|
159
|
-
- Click any row → detail panel: full prompt,
|
|
135
|
+
- Click any row → detail panel: full prompt, response, reasoning, call graph
|
|
160
136
|
- Click AI Credits → cost breakdown per token type
|
|
161
|
-
- Click Reasoning
|
|
162
|
-
- Click Skills / Agents / MCPs
|
|
163
|
-
- Real-time updates via Socket.io
|
|
164
|
-
- Dark theme
|
|
137
|
+
- Click Reasoning → full reasoning text
|
|
138
|
+
- Click Skills / Agents / MCPs → filtered call list
|
|
139
|
+
- Real-time updates via Socket.io
|
|
165
140
|
|
|
166
141
|
---
|
|
167
142
|
|
|
168
|
-
##
|
|
143
|
+
## Prompt Refinement
|
|
169
144
|
|
|
170
|
-
|
|
171
|
-
copilot-tracer --ui console --no-proxy
|
|
172
|
-
```
|
|
145
|
+
The web UI includes a prompt optimizer. Click "Refine Prompt" in the trace detail panel.
|
|
173
146
|
|
|
174
|
-
|
|
147
|
+
Techniques applied:
|
|
148
|
+
- Role grounding, imperative clarity, output format, chain-of-thought
|
|
149
|
+
- Noise removal, constraint injection, redundancy cleanup
|
|
175
150
|
|
|
176
151
|
---
|
|
177
152
|
|
|
@@ -179,30 +154,45 @@ Live updating table in terminal. Same columns as web UI. TOTALS row pinned at to
|
|
|
179
154
|
|
|
180
155
|
| Flag | Description |
|
|
181
156
|
|------|-------------|
|
|
182
|
-
| `--
|
|
183
|
-
| `--ui console` | Start console table UI |
|
|
184
|
-
| `--ui both` | Both web + console |
|
|
185
|
-
| `--port 4747` | Web UI port (default: 4747) |
|
|
186
|
-
| `--no-proxy` | Web/console only, no ACP proxy |
|
|
187
|
-
| `--session <id>` | Custom session ID |
|
|
157
|
+
| `--daemon` | Run as background daemon (always-on OTLP receiver) |
|
|
188
158
|
| `--setup` | Auto-detect and configure env vars |
|
|
159
|
+
| `--port <port>` | Web UI port (default: 4747) |
|
|
160
|
+
| `--ui <mode>` | UI mode: console \| web \| both (normal mode only) |
|
|
161
|
+
| `--no-proxy` | Web/console only, no ACP proxy (normal mode only) |
|
|
162
|
+
| `--project-path <path>` | Project source path (normal mode only) |
|
|
163
|
+
| `--session <id>` | Custom session ID (normal mode only) |
|
|
189
164
|
| `--debug` | Verbose logging |
|
|
190
165
|
|
|
191
166
|
---
|
|
192
167
|
|
|
193
|
-
##
|
|
194
|
-
|
|
195
|
-
Traces persist to `~/.copilot-tracer/traces.db` (SQLite). Safe to keep across sessions.
|
|
168
|
+
## Manual Setup (alternative)
|
|
196
169
|
|
|
197
|
-
|
|
170
|
+
Add to `~/.zshrc`:
|
|
198
171
|
|
|
199
172
|
```bash
|
|
200
|
-
|
|
201
|
-
|
|
173
|
+
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4747
|
|
174
|
+
export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true
|
|
175
|
+
export COPILOT_OTEL_ENABLED=true
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
For VS Code, add to `~/Library/Application Support/Code/User/settings.json`:
|
|
179
|
+
|
|
180
|
+
```json
|
|
181
|
+
"terminal.integrated.env.osx": {
|
|
182
|
+
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4747",
|
|
183
|
+
"OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT": "true",
|
|
184
|
+
"COPILOT_OTEL_ENABLED": "true"
|
|
185
|
+
}
|
|
202
186
|
```
|
|
203
187
|
|
|
204
188
|
---
|
|
205
189
|
|
|
190
|
+
## Storage
|
|
191
|
+
|
|
192
|
+
Traces persist to `~/.copilot-tracer/traces.db` (SQLite). Safe to keep across sessions.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
206
196
|
## Build & Publish
|
|
207
197
|
|
|
208
198
|
```bash
|
|
@@ -213,18 +203,24 @@ npx tsc # compile to dist/
|
|
|
213
203
|
To publish a new release to npm:
|
|
214
204
|
|
|
215
205
|
```bash
|
|
216
|
-
#
|
|
206
|
+
# Login first
|
|
207
|
+
npm login
|
|
208
|
+
|
|
209
|
+
# Patch version (1.0.4 → 1.0.5)
|
|
217
210
|
bash scripts/publish.sh
|
|
218
211
|
|
|
219
|
-
#
|
|
212
|
+
# Minor version
|
|
220
213
|
bash scripts/publish.sh minor
|
|
221
214
|
|
|
222
|
-
#
|
|
215
|
+
# Major version
|
|
216
|
+
bash scripts/publish.sh major
|
|
217
|
+
|
|
218
|
+
# Beta pre-release
|
|
223
219
|
bash scripts/publish.sh --tag beta --pre beta
|
|
224
220
|
```
|
|
225
221
|
|
|
226
222
|
The script will:
|
|
227
|
-
1. Check npm authentication
|
|
223
|
+
1. Check npm authentication
|
|
228
224
|
2. Verify git working tree is clean
|
|
229
225
|
3. Type-check + build
|
|
230
226
|
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
|
}
|