copilot-tracer 1.0.4 → 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 CHANGED
@@ -1,246 +1,196 @@
1
1
  # copilot-tracer
2
2
 
3
- Real-time tracing and prompt-refinement tool for **GitHub Copilot CLI** and **VS Code Copilot extension**.
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, skill invocations, and duration — all in one place. It also includes a prompt optimizer that rewrites prompts using role grounding, imperative clarity, output formatting, constraint injection, and noise removal. Works via native **OpenTelemetry (OTLP)** integration built into GitHub Copilot, with an optional ACP proxy mode for live CLI tracing.
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
- - **Zero-intrusion capture** — uses Copilot's built-in OTel support. Set 2 env vars, done.
12
- - **Works everywhere** — captures both Copilot CLI (`copilot -p "..."`) and VS Code Copilot Chat
13
- - **Prompt refinement** — rewrites prompts with stronger instructions, clearer outputs, and less noise
14
- - **Real-time web UI** — live dashboard at `http://localhost:4747` with dark theme
15
- - **Full prompt & response** see exactly what you sent and what Copilot replied
16
- - **Token breakdown** — input, output, cached, reasoning, written tokens per request
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
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
- ## Prerequisites
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
- Requires Node.js v18+. The `copilot-tracer` command is available globally after install.
40
-
41
- > **Building from source**
42
- > ```bash
43
- > git clone https://github.com/chuongnd/copilot-tracer
44
- > cd copilot-tracer && npm install && npx tsc
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. Start the daemon on port 4747
47
35
 
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:
36
+ Then apply env vars in your current shell:
53
37
 
54
38
  ```bash
55
- copilot-tracer --setup
39
+ source ~/.zshrc
56
40
  ```
57
41
 
58
- What it does:
59
- - Detects `copilot` CLI path and version
60
- - Detects VS Code version and confirms built-in Copilot
61
- - Patches `~/.zshrc` (or `~/.bashrc`) with OTEL env vars
62
- - 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.
63
43
 
64
- Example output:
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
- ```
44
+ Open **http://localhost:4747** to see the dashboard.
71
45
 
72
- Then apply the env vars:
46
+ ---
47
+
48
+ ## How It Works
73
49
 
74
- ```bash
75
- source ~/.zshrc
76
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
+ └─────────────────────────────────────────────────────────┘
77
59
 
78
- Restart VS Code completely (Cmd+Q, then reopen).
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
+ ```
79
75
 
80
76
  ---
81
77
 
82
- ## Manual Setup (alternative)
78
+ ## Usage
83
79
 
84
- If you prefer to configure manually, add these to `~/.zshrc`:
80
+ ### Daemon mode (recommended)
85
81
 
86
82
  ```bash
87
- export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4747
88
- export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true
89
- export COPILOT_OTEL_ENABLED=true
90
- ```
83
+ # First time: setup + start daemon
84
+ copilot-tracer --setup --daemon
91
85
 
92
- For VS Code, add to `~/Library/Application Support/Code/User/settings.json`:
86
+ # Subsequent starts
87
+ copilot-tracer --daemon
93
88
 
94
- ```json
95
- "terminal.integrated.env.osx": {
96
- "OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4747",
97
- "OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT": "true",
98
- "COPILOT_OTEL_ENABLED": "true"
99
- }
89
+ # Custom port
90
+ copilot-tracer --daemon --port 8080
100
91
  ```
101
92
 
102
- ---
93
+ ### Normal mode (legacy)
103
94
 
104
- ## Start Tracer
95
+ Per-session mode with optional ACP proxy for live CLI tracing:
105
96
 
106
97
  ```bash
107
- copilot-tracer --ui web --port 4747 --no-proxy
108
- ```
109
-
110
- Open **http://localhost:4747** — shows "waiting for copilot CLI activity".
98
+ # Web UI only (read from DB)
99
+ copilot-tracer --ui web --no-proxy
111
100
 
112
- ---
101
+ # With project path
102
+ copilot-tracer --ui web --no-proxy --project-path /path/to/repo
113
103
 
114
- ## Use Copilot Normally
104
+ # With ACP proxy (wraps copilot CLI)
105
+ copilot-tracer --ui web
106
+ ```
115
107
 
116
- No change to how you use Copilot. Just run as usual:
108
+ ### Setup only
117
109
 
118
110
  ```bash
