copilot-tracer 1.0.5 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # copilot-tracer
2
2
 
3
- Real-time tracing and prompt-refinement companion for **GitHub Copilot CLI** and **VS Code Copilot extension**.
3
+ Real-time tracing and prompt-refinement companion for **GitHub Copilot CLI**, **Claude Code**, and **VS Code Copilot extension**.
4
4
 
5
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
 
@@ -11,7 +11,7 @@ Captures every prompt, response, token usage, AI credits, tool calls, and durati
11
11
  - **Daemon mode** — install once, run forever. Collects traces from all projects automatically
12
12
  - **Auto project detection** — detects project from `github.copilot.git.repository` in OTLP spans
13
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
14
+ - **Works everywhere** — captures GitHub Copilot CLI, Claude Code, and VS Code Copilot Chat
15
15
  - **Dashboard** — overview of all projects with token usage, credits, and session counts
16
16
  - **Live tracer** — real-time trace table per project with detail panel
17
17
  - **Prompt refinement** — rewrites prompts with stronger instructions and less noise
@@ -31,7 +31,8 @@ This will:
31
31
  1. Detect your Copilot CLI and VS Code installation
32
32
  2. Patch `~/.zshrc` with OTEL env vars
33
33
  3. Patch VS Code `settings.json` with terminal env vars
34
- 4. Start the daemon on port 4747
34
+ 4. Enable Claude Code OTLP logs/events and enhanced beta traces
35
+ 5. Start the daemon on port 4747
35
36
 
36
37
  Then apply env vars in your current shell:
37
38
 
@@ -39,7 +40,9 @@ Then apply env vars in your current shell:
39
40
  source ~/.zshrc
40
41
  ```
41
42
 
42
- Restart VS Code once. After that, the daemon collects traces from all your Copilot sessions automatically.
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.
43
46
 
44
47
  Open **http://localhost:4747** to see the dashboard.
45
48
 
@@ -51,20 +54,20 @@ Open **http://localhost:4747** to see the dashboard.
51
54
  ┌─────────────────────────────────────────────────────────┐
52
55
  │ copilot-tracer --daemon (runs once, stays running) │
53
56
  │ │
54
- │ OTLP Receiver ← Copilot CLI + VS Code │
57
+ │ OTLP Receiver ← Copilot CLI + Claude Code + VS Code │
55
58
  │ (auto-detects project from github.copilot.git.repository)│
56
59
  │ │
57
60
  │ SQLite DB → Dashboard + Live Tracer (Socket.io) │
58
61
  └─────────────────────────────────────────────────────────┘
59
62
 
60
- Copilot CLI / VS Code Copilot Chat
63
+ Copilot CLI / Claude Code / VS Code Copilot Chat
61
64
 
62
65
  │ OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4747
63
66
 
64
- POST /v1/traces (OpenTelemetry OTLP JSON)
67
+ POST /v1/traces and /v1/logs (OpenTelemetry OTLP JSON)
65
68
 
66
69
 
67
- copilot-tracer parses spans → tokens, credits, tool calls
70
+ copilot-tracer parses spans and events → tokens, credits, tool calls
68
71
 
69
72
 
70
73
  SQLite DB (~/.copilot-tracer/traces.db)
@@ -121,6 +124,7 @@ Open http://localhost:4747 after starting the daemon.
121
124
  - **Summary cards** — total projects, sessions, tokens, credits
122
125
  - **Project cards** — each project shows path, session count, tokens, credits, last active
123
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" />
124
128
 
125
129
  ---
126
130
 
@@ -138,6 +142,10 @@ Real-time trace table for a specific project.
138
142
  - Click Skills / Agents / MCPs → filtered call list
139
143
  - Real-time updates via Socket.io
140
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" />
148
+
141
149
  ---
142
150
 
143
151
  ## Prompt Refinement
@@ -173,8 +181,21 @@ Add to `~/.zshrc`:
173
181
  export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4747
174
182
  export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true
175
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
176
193
  ```
177
194
 
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
+
178
199
  For VS Code, add to `~/Library/Application Support/Code/User/settings.json`:
179
200
 
