copilot-tracer 1.0.9 → 1.0.10
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/dist/setup.js +96 -12
- package/package.json +1 -1
package/dist/setup.js
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* 1. Detect copilot CLI (which copilot)
|
|
6
6
|
* 2. Detect VS Code installation + built-in copilot (v1.99+)
|
|
7
7
|
* 3. Inject OTEL env vars into:
|
|
8
|
-
* - Shell profile
|
|
9
|
-
*
|
|
8
|
+
* - Shell profile: ~/.zshrc / ~/.bashrc / ~/.zprofile (macOS/Linux),
|
|
9
|
+
* $PROFILE — Documents\PowerShell\Microsoft.PowerShell_profile.ps1 (Windows)
|
|
10
|
+
* - VS Code settings.json (terminal.integrated.env.osx / .linux / .windows)
|
|
10
11
|
* 4. Print a summary and next steps
|
|
11
12
|
*/
|
|
12
13
|
import { execSync } from 'child_process';
|
|
@@ -23,7 +24,10 @@ const OTEL_TRACES_EXPORTER_KEY = 'OTEL_TRACES_EXPORTER';
|
|
|
23
24
|
const OTEL_PROTOCOL_KEY = 'OTEL_EXPORTER_OTLP_PROTOCOL';
|
|
24
25
|
const OTEL_LOG_PROMPTS_KEY = 'OTEL_LOG_USER_PROMPTS';
|
|
25
26
|
const OTEL_LOG_RESPONSES_KEY = 'OTEL_LOG_ASSISTANT_RESPONSES';
|
|
26
|
-
function
|
|
27
|
+
function isWindows() {
|
|
28
|
+
return process.platform === 'win32';
|
|
29
|
+
}
|
|
30
|
+
function otelEnvBlockPosix(port) {
|
|
27
31
|
return [
|
|
28
32
|
`# >>> copilot-tracer OTLP config (auto-added) >>>`,
|
|
29
33
|
`export ${OTEL_ENDPOINT_KEY}=http://localhost:${port}`,
|
|
@@ -75,6 +79,53 @@ function otelEnvBlock(port) {
|
|
|
75
79
|
`# <<< copilot-tracer <<<`,
|
|
76
80
|
].join('\n');
|
|
77
81
|
}
|
|
82
|
+
function otelEnvBlockPowerShell(port) {
|
|
83
|
+
return [
|
|
84
|
+
`# >>> copilot-tracer OTLP config (auto-added) >>>`,
|
|
85
|
+
`$env:${OTEL_ENDPOINT_KEY} = "http://localhost:${port}"`,
|
|
86
|
+
`$env:${OTEL_CONTENT_KEY} = "true"`,
|
|
87
|
+
`$env:${OTEL_ENABLED_KEY} = "true"`,
|
|
88
|
+
`$env:${CLAUDE_TELEMETRY_KEY} = "1"`,
|
|
89
|
+
`$env:${CLAUDE_TRACES_KEY} = "1"`,
|
|
90
|
+
`$env:${OTEL_LOGS_EXPORTER_KEY} = "otlp"`,
|
|
91
|
+
`$env:${OTEL_TRACES_EXPORTER_KEY} = "otlp"`,
|
|
92
|
+
`$env:${OTEL_PROTOCOL_KEY} = "http/json"`,
|
|
93
|
+
`$env:${OTEL_LOG_PROMPTS_KEY} = "1"`,
|
|
94
|
+
`$env:${OTEL_LOG_RESPONSES_KEY} = "1"`,
|
|
95
|
+
``,
|
|
96
|
+
`# Tag every copilot prompt with the terminal folder it ran from, so the`,
|
|
97
|
+
`# tracer can attribute it to the right project. OTLP carries no working-dir,`,
|
|
98
|
+
`# so we inject it via OTEL_RESOURCE_ATTRIBUTES (percent-encoded).`,
|
|
99
|
+
`function copilot {`,
|
|
100
|
+
` $_wd = (Get-Location).Path.Replace('\\','/')`,
|
|
101
|
+
` $_wd = [uri]::EscapeDataString($_wd).Replace('%2F','/')`,
|
|
102
|
+
` if ($env:OTEL_RESOURCE_ATTRIBUTES) {`,
|
|
103
|
+
` $parts = $env:OTEL_RESOURCE_ATTRIBUTES -split ',' | Where-Object { $_ -notmatch '^github\\.copilot\\.working_dir=' }`,
|
|
104
|
+
` $env:OTEL_RESOURCE_ATTRIBUTES = $parts -join ','`,
|
|
105
|
+
` if ($env:OTEL_RESOURCE_ATTRIBUTES) { $env:OTEL_RESOURCE_ATTRIBUTES += ',' }`,
|
|
106
|
+
` }`,
|
|
107
|
+
` $env:OTEL_RESOURCE_ATTRIBUTES = "$($env:OTEL_RESOURCE_ATTRIBUTES)github.copilot.working_dir=$_wd"`,
|
|
108
|
+
` $cmd = Get-Command copilot -CommandType Application,ExternalScript -ErrorAction SilentlyContinue | Select-Object -First 1`,
|
|
109
|
+
` if ($cmd) { & $cmd.Source @args } else { & copilot.cmd @args }`,
|
|
110
|
+
`}`,
|
|
111
|
+
``,
|
|
112
|
+
`function claude {`,
|
|
113
|
+
` $_wd = (Get-Location).Path.Replace('\\','/')`,
|
|
114
|
+
` $_wd = [uri]::EscapeDataString($_wd).Replace('%2F','/')`,
|
|
115
|
+
` if ($env:OTEL_RESOURCE_ATTRIBUTES) {`,
|
|
116
|
+
` $env:OTEL_RESOURCE_ATTRIBUTES += ",claude_code.working_dir=$_wd"`,
|
|
117
|
+
` } else {`,
|
|
118
|
+
` $env:OTEL_RESOURCE_ATTRIBUTES = "claude_code.working_dir=$_wd"`,
|
|
119
|
+
` }`,
|
|
120
|
+
` $cmd = Get-Command claude -CommandType Application,ExternalScript -ErrorAction SilentlyContinue | Select-Object -First 1`,
|
|
121
|
+
` if ($cmd) { & $cmd.Source @args } else { & claude.cmd @args }`,
|
|
122
|
+
`}`,
|
|
123
|
+
`# <<< copilot-tracer <<<`,
|
|
124
|
+
].join('\n');
|
|
125
|
+
}
|
|
126
|
+
function otelEnvBlock(port) {
|
|
127
|
+
return isWindows() ? otelEnvBlockPowerShell(port) : otelEnvBlockPosix(port);
|
|
128
|
+
}
|
|
78
129
|
function vscodeEnvBlock(port) {
|
|
79
130
|
return {
|
|
80
131
|
[OTEL_ENDPOINT_KEY]: `http://localhost:${port}`,
|
|
@@ -225,15 +276,33 @@ function detectVSCode() {
|
|
|
225
276
|
return { found: true, version, hasBuiltinCopilot };
|
|
226
277
|
}
|
|
227
278
|
catch {
|
|
228
|
-
// Try
|
|
229
|
-
const appPath =
|
|
230
|
-
|
|
279
|
+
// Try well-known install locations directly
|
|
280
|
+
const appPath = process.platform === 'darwin'
|
|
281
|
+
? '/Applications/Visual Studio Code.app'
|
|
282
|
+
: isWindows()
|
|
283
|
+
? path.join(process.env.LOCALAPPDATA ?? path.join(os.homedir(), 'AppData', 'Local'), 'Programs', 'Microsoft VS Code', 'Code.exe')
|
|
284
|
+
: null;
|
|
285
|
+
if (appPath && fs.existsSync(appPath)) {
|
|
231
286
|
return { found: true, hasBuiltinCopilot: true, version: 'unknown (app found)' };
|
|
232
287
|
}
|
|
233
288
|
return { found: false, hasBuiltinCopilot: false };
|
|
234
289
|
}
|
|
235
290
|
}
|
|
236
291
|
function detectShellProfile() {
|
|
292
|
+
if (isWindows()) {
|
|
293
|
+
const candidates = [
|
|
294
|
+
// PowerShell 7+ ($PROFILE for `pwsh`)
|
|
295
|
+
path.join(os.homedir(), 'Documents', 'PowerShell', 'Microsoft.PowerShell_profile.ps1'),
|
|
296
|
+
// Windows PowerShell 5.1 ($PROFILE for `powershell.exe`)
|
|
297
|
+
path.join(os.homedir(), 'Documents', 'WindowsPowerShell', 'Microsoft.PowerShell_profile.ps1'),
|
|
298
|
+
];
|
|
299
|
+
for (const p of candidates) {
|
|
300
|
+
if (fs.existsSync(p))
|
|
301
|
+
return p;
|
|
302
|
+
}
|
|
303
|
+
// Default to the PowerShell 7+ profile (create it)
|
|
304
|
+
return candidates[0];
|
|
305
|
+
}
|
|
237
306
|
const candidates = [
|
|
238
307
|
path.join(os.homedir(), '.zshrc'),
|
|
239
308
|
path.join(os.homedir(), '.zprofile'),
|
|
@@ -247,10 +316,22 @@ function detectShellProfile() {
|
|
|
247
316
|
// Default to .zshrc (create it)
|
|
248
317
|
return path.join(os.homedir(), '.zshrc');
|
|
249
318
|
}
|
|
319
|
+
/** VS Code's per-platform key for `terminal.integrated.env.*`. */
|
|
320
|
+
function getVSCodeEnvKey() {
|
|
321
|
+
if (process.platform === 'darwin')
|
|
322
|
+
return 'terminal.integrated.env.osx';
|
|
323
|
+
if (isWindows())
|
|
324
|
+
return 'terminal.integrated.env.windows';
|
|
325
|
+
return 'terminal.integrated.env.linux';
|
|
326
|
+
}
|
|
250
327
|
function getVSCodeSettingsPath() {
|
|
251
328
|
if (process.platform === 'darwin') {
|
|
252
329
|
return path.join(os.homedir(), 'Library/Application Support/Code/User/settings.json');
|
|
253
330
|
}
|
|
331
|
+
if (isWindows()) {
|
|
332
|
+
const appData = process.env.APPDATA ?? path.join(os.homedir(), 'AppData', 'Roaming');
|
|
333
|
+
return path.join(appData, 'Code', 'User', 'settings.json');
|
|
334
|
+
}
|
|
254
335
|
// Linux (and WSL)
|
|
255
336
|
return path.join(os.homedir(), '.config/Code/User/settings.json');
|
|
256
337
|
}
|
|
@@ -258,6 +339,9 @@ function getVSCodeSettingsPath() {
|
|
|
258
339
|
function patchShellProfile(profilePath, port) {
|
|
259
340
|
const content = fs.existsSync(profilePath) ? fs.readFileSync(profilePath, 'utf8') : '';
|
|
260
341
|
const block = otelEnvBlock(port);
|
|
342
|
+
// The PowerShell profile dir (Documents\PowerShell or \WindowsPowerShell) often
|
|
343
|
+
// doesn't exist yet — unlike ~/.zshrc's parent, which is always the home dir.
|
|
344
|
+
fs.mkdirSync(path.dirname(profilePath), { recursive: true });
|
|
261
345
|
// Already has our block?
|
|
262
346
|
if (content.includes('copilot-tracer OTLP config')) {
|
|
263
347
|
// Only skip if the embedded block is byte-identical to what we'd generate now —
|
|
@@ -287,7 +371,7 @@ function patchVSCodeSettings(settingsPath, port) {
|
|
|
287
371
|
catch {
|
|
288
372
|
return { action: 'skipped', reason: 'could not parse settings.json' };
|
|
289
373
|
}
|
|
290
|
-
const envKey =
|
|
374
|
+
const envKey = getVSCodeEnvKey();
|
|
291
375
|
const existing = (settings[envKey] ?? {});
|
|
292
376
|
const newEnv = vscodeEnvBlock(port);
|
|
293
377
|
// Already set correctly only if every current key/value is present — checking a
|
|
@@ -342,16 +426,17 @@ export function runSetup(port, silent = false) {
|
|
|
342
426
|
if (profilePath) {
|
|
343
427
|
const result = patchShellProfile(profilePath, port);
|
|
344
428
|
const label = path.basename(profilePath);
|
|
429
|
+
const reload = isWindows() ? `. ${profilePath}` : `source ${profilePath}`;
|
|
345
430
|
if (result.action === 'added') {
|
|
346
431
|
console.log(`\n${CHECK} Shell profile patched: ${label}`);
|
|
347
432
|
console.log(` ${ARROW} Added Copilot + Claude Code OTLP env vars`);
|
|
348
433
|
console.log(` ${ARROW} Added copilot() wrapper — tags each prompt with the terminal folder`);
|
|
349
|
-
console.log(` ${ARROW} Run:
|
|
434
|
+
console.log(` ${ARROW} Run: ${reload}`);
|
|
350
435
|
}
|
|
351
436
|
else if (result.action === 'updated') {
|
|
352
437
|
console.log(`\n${CHECK} Shell profile updated: ${label}`);
|
|
353
438
|
console.log(` ${ARROW} Updated port to ${port} + Claude Code/Copilot OTLP config`);
|
|
354
|
-
console.log(` ${ARROW} Run:
|
|
439
|
+
console.log(` ${ARROW} Run: ${reload}`);
|
|
355
440
|
}
|
|
356
441
|
else {
|
|
357
442
|
console.log(`\n${CHECK} Shell profile: already configured (${label})`);
|
|
@@ -363,7 +448,7 @@ export function runSetup(port, silent = false) {
|
|
|
363
448
|
const result = patchVSCodeSettings(settingsPath, port);
|
|
364
449
|
if (result.action === 'added') {
|
|
365
450
|
console.log(`\n${CHECK} VS Code settings patched`);
|
|
366
|
-
console.log(` ${ARROW} Added
|
|
451
|
+
console.log(` ${ARROW} Added ${getVSCodeEnvKey()} with OTEL vars`);
|
|
367
452
|
console.log(` ${ARROW} Restart VS Code to apply`);
|
|
368
453
|
}
|
|
369
454
|
else if (result.action === 'updated') {
|
|
@@ -411,10 +496,9 @@ export function runSetup(port, silent = false) {
|
|
|
411
496
|
process.env[OTEL_LOG_RESPONSES_KEY] = '1';
|
|
412
497
|
// 7. Summary
|
|
413
498
|
if (!silent) {
|
|
414
|
-
const profileBase = profilePath ? path.basename(profilePath) : '.zshrc';
|
|
415
499
|
console.log('\n────────────────────────────────────────────────');
|
|
416
500
|
console.log(' One manual step required:\n');
|
|
417
|
-
console.log(` source
|
|
501
|
+
console.log(` ${isWindows() ? `. ${profilePath}` : `source ${profilePath}`}`);
|
|
418
502
|
console.log(` (opens a new terminal already? — env is already active there)`);
|
|
419
503
|
if (vscode.found)
|
|
420
504
|
console.log('\n Restart VS Code once to pick up the new terminal env.');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "copilot-tracer",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
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",
|