mirror of
https://github.com/andrepimenta/claude-code-chat.git
synced 2026-05-30 00:05:44 +08:00
Add message milestone analytics and install diagnostics metadata
Track lifetime successful messages in globalState and emit milestone events at 1, 50, 100, 200, ... Surface platform/arch on all install outcomes and split out a dedicated WSL_NOT_SUPPORTED error code. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -998,7 +998,8 @@ class ClaudeChatProvider {
|
|||||||
...process.env,
|
...process.env,
|
||||||
FORCE_COLOR: '0',
|
FORCE_COLOR: '0',
|
||||||
NO_COLOR: '1',
|
NO_COLOR: '1',
|
||||||
...customEnvVars // Apply custom environment variables (ANTHROPIC_AUTH_TOKEN, ANTHROPIC_BASE_URL, etc.)
|
...customEnvVars, // Apply custom environment variables (ANTHROPIC_AUTH_TOKEN, ANTHROPIC_BASE_URL, etc.)
|
||||||
|
CLAUDE_CODE_ENTRYPOINT: 'claude-vscode'
|
||||||
};
|
};
|
||||||
|
|
||||||
// OpenCredits: clear Anthropic-specific vars so Claude CLI uses env vars directly
|
// OpenCredits: clear Anthropic-specific vars so Claude CLI uses env vars directly
|
||||||
@@ -1031,6 +1032,7 @@ class ClaudeChatProvider {
|
|||||||
wslEnvOverrides['DISABLE_TELEMETRY'] = 'true';
|
wslEnvOverrides['DISABLE_TELEMETRY'] = 'true';
|
||||||
wslEnvOverrides['DISABLE_COST_WARNINGS'] = 'true';
|
wslEnvOverrides['DISABLE_COST_WARNINGS'] = 'true';
|
||||||
}
|
}
|
||||||
|
wslEnvOverrides['CLAUDE_CODE_ENTRYPOINT'] = 'claude-vscode';
|
||||||
const envExports = Object.entries(wslEnvOverrides)
|
const envExports = Object.entries(wslEnvOverrides)
|
||||||
.map(([k, v]) => `export ${k}="${v.replace(/"/g, '\\"')}"`)
|
.map(([k, v]) => `export ${k}="${v.replace(/"/g, '\\"')}"`)
|
||||||
.join(' && ');
|
.join(' && ');
|
||||||
@@ -1576,6 +1578,19 @@ class ClaudeChatProvider {
|
|||||||
this._totalCost += jsonData.total_cost_usd;
|
this._totalCost += jsonData.total_cost_usd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lifetime success counter — survives reloads, scoped to the
|
||||||
|
// extension globalState. Used for milestone analytics (1, 50, 100, 200, …).
|
||||||
|
try {
|
||||||
|
const prev = this._context.globalState.get<number>('lifetimeMessageSuccessCount', 0) || 0;
|
||||||
|
const next = prev + 1;
|
||||||
|
this._context.globalState.update('lifetimeMessageSuccessCount', next);
|
||||||
|
if (next === 1 || next === 50 || (next > 50 && next % 100 === 0)) {
|
||||||
|
this._postMessage({ type: 'messageMilestone', count: next });
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// best-effort — analytics shouldn't break the response path
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Send updated totals to webview
|
// Send updated totals to webview
|
||||||
this._postMessage({
|
this._postMessage({
|
||||||
@@ -3632,6 +3647,8 @@ class ClaudeChatProvider {
|
|||||||
|
|
||||||
const config = vscode.workspace.getConfiguration('claudeCodeChat');
|
const config = vscode.workspace.getConfiguration('claudeCodeChat');
|
||||||
const wslEnabled = config.get<boolean>('wsl.enabled', false);
|
const wslEnabled = config.get<boolean>('wsl.enabled', false);
|
||||||
|
const platform = process.platform;
|
||||||
|
const arch = os.arch();
|
||||||
|
|
||||||
// WSL install needs to run inside the distro, not on the Windows host.
|
// WSL install needs to run inside the distro, not on the Windows host.
|
||||||
// The old shell-based flow didn't handle this either — not regressing,
|
// The old shell-based flow didn't handle this either — not regressing,
|
||||||
@@ -3643,7 +3660,9 @@ class ClaudeChatProvider {
|
|||||||
success: false,
|
success: false,
|
||||||
method,
|
method,
|
||||||
error: 'WSL mode: please install Claude inside your WSL distro, then set claudeCodeChat.wsl.claudePath.',
|
error: 'WSL mode: please install Claude inside your WSL distro, then set claudeCodeChat.wsl.claudePath.',
|
||||||
errorCode: 'UNSUPPORTED_PLATFORM'
|
errorCode: 'WSL_NOT_SUPPORTED',
|
||||||
|
platform,
|
||||||
|
arch
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -3653,8 +3672,10 @@ class ClaudeChatProvider {
|
|||||||
type: 'installComplete',
|
type: 'installComplete',
|
||||||
success: false,
|
success: false,
|
||||||
method,
|
method,
|
||||||
error: `Unsupported platform: ${process.platform}/${os.arch()}. Install Claude manually from https://code.claude.com.`,
|
error: `Unsupported platform: ${platform}/${arch}. Install Claude manually from https://code.claude.com.`,
|
||||||
errorCode: 'UNSUPPORTED_PLATFORM'
|
errorCode: 'UNSUPPORTED_PLATFORM',
|
||||||
|
platform,
|
||||||
|
arch
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -3683,7 +3704,9 @@ class ClaudeChatProvider {
|
|||||||
configuredPath: existing ? undefined : result.binaryPath,
|
configuredPath: existing ? undefined : result.binaryPath,
|
||||||
existingPathRespected: !!existing,
|
existingPathRespected: !!existing,
|
||||||
source: result.source,
|
source: result.source,
|
||||||
version: result.version
|
version: result.version,
|
||||||
|
platform,
|
||||||
|
arch
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const d = err instanceof DownloaderError ? err : null;
|
const d = err instanceof DownloaderError ? err : null;
|
||||||
@@ -3698,7 +3721,9 @@ class ClaudeChatProvider {
|
|||||||
// analytics can bucket "both npm+cdn failed with NETWORK" vs
|
// analytics can bucket "both npm+cdn failed with NETWORK" vs
|
||||||
// "npm INTEGRITY, cdn NETWORK" etc.
|
// "npm INTEGRITY, cdn NETWORK" etc.
|
||||||
npmCode: typeof details?.npmCode === 'string' ? details.npmCode : undefined,
|
npmCode: typeof details?.npmCode === 'string' ? details.npmCode : undefined,
|
||||||
cdnCode: typeof details?.cdnCode === 'string' ? details.cdnCode : undefined
|
cdnCode: typeof details?.cdnCode === 'string' ? details.cdnCode : undefined,
|
||||||
|
platform,
|
||||||
|
arch
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2933,19 +2933,23 @@ const getScript = (isTelemetryEnabled: boolean, opencreditsApiUrl: string = 'htt
|
|||||||
if (ocOption) ocOption.style.display = opencreditsEnabled ? '' : 'none';
|
if (ocOption) ocOption.style.display = opencreditsEnabled ? '' : 'none';
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
const baseProps = { source: extra && extra.source, version: extra && extra.version };
|
const existingPathRespected = !!(extra && extra.existingPathRespected);
|
||||||
|
const autoConfigured = !!(extra && extra.configuredPath);
|
||||||
|
sendStats('Install success', {
|
||||||
|
source: extra && extra.source,
|
||||||
|
version: extra && extra.version,
|
||||||
|
platform: extra && extra.platform,
|
||||||
|
arch: extra && extra.arch,
|
||||||
|
existingPathRespected: existingPathRespected,
|
||||||
|
autoConfigured: autoConfigured
|
||||||
|
});
|
||||||
|
successEl.querySelector('.install-success-text').textContent = 'Installed';
|
||||||
if (extra && extra.configuredPath) {
|
if (extra && extra.configuredPath) {
|
||||||
sendStats('Install auto configured path', Object.assign({ existingPathRespected: !!extra.existingPathRespected }, baseProps));
|
|
||||||
successEl.querySelector('.install-success-text').textContent = 'Installed';
|
|
||||||
successEl.querySelector('.install-success-hint').textContent = 'Configured automatically. Send a message to get started.';
|
successEl.querySelector('.install-success-hint').textContent = 'Configured automatically. Send a message to get started.';
|
||||||
} else if (extra && extra.existingPathRespected) {
|
} else if (existingPathRespected) {
|
||||||
sendStats('Install success', baseProps);
|
|
||||||
successEl.querySelector('.install-success-text').textContent = 'Installed';
|
|
||||||
successEl.querySelector('.install-success-hint').textContent =
|
successEl.querySelector('.install-success-hint').textContent =
|
||||||
'Your existing executable.path setting was left unchanged. Send a message to get started.';
|
'Your existing executable.path setting was left unchanged. Send a message to get started.';
|
||||||
} else {
|
} else {
|
||||||
sendStats('Install success', baseProps);
|
|
||||||
successEl.querySelector('.install-success-text').textContent = 'Installed';
|
|
||||||
successEl.querySelector('.install-success-hint').textContent = 'Send a message to get started';
|
successEl.querySelector('.install-success-hint').textContent = 'Send a message to get started';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -2954,6 +2958,8 @@ const getScript = (isTelemetryEnabled: boolean, opencreditsApiUrl: string = 'htt
|
|||||||
errorCode: errorCode,
|
errorCode: errorCode,
|
||||||
npmCode: extra && extra.npmCode,
|
npmCode: extra && extra.npmCode,
|
||||||
cdnCode: extra && extra.cdnCode,
|
cdnCode: extra && extra.cdnCode,
|
||||||
|
platform: extra && extra.platform,
|
||||||
|
arch: extra && extra.arch,
|
||||||
error: (error || 'Unknown error').substring(0, 200)
|
error: (error || 'Unknown error').substring(0, 200)
|
||||||
});
|
});
|
||||||
successEl.querySelector('.install-success-icon').style.display = 'none';
|
successEl.querySelector('.install-success-icon').style.display = 'none';
|
||||||
@@ -2962,6 +2968,10 @@ const getScript = (isTelemetryEnabled: boolean, opencreditsApiUrl: string = 'htt
|
|||||||
successEl.querySelector('.install-success-text').textContent = 'Unsupported platform';
|
successEl.querySelector('.install-success-text').textContent = 'Unsupported platform';
|
||||||
successEl.querySelector('.install-success-hint').textContent =
|
successEl.querySelector('.install-success-hint').textContent =
|
||||||
error || 'Your platform is not supported. Install Claude manually from https://code.claude.com.';
|
error || 'Your platform is not supported. Install Claude manually from https://code.claude.com.';
|
||||||
|
} else if (errorCode === 'WSL_NOT_SUPPORTED') {
|
||||||
|
successEl.querySelector('.install-success-text').textContent = 'WSL mode';
|
||||||
|
successEl.querySelector('.install-success-hint').textContent =
|
||||||
|
error || 'Install Claude inside your WSL distro and set claudeCodeChat.wsl.claudePath.';
|
||||||
} else {
|
} else {
|
||||||
successEl.querySelector('.install-success-text').textContent = 'Installation failed';
|
successEl.querySelector('.install-success-text').textContent = 'Installation failed';
|
||||||
successEl.querySelector('.install-success-hint').textContent =
|
successEl.querySelector('.install-success-hint').textContent =
|
||||||
@@ -3807,6 +3817,10 @@ const getScript = (isTelemetryEnabled: boolean, opencreditsApiUrl: string = 'htt
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'messageMilestone':
|
||||||
|
sendStats('Message milestone', { count: message.count });
|
||||||
|
break;
|
||||||
|
|
||||||
case 'showRestoreOption':
|
case 'showRestoreOption':
|
||||||
showRestoreContainer(message.data);
|
showRestoreContainer(message.data);
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user