180
201
  ```json
@@ -14,6 +14,7 @@
14
14
  * chat <model> span attrs: same as above
15
15
  * User message event: github.copilot.user.message
16
16
  */
17
+ import { randomUUID } from 'crypto';
17
18
  import { upsertTrace, createSession, deleteTrace, ensureProject, ensureProjectByRepo } from './db.js';
18
19
  import { traceEvents } from './proxy.js';
19
20
  // ── Helpers ───────────────────────────────────────────────────────────────────
@@ -36,6 +37,27 @@ function nanoToMs(nano) {
36
37
  function nanoToIso(nano) {
37
38
  return new Date(nanoToMs(nano)).toISOString();
38
39
  }
40
+ function getStringAttr(attrs, ...keys) {
41
+ for (const key of keys) {
42
+ const value = getAttr(attrs, key);
43
+ if (value !== undefined && String(value).trim())
44
+ return String(value);
45
+ }
46
+ return undefined;
47
+ }
48
+ function getBodyText(body) {
49
+ if (!body)
50
+ return undefined;
51
+ if (body.stringValue !== undefined)
52
+ return body.stringValue;
53
+ if (body.intValue !== undefined)
54
+ return String(body.intValue);
55
+ if (body.doubleValue !== undefined)
56
+ return String(body.doubleValue);
57
+ if (body.boolValue !== undefined)
58
+ return String(body.boolValue);
59
+ return undefined;
60
+ }
39
61
  const inFlight = new Map(); // traceId → InFlight
40
62
  // Sessions are created lazily. Always upsert so project_id gets backfilled
41
63
  // when the session was created earlier without a project.
@@ -53,7 +75,7 @@ function resolveProjectId(repoUrl, workingDir, defaultProjectId) {
53
75
  return defaultProjectId;
54
76
  }
55
77
  function detectWorkingDir(attrs) {
56
- for (const key of ['process.working_directory', 'github.copilot.working_dir']) {
78
+ for (const key of ['process.working_directory', 'github.copilot.working_dir', 'claude_code.working_dir']) {
57
79
  const v = getAttr(attrs, key);
58
80
  if (v && String(v).trim())
59
81
  return String(v).trim();
@@ -65,6 +87,116 @@ function detectWorkingDir(attrs) {
65
87
  const pendingChatIds = new Map(); // `chat:${traceId}` → list of entryIds
66
88
  // Buffer tool calls that arrive before invoke_agent
67
89
  const pendingToolCalls = new Map(); // traceId → tool calls
90
+ const claudePromptEntries = new Map(); // prompt.id → trace entry
91
+ const claudeInteractionEntries = new Map(); // traceId → interaction entry
92
+ const CLAUDE_STATE_LIMIT = 1000;
93
+ function rememberClaudeEntry(map, key, entry) {
94
+ map.set(key, entry);
95
+ if (map.size > CLAUDE_STATE_LIMIT) {
96
+ const oldest = map.keys().next().value;
97
+ if (oldest)
98
+ map.delete(oldest);
99
+ }
100
+ }
101
+ function claudeEventId(record, attrs, eventName) {
102
+ const messageId = getStringAttr(attrs, 'message.uuid', 'tool_use_id');
103
+ const promptId = getStringAttr(attrs, 'prompt.id');
104
+ return `claude:${messageId ?? promptId ?? record.traceId ?? randomUUID()}:${eventName}`;
105
+ }
106
+ function processClaudeLogRecord(record, resourceAttrs, sessionId, projectId, workingDir) {
107
+ const attrs = record.attributes ?? [];
108
+ const eventName = getStringAttr(attrs, 'event.name') ?? getBodyText(record.body);
109
+ if (!eventName || !eventName.startsWith('claude_code.'))
110
+ return;
111
+ const eventTime = getStringAttr(attrs, 'event.timestamp');
112
+ const dateTime = eventTime ?? (record.timeUnixNano ? nanoToIso(record.timeUnixNano) : new Date().toISOString());
113
+ const promptId = getStringAttr(attrs, 'prompt.id');
114
+ const resolvedProjectId = resolveProjectId(getStringAttr(resourceAttrs, 'github.copilot.git.repository', 'vcs.repository.url'), getStringAttr(attrs, 'process.working_directory', 'github.copilot.working_dir', 'claude_code.working_dir') ?? workingDir, projectId);
115
+ const eventSessionId = getStringAttr(attrs, 'session.id') ?? sessionId;
116
+ if (eventName === 'claude_code.user_prompt') {
117
+ const entry = {
118
+ id: claudeEventId(record, attrs, 'prompt'),
119
+ sessionId: eventSessionId,
120
+ dateTime,
121
+ prompt: getStringAttr(attrs, 'prompt') ?? '[Claude Code prompt]',
122
+ tokens: { input: 0, output: 0, cached: 0, reasoning: 0, written: 0, total: 0 },
123
+ aiCredits: 0,
124
+ durationMs: 0,
125
+ toolCalls: [],
126
+ skillCount: 0,
127
+ agentCount: 0,
128
+ mcpCount: 0,
129
+ status: 'running',
130
+ };
131
+ if (promptId)
132
+ rememberClaudeEntry(claudePromptEntries, promptId, entry);
133
+ ensureSession(eventSessionId, resolvedProjectId);
134
+ upsertTrace(entry);
135
+ traceEvents.emit('trace:update', entry);
136
+ return;
137
+ }
138
+ if (eventName === 'claude_code.assistant_response') {
139
+ const existingEntry = promptId ? claudePromptEntries.get(promptId) : undefined;
140
+ const entry = existingEntry ?? {
141
+ id: claudeEventId(record, attrs, 'response'),
142
+ sessionId: eventSessionId,
143
+ dateTime,
144
+ prompt: '[Claude Code response]',
145
+ tokens: { input: 0, output: 0, cached: 0, reasoning: 0, written: 0, total: 0 },
146
+ aiCredits: 0,
147
+ durationMs: 0,
148
+ toolCalls: [],
149
+ skillCount: 0,
150
+ agentCount: 0,
151
+ mcpCount: 0,
152
+ status: 'running',
153
+ };
154
+ entry.response = getStringAttr(attrs, 'response');
155
+ entry.status = 'done';
156
+ entry.durationMs = Number(getStringAttr(attrs, 'duration_ms') ?? 0);
157
+ ensureSession(eventSessionId, resolvedProjectId);
158
+ upsertTrace(entry);
159
+ traceEvents.emit('trace:update', entry);
160
+ traceEvents.emit('trace:done', entry);
161
+ return;
162
+ }
163
+ if (eventName === 'claude_code.tool_result') {
164
+ const entry = promptId ? claudePromptEntries.get(promptId) : undefined;
165
+ if (!entry)
166
+ return;
167
+ const toolName = getStringAttr(attrs, 'tool_name') ?? 'Claude Code tool';
168
+ const toolId = getStringAttr(attrs, 'tool_use_id') ?? randomUUID();
169
+ if (entry.toolCalls.some(call => call.id === toolId))
170
+ return;
171
+ entry.toolCalls.push({
172
+ id: toolId,
173
+ name: toolName,
174
+ type: detectToolType(toolName),
175
+ input: {},
176
+ startedAt: Date.parse(dateTime),
177
+ endedAt: Date.parse(dateTime),
178
+ durationMs: Number(getStringAttr(attrs, 'duration_ms') ?? 0),
179
+ error: getStringAttr(attrs, 'error'),
180
+ });
181
+ upsertTrace(entry);
182
+ traceEvents.emit('trace:update', entry);
183
+ }
184
+ }
185
+ function processClaudeLogs(payload, defaultSessionId, projectId) {
186
+ if (!payload || !Array.isArray(payload.resourceLogs)) {
187
+ throw new Error('OTLP logs payload must contain resourceLogs');
188
+ }
189
+ for (const resourceLogs of payload.resourceLogs ?? []) {
190
+ const resourceAttrs = resourceLogs.resource?.attributes ?? [];
191
+ const sessionId = getStringAttr(resourceAttrs, 'session.id') ?? defaultSessionId;
192
+ const workingDir = detectWorkingDir(resourceAttrs);
193
+ for (const scopeLogs of resourceLogs.scopeLogs ?? []) {
194
+ for (const record of scopeLogs.logRecords ?? []) {
195
+ processClaudeLogRecord(record, resourceAttrs, sessionId, projectId, workingDir);
196
+ }
197
+ }
198
+ }
199
+ }
68
200
  function processSpans(spans, sessionId, projectId, workingDir) {
69
201
  for (const span of spans) {
70
202
  // DEBUG — log raw span to stderr when COPILOT_TRACER_DEBUG=1
@@ -75,6 +207,53 @@ function processSpans(spans, sessionId, projectId, workingDir) {
75
207
  const spanName = span.name;
76
208
  const traceId = span.traceId;
77
209
  const spanId = span.spanId;
210
+ if (spanName === 'claude_code.interaction') {
211
+ const attrs = span.attributes ?? [];
212
+ const inputTokens = Number(getAttr(attrs, 'input_tokens') ?? 0);
213
+ const outputTokens = Number(getAttr(attrs, 'output_tokens') ?? 0);
214
+ const entry = {
215
+ id: spanId,
216
+ sessionId: getStringAttr(attrs, 'session.id') ?? sessionId,
217
+ dateTime: nanoToIso(span.startTimeUnixNano),
218
+ prompt: getStringAttr(attrs, 'user_prompt') ?? '[Claude Code interaction]',
219
+ tokens: { input: inputTokens, output: outputTokens, cached: Number(getAttr(attrs, 'cache_read_tokens') ?? 0), reasoning: 0, written: outputTokens, total: inputTokens + outputTokens },
220
+ aiCredits: Number(getAttr(attrs, 'cost_usd') ?? 0),
221
+ durationMs: Number(getAttr(attrs, 'interaction.duration_ms')
222
+ ?? (nanoToMs(span.endTimeUnixNano) - nanoToMs(span.startTimeUnixNano))),
223
+ toolCalls: [],
224
+ skillCount: 0,
225
+ agentCount: 0,
226
+ mcpCount: 0,
227
+ status: (span.status?.code ?? 0) === 2 ? 'error' : 'done',
228
+ error: span.status?.message,
229
+ };
230
+ ensureSession(entry.sessionId, resolveProjectId(getAttr(attrs, 'vcs.repository.url'), detectWorkingDir(attrs) ?? workingDir, projectId));
231
+ upsertTrace(entry);
232
+ rememberClaudeEntry(claudeInteractionEntries, traceId, entry);
233
+ traceEvents.emit('trace:update', entry);
234
+ traceEvents.emit('trace:done', entry);
235
+ continue;
236
+ }
237
+ if (spanName === 'claude_code.llm_request') {
238
+ const inputTokens = Number(getAttr(attrs, 'input_tokens') ?? 0);
239
+ const outputTokens = Number(getAttr(attrs, 'output_tokens') ?? 0);
240
+ const cachedTokens = Number(getAttr(attrs, 'cache_read_tokens') ?? 0);
241
+ const entry = claudeInteractionEntries.get(traceId);
242
+ if (entry) {
243
+ entry.tokens = {
244
+ input: entry.tokens.input + inputTokens,
245
+ output: entry.tokens.output + outputTokens,
246
+ cached: entry.tokens.cached + cachedTokens,
247
+ reasoning: 0,
248
+ written: entry.tokens.written + outputTokens,
249
+ total: entry.tokens.total + inputTokens + outputTokens,
250
+ };
251
+ entry.aiCredits += Number(getAttr(attrs, 'cost_usd') ?? 0);
252
+ upsertTrace(entry);
253
+ traceEvents.emit('trace:update', entry);
254
+ }
255
+ continue;
256
+ }
78
257
  // ── invoke_agent span = top-level agent turn ──────────────────────────
79
258
  if (spanName === 'invoke_agent') {
80
259
  const startMs = nanoToMs(span.startTimeUnixNano);
@@ -426,8 +605,17 @@ export function registerOtlpRoutes(app, defaultSessionId, projectId) {
426
605
  res.status(400).json({ error: 'invalid payload' });
427
606
  }
428
607
  });
429
- // Metrics + logs accept and ignore
608
+ app.post('/v1/logs', (req, res) => {
609
+ try {
610
+ processClaudeLogs(req.body, defaultSessionId, projectId);
611
+ res.status(200).json({ partialSuccess: {} });
612
+ }
613
+ catch (e) {
614
+ console.error('[OTLP] log parse error:', e);
615
+ res.status(400).json({ error: 'invalid payload' });
616
+ }
617
+ });
618
+ // Metrics remain accepted for Claude Code dashboards but are not trace entries.
430
619
  app.post('/v1/metrics', (_req, res) => res.status(200).json({ partialSuccess: {} }));
431
- app.post('/v1/logs', (_req, res) => res.status(200).json({ partialSuccess: {} }));
432
- console.log(' 📡 OTLP receiver ready on /v1/traces');
620
+ console.log(' 📡 OTLP receiver ready on /v1/traces and /v1/logs');
433
621
  }
package/dist/setup.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * copilot-tracer setup — auto-detect copilot CLI + VS Code and inject OTLP env config
2
+ * copilot-tracer setup — auto-detect Copilot/VS Code and inject OTLP env config
3
3
  *
4
4
  * What it does:
5
5
  * 1. Detect copilot CLI (which copilot)
@@ -16,12 +16,26 @@ import os from 'os';
16
16
  const OTEL_ENDPOINT_KEY = 'OTEL_EXPORTER_OTLP_ENDPOINT';
17
17
  const OTEL_CONTENT_KEY = 'OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT';
18
18
  const OTEL_ENABLED_KEY = 'COPILOT_OTEL_ENABLED';
19
+ const CLAUDE_TELEMETRY_KEY = 'CLAUDE_CODE_ENABLE_TELEMETRY';
20
+ const CLAUDE_TRACES_KEY = 'CLAUDE_CODE_ENHANCED_TELEMETRY_BETA';
21
+ const OTEL_LOGS_EXPORTER_KEY = 'OTEL_LOGS_EXPORTER';
22
+ const OTEL_TRACES_EXPORTER_KEY = 'OTEL_TRACES_EXPORTER';
23
+ const OTEL_PROTOCOL_KEY = 'OTEL_EXPORTER_OTLP_PROTOCOL';
24
+ const OTEL_LOG_PROMPTS_KEY = 'OTEL_LOG_USER_PROMPTS';
25
+ const OTEL_LOG_RESPONSES_KEY = 'OTEL_LOG_ASSISTANT_RESPONSES';
19
26
  function otelEnvBlock(port) {
20
27
  return [
21
28
  `# >>> copilot-tracer OTLP config (auto-added) >>>`,