119
- # Copilot CLI
120
- copilot -p "how to convert microservice to modular" --allow-all-tools
121
-
122
- # Or use Copilot Chat in VS Code
111
+ # Just patch env vars without starting
112
+ copilot-tracer --setup
123
113
  ```
124
114
 
125
- Traces appear instantly in the web UI as each request completes.
126
-
127
115
  ---
128
116
 
129
- ## How It Works
117
+ ## Dashboard
130
118
 
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
- ```
119
+ Open http://localhost:4747 after starting the daemon.
148
120
 
149
- Copilot has built-in OpenTelemetry instrumentation. When `OTEL_EXPORTER_OTLP_ENDPOINT` is set, it pushes all trace data to that endpoint automatically — both CLI and VS Code extension.
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
150
124
 
151
125
  ---
152
126
 
153
- ## Web UI
127
+ ## Live Tracer
154
128
 
155
- Open http://localhost:4747 after starting the tracer.
129
+ Real-time trace table for a specific project.
156
130
 
157
131
  **Table columns:**
158
132
  | Date/Time | Prompt | AI Credits | Duration | Cached | Written | Reasoning | Skills | Agents | MCPs |
159
133
 
160
134
  **Interactive features:**
161
- - Click any row → detail panel: full prompt, full response, reasoning text, call graph
135
+ - Click any row → detail panel: full prompt, response, reasoning, call graph
162
136
  - Click AI Credits → cost breakdown per token type
163
- - Click Reasoning count → full reasoning text
164
- - Click Skills / Agents / MCPs pill → filtered call list with input/output/duration
165
- - Real-time updates via Socket.io — no page refresh needed
166
- - Dark theme
137
+ - Click Reasoning → full reasoning text
138
+ - Click Skills / Agents / MCPs → filtered call list
139
+ - Real-time updates via Socket.io
167
140
 
168
141
  ---
169
142
 
170
- ## Console UI
143
+ ## Prompt Refinement
171
144
 
172
- ```bash
173
- copilot-tracer --ui console --no-proxy
174
- ```
145
+ The web UI includes a prompt optimizer. Click "Refine Prompt" in the trace detail panel.
175
146
 
176
- Live updating table in terminal. Same columns as web UI. TOTALS row pinned at top.
147
+ Techniques applied:
148
+ - Role grounding, imperative clarity, output format, chain-of-thought
149
+ - Noise removal, constraint injection, redundancy cleanup
177
150
 
178
151
  ---
179
152
 
180
- ## Prompt Refinement
153
+ ## CLI Flags
181
154
 
182
- The web UI exposes `POST /api/refine` to improve a raw prompt before sending it to Copilot.
155
+ | Flag | Description |
156
+ |------|-------------|
157
+ | `--daemon` | Run as background daemon (always-on OTLP receiver) |
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) |
164
+ | `--debug` | Verbose logging |
183
165
 
184
- It currently applies these techniques:
166
+ ---
185
167
 
186
- - **Role grounding** — adds an expert persona when the prompt has none
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
168
+ ## Manual Setup (alternative)
193
169
 
194
- Example request:
170
+ Add to `~/.zshrc`:
195
171
 
196
172
  ```bash
197
- curl -s http://localhost:4747/api/refine \
198
- -H 'content-type: application/json' \
199
- -d '{"prompt":"help me write a plan for migrating a monolith"}'
173
+ export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4747
174
+ export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true
175
+ export COPILOT_OTEL_ENABLED=true
200
176
  ```
201
177
 
202
- Response shape:
178
+ For VS Code, add to `~/Library/Application Support/Code/User/settings.json`:
203
179
 
204
180
  ```json
205
- {
206
- "ok": true,
207
- "optimized": "",
208
- "issues": [],
209
- "techniques": [],
210
- "origTok": 10,
211
- "newTok": 22,
212
- "inputSavingPct": 0
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"
213
185
  }
214
186
  ```
215
187
 
216
188
  ---
217
189
 
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
190
  ## Storage
234
191
 
235
192
  Traces persist to `~/.copilot-tracer/traces.db` (SQLite). Safe to keep across sessions.
236
193
 
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
194
  ---
245
195
 
246
196
  ## Build & Publish