22
29
  `export ${OTEL_ENDPOINT_KEY}=http://localhost:${port}`,
23
30
  `export ${OTEL_CONTENT_KEY}=true`,
24
31
  `export ${OTEL_ENABLED_KEY}=true`,
32
+ `export ${CLAUDE_TELEMETRY_KEY}=1`,
33
+ `export ${CLAUDE_TRACES_KEY}=1`,
34
+ `export ${OTEL_LOGS_EXPORTER_KEY}=otlp`,
35
+ `export ${OTEL_TRACES_EXPORTER_KEY}=otlp`,
36
+ `export ${OTEL_PROTOCOL_KEY}=http/json`,
37
+ `export ${OTEL_LOG_PROMPTS_KEY}=1`,
38
+ `export ${OTEL_LOG_RESPONSES_KEY}=1`,
25
39
  ``,
26
40
  `# Tag every copilot prompt with the terminal folder it ran from, so the`,
27
41
  `# tracer can attribute it to the right project. OTLP carries no working-dir,`,
@@ -42,6 +56,22 @@ function otelEnvBlock(port) {
42
56
  ` export OTEL_RESOURCE_ATTRIBUTES`,
43
57
  ` command copilot "\$@"`,
44
58
  `}`,
59
+ ``,
60
+ `claude() {`,
61
+ ` local _wd`,
62
+ ` if command -v python3 >/dev/null 2>&1; then`,
63
+ ` _wd="$(pwd | python3 -c 'import sys,urllib.parse;print(urllib.parse.quote(sys.stdin.read().strip(), safe="/"))')"`,
64
+ ` else`,
65
+ ` _wd="$(pwd)"`,
66
+ ` fi`,
67
+ ` if [ -n "\${OTEL_RESOURCE_ATTRIBUTES:-}" ]; then`,
68
+ ` OTEL_RESOURCE_ATTRIBUTES="\${OTEL_RESOURCE_ATTRIBUTES},claude_code.working_dir=\${_wd}"`,
69
+ ` else`,
70
+ ` OTEL_RESOURCE_ATTRIBUTES="claude_code.working_dir=\${_wd}"`,
71
+ ` fi`,
72
+ ` export OTEL_RESOURCE_ATTRIBUTES`,
73
+ ` command claude "\$@"`,
74
+ `}`,
45
75
  `# <<< copilot-tracer <<<`,
46
76
  ].join('\n');
47
77
  }
@@ -50,6 +80,13 @@ function vscodeEnvBlock(port) {
50
80
  [OTEL_ENDPOINT_KEY]: `http://localhost:${port}`,
51
81
  [OTEL_CONTENT_KEY]: 'true',
52
82
  [OTEL_ENABLED_KEY]: 'true',
83
+ [CLAUDE_TELEMETRY_KEY]: '1',
84
+ [CLAUDE_TRACES_KEY]: '1',
85
+ [OTEL_LOGS_EXPORTER_KEY]: 'otlp',
86
+ [OTEL_TRACES_EXPORTER_KEY]: 'otlp',
87
+ [OTEL_PROTOCOL_KEY]: 'http/json',
88
+ [OTEL_LOG_PROMPTS_KEY]: '1',
89
+ [OTEL_LOG_RESPONSES_KEY]: '1',
53
90
  };
54
91
  }
55
92
  // ── Detection helpers ─────────────────────────────────────────────────────────
@@ -193,13 +230,13 @@ export function runSetup(port, silent = false) {
193
230
  const label = path.basename(profilePath);
194
231
  if (result.action === 'added') {
195
232
  console.log(`\n${CHECK} Shell profile patched: ${label}`);
196
- console.log(` ${ARROW} Added OTEL env vars (endpoint, content capture)`);
233
+ console.log(` ${ARROW} Added Copilot + Claude Code OTLP env vars`);
197
234
  console.log(` ${ARROW} Added copilot() wrapper — tags each prompt with the terminal folder`);
198
235
  console.log(` ${ARROW} Run: source ${profilePath}`);
199
236
  }
200
237
  else if (result.action === 'updated') {
201
238
  console.log(`\n${CHECK} Shell profile updated: ${label}`);
202
- console.log(` ${ARROW} Updated port to ${port} + copilot() wrapper`);
239
+ console.log(` ${ARROW} Updated port to ${port} + Claude Code/Copilot OTLP config`);
203
240
  console.log(` ${ARROW} Run: source ${profilePath}`);
204
241
  }
205
242
  else {
@@ -231,6 +268,13 @@ export function runSetup(port, silent = false) {
231
268
  process.env[OTEL_ENDPOINT_KEY] = `http://localhost:${port}`;
232
269
  process.env[OTEL_CONTENT_KEY] = 'true';
233
270
  process.env[OTEL_ENABLED_KEY] = 'true';
271
+ process.env[CLAUDE_TELEMETRY_KEY] = '1';
272
+ process.env[CLAUDE_TRACES_KEY] = '1';
273
+ process.env[OTEL_LOGS_EXPORTER_KEY] = 'otlp';
274
+ process.env[OTEL_TRACES_EXPORTER_KEY] = 'otlp';
275
+ process.env[OTEL_PROTOCOL_KEY] = 'http/json';
276
+ process.env[OTEL_LOG_PROMPTS_KEY] = '1';
277
+ process.env[OTEL_LOG_RESPONSES_KEY] = '1';
234
278
  // 6. Summary
235
279
  if (!silent) {
236
280
  const profileBase = profilePath ? path.basename(profilePath) : '.zshrc';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "copilot-tracer",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "Real-time tracing and prompt-refinement companion for GitHub Copilot CLI and VS Code Copilot — tracks tokens, AI credits, tool calls, and refined prompts with console and web UI",
5
5
  "keywords": [
6
6
  "copilot",
@@ -14,7 +14,7 @@
14
14
  "license": "MIT",
15
15
  "repository": {
16
16
  "type": "git",
17
- "url": "https://github.com/chuongnd/copilot-tracer.git"
17
+ "url": "https://github.com/chuongxl/copilot-tracer.git"
18
18
  },
19
19
  "engines": {
20
20
  "node": ">=18"