@@ -253,18 +203,24 @@ npx tsc # compile to dist/
253
203
  To publish a new release to npm:
254
204
 
255
205
  ```bash
256
- # Bump patch version (1.0.0 → 1.0.1), build, publish, git-tag
206
+ # Login first
207
+ npm login
208
+
209
+ # Patch version (1.0.4 → 1.0.5)
257
210
  bash scripts/publish.sh
258
211
 
259
- # Bump minor version
212
+ # Minor version
260
213
  bash scripts/publish.sh minor
261
214
 
262
- # Publish a beta pre-release
215
+ # Major version
216
+ bash scripts/publish.sh major
217
+
218
+ # Beta pre-release
263
219
  bash scripts/publish.sh --tag beta --pre beta
264
220
  ```
265
221
 
266
222
  The script will:
267
- 1. Check npm authentication (`npm login` required first)
223
+ 1. Check npm authentication
268
224
  2. Verify git working tree is clean
269
225
  3. Type-check + build
270
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 { createSession, getTraces, getSessionSummary } from './db.js';
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
- // Force no-proxy web mode — user just needs to open the browser
31
- opts.proxy = false;
32
- opts.ui = 'web';
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
- // Start Console UI refresh loop
43
- if (opts.ui === 'console' || opts.ui === 'both') {
44
- const refreshConsole = () => {
45
- const entries = getTraces(sessionId, 50);
46
- const summary = getSessionSummary(sessionId);
47
- renderConsoleTable(entries, summary ?? undefined);
48
- };
49
- traceEvents.on('trace:update', refreshConsole);
50
- traceEvents.on('trace:done', refreshConsole);
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
- // ACP Proxy — wrap copilot CLI
54
- if (opts.proxy !== false) {
55
- const copilotArgs = ['--acp', '--stdio', ...program.args];
56
- const child = spawn(opts.cmd, copilotArgs, {
57
- stdio: ['pipe', 'pipe', 'inherit'],
58
- });
59
- if (!child.pid) {
60
- console.error(`\n ❌ Failed to start: ${opts.cmd} ${copilotArgs.join(' ')}`);
61
- console.error(' Make sure GitHub Copilot CLI is installed: npm install -g @github/copilot-cli\n');
62
- process.exit(1);
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
- // Parse newline-delimited JSON (NDJSON) from copilot
65
- const stdinRl = readline.createInterface({ input: process.stdin });
66
- const stdoutRl = readline.createInterface({ input: child.stdout });
67
- const debug = opts.debug === true;
68
- const logFile = debug ? fs.createWriteStream(`/tmp/copilot-tracer-${sessionId.slice(0, 8)}.ndjson`, { flags: 'a' }) : null;
69
- function debugLog(direction, raw, parsed) {
70
- if (!debug)
71
- return;
72
- const entry = JSON.stringify({ ts: new Date().toISOString(), dir: direction, raw, parsed });
73
- process.stderr.write('[TRACER] ' + entry + '\n');
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
- // stdin copilot (user copilot = 'out' direction from user's perspective)
77
- stdinRl.on('line', (line) => {
78
- let parsed;
79
- try {
80
- parsed = JSON.parse(line);
81
- handleAcpMessage(sessionId, parsed, 'out'); // outbound = user sending to copilot
82
- }
83
- catch (e) {
84
- // Not JSON plain text from terminal, not ACP
85
- if (debug)
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
- debugLog('→ copilot', line, parsed);
89
- child.stdin.write(line + '\n');
90
- });
91
- // copilot stdout (copilot user = 'in' direction from user's perspective)
92
- stdoutRl.on('line', (line) => {
93
- let parsed;
94
- try {
95
- parsed = JSON.parse(line);
96
- handleAcpMessage(sessionId, parsed, 'in'); // inbound = copilot sending to user
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
- catch (e) {
99
- if (debug)
100
- process.stderr.write(`[TRACER] stdout non-JSON: ${line}\n`);
101
- }
102
- debugLog('← copilot', line, parsed);
103
- process.stdout.write(line + '\n');
104
- });
105
- child.on('exit', (code) => {
106
- console.log(`\n Copilot CLI exited (code ${code})\n`);
107
- process.exit(code ?? 0);
108
- });
109
- process.on('SIGINT', () => { child.kill(); process.exit(0); });
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
